├── .gitignore ├── chatgpt-welcome.wav ├── requirements.txt ├── README.md └── chatgpt_agi.py /.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | -------------------------------------------------------------------------------- /chatgpt-welcome.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/speakupnl/chatgpt-agi/HEAD/chatgpt-welcome.wav -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp==3.8.4 2 | aiosignal==1.3.1 3 | async-timeout==4.0.2 4 | attrs==22.2.0 5 | certifi==2022.12.7 6 | charset-normalizer==3.1.0 7 | click==8.1.3 8 | frozenlist==1.3.3 9 | gTTS==2.3.1 10 | idna==3.4 11 | multidict==6.0.4 12 | openai==0.27.4 13 | pydub==0.25.1 14 | pyst2==0.5.1 15 | requests==2.28.2 16 | six==1.16.0 17 | tqdm==4.65.0 18 | urllib3==1.26.15 19 | yarl==1.8.2 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Asterisk ChatGPT intergration - Proof of Concept 2 | 3 | Read the blogpost about this [here](https://developer.speakup.nl/asterisk-meets-chatgpt-enhancing-telecommunications-with-ai/) 4 | 5 | A proof of concept AGI script that integrates Asterisk with ChatGPT to hold converstations with ChatGPT. 6 | 7 | ## Deployment 8 | #### Cloning and installing dependencies 9 | Clone the repo somewhere on your Asterisk system. For example, to `/usr/local/src/`: 10 | 11 | ```bash 12 | cd /usr/local/src/ 13 | git clone https://github.com/speakupnl/chatgpt-agi.git 14 | ``` 15 | 16 | Then, create a virtual environment and install the dependencies: 17 | 18 | ```bash 19 | cd chatgpt-agi 20 | python3 -m venv venv 21 | source venv/bin/activate 22 | pip3 install -r requirements.txt 23 | deactivate 24 | ``` 25 | 26 | Make sure to replace the API key in `chatgpt_agi.py` to your own. 27 | 28 | ```bash 29 | vim chatgpt_agi.py 30 | ``` 31 | 32 | #### Configuring Asterisk 33 | Copy the `chatgpt-welcome.wav` or replace it with your own. 34 | 35 | Please note, the actual path of your sounds directory may be different depending on your system. 36 | 37 | ```bash 38 | cp chatgpt-welcome.wav /usr/share/asterisk/sounds/ 39 | ``` 40 | 41 | Next, edit your `extensions.conf`. 42 | 43 | ```bash 44 | vim /etc/asterisk/extensions.conf 45 | ``` 46 | 47 | Here is an example of what the dialplan might look like. Replace the phone number to your own. 48 | 49 | ```ini 50 | exten = 31532401205,1,Noop(ChatGPT) 51 | same = n,answer() 52 | same = n,AGI(/usr/local/src/chatgpt-agi/venv/bin/python3 /usr/local/src/chatgpt-agi/openai_agi.py) 53 | ``` 54 | 55 | Reload the Asterisk dialplan 56 | 57 | ```bash 58 | asterisk -rx 'dialplan reload' 59 | ``` 60 | 61 | And call away! 62 | 63 | 64 | ## Troubleshooting 65 | If you experience any trouble, check the Asterisk console: 66 | 67 | ```bash 68 | asterisk -rvvv 69 | ``` 70 | 71 | or check the Asterisk syslog. On systems with `systemd`: 72 | 73 | ```bash 74 | journalctl -fu asterisk 75 | ``` 76 | -------------------------------------------------------------------------------- /chatgpt_agi.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/src/chatgpt-agi/venv/bin/python3 2 | 3 | import os 4 | import random 5 | import openai 6 | from gtts import gTTS 7 | from pydub import AudioSegment 8 | from asterisk.agi import AGI 9 | 10 | openai.api_key = "" 11 | 12 | messages = [ 13 | {"role": "system", "content": "You are a helpful assistant on a phone call."}, 14 | ] 15 | 16 | def send_request(prompt): 17 | 18 | response = openai.ChatCompletion.create( 19 | model="gpt-3.5-turbo", 20 | messages=messages 21 | ) 22 | 23 | response = response['choices'][0]['message']['content'] 24 | return response 25 | 26 | # Start program 27 | agi = AGI() 28 | callerId = agi.env['agi_callerid'] 29 | agi.verbose(f"call from {callerId}") 30 | filepath = "/usr/share/asterisk/sounds" 31 | 32 | # Play welcome 33 | agi.stream_file(f"{filepath}/chatgpt-welcome", "1234567890*#") 34 | 35 | while True: 36 | n = random.randint(1, 9999999999) # generate a random number between 1 and 9999999999 37 | filename = str(n).zfill(10) # pad with zeros and add extension 38 | 39 | agi.verbose("Recording started...") 40 | agi.record_file(f"{filename}", "wav", "#", 10000, 0, True, 2) 41 | 42 | agi.verbose("Recording stopped. Processing now...") 43 | 44 | # Cloud Whisper 45 | audio_file= open(f"{filepath}/{filename}.wav", "rb") 46 | result = openai.Audio.transcribe("whisper-1", audio_file) 47 | 48 | # Local hosted whisper (to use this, add `import whisper` to the top of this script and commend the two lines for 'cloud whisper') 49 | #model = whisper.load_model("base") 50 | #result = model.transcribe(f"{filepath}/{filename}.wav", fp16=False, language='Dutch') 51 | 52 | agi.verbose("I heard: " + result["text"]) 53 | prompt = result["text"] 54 | messages.append({"role": "user", "content": prompt}), 55 | 56 | # Send request to OpenAI API 57 | original_response = send_request(prompt) 58 | 59 | # Check if the API call was successful 60 | if original_response is None: 61 | agi.verbose("You broke it") 62 | exit(1) 63 | 64 | # Clean up the response 65 | response = original_response.replace('\n', ' ') 66 | response = original_response.replace('"', '\'') 67 | response = original_response.replace('[HANGUP]', '') 68 | 69 | # Return the completed text to Asterisk 70 | agi.verbose("I got back: " + response) 71 | agi.set_variable("Result", response) 72 | messages.append({"role": "assistant", "content": response}), 73 | 74 | tts = gTTS(response, lang='nl') 75 | tts.save(f"{filepath}/{filename}_response.mp3") 76 | 77 | # Load the audio file 78 | sound = AudioSegment.from_file(f"{filepath}/{filename}_response.mp3", format="mp3") 79 | 80 | # Set the sample rate to 8kHz 81 | sound = sound.set_frame_rate(8000) 82 | 83 | # Set the number of channels to mono 84 | sound = sound.set_channels(1) 85 | 86 | # Export the audio file as a WAV file 87 | sound.export(f"{filepath}/{filename}_response.wav", format="wav") 88 | 89 | agi.stream_file(f"{filepath}/{filename}_response") 90 | #agi.appexec('MP3Player', f"{filepath}/{filename}_response.mp3") 91 | 92 | os.remove(f"{filepath}/{filename}.wav") 93 | os.remove(f"{filepath}/{filename}_response.mp3") 94 | os.remove(f"{filepath}/{filename}_response.wav") 95 | 96 | if original_response.endswith("[HANGUP]"): 97 | agi.hangup() 98 | --------------------------------------------------------------------------------