Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Telegram Bot integration & Voice Prompt #1135

Closed
wants to merge 75 commits into from
Closed
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
9b20855
Make my own version
Wladastic Apr 12, 2023
62eab00
telegram bot sketch
Wladastic Apr 13, 2023
ed520e2
Merge branch 'master' into wlad-version
Wladastic Apr 13, 2023
9fc04ce
whitespace fix
Wladastic Apr 13, 2023
001f51b
reformat for linter
Wladastic Apr 13, 2023
90e0ce5
Merge pull request #1 from Wladastic/wlad-version
Wladastic Apr 13, 2023
ad36d95
Merge pull request #2 from Wladastic/master
Wladastic Apr 13, 2023
5dc86af
Merge branch 'master' into wlad-version
Wladastic Apr 13, 2023
240f614
ttt
Wladastic Apr 13, 2023
da4cabd
Merge branch 'wlad-version' of https://github.com/Wladastic/Auto-GPT …
Wladastic Apr 13, 2023
5ad4e3d
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 13, 2023
da4b434
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 13, 2023
fd26b04
speechrecognition requirement
Wladastic Apr 13, 2023
066d9f7
cleanup main
Wladastic Apr 13, 2023
c30ca78
fix main
Wladastic Apr 13, 2023
3de53e4
fix send_message in main
Wladastic Apr 13, 2023
8c67485
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 13, 2023
4e3b48d
t
Wladastic Apr 13, 2023
c25920c
fix telegram disbled
Wladastic Apr 13, 2023
3f8a64e
fix telegram disbled
Wladastic Apr 13, 2023
026f6f1
added default ENTER instead of y
Wladastic Apr 14, 2023
bbf44fb
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 14, 2023
2bbd84f
cleaner config
Wladastic Apr 14, 2023
ec46520
telegram running!
Wladastic Apr 14, 2023
9b3c700
debug listening for response
Wladastic Apr 14, 2023
c28969b
add stop and fix async
Wladastic Apr 14, 2023
015a351
Cleaner, but getting stuck on start...
Wladastic Apr 14, 2023
6d5107d
bugfixes.. but thread still blocked by ask_user method
Wladastic Apr 14, 2023
32493fb
much more work to figure out than I thought
Wladastic Apr 14, 2023
a145c80
thread block fix attempt
Wladastic Apr 15, 2023
01696b5
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 15, 2023
9188317
update
Wladastic Apr 15, 2023
feb88fb
update config
Wladastic Apr 15, 2023
df44f18
fix __main.py__ starting
Wladastic Apr 15, 2023
d6b5073
fix asyncio import
Wladastic Apr 15, 2023
a536414
telegram bot
Wladastic Apr 15, 2023
2644852
allow feedback input from telegram
Wladastic Apr 15, 2023
905079b
Merge branch 'Significant-Gravitas:master' into wlad-version
Wladastic Apr 15, 2023
5ac1b52
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 15, 2023
7ed8f3f
autogpt package fixes
Wladastic Apr 15, 2023
e8b5781
fix imports
Wladastic Apr 15, 2023
320c130
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 15, 2023
7b7fe06
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 16, 2023
a970f05
fix linting
Wladastic Apr 16, 2023
6c3abed
it works!
Wladastic Apr 16, 2023
5a31f04
last touchup and done!
Wladastic Apr 16, 2023
62d2743
remove dockerfilechange
Wladastic Apr 16, 2023
a3bd771
clean __main__.py
Wladastic Apr 16, 2023
4686a9e
Show "Thinking.." so that bot doesn't look dead.
Wladastic Apr 16, 2023
813d3b1
add message "exiting..."
Wladastic Apr 16, 2023
4d02a69
clean for pipeline
Wladastic Apr 16, 2023
1b32c22
clean for pipeline
Wladastic Apr 16, 2023
2104712
use "python autogpt/start_bot.py --gpt3only --speak" works too now
Wladastic Apr 16, 2023
f5c4ee8
listen to /stop command on ask_user too.
Wladastic Apr 16, 2023
7731c32
listen to /stop command on ask_user too.
Wladastic Apr 16, 2023
d5ed8a7
format
Wladastic Apr 16, 2023
b773b02
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 16, 2023
51465a3
change loop order to fix macos run
Wladastic Apr 16, 2023
dbe708d
fixes with new merges on master...
Wladastic Apr 16, 2023
59aebdc
tasklist instead of ps on windows
Wladastic Apr 16, 2023
513768e
Merge branch 'master' into wlad-version
Wladastic Apr 16, 2023
4085fbd
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 16, 2023
96b28de
fix response elif
Wladastic Apr 16, 2023
702e778
Merge branch 'master' into wlad-version
Wladastic Apr 17, 2023
027af8c
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 18, 2023
ce63bb7
start with python3 if no python & added /yes /no clickable options
Wladastic Apr 18, 2023
4284819
remove AUTOGPT starting now message
Wladastic Apr 18, 2023
7fe8b48
fixed black formatting error
Wladastic Apr 18, 2023
e42fc14
isort fixed && selenium macos check
Wladastic Apr 18, 2023
7864e8a
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 18, 2023
0ecda8c
Merge branch 'master' into wlad-version
Wladastic Apr 19, 2023
bf62cfd
shorten message on Error
Wladastic Apr 19, 2023
f672d3f
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 19, 2023
95b4801
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 19, 2023
d96c4da
Merge remote-tracking branch 'upstream/master' into wlad-version
Wladastic Apr 20, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,26 @@ USE_MAC_OS_TTS=False
ELEVENLABS_API_KEY=your-elevenlabs-api-key
ELEVENLABS_VOICE_1_ID=your-voice-id-1
ELEVENLABS_VOICE_2_ID=your-voice-id-2


################################################################################
### VOICE INPUT PROVIDER
################################################################################

### MAC OS
# USE_MAC_OS_VOICE_INPUT - Use Mac OS voice input or not (Default: False)
USE_MAC_OS_VOICE_INPUT=False

### GOOGLE
# GOOGLE_CLOUD_API_KEY - Google Cloud API key (Example: my-google-cloud-api-key)
GOOGLE_CLOUD_API_KEY=your-google-cloud-api-key


################################################################################
### TELEGRAM BOT
################################################################################
# TELEGRAM_BOT_TOKEN - Telegram bot token (Example: my-telegram-bot-token)
# TELEGRAM_BOT_CHAT_ID - Telegram bot chat ID (Example: my-telegram-bot-chat-id)
TELEGRAM_ENABLED=False
TELEGRAM_API_KEY=your-telegram-bot-token
TELEGRAM_CHAT_ID=your-telegram-bot-chat-id
6 changes: 5 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Use an official Python base image from the Docker Hub
FROM python:3.11-slim



# Set environment variables
ENV PIP_NO_CACHE_DIR=yes \
PYTHONUNBUFFERED=1 \
Expand All @@ -16,8 +18,10 @@ USER appuser
COPY --chown=appuser:appuser requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt

COPY --chown=appuser:appuser auto-gpt.json .
COPY --chown=appuser:appuser ai_settings.yaml .
# Copy the application files
COPY --chown=appuser:appuser scripts/ .

# Set the entrypoint
ENTRYPOINT ["python", "main.py"]
ENTRYPOINT ["python", "main.py"]
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ Pillow
coverage
flake8
numpy
SpeechRecognition
python-telegram-bot
2 changes: 1 addition & 1 deletion scripts/ai_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def __init__(self, ai_name: str="", ai_role: str="", ai_goals: list=[]) -> None:
self.ai_goals = ai_goals

# Soon this will go in a folder where it remembers more stuff about the run(s)
SAVE_FILE = os.path.join(os.path.dirname(__file__), '..', 'ai_settings.yaml')
SAVE_FILE = os.path.join(os.path.dirname(__file__), '.', 'ai_settings.yaml')

@classmethod
def load(cls: object, config_file: str=SAVE_FILE) -> object:
Expand Down
12 changes: 10 additions & 2 deletions scripts/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,20 @@ def __init__(self):
openai.api_version = self.openai_api_version

self.elevenlabs_api_key = os.getenv("ELEVENLABS_API_KEY")
self.elevenlabs_voice_1_id = os.getenv("ELEVENLABS_VOICE_1_ID")
self.elevenlabs_voice_2_id = os.getenv("ELEVENLABS_VOICE_2_ID")

self.use_mac_os_voice_input = False
self.use_mac_os_voice_input = os.getenv("USE_MAC_OS_VOICE_INPUT")

self.use_mac_os_tts = False
self.use_mac_os_tts = os.getenv("USE_MAC_OS_TTS")

self.telegram_enabled = os.getenv("TELEGRAM_ENABLED") == 'True'
self.telegram_api_key = os.getenv("TELEGRAM_API_KEY")
self.telegram_chat_id = os.getenv("TELEGRAM_CHAT_ID")

self.elevenlabs_voice_1_id = os.getenv("ELEVENLABS_VOICE_1_ID")
self.elevenlabs_voice_2_id = os.getenv("ELEVENLABS_VOICE_2_ID")

self.google_api_key = os.getenv("GOOGLE_API_KEY")
self.custom_search_engine_id = os.getenv("CUSTOM_SEARCH_ENGINE_ID")

Expand Down
27 changes: 23 additions & 4 deletions scripts/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
from logger import logger
import logging
from prompt import get_prompt
import threading

cfg = Config()
if cfg.telegram_enabled:
from telegram_chat import TelegramUtils, application


def check_openai_api_key():
Expand Down Expand Up @@ -117,6 +120,9 @@ def print_assistant_thoughts(assistant_reply):
if cfg.speak_mode and assistant_thoughts_speak:
speak.say_text(assistant_thoughts_speak)

if cfg.telegram_enabled:
TelegramUtils.send_message(assistant_thoughts_text)

return assistant_reply_json
except json.decoder.JSONDecodeError as e:
logger.error("Error: Invalid JSON\n", assistant_reply)
Expand Down Expand Up @@ -374,8 +380,22 @@ def start_interaction_loop(self):
f"Enter 'y' to authorise command, 'y -N' to run N continuous commands, 'n' to exit program, or enter feedback for {self.ai_name}...",
flush=True)
while True:
console_input = utils.clean_input(Fore.MAGENTA + "Input:" + Style.RESET_ALL)
if console_input.lower().rstrip() == "y":
if cfg.speak_mode and not cfg.telegram_enabled:
if command_name != "do_nothing":
console_input = utils.clean_input(
f"I want to {command_name}, is that okay? \n Input:", talk=True)
else:
console_input = utils.clean_input(
"I decided to just continue thinking. Is that okay? \n Input:", talk=True)
else:
if cfg.telegram_enabled:
console_input = TelegramUtils.ask_user(
f"I want to execute {command_name} and {arguments}. Is that okay?")
else:
console_input = utils.clean_input(
Fore.MAGENTA + "Input:" + Style.RESET_ALL)

if console_input.lower() == "y" or console_input.lower() == "yes" or console_input.lower() == "y -1" or console_input.lower() == "okay" or console_input.lower() == "ok":
self.user_input = "GENERATE NEXT COMMAND JSON"
break
elif console_input.lower().startswith("y -"):
Expand Down Expand Up @@ -436,6 +456,5 @@ def start_interaction_loop(self):
"system", "Unable to execute command"))
logger.typewriter_log("SYSTEM: ", Fore.YELLOW, "Unable to execute command")


if __name__ == "__main__":
main()
main()
37 changes: 27 additions & 10 deletions scripts/speak.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from threading import Lock, Semaphore
import threading
import gtts
import os
import random
from playsound import playsound
import requests
from config import Config
cfg = Config()
import gtts
import threading
from threading import Lock, Semaphore

# Default voice IDs
default_voices = ["ErXwobaYiN019PkySvjV", "EXAVITQu4vr4xnSDxMaL"]
Expand All @@ -19,8 +20,10 @@

# Use custom voice IDs if provided and not placeholders, otherwise use default voice IDs
voices = [
custom_voice_1 if custom_voice_1 and custom_voice_1 not in placeholders else default_voices[0],
custom_voice_2 if custom_voice_2 and custom_voice_2 not in placeholders else default_voices[1]
custom_voice_1 if custom_voice_1 and custom_voice_1 not in placeholders else default_voices[
0],
custom_voice_2 if custom_voice_2 and custom_voice_2 not in placeholders else default_voices[
1]
]

tts_headers = {
Expand Down Expand Up @@ -61,14 +64,28 @@ def gtts_speech(text):
os.remove("speech.mp3")


macos_voice_names = [
"Zoe (Premium)",
"Ava (Premium)",
"com.apple.speech.synthesis.voice.custom.siri.aaron",
"Samantha",
"com.apple.speech.synthesis.voice.custom.siri.riya",
"com.apple.speech.synthesis.voice.custom.siri.gordon",
"com.apple.speech.synthesis.voice.custom.siri.arthur",
"com.apple.speech.synthesis.voice.custom.siri.aidan",
"com.apple.speech.synthesis.voice.custom.siri.akash",
"com.apple.speech.synthesis.voice.custom.siri.xander",
]


def macos_tts_speech(text, voice_index=0):
if voice_index == 0:
os.system(f'say "{text}"')
os.system(f'say -v "{macos_voice_names[0]}" "{text}"')
else:
if voice_index == 1:
os.system(f'say -v "Ava (Premium)" "{text}"')
else:
os.system(f'say -v Samantha "{text}"')
random_voice_index = random.randint(0, len(macos_voice_names) - 1)
os.system(f'say -v "{macos_voice_names[random_voice_index]}" "{text}"')




def say_text(text, voice_index=0):
Expand Down
37 changes: 37 additions & 0 deletions scripts/start_bot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import asyncio
import main

from telegram.ext import CommandHandler, MessageHandler, CallbackContext, Application
from telegram.ext import filters
from telegram_chat import TelegramUtils, application, is_authorized_user, handle_response, Update
import os

main_started = False

async def start(update: Update, context: CallbackContext):
global main_started
if is_authorized_user(update):
if(main_started):
await update.message.reply_text("Already started!")
else:
main_started = True
await update.message.reply_text("Starting Auto-GPT now!")
os.system("python3 ./main.py --gpt3only --speak ")


def main():
print("Starting up...")
asyncio.run(TelegramUtils().send_message("Hello! I need you to confirm with /start to start me. <3"))
application.add_handler(CommandHandler("start", start))
application.add_handler(MessageHandler(filters.TEXT, handle_response))

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
loop.run_until_complete(application.run_polling())
except KeyboardInterrupt:
pass


if __name__ == "__main__":
main()
79 changes: 79 additions & 0 deletions scripts/telegram_chat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import asyncio
import threading
from functools import wraps
from threading import Lock, Semaphore

from config import Config
from telegram import Bot, Update
from telegram.ext import (Application, CallbackContext, MessageHandler, filters)

cfg = Config()
response_received = threading.Event()
response_text = ""

mutex_lock = Lock() # Ensure only one sound is played at a time
# The amount of sounds to queue before blocking the main thread
queue_semaphore = Semaphore(1)

application = Application.builder().token(cfg.telegram_api_key).build()


def is_authorized_user(update: Update):
return update.effective_user.id == int(cfg.telegram_chat_id)


def handle_response(update: Update, context: CallbackContext):
global response_received, response_text

if is_authorized_user(update):
response_text = update.message.text
response_received.set()

def start_listening():
print("listeing to telegram")
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
application.add_handler(MessageHandler(filters.TEXT, handle_response))
loop.run_until_complete(application.run_polling())
except KeyboardInterrupt:
pass

class TelegramUtils:
@staticmethod
async def send_message(message):
bot_token = cfg.telegram_api_key
recipient_chat_id = cfg.telegram_chat_id
await Bot(bot_token).send_message(chat_id=recipient_chat_id, text=message)

@staticmethod
def ask_user(question):
global response_received, response_text

response_received.clear()
response_text = ""

asyncio.run(TelegramUtils.send_message(question))
start_listening()

print("Waiting for response...")
response_received.wait()
return response_text



class SignalSafeEventLoop(asyncio.SelectorEventLoop):
def add_signal_handler(self, sig, callback, *args):
pass

def remove_signal_handler(self, sig):
pass


def run_in_signal_safe_loop(coro):
@wraps(coro)
def wrapper(*args, **kwargs):
loop = SignalSafeEventLoop()
asyncio.set_event_loop(loop)
return loop.run_until_complete(coro(*args, **kwargs))
return wrapper
Loading