├── .gitignore
├── README.md
├── audio
└── audio_chat.py
├── functions
├── conv_history.py
├── guide.py
├── html_guide
│ ├── btn_copy.js
│ ├── guide.css
│ └── guide.html
├── start_chatbot.py
└── start_talk.py
├── main.py
├── requirements.txt
├── ressources
├── agentis_logo.png
├── guide_button.png
├── interface_talk_settings.png
├── list_example_voices.png
└── web_chatbot.png
├── start-app.bat
└── web
├── static
└── agentis_favicon.ico
└── web_chat.py
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 | .env
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Agentis
2 | 
3 |
4 | **Agentis** is an application with an interface to facilitate the installation of Ollama to download your **AI models locally** and also has a guide of the commands to execute.
5 |
6 | Also, **Agentis** has a **dynamic web interface** with several themes and allows the user to chat with the model of their choice locally on a modern web interface, the text conversation can be saved in a CSV or HTML file.
7 |
8 | Moreover, **Agentis** use several **synthetic voices** that you allow to talk with your local models.
9 |
10 | To launch the code in python please be careful to have python install on your machine as well as all the required packages that you can find bellow.
11 |
12 |
13 | ## Run Agentis
14 |
15 | You can click on the **'start-app.bat'** and the application will **launch and make the installation automatically**.
16 |
17 | If you want to run the code from your code environment, do this :
18 |
19 | => You need to install **Python 3.11**
20 |
21 | 1-/ Clone this repository ```git clone https://github.com/nixiz0/Agentis.git```
22 |
23 | 2-/ Create your environment ```python -m venv .env```
24 |
25 | 3-/ Download required libraries ```pip install -r requirements.txt```
26 |
27 | 4- Run the main.py ```python main.py```
28 |
29 | Once the main.py is launched please follow the **installation guide** to have Ollama and launch your server as well as install your models.
30 |
31 | 
32 |
33 |
34 | ## ChatBot Info
35 |
36 | As mentioned, you can chat with your models locally (with text) once you have launched the ollama server in parallel, you have the possibility to download in CSV and HTML your conversation, the files will be downloaded in your download directory from your computer.
37 |
38 | 
39 |
40 |
41 | ## Talking with your Models
42 |
43 | 
44 |
45 | To talk to your model you must :
46 | 1. Put the model that you installed and launched in the first input.
47 |
48 | 2. Select a language, this is important because if you select the wrong language the voice recognition will not be adapted and will therefore not understand what you are saying.
49 |
50 | 3. Select from the list of all your microphones the one you want to use.
51 |
52 | 4. Select a voice from the list you have, obviously please select the synthetic voice which is adapted to your language (normally you will find next to each voice the language that the voice use).
53 |
54 | And that's it, please remember to have launched your ollama server in parallel and to have installed the local models that you want to use for this to work.
55 |
56 | **Vocal commands that you can use :**
57 | - If you said these words in the same order followed by the video you want to search for **'recherche sur youtube', 'find on youtube', 'find in youtube'**, it will launch youtube and search the video that you asked.
58 |
59 | - If you said these words in the same order **'quelle heure est-il', 'l\'heure actuelle', 'what time is it'**, it will return you the current time.
60 |
61 | - If you said these words in the same order **'date actuelle', 'date d\'aujourd\'hui', 'current date', 'today\'s date', 'date of today'**, it will return you the current date.
62 |
63 | - If you said these words in the same order **'sauvegarde notre discussion', 'sauvegarde notre conversation', 'sauvegarde la discussion', 'sauvegarde la conversation', 'save our discussion', 'save our conversation', 'save the discussion', 'save the conversation'**, it will saved all your discussion with the model on a CSV file (in your download folder).
64 |
65 | - If you said these words in the same order **'stoppe notre discussion', 'stoppe notre conversation', 'stoppe la discussion', 'stoppe la conversation', 'stop our discussion', 'stop our conversation', 'stop the discussion', 'stop the conversation'**, it will stop the conversation.
66 |
67 |
68 | ## To have more Synthetic Voices Available (on Windows)
69 |
70 | 
71 |
72 | If you want to have more synthetic voices available, on Windows you have to go to the narrator settings and you can download the voices you want.
73 |
74 | If this doesn't work and doesn't recognize the voices you have installed on the narrator settings, follow this steps :
75 | 1. Open the **Registry Editor** by pressing the **“Windows” and “R”** keys simultaneously, then type **“regedit”** and press Enter.
76 |
77 | 2. Navigate to the registry key : **HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens**.
78 |
79 | 3. Export this key to a **REG file** (with a right click on the file).
80 |
81 | 4. Open this file with a text editor and replace all occurrences of **HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech_OneCore\Voices\Tokens**
82 | with **HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SPEECH\Voices\Tokens**.
83 |
84 | 5. Save the modified file and double-click it to import the changes to the registry.
85 |
86 |
87 | ## Tech Used
88 |
89 | **AI-Models:** Ollama (version 0.1.20 minimum)
90 |
91 | **Interface:** Tkinter
92 |
93 | **Talk with AI:** pyaudio (detect audio devices) / pyttsx3 (text-to-speech conversion) / speech_recognition (recognize voice and translate to text)
94 |
95 | **Computer Commands:** pywhatkit (search on youtube videos)
96 |
97 |
98 | ## Author
99 |
100 | - [@nixiz0](https://github.com/nixiz0)
--------------------------------------------------------------------------------
/audio/audio_chat.py:
--------------------------------------------------------------------------------
1 | import csv
2 | import pyttsx3
3 | import speech_recognition as sr
4 | import pywhatkit
5 | import requests
6 | import json
7 | import os
8 | import datetime
9 |
10 |
11 | def start_talk_chatbot(model, language="en-EN", mic_index=0, voice_id='HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\MSTTS_V110_enGB_HazelM'):
12 | url = "http://localhost:11434/api/chat"
13 | headers = {'Content-Type': "application/json",}
14 | conversation_history = []
15 |
16 | # Initialize the text-to-speech engine
17 | engine = pyttsx3.init()
18 |
19 | # Set the selected voice
20 | engine.setProperty('voice', voice_id)
21 |
22 | # Initialize the voice recognizer
23 | recognizer = sr.Recognizer()
24 |
25 | def beforeSay(response):
26 | return response
27 |
28 | def say(response):
29 | if len(response) == 0:
30 | return
31 | engine.say(beforeSay(response))
32 | engine.runAndWait()
33 |
34 | def generate_response(prompt, chat_history):
35 | if len(prompt) == 0:
36 | return "", chat_history
37 |
38 | full_prompt = []
39 | for i in chat_history:
40 | full_prompt.append({
41 | "role": "user",
42 | "content": i[0]
43 | })
44 | full_prompt.append({
45 | "role": "assistant",
46 | "content": i[1]
47 | })
48 | full_prompt.append({
49 | "role": "user",
50 | "content": prompt
51 | })
52 |
53 | data = {
54 | "model": model,
55 | "stream": True,
56 | "messages": full_prompt,
57 | }
58 |
59 | response = requests.post(url, headers=headers, data=json.dumps(data), stream=True)
60 |
61 | if response.status_code == 200:
62 | print('\nAssistant:', end='')
63 | all_response = ''
64 | this_response = ''
65 | for line in response.iter_lines():
66 | if line:
67 | jsonData = json.loads(line)
68 | this_response += jsonData["message"]['content']
69 | if '.' in this_response or '?' in this_response or '!' in this_response:
70 | print(f'{this_response}', end='')
71 | say(this_response)
72 | all_response += this_response
73 | this_response = ''
74 | if len(this_response) > 0:
75 | print(f'{this_response}', end='')
76 | say(this_response)
77 | all_response += this_response
78 | this_response = ''
79 | chat_history.append((prompt, all_response))
80 |
81 | return "", chat_history
82 | else:
83 | return "Error: Unable to fetch response", chat_history
84 |
85 | def save_conversation(conversation_history):
86 | filename = f"conversation_history.csv"
87 | with open(os.path.join(os.path.expanduser('~'), 'Downloads', filename), 'w', newline='', encoding='utf-8') as file:
88 | writer = csv.writer(file)
89 | writer.writerow(["User", "Assistant"])
90 | for chat in conversation_history:
91 | writer.writerow([chat[0], chat[1]])
92 |
93 | while True:
94 | with sr.Microphone(device_index=mic_index) as source:
95 | print("\nListening...")
96 | audio = recognizer.listen(source)
97 |
98 | try:
99 | # Recognize user voice
100 | user_input = recognizer.recognize_google(audio, language=language)
101 | print("\nUser: " + user_input)
102 |
103 | # Check if the user wants to search in YouTube a video
104 | detect_youtube_keywords = ['recherche sur youtube', 'find on youtube', 'find in youtube']
105 | if any(keyword in user_input.lower() for keyword in detect_youtube_keywords):
106 | ytb_command = user_input.replace('Open YouTube and find', '')
107 | pywhatkit.playonyt(ytb_command)
108 | continue
109 |
110 | # Check if the user wants to check the time
111 | detect_time_keywords = ['quelle heure est-il', 'l\'heure actuelle', 'what time is it']
112 | if any(keyword in user_input.lower() for keyword in detect_time_keywords):
113 | engine.say(datetime.datetime.now().strftime('%H:%M:%S'))
114 | engine.runAndWait()
115 | continue
116 |
117 | # Check if the user wants to check the date
118 | detect_datetime_keywords = ['date actuelle', 'date d\'aujourd\'hui',
119 | 'current date', 'today\'s date', 'date of today'
120 | ]
121 | if any(keyword in user_input.lower() for keyword in detect_datetime_keywords):
122 | current_datetime = datetime.datetime.now()
123 | formatted_datetime = current_datetime.strftime('%A %d %B %Y - %H:%M')
124 | engine.say(formatted_datetime)
125 | engine.runAndWait()
126 | continue
127 |
128 | # Check if the user wants to save the conversation
129 | detect_save_keyords = ['sauvegarde notre discussion', 'sauvegarde notre conversation', 'sauvegarde la discussion', 'sauvegarde la conversation',
130 | 'save our discussion', 'save our conversation', 'save the discussion', 'save the conversation',
131 | ]
132 | if any(keyword in user_input.lower() for keyword in detect_save_keyords):
133 | save_conversation(conversation_history)
134 | print("Conversation saved.")
135 | continue
136 |
137 | # Check if the user wants to stop the conversation
138 | detect_stop_keyords = ['stoppe notre discussion', 'stoppe notre conversation', 'stoppe la discussion', 'stoppe la conversation',
139 | 'stop our discussion', 'stop our conversation', 'stop the discussion', 'stop the conversation',
140 | ]
141 | if any(keyword in user_input.lower() for keyword in detect_stop_keyords):
142 | engine.say("Okay Bye")
143 | engine.runAndWait()
144 | print("Stopping the conversation.")
145 | break
146 |
147 | # Generate a response
148 | user_input_str = str(user_input)
149 | _, chat_history = generate_response(user_input_str, conversation_history)
150 |
151 | except sr.UnknownValueError:
152 | print("Google Speech Recognition could not understand audio")
153 | except sr.RequestError as e:
154 | print("Could not request results from Google Speech Recognition service; {0}".format(e))
--------------------------------------------------------------------------------
/functions/conv_history.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import subprocess
4 |
5 |
6 | def conversation_history():
7 | if sys.platform.startswith('linux') or sys.platform.startswith('darwin'):
8 | download_folder = os.path.expanduser("~") + "/Downloads"
9 | if os.path.isdir(download_folder):
10 | if sys.platform.startswith('linux'):
11 | # For Linux
12 | subprocess.Popen(['xdg-open', download_folder])
13 | elif sys.platform.startswith('darwin'):
14 | # For MacOS
15 | subprocess.Popen(['open', download_folder])
16 | else:
17 | print("Download folder not found.")
18 | elif sys.platform.startswith('win'):
19 | # For Windows
20 | subprocess.Popen(['explorer', os.path.join(os.path.expanduser("~"), "Downloads")])
21 | else:
22 | print("Unsupported operating system.")
--------------------------------------------------------------------------------
/functions/guide.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 | import requests
4 | import webbrowser
5 | import subprocess
6 |
7 |
8 | def open_html_file(file_path):
9 | webbrowser.open(f"file://{os.path.realpath(file_path)}")
10 |
11 | def installation_guide():
12 | html_file_path = "functions/html_guide/guide.html"
13 | try:
14 | # Checks if WSL is installed
15 | wsl_install = subprocess.run(["wsl", "-l"], capture_output=True, text=True)
16 | if wsl_install.returncode != 0:
17 | # Download and install WSL if not already done
18 | subprocess.run(["wsl", "--install"], check=True)
19 | subprocess.run(["wsl", "sudo", "apt", "update", "&&", "sudo", "apt", "upgrade"], check=True)
20 | open_html_file(html_file_path)
21 | else:
22 | print("WSL is already installed.")
23 | open_html_file(html_file_path)
24 |
25 | except subprocess.CalledProcessError as e:
26 | print(f"An error has occurred: {e}")
27 |
28 |
--------------------------------------------------------------------------------
/functions/html_guide/btn_copy.js:
--------------------------------------------------------------------------------
1 | // Sélectionner tous les éléments avec la classe "command"
2 | const commandElements = document.querySelectorAll('.command');
3 |
4 | // Pour chaque élément, ajouter un bouton de copie
5 | commandElements.forEach(element => {
6 | const copyButton = document.createElement('button');
7 | copyButton.innerHTML = '+';
8 | copyButton.classList.add('copy-button');
9 |
10 | // Créer un gestionnaire d'événements pour le clic sur le bouton de copie
11 | copyButton.addEventListener('click', (event) => {
12 | const textToCopy = element.textContent.trim();
13 |
14 | // Créer un texte temporaire pour copier le texte sans inclure le bouton
15 | const tempElem = document.createElement('textarea');
16 | tempElem.value = textToCopy;
17 | document.body.appendChild(tempElem);
18 | tempElem.select();
19 | document.execCommand('copy');
20 | document.body.removeChild(tempElem);
21 | });
22 |
23 | // Ajouter le bouton de copie à côté de l'élément
24 | element.parentNode.insertBefore(copyButton, element.nextSibling);
25 | });
26 |
--------------------------------------------------------------------------------
/functions/html_guide/guide.css:
--------------------------------------------------------------------------------
1 | ::-webkit-scrollbar {
2 | width: 14px;
3 | }
4 |
5 | ::-webkit-scrollbar-track {
6 | background-color: #4c4c4c;
7 | }
8 |
9 | ::-webkit-scrollbar-thumb {
10 | background-color: #292929;
11 | border-radius: 6px;
12 | border: 3px solid #ffffff;
13 | }
14 |
15 | html, body {
16 | margin: 0;
17 | padding: 0;
18 | list-style: none;
19 | font-family: 'Times New Roman', Times, serif;
20 | }
21 |
22 | body {
23 | background-color: #384454;
24 | color: white;
25 | text-shadow: 0px 0px 4px #000000;
26 | }
27 |
28 | ul, ol {
29 | list-style: none;
30 | }
31 |
32 | a {
33 | text-decoration: none;
34 | text-shadow: 0px 0px 4px #000000;
35 | color: cyan;
36 | }
37 |
38 | .main {
39 | text-align: center;
40 | font-size: 3vh;
41 | }
42 |
43 | .agentis_logo {
44 | margin-top: 1em;
45 | }
46 |
47 | .agentis_logo img {
48 | width: 10vh;
49 | height: auto;
50 | }
51 |
52 | h1 {
53 | color: cyan;
54 | text-shadow: 0px 0px 4px #000000;
55 | }
56 |
57 | h3 {
58 | text-decoration: underline;
59 | }
60 |
61 | .shell_explain {
62 |
63 | }
64 |
65 | .command {
66 | color: #1ec91e;
67 | position: relative;
68 | }
69 |
70 | .attention {
71 | color: red;
72 | font-size: 1.45em;
73 | }
74 |
75 | .basic_title {
76 | color: #ff8400;
77 | font-size: 1.45em;
78 | }
79 |
80 | .shell_details, .download_models {
81 | margin-top: 3em;
82 | }
83 |
84 | /* Styles pour le bouton de copie */
85 | .copy-button {
86 | cursor: pointer;
87 | padding: 4px 7px;
88 | background-color: #767676;
89 | color: white;
90 | border: none;
91 | border-radius: 5px;
92 | margin-left: 5px;
93 | font-size: 0.6em;
94 | }
95 |
96 | .copy-button:hover {
97 | background-color: #696969;
98 | }
99 |
100 | .copy-button:active {
101 | background-color: #565656;
102 | }
103 |
--------------------------------------------------------------------------------
/functions/html_guide/guide.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Agentis Guide
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
Installation Guide of Agentis
17 |
18 |
19 |
Open Ubuntu Shell and run this commands :
20 |
21 |
curl https://ollama.ai/install.sh | sh
22 |
ollama serve
23 |
24 |
25 | Attention
26 |
27 | If you have this message :
28 |
29 | Error: listen tcp 127.0.0.1:11434: bind: address already in use
30 |
31 |
32 | Then execute this command :
33 |
34 | sudo systemctl stop ollama
35 |
36 |
37 | (Sudo will ask your user password
38 |
39 | that you set when installing WSL for Ubuntu)
40 |
41 |
42 |
43 |
44 |
Download & Use Local Models
45 |
46 | You click on Start button
47 |
48 | On the input you have to enter the model you want
49 |
50 | Attention
51 |
52 | You have to download previously the model in your machine
53 |
54 | How ?
55 |
56 | Go on this website : ollama.ai/library.
57 |
58 | Find models you want, and go in your Ubuntu shell and run :
59 |
60 | ollama pull 'name model'
61 |
62 | You can return on Agentis Menu and click on start
63 |
64 | Then put on the input the name of one model that you have downloaded
65 |
66 | If you want to see all the models that you have downloaded
67 |
68 | Run this command on your Ubuntu shell :
69 |
70 | ollama list
71 |
72 |
73 | Download History
74 |
75 | The HTML History button allows you to download your conversation
76 |
77 | with your model and stores it in your "download" folder on your computer
78 |
79 | The CSV History button allows you to download your conversation
80 |
81 | with your model and stores it in your "download" folder on your computer
82 |
83 | Also you have on the app interface in Python the
84 |
85 | button "Open History"
86 |
87 | which allows direct access to the download file where
88 |
89 | you will find your histories in html and or csv
90 |