khulnasoft commited on
Commit
9b674e9
·
verified ·
1 Parent(s): 41af403

Upload 48 files

Browse files
Files changed (49) hide show
  1. .gitattributes +1 -0
  2. example_use_cases/workday_summerizer.md +55 -0
  3. gpt_computer_assistant/__init__.py +7 -0
  4. gpt_computer_assistant/agent/__init__.py +4 -0
  5. gpt_computer_assistant/agent/agent.py +80 -0
  6. gpt_computer_assistant/agent/agent_tools.py +56 -0
  7. gpt_computer_assistant/agent/assistant.py +247 -0
  8. gpt_computer_assistant/agent/background.py +15 -0
  9. gpt_computer_assistant/agent/chat_history.py +22 -0
  10. gpt_computer_assistant/agent/process.py +266 -0
  11. gpt_computer_assistant/agentic.py +34 -0
  12. gpt_computer_assistant/api.py +198 -0
  13. gpt_computer_assistant/audio/__init__.py +1 -0
  14. gpt_computer_assistant/audio/record.py +140 -0
  15. gpt_computer_assistant/audio/stt.py +65 -0
  16. gpt_computer_assistant/audio/tts.py +77 -0
  17. gpt_computer_assistant/audio/wake_word.py +37 -0
  18. gpt_computer_assistant/custom_callback.py +19 -0
  19. gpt_computer_assistant/display_tools.py +220 -0
  20. gpt_computer_assistant/gpt_computer_assistant.py +1125 -0
  21. gpt_computer_assistant/gui/__init__.py +0 -0
  22. gpt_computer_assistant/gui/button.py +165 -0
  23. gpt_computer_assistant/gui/llmsettings.py +236 -0
  24. gpt_computer_assistant/gui/settings.py +352 -0
  25. gpt_computer_assistant/gui/signal.py +28 -0
  26. gpt_computer_assistant/llm.py +71 -0
  27. gpt_computer_assistant/llm_settings.py +71 -0
  28. gpt_computer_assistant/remote.py +59 -0
  29. gpt_computer_assistant/screen/__init__.py +0 -0
  30. gpt_computer_assistant/screen/shot.py +49 -0
  31. gpt_computer_assistant/standard_tools.py +218 -0
  32. gpt_computer_assistant/start.py +57 -0
  33. gpt_computer_assistant/teams.py +274 -0
  34. gpt_computer_assistant/tooler.py +25 -0
  35. gpt_computer_assistant/top_bar_wrapper.py +19 -0
  36. gpt_computer_assistant/utils/db.py +428 -0
  37. gpt_computer_assistant/utils/media/Audio.png +0 -0
  38. gpt_computer_assistant/utils/media/Down.png +0 -0
  39. gpt_computer_assistant/utils/media/Microphone.png +0 -0
  40. gpt_computer_assistant/utils/media/SF-Pro-Text-Bold.otf +3 -0
  41. gpt_computer_assistant/utils/media/Screenshot.png +0 -0
  42. gpt_computer_assistant/utils/media/Up.png +0 -0
  43. gpt_computer_assistant/utils/media/icon.ico +0 -0
  44. gpt_computer_assistant/utils/media/icon_16.png +0 -0
  45. gpt_computer_assistant/utils/media/icon_24.png +0 -0
  46. gpt_computer_assistant/utils/media/icon_256.png +0 -0
  47. gpt_computer_assistant/utils/media/icon_32.png +0 -0
  48. gpt_computer_assistant/utils/media/icon_48.png +0 -0
  49. gpt_computer_assistant/utils/telemetry.py +49 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ gpt_computer_assistant/utils/media/SF-Pro-Text-Bold.otf filter=lfs diff=lfs merge=lfs -text
example_use_cases/workday_summerizer.md ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Introduction
2
+ In this example we have an idea to summerize whole day of an employee via GPT Computer Assistant.
3
+
4
+
5
+
6
+ # Code
7
+ ```console
8
+ computerassistant --api
9
+ ```
10
+
11
+
12
+ ```python
13
+ from gpt_computer_assistant.remote import remote
14
+
15
+
16
+
17
+ remote.profile("Screen Analysis")
18
+
19
+ # We will loop for 5 minutes
20
+
21
+ loop_results = []
22
+
23
+
24
+ for i in range(1000):
25
+ remote.reset_memory()
26
+
27
+ remote.just_screenshot()
28
+
29
+ detailed_analyses = remote.input("What is in the scren, detailed analyses")
30
+ app_name = remote.input("What is the app that the employee is using?")
31
+ subject = remote.input("What is the subject of this usage of the app?")
32
+ activity = remote.input("What is the employee doing now?")
33
+ loop_results.append({"detailed_analyses": detailed_analyses, "app_name": app_name, "subject": subject, "activity": activity})
34
+
35
+
36
+ remote.wait(10)
37
+
38
+
39
+ # Summery of the work day
40
+
41
+ summery_results = []
42
+
43
+ remote.profile("Summerizer")
44
+ remote.reset_memory()
45
+ for i in loop_results:
46
+
47
+ total_string = i["detailed_analyses"] + " " + i["app_name"] + " " + i["subject"] + " " + i["activity"]
48
+ total_string = "Please summerize the work day" + total_string
49
+ summerized = remote.input(total_string)
50
+ summery_results.append(summerized)
51
+
52
+
53
+ print("Summery: ", summery_results)
54
+
55
+ ```
gpt_computer_assistant/__init__.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from .start import start
2
+
3
+ from .agentic import Agent
4
+
5
+ from .tooler import Tool
6
+
7
+ __version__ = '0.19.1'
gpt_computer_assistant/agent/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ from .agent import *
2
+ from .assistant import *
3
+ from .background import *
4
+ from .chat_history import *
gpt_computer_assistant/agent/agent.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ try:
2
+ from ..llm import get_model
3
+ from ..utils.db import *
4
+ from ..llm_settings import llm_settings
5
+ from ..tooler import *
6
+ from ..display_tools import *
7
+ from ..teams import *
8
+ from .agent_tools import get_tools
9
+ except ImportError:
10
+ from llm import get_model
11
+ from utils.db import *
12
+ from llm_settings import llm_settings
13
+ from tooler import *
14
+ from display_tools import *
15
+ from teams import *
16
+ from agent_tools import get_tools
17
+
18
+
19
+ from langchain.agents import AgentExecutor, create_json_chat_agent
20
+
21
+
22
+ from langgraph.prebuilt import chat_agent_executor
23
+
24
+
25
+ custom_tools = []
26
+
27
+
28
+
29
+
30
+ prompt_cache = {}
31
+
32
+
33
+ def get_prompt(name):
34
+ global prompt_cache
35
+ if name in prompt_cache:
36
+ return prompt_cache[name]
37
+ else:
38
+ from langchain import hub
39
+
40
+ prompt = hub.pull(name)
41
+ prompt_cache[name] = prompt
42
+ return prompt
43
+
44
+
45
+
46
+ def get_agent_executor():
47
+ global custom_tools
48
+ tools = get_tools()
49
+ tools += custom_tools
50
+
51
+ if is_predefined_agents_setting_active():
52
+ try:
53
+ import crewai
54
+ tools += [search_on_internet_and_report_team, generate_code_with_aim_team]
55
+ except ImportError:
56
+ pass
57
+
58
+
59
+ model = load_model_settings()
60
+
61
+
62
+ if llm_settings[model]["provider"] == "openai":
63
+ tools += [click_on_a_text_on_the_screen, click_on_a_icon_on_the_screen, move_on_a_text_on_the_screen, move_on_a_icon_on_the_screen, mouse_scroll]
64
+
65
+
66
+ if llm_settings[model]["provider"] == "openai" or llm_settings[model]["provider"] == "groq":
67
+ return chat_agent_executor.create_tool_calling_executor(get_model(), tools)
68
+
69
+
70
+
71
+ if llm_settings[model]["provider"] == "ollama":
72
+ from langchain import hub
73
+
74
+ prompt = get_prompt("hwchase17/react-chat-json")
75
+ the_agent = create_json_chat_agent(get_model(), tools, prompt)
76
+ return AgentExecutor(
77
+ agent=the_agent, tools=tools, verbose=True, handle_parsing_errors=True
78
+ )
79
+
80
+
gpt_computer_assistant/agent/agent_tools.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ try:
2
+ from ..utils.db import *
3
+ from ..tooler import *
4
+ from ..display_tools import *
5
+ from ..teams import *
6
+ except ImportError:
7
+
8
+ from utils.db import *
9
+
10
+ from tooler import *
11
+ from display_tools import *
12
+ from teams import *
13
+
14
+
15
+
16
+ custom_tools = []
17
+
18
+
19
+
20
+ def load_tiger_tools():
21
+ try:
22
+ from upsonic import Tiger
23
+ tools = Tiger()
24
+ tools.enable_auto_requirements = True
25
+ tools = tools.langchain()
26
+ return tools
27
+ except:
28
+ return False
29
+
30
+
31
+ def load_default_tools():
32
+ from ..standard_tools import get_standard_tools
33
+ return get_standard_tools()
34
+
35
+
36
+
37
+
38
+ cached_tiger_tools = None
39
+
40
+ def get_tiger_tools():
41
+ global cached_tiger_tools
42
+ if cached_tiger_tools is None:
43
+ cached_tiger_tools = load_tiger_tools()
44
+ return cached_tiger_tools
45
+
46
+ if is_online_tools_setting_active():
47
+ get_tiger_tools()
48
+
49
+ def get_tools():
50
+ if is_online_tools_setting_active():
51
+ tools = get_tiger_tools()
52
+ if not tools:
53
+ tools = load_default_tools()
54
+ else:
55
+ tools = load_default_tools()
56
+ return tools
gpt_computer_assistant/agent/assistant.py ADDED
@@ -0,0 +1,247 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_core.messages import HumanMessage, SystemMessage, AIMessage
2
+
3
+ from .chat_history import *
4
+ from .agent import *
5
+
6
+
7
+ try:
8
+ from ..screen.shot import *
9
+ from ..utils.db import load_model_settings, agents
10
+ from ..llm import get_model
11
+ from ..llm_settings import each_message_extension, llm_settings
12
+ except ImportError:
13
+ from screen.shot import *
14
+ from utils.db import load_model_settings, agents
15
+ from llm import get_model
16
+ from llm_settings import each_message_extension, llm_settings
17
+
18
+ config = {"configurable": {"thread_id": "abc123"}}
19
+
20
+
21
+ def agentic(
22
+ llm_input, llm_history, client, screenshot_path=None, dont_save_image=False
23
+ ):
24
+ global agents
25
+ from crewai import Task, Crew
26
+
27
+ from crewai import Agent as crewai_Agent
28
+
29
+ the_agents = []
30
+
31
+ for each in agents:
32
+ the_agents.append(
33
+ crewai_Agent(
34
+ role=each["role"],
35
+ goal=each["goal"],
36
+ backstory=each["backstory"],
37
+ llm=get_model(high_context=True),
38
+ )
39
+ )
40
+
41
+ agents = the_agents
42
+
43
+ print("LLM INPUT", llm_input)
44
+
45
+ def image_explaination():
46
+ the_message = [
47
+ {"type": "text", "text": "Explain the image"},
48
+ ]
49
+
50
+ if screenshot_path:
51
+ base64_image = encode_image(screenshot_path)
52
+ the_message.append(
53
+ {
54
+ "type": "image_url",
55
+ "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"},
56
+ },
57
+ )
58
+ print("LEN OF İMAGE", len(base64_image))
59
+
60
+ the_message = HumanMessage(content=the_message)
61
+ get_chat_message_history().add_message(the_message)
62
+
63
+ the_model = load_model_settings()
64
+
65
+ if llm_settings[the_model]["provider"] == "openai":
66
+ msg = get_agent_executor().invoke(
67
+ {"messages": llm_history + [the_message]}, config=config
68
+ )
69
+
70
+ if llm_settings[the_model]["provider"] == "google":
71
+ msg = get_agent_executor().invoke(
72
+ {"messages": llm_history + [the_message]}, config=config
73
+ )
74
+
75
+ if llm_settings[the_model]["provider"] == "ollama":
76
+
77
+ msg = get_agent_executor().invoke(
78
+ {
79
+ "input": the_message,
80
+ "chat_history": llm_history,
81
+ }
82
+ )
83
+
84
+ the_last_messages = msg["messages"]
85
+
86
+ return the_last_messages[-1].content
87
+
88
+ if screenshot_path:
89
+ image_explain = image_explaination()
90
+ llm_input += "User Sent Image and image content is: " + image_explain
91
+
92
+
93
+
94
+ llm_input = llm_input + each_message_extension
95
+
96
+
97
+ task = Task(
98
+ description=llm_input, expected_output="Answer", agent=agents[0], tools=get_tools()
99
+ )
100
+
101
+ the_crew = Crew(
102
+ agents=agents,
103
+ tasks=[task],
104
+ full_output=True,
105
+ verbose=True,
106
+ )
107
+
108
+ result = the_crew.kickoff()["final_output"]
109
+
110
+ get_chat_message_history().add_message(HumanMessage(content=[llm_input.replace(each_message_extension, "")]))
111
+ get_chat_message_history().add_message(AIMessage(content=[result]))
112
+
113
+ return result
114
+
115
+
116
+ def assistant(
117
+ llm_input, llm_history, client, screenshot_path=None, dont_save_image=False
118
+ ):
119
+
120
+ if len(agents) != 0:
121
+ print("Moving to Agentic")
122
+ return agentic(llm_input, llm_history, client, screenshot_path, dont_save_image)
123
+
124
+ print("LLM INPUT", llm_input)
125
+
126
+ llm_input = llm_input + each_message_extension
127
+
128
+ the_message = [
129
+ {"type": "text", "text": f"{llm_input}"},
130
+ ]
131
+
132
+ if screenshot_path:
133
+ base64_image = encode_image(screenshot_path)
134
+ the_message.append(
135
+ {
136
+ "type": "image_url",
137
+ "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"},
138
+ },
139
+ )
140
+ print("LEN OF IMAGE", len(base64_image))
141
+
142
+
143
+
144
+ the_message = HumanMessage(content=the_message)
145
+ get_chat_message_history().add_message(the_message)
146
+
147
+ the_model = load_model_settings()
148
+
149
+ if llm_settings[the_model]["provider"] == "openai":
150
+ msg = get_agent_executor().invoke(
151
+ {"messages": llm_history + [the_message]}, config=config
152
+ )
153
+
154
+ if llm_settings[the_model]["provider"] == "google":
155
+ the_history = []
156
+ for message in llm_history:
157
+ try:
158
+
159
+ if isinstance(message, SystemMessage):
160
+ the_mes = HumanMessage(content=message.content[0]["text"])
161
+ the_history.append(the_mes)
162
+ elif isinstance(message, HumanMessage):
163
+ the_mes = HumanMessage(content=message.content[0]["text"])
164
+ the_history.append(the_mes)
165
+ else:
166
+ the_mes = AIMessage(content=message.content[0]["text"])
167
+ the_history.append(the_mes)
168
+ except:
169
+ the_mes = AIMessage(content=message.content)
170
+ the_history.append(the_mes)
171
+
172
+ llm_input += each_message_extension
173
+
174
+ the_last_message = HumanMessage(content=llm_input)
175
+ msg = get_agent_executor().invoke(
176
+ {"messages": the_history + [the_last_message]}, config=config
177
+ )
178
+
179
+ elif llm_settings[the_model]["provider"] == "groq":
180
+ the_history = []
181
+ for message in llm_history:
182
+ try:
183
+
184
+ if isinstance(message, SystemMessage):
185
+ the_mes = SystemMessage(content=message.content[0]["text"])
186
+ the_history.append(the_mes)
187
+ elif isinstance(message, HumanMessage):
188
+ the_mes = HumanMessage(content=message.content[0]["text"])
189
+ the_history.append(the_mes)
190
+ else:
191
+ the_mes = AIMessage(content=message.content[0]["text"])
192
+ the_history.append(the_mes)
193
+ except:
194
+ the_mes = AIMessage(content=message.content)
195
+ the_history.append(the_mes)
196
+
197
+ llm_input += each_message_extension
198
+
199
+ the_last_message = HumanMessage(content=llm_input)
200
+ msg = get_agent_executor().invoke(
201
+ {"messages": the_history + [the_last_message]}, config=config
202
+ )
203
+
204
+ elif llm_settings[the_model]["provider"] == "ollama":
205
+
206
+ msg = get_agent_executor().invoke(
207
+ {
208
+ "input": the_message,
209
+ "chat_history": llm_history,
210
+ }
211
+ )
212
+
213
+ the_last_messages = msg["messages"]
214
+
215
+
216
+
217
+ if dont_save_image and screenshot_path is not None:
218
+ currently_messages = get_chat_message_history().messages
219
+
220
+ last_message = currently_messages[-1].content[0]
221
+ currently_messages.remove(currently_messages[-1])
222
+
223
+ get_chat_message_history().clear()
224
+ for message in currently_messages:
225
+ get_chat_message_history().add_message(message)
226
+ get_chat_message_history().add_message(HumanMessage(content=[last_message]))
227
+
228
+ get_chat_message_history().add_message(the_last_messages[-1])
229
+
230
+
231
+
232
+
233
+ # Replace each_message_extension with empty string
234
+ list_of_messages = get_chat_message_history().messages
235
+
236
+ get_chat_message_history().clear()
237
+
238
+ for message in list_of_messages:
239
+ try:
240
+ message.content[0]["text"] = message.content[0]["text"].replace(each_message_extension, "")
241
+ get_chat_message_history().add_message(message)
242
+ except:
243
+ get_chat_message_history().add_message(message)
244
+
245
+
246
+
247
+ return the_last_messages[-1].content
gpt_computer_assistant/agent/background.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_core.messages import SystemMessage
2
+ from .chat_history import *
3
+ from ..llm_settings import first_message
4
+
5
+
6
+ llm_history_oiginal = [
7
+ SystemMessage(
8
+ content=[
9
+ {
10
+ "type": "text",
11
+ "text": first_message,
12
+ }
13
+ ]
14
+ ),
15
+ ]
gpt_computer_assistant/agent/chat_history.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain_community.chat_message_histories import SQLChatMessageHistory
2
+ from .background import llm_history_oiginal
3
+ try:
4
+ from ..utils.db import get_history_db
5
+ except ImportError:
6
+ from utils.db import get_history_db
7
+
8
+
9
+ def get_chat_message_history():
10
+
11
+ connection = SQLChatMessageHistory(
12
+ session_id="abc123", connection_string=f"sqlite:///{get_history_db()}"
13
+ )
14
+ if len(connection.messages) == 0:
15
+ connection.add_message(llm_history_oiginal[0])
16
+
17
+ return connection
18
+
19
+
20
+ def clear_chat_history():
21
+ get_chat_message_history().clear()
22
+ get_chat_message_history().add_message(llm_history_oiginal[0])
gpt_computer_assistant/agent/process.py ADDED
@@ -0,0 +1,266 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ try:
2
+ from ..llm import *
3
+ from .assistant import *
4
+ from .chat_history import *
5
+ from ..audio.tts import text_to_speech
6
+ from ..audio.stt import speech_to_text
7
+ from ..audio.record import audio_data
8
+ from ..gui.signal import signal_handler
9
+ from ..utils.db import *
10
+ from ..utils.telemetry import my_tracer, os_name
11
+ except ImportError:
12
+ from llm import *
13
+ from agent.assistant import *
14
+ from agent.chat_history import *
15
+ from audio.tts import text_to_speech
16
+ from audio.stt import speech_to_text
17
+ from audio.record import audio_data
18
+ from gui.signal import signal_handler
19
+ from utils.db import *
20
+ from utils.telemetry import my_tracer, os_name
21
+
22
+
23
+ import threading
24
+ import traceback
25
+
26
+
27
+ from pygame import mixer
28
+
29
+
30
+ import time
31
+
32
+ last_ai_response = None
33
+ user_id = load_user_id()
34
+ os_name_ = os_name()
35
+
36
+
37
+
38
+ def tts_if_you_can(text:str, not_threaded=False, status_edit=False, bypass_other_settings = False):
39
+ try:
40
+ from ..gpt_computer_assistant import the_main_window
41
+ if (not is_just_text_model_active() and not the_main_window.api_enabled) or bypass_other_settings:
42
+ response_path = text_to_speech(text)
43
+ if status_edit:
44
+ signal_handler.assistant_response_ready.emit()
45
+
46
+ def play_audio():
47
+ for each_r in response_path:
48
+ mixer.init()
49
+ mixer.music.load(each_r)
50
+ mixer.music.play()
51
+ while mixer.music.get_busy():
52
+ if the_main_window.stop_talking:
53
+ mixer.music.stop()
54
+ break
55
+ time.sleep(0.1)
56
+ if status_edit:
57
+ signal_handler.assistant_response_stopped.emit()
58
+ if not not_threaded:
59
+ playback_thread = threading.Thread(target=play_audio)
60
+ playback_thread.start()
61
+ else:
62
+ play_audio()
63
+ except Exception as e:
64
+ pass
65
+
66
+
67
+
68
+
69
+ def process_audio(take_screenshot=True, take_system_audio=False, dont_save_image=False):
70
+ with my_tracer.start_span("process_audio") as span:
71
+ span.set_attribute("user_id", user_id)
72
+ span.set_attribute("os_name", os_name_)
73
+ try:
74
+ global audio_data, last_ai_response
75
+ from ..gpt_computer_assistant import the_input_box, the_main_window
76
+ from ..audio.record import audio_data, the_input_box_pre
77
+
78
+
79
+ transcription = speech_to_text(mic_record_location)
80
+
81
+ if take_system_audio:
82
+
83
+ transcription2 = speech_to_text(system_sound_location)
84
+
85
+ llm_input = transcription
86
+
87
+ print("Previously AI response", last_ai_response, "end prev")
88
+
89
+ print("Input Box AI", the_input_box_pre)
90
+
91
+
92
+ if (
93
+ the_input_box_pre != ""
94
+ and not the_input_box_pre.startswith("System:")
95
+ and the_input_box_pre not in last_ai_response
96
+ ):
97
+ llm_input += the_input_box_pre
98
+
99
+ if take_system_audio:
100
+ llm_input += " \n Other of USER: " + transcription2
101
+
102
+ if the_input_box.toPlainText().startswith("System:"):
103
+ the_main_window.update_from_thread("Transciption Completed. Running AI...")
104
+
105
+
106
+ print("LLM INPUT (screenshot)", llm_input)
107
+
108
+ llm_output = assistant(
109
+ llm_input,
110
+ get_chat_message_history().messages,
111
+ get_client(),
112
+ screenshot_path=screenshot_path if take_screenshot else None,
113
+ dont_save_image=dont_save_image,
114
+ )
115
+ if the_input_box.toPlainText().startswith("System:"):
116
+ the_main_window.update_from_thread("AI Response Completed. Generating Audio...")
117
+ last_ai_response = llm_output
118
+
119
+ from ..gpt_computer_assistant import the_main_window
120
+
121
+ signal_handler.assistant_response_ready.emit()
122
+
123
+ def play_text():
124
+ from ..gpt_computer_assistant import the_input_box, the_main_window
125
+
126
+ the_main_window.complated_answer = True
127
+ the_main_window.manuel_stop = True
128
+ while the_main_window.reading_thread or the_main_window.reading_thread_2:
129
+ time.sleep(0.1)
130
+ the_main_window.read_part_task()
131
+ if the_main_window.stop_talking:
132
+ the_main_window.stop_talking = False
133
+ signal_handler.assistant_response_stopped.emit()
134
+
135
+ playback_thread = threading.Thread(target=play_text)
136
+ playback_thread.start()
137
+ except Exception as e:
138
+ print("Error in process_audio", e)
139
+ traceback.print_exc()
140
+ from ..gpt_computer_assistant import the_input_box, the_main_window
141
+ the_main_window.update_from_thread("EXCEPTION: " + str(e))
142
+ tts_if_you_can("Exception occurred. Please check the logs.")
143
+ signal_handler.assistant_response_stopped.emit()
144
+
145
+
146
+ def process_screenshot():
147
+ with my_tracer.start_span("process_screenshot") as span:
148
+ span.set_attribute("user_id", user_id)
149
+ span.set_attribute("os_name", os_name_)
150
+ try:
151
+
152
+
153
+ global last_ai_response
154
+ from ..gpt_computer_assistant import the_input_box, the_main_window
155
+ from ..audio.record import audio_data, the_input_box_pre
156
+
157
+ llm_input = "I just take a screenshot. for you to remember. Just say ok."
158
+
159
+
160
+ if (
161
+ the_input_box_pre != ""
162
+ and not the_input_box_pre.startswith("System:")
163
+ and the_input_box_pre not in last_ai_response
164
+ ):
165
+ llm_input += the_input_box_pre
166
+
167
+ print("LLM INPUT (just screenshot)", llm_input)
168
+
169
+ if the_input_box.toPlainText().startswith("System:"):
170
+ the_main_window.update_from_thread("Transciption Completed. Running AI...")
171
+
172
+
173
+
174
+ llm_output = assistant(
175
+ llm_input,
176
+ get_chat_message_history().messages,
177
+ get_client(),
178
+ screenshot_path=just_screenshot_path,
179
+ dont_save_image=False,
180
+ )
181
+
182
+ if the_input_box.toPlainText().startswith("System:"):
183
+ the_main_window.update_from_thread("AI Response Completed. Generating Audio...")
184
+
185
+ last_ai_response = llm_output
186
+
187
+ from ..gpt_computer_assistant import the_main_window
188
+
189
+ signal_handler.assistant_response_ready.emit()
190
+
191
+ def play_text():
192
+ from ..gpt_computer_assistant import the_input_box, the_main_window
193
+
194
+
195
+ the_main_window.complated_answer = True
196
+ the_main_window.manuel_stop = True
197
+ while the_main_window.reading_thread or the_main_window.reading_thread_2:
198
+ time.sleep(0.1)
199
+ the_main_window.read_part_task()
200
+ if the_main_window.stop_talking:
201
+ the_main_window.stop_talking = False
202
+ signal_handler.assistant_response_stopped.emit()
203
+
204
+ playback_thread = threading.Thread(target=play_text)
205
+ playback_thread.start()
206
+
207
+
208
+ except Exception as e:
209
+ print("Error in process_screenshot", e)
210
+ traceback.print_exc()
211
+ from ..gpt_computer_assistant import the_input_box, the_main_window
212
+ the_main_window.update_from_thread("EXCEPTION: " + str(e))
213
+ tts_if_you_can("Exception occurred. Please check the logs.")
214
+ signal_handler.assistant_response_stopped.emit()
215
+
216
+
217
+
218
+ def process_text(text, screenshot_path=None):
219
+ with my_tracer.start_span("process_text") as span:
220
+ span.set_attribute("user_id", user_id)
221
+ span.set_attribute("os_name", os_name_)
222
+ try:
223
+
224
+ global last_ai_response
225
+
226
+ llm_input = text
227
+
228
+
229
+ llm_output = assistant(
230
+ llm_input,
231
+ get_chat_message_history().messages,
232
+ get_client(),
233
+ screenshot_path=screenshot_path,
234
+ dont_save_image=True,
235
+ )
236
+ last_ai_response = llm_output
237
+
238
+ from ..gpt_computer_assistant import the_main_window
239
+ signal_handler.assistant_response_ready.emit()
240
+
241
+ def play_text():
242
+ from ..gpt_computer_assistant import the_input_box, the_main_window
243
+
244
+
245
+ the_main_window.complated_answer = True
246
+ the_main_window.manuel_stop = True
247
+ while the_main_window.reading_thread or the_main_window.reading_thread_2:
248
+ time.sleep(0.1)
249
+ the_main_window.read_part_task()
250
+ if the_main_window.stop_talking:
251
+ the_main_window.stop_talking = False
252
+ signal_handler.assistant_response_stopped.emit()
253
+
254
+ playback_thread = threading.Thread(target=play_text)
255
+ playback_thread.start()
256
+
257
+
258
+ except Exception as e:
259
+ print("Error in process_text", e)
260
+ traceback.print_exc()
261
+ from ..gpt_computer_assistant import the_input_box, the_main_window
262
+ the_main_window.update_from_thread("EXCEPTION: " + str(e))
263
+ tts_if_you_can("Exception occurred. Please check the logs.")
264
+ signal_handler.assistant_response_stopped.emit()
265
+
266
+
gpt_computer_assistant/agentic.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from .utils.db import agents
2
+
3
+ class Agent:
4
+ """
5
+ Represents an agent within the system.
6
+
7
+ This class defines an agent with a specific role, goal, and backstory. Upon initialization,
8
+ the agent is added to the global list of agents.
9
+
10
+ Attributes:
11
+ - role (str): The role of the agent.
12
+ - goal (str): The goal or objective of the agent.
13
+ - backstory (str): The backstory or history of the agent.
14
+
15
+ Methods:
16
+ - __init__(role, goal, backstory): Initializes the Agent object and adds it to the global list of agents.
17
+
18
+ Global Variables:
19
+ - agents (list): A global list containing information about all agents in the system.
20
+ """
21
+ def __init__(self, role, goal, backstory):
22
+ """
23
+ Initializes a new Agent object and adds it to the global list of agents.
24
+
25
+ Parameters:
26
+ - role (str): The role of the agent.
27
+ - goal (str): The goal or objective of the agent.
28
+ - backstory (str): The backstory or history of the agent.
29
+
30
+ Returns:
31
+ None
32
+ """
33
+ global agents
34
+ agents.append({"role": role, "goal": goal, "backstory": backstory})
gpt_computer_assistant/api.py ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Create a python api and start_api function via flask
2
+
3
+ from flask import Flask, request, jsonify
4
+ import threading
5
+ import time
6
+
7
+ from werkzeug.serving import make_server
8
+
9
+ app = Flask(__name__)
10
+
11
+ @app.route("/input", methods=["POST"])
12
+ def input():
13
+ """
14
+ This function receives input from the user and returns the response.
15
+ """
16
+ data = request.json
17
+ text = data["text"]
18
+ screen = data["screen"]
19
+ talk = data["talk"]
20
+ print("Input:", text)
21
+ from .gpt_computer_assistant import the_main_window, the_input_box
22
+
23
+ firsst_text = the_input_box.toPlainText()
24
+
25
+ if talk == "true":
26
+ the_main_window.api_enabled = False
27
+ the_main_window.manuel_stop = True
28
+
29
+ if screen != "true":
30
+ the_main_window.button_handler.input_text(text)
31
+ else:
32
+ the_main_window.button_handler.input_text_screenshot(text)
33
+
34
+
35
+ while the_input_box.toPlainText() == firsst_text:
36
+ time.sleep(0.3)
37
+
38
+ while the_input_box.toPlainText().startswith("System:"):
39
+ time.sleep(0.3)
40
+
41
+ response = the_input_box.toPlainText()
42
+
43
+
44
+
45
+ if talk == "true":
46
+ the_main_window.api_enabled = True
47
+
48
+ return jsonify({"response": response})
49
+
50
+
51
+ @app.route("/screenshot", methods=["POST"])
52
+ def screenshot():
53
+ """
54
+ This function receives a screenshot from the user and returns the response.
55
+ """
56
+ from .gpt_computer_assistant import the_main_window, the_input_box
57
+ firsst_text = the_input_box.toPlainText()
58
+ the_main_window.button_handler.just_screenshot()
59
+
60
+ while the_input_box.toPlainText() == firsst_text:
61
+ time.sleep(0.3)
62
+
63
+ while the_input_box.toPlainText().startswith("System:"):
64
+ time.sleep(0.3)
65
+
66
+ response = the_input_box.toPlainText()
67
+
68
+ return jsonify({"response": response})
69
+
70
+
71
+
72
+ @app.route("/tts", methods=["POST"])
73
+ def tts():
74
+ """
75
+ This function receives a text to speech request from the user and returns the response.
76
+ """
77
+ from .gpt_computer_assistant import the_main_window, the_input_box
78
+ the_main_window.api_enabled = False
79
+ the_main_window.manuel_stop = True
80
+ data = request.json
81
+ text = data["text"]
82
+ print("TTS:", text)
83
+ from .agent.process import tts_if_you_can
84
+ tts_if_you_can(text, not_threaded=True, status_edit=True)
85
+ the_main_window.api_enabled = True
86
+ return jsonify({"response": "TTS request received"})
87
+
88
+ @app.route("/profile", methods=["POST"])
89
+ def profile():
90
+ """
91
+ This function sets the profile for the application.
92
+ """
93
+ data = request.json
94
+ profile = data["profile"]
95
+ print("Profile:", profile)
96
+ from .utils.db import set_profile
97
+ set_profile(profile)
98
+ from .gpt_computer_assistant import the_main_window
99
+ the_main_window.update_from_thread("Profile set to "+profile)
100
+ return jsonify({"response": "Profile set to "+profile})
101
+
102
+
103
+ @app.route("/reset_memory", methods=["POST"])
104
+ def reset_memory():
105
+ """
106
+ This function resets the memory of the application.
107
+ """
108
+ from .agent.chat_history import clear_chat_history
109
+ clear_chat_history()
110
+ from .gpt_computer_assistant import the_main_window
111
+ the_main_window.update_from_thread("Memory reset")
112
+ return jsonify({"response": "Memory reset"})
113
+
114
+
115
+
116
+ @app.route("/activate_predefined_agents", methods=["POST"])
117
+ def enable_predefined_agents():
118
+ """
119
+ This function enables predefined agents for the application.
120
+ """
121
+ from .utils.db import activate_predefined_agents_setting
122
+ activate_predefined_agents_setting()
123
+ from .gpt_computer_assistant import the_main_window
124
+ the_main_window.update_from_thread("Predefined agents enabled")
125
+ return jsonify({"response": "Predefined agents enabled"})
126
+
127
+ @app.route("/deactivate_predefined_agents", methods=["POST"])
128
+ def disable_predefined_agents():
129
+ """
130
+ This function disables predefined agents for the application.
131
+ """
132
+ from .utils.db import deactivate_predefined_agents_setting
133
+ deactivate_predefined_agents_setting()
134
+ from .gpt_computer_assistant import the_main_window
135
+ the_main_window.update_from_thread("Predefined agents disabled")
136
+ return jsonify({"response": "Predefined agents disabled"})
137
+
138
+
139
+ @app.route("/activate_online_tools", methods=["POST"])
140
+ def enable_online_tools():
141
+ """
142
+ This function enables online tools for the application.
143
+ """
144
+ from .utils.db import activate_online_tools_setting
145
+ activate_online_tools_setting()
146
+ from .gpt_computer_assistant import the_main_window
147
+ the_main_window.update_from_thread("Online tools enabled")
148
+ return jsonify({"response": "Online tools enabled"})
149
+
150
+
151
+
152
+ @app.route("/deactivate_online_tools", methods=["POST"])
153
+ def disable_online_tools():
154
+ """
155
+ This function disables online tools for the application.
156
+ """
157
+ from .utils.db import deactivate_online_tools_setting
158
+ deactivate_online_tools_setting()
159
+ from .gpt_computer_assistant import the_main_window
160
+ the_main_window.update_from_thread("Online tools disabled")
161
+ return jsonify({"response": "Online tools disabled"})
162
+
163
+
164
+ class ServerThread(threading.Thread):
165
+ def __init__(self, app, host, port):
166
+ threading.Thread.__init__(self)
167
+ self.srv = make_server(host, port, app)
168
+ self.ctx = app.app_context()
169
+ self.ctx.push()
170
+
171
+ def run(self):
172
+ print("Starting server")
173
+ self.srv.serve_forever()
174
+
175
+ def shutdown(self):
176
+ print("Stopping server")
177
+ self.srv.shutdown()
178
+
179
+ server_thread = None
180
+
181
+ def start_api():
182
+ global server_thread
183
+ if server_thread is None:
184
+ server_thread = ServerThread(app, "localhost", 7541)
185
+ server_thread.start()
186
+ print("API started")
187
+ else:
188
+ print("API is already running")
189
+
190
+ def stop_api():
191
+ global server_thread
192
+ if server_thread is not None:
193
+ server_thread.shutdown()
194
+ server_thread.join()
195
+ server_thread = None
196
+ print("API stopped")
197
+ else:
198
+ print("API is not running")
gpt_computer_assistant/audio/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from .record import *
gpt_computer_assistant/audio/record.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ try:
2
+ from ..gui.signal import *
3
+ from ..utils.db import *
4
+ from ..utils.telemetry import my_tracer, os_name
5
+ except ImportError:
6
+ from gui.signal import *
7
+ from utils.db import *
8
+ from utils.telemetry import my_tracer, os_name
9
+ import numpy as np
10
+ import sounddevice as sd
11
+ import soundfile as sf
12
+ import scipy.io.wavfile as wavfile
13
+ import soundcard as sc
14
+ import threading
15
+ import time
16
+
17
+ samplerate = 48000 # Updated samplerate for better quality
18
+ channels = 1
19
+ recording = False
20
+
21
+ audio_data = None
22
+
23
+ user_id = load_user_id()
24
+ os_name_ = os_name()
25
+
26
+ the_input_box_pre = ""
27
+
28
+
29
+
30
+ import queue
31
+
32
+ # Initialize a queue to keep the last N audio levels (rolling window)
33
+ audio_levels = queue.Queue(maxsize=10) # Adjust size as needed
34
+
35
+ def calculate_dynamic_threshold():
36
+ """Calculate a dynamic threshold based on recent audio levels."""
37
+ if audio_levels.qsize() == 0:
38
+ return 0.01 # Default threshold if no data is available
39
+ else:
40
+ # Calculate the average of the last N audio levels
41
+ return np.mean(list(audio_levels.queue)) * 2 # Adjust multiplier as needed
42
+
43
+
44
+ silence_start_time = None
45
+
46
+ auto_stop_recording = True
47
+
48
+
49
+ def start_recording(take_system_audio, buttonhandler):
50
+ """Start recording audio from microphone and/or system sound.
51
+
52
+
53
+ """
54
+ with my_tracer.start_span("start_recording") as span:
55
+ span.set_attribute("user_id", user_id)
56
+ span.set_attribute("os_name", os_name_)
57
+
58
+ global the_input_box_pre
59
+ from ..gpt_computer_assistant import the_input_box, the_main_window
60
+ the_input_box_pre = the_input_box.toPlainText()
61
+
62
+ the_main_window.update_from_thread("Click again when recording is done")
63
+ global recording, audio_data, silence_start_time, auto_stop_recording
64
+ recording = True
65
+ audio_data = np.array([], dtype="float32")
66
+ print("Recording started...")
67
+
68
+ threshold = 0.01 # Define the threshold for stopping the recording
69
+ silence_duration = 2 # Duration in seconds to consider as silence before stopping
70
+ silence_start_time = None
71
+ recording_start_time = time.time() # Record the start time of the recording
72
+
73
+ auto_stop_recording = is_auto_stop_recording_setting_active()
74
+
75
+
76
+ def callback(indata, frames, time_info, status):
77
+ global audio_data, recording, silence_start_time, auto_stop_recording
78
+ current_level = np.max(np.abs(indata))
79
+
80
+
81
+ # Add the current level to the queue
82
+ if audio_levels.full():
83
+ audio_levels.get() # Remove the oldest level if the queue is full
84
+ audio_levels.put(current_level)
85
+
86
+ # Calculate dynamic threshold based on recent audio levels
87
+ dynamic_threshold = calculate_dynamic_threshold()
88
+
89
+
90
+ if recording:
91
+ audio_data = np.append(audio_data, indata)
92
+ # Check if the audio is below the dynamic threshold
93
+ if current_level < dynamic_threshold and auto_stop_recording:
94
+ if silence_start_time is None:
95
+ silence_start_time = time.time() # Mark the start of silence
96
+
97
+ # Ensure recording has been ongoing for at least 3 seconds before considering auto-stop
98
+ elif (time.time() - silence_start_time) > silence_duration and (time.time() - recording_start_time) > 3:
99
+ recording = False
100
+ buttonhandler.recording = False
101
+
102
+ else:
103
+ silence_start_time = None
104
+
105
+
106
+ def record_audio():
107
+ with my_tracer.start_span("record_audio") as span:
108
+ span.set_attribute("user_id", user_id)
109
+ span.set_attribute("os_name", os_name_)
110
+ global recording
111
+ mics = sc.all_microphones(include_loopback=True)
112
+ default_mic = mics[0]
113
+ data = []
114
+ with default_mic.recorder(samplerate=148000) as mic:
115
+ print("Recording...")
116
+ while recording:
117
+ frame = mic.record(numframes=4096)
118
+ data.append(frame)
119
+ data = np.concatenate(data, axis=0)
120
+ data_int16 = (data * 32767).astype("int16")
121
+ wavfile.write(system_sound_location, 148000, data_int16)
122
+
123
+ if take_system_audio:
124
+ recording_thread = threading.Thread(target=record_audio)
125
+ recording_thread.start()
126
+
127
+ with sd.InputStream(callback=callback, channels=channels, samplerate=samplerate):
128
+ while recording:
129
+ sd.sleep(100)
130
+
131
+ if not recording:
132
+ sf.write(mic_record_location, audio_data, samplerate)
133
+ print("Audio saved as voice_input.wav")
134
+ signal_handler.recording_stopped.emit()
135
+
136
+ def stop_recording():
137
+ """Stop recording audio."""
138
+ global recording
139
+ recording = False
140
+ print("Recording stopped")
gpt_computer_assistant/audio/stt.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ try:
2
+ from ..llm import get_client
3
+ except ImportError:
4
+ from llm import get_client
5
+
6
+ import os
7
+ from pydub import AudioSegment
8
+
9
+
10
+ def split_audio(file_path, max_size=20 * 1024 * 1024):
11
+ """Split an audio file into smaller parts if it exceeds a maximum size.
12
+
13
+ Args:
14
+ file_path (str): The path to the audio file to be split.
15
+ max_size (int): The maximum size in bytes for each split part. Defaults to 20 MB.
16
+
17
+ Returns:
18
+ list: A list of tuples containing the split audio segments and their respective file paths.
19
+ """
20
+ audio = AudioSegment.from_wav(file_path)
21
+ file_size = os.path.getsize(file_path)
22
+ if file_size <= max_size:
23
+ return [(audio, file_path)]
24
+
25
+ # Calculate the number of parts needed
26
+ num_parts = file_size // max_size + 1
27
+ part_length = len(audio) // num_parts
28
+ parts = []
29
+
30
+ for i in range(num_parts):
31
+ start = i * part_length
32
+ end = (i + 1) * part_length if (i + 1) < num_parts else len(audio)
33
+ part = audio[start:end]
34
+ part_path = f"{file_path[:-4]}_part_{i+1}.wav"
35
+ part.export(part_path, format="wav")
36
+ parts.append((part, part_path))
37
+
38
+ return parts
39
+
40
+
41
+ def speech_to_text(location):
42
+ """Convert speech audio file to text using an external service.
43
+
44
+ Args:
45
+ location (str): The path to the speech audio file.
46
+
47
+ Returns:
48
+ str: The transcribed text from the speech audio file.
49
+ """
50
+ audio_parts = split_audio(location)
51
+ transcriptions = []
52
+
53
+ for part, part_path in audio_parts:
54
+ with open(part_path, "rb") as audio_file:
55
+ transcription = get_client().audio.transcriptions.create(
56
+ model="whisper-1", file=audio_file
57
+ )
58
+ transcriptions.append(transcription)
59
+ os.remove(part_path) # Clean up the temporary file immediately after processing
60
+
61
+ # Merge transcriptions (assuming it's a list of text segments)
62
+ full_transcription = " ".join(
63
+ transcription.text for transcription in transcriptions
64
+ )
65
+ return full_transcription
gpt_computer_assistant/audio/tts.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ try:
2
+ from ..llm import *
3
+ from ..utils.db import artifacts_dir
4
+ except ImportError:
5
+ from llm import *
6
+ from utils.db import artifacts_dir
7
+
8
+ import os
9
+ import hashlib
10
+ import random
11
+ import threading
12
+
13
+ supported_openai_speakers = ["fable"]
14
+
15
+ def random_model(exclude):
16
+ models = supported_openai_speakers.copy()
17
+ models.remove(exclude)
18
+ return random.choice(models)
19
+
20
+ def generate_speech_chunk(text_chunk, index, voice, results):
21
+ sha = hashlib.sha256(text_chunk.encode()).hexdigest()
22
+ location = os.path.join(artifacts_dir, f"{sha}.mp3")
23
+
24
+ if os.path.exists(location):
25
+ results[index] = location
26
+ else:
27
+ response = get_client().audio.speech.create(
28
+ model="tts-1",
29
+ voice=voice,
30
+ input=text_chunk,
31
+ )
32
+ response.stream_to_file(location)
33
+ results[index] = location
34
+
35
+ def split_text_to_sentences(text, max_chunk_size=300):
36
+ """Splits text into sentences and ensures chunks do not exceed max_chunk_size."""
37
+ sentences = text.split('.')
38
+ chunks = []
39
+ current_chunk = ""
40
+
41
+ for sentence in sentences:
42
+ sentence = sentence.strip()
43
+ if len(current_chunk) + len(sentence) + 1 <= max_chunk_size:
44
+ current_chunk += (sentence + '. ')
45
+ else:
46
+ chunks.append(current_chunk.strip())
47
+ current_chunk = sentence + '. '
48
+
49
+ if current_chunk:
50
+ chunks.append(current_chunk.strip())
51
+
52
+ return chunks
53
+
54
+ def text_to_speech(text):
55
+ text_chunks = split_text_to_sentences(text)
56
+
57
+ threads = []
58
+ results = [None] * len(text_chunks)
59
+
60
+ initial_voice = random.choice(supported_openai_speakers)
61
+
62
+ for i, chunk in enumerate(text_chunks):
63
+ voice = initial_voice if i % 2 == 0 else random_model(initial_voice) # Alternate voices
64
+ thread = threading.Thread(
65
+ target=generate_speech_chunk,
66
+ args=(chunk, i, voice, results)
67
+ )
68
+ threads.append(thread)
69
+ thread.start()
70
+
71
+ for thread in threads:
72
+ thread.join()
73
+
74
+ mp3_files = [result for result in results if result is not None]
75
+
76
+ return mp3_files
77
+
gpt_computer_assistant/audio/wake_word.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import struct
3
+
4
+ from ..utils.db import load_pvporcupine_api_key
5
+
6
+
7
+ def wake_word(the_main_window):
8
+ import pvporcupine
9
+ import pyaudio
10
+
11
+ porcupine = pvporcupine.create(access_key=load_pvporcupine_api_key(),
12
+ keywords=pvporcupine.KEYWORDS)
13
+ # Initialize PyAudio
14
+ pa = pyaudio.PyAudio()
15
+
16
+ # Open an audio stream
17
+ audio_stream = pa.open(
18
+ rate=porcupine.sample_rate,
19
+ channels=1,
20
+ format=pyaudio.paInt16,
21
+ input=True,
22
+ frames_per_buffer=porcupine.frame_length
23
+ )
24
+
25
+ print("Listening for wake word...")
26
+
27
+ # Continuously listen for the wake word
28
+ while the_main_window.wake_word_active:
29
+ pcm = audio_stream.read(porcupine.frame_length)
30
+ pcm = struct.unpack_from("h" * porcupine.frame_length, pcm)
31
+
32
+ # Process the audio frame and check for the wake word
33
+ keyword_index = porcupine.process(pcm)
34
+
35
+ if keyword_index >= 0:
36
+ print("Wake word detected!")
37
+ return True
gpt_computer_assistant/custom_callback.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Callback Handler streams to stdout on new llm token."""
2
+ from langchain.callbacks.streaming_stdout_final_only import FinalStreamingStdOutCallbackHandler
3
+ from typing import Any, Dict, List, Optional
4
+
5
+ class customcallback(FinalStreamingStdOutCallbackHandler):
6
+ def on_llm_new_token(self, token: str, **kwargs: Any) -> None:
7
+
8
+ self.append_to_last_tokens(token)
9
+
10
+
11
+ if self.check_if_answer_reached():
12
+ self.answer_reached = True
13
+
14
+ return
15
+
16
+
17
+ if self.answer_reached:
18
+ from .gpt_computer_assistant import the_main_window
19
+ the_main_window.set_text_to_input_box(token)
gpt_computer_assistant/display_tools.py ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain.tools import tool
2
+ import traceback
3
+
4
+ try:
5
+ from .utils.db import load_api_key
6
+ from .llm import get_model
7
+ except ImportError:
8
+ from utils.db import load_api_key
9
+ from llm import get_model
10
+
11
+
12
+ def click_on_a_text_on_the_screen_(text:str, click_type: str = "singular") -> bool:
13
+ """
14
+ A function to click on a text on the screen.
15
+
16
+ Parameters:
17
+ - text (str): The text to be clicked on.
18
+ - click_type (str): The type of click to be performed. The default value is "singular". Possible values are "singular" and "double".
19
+
20
+ Returns:
21
+ - bool: True if the text was clicked on successfully, False otherwise.
22
+ """
23
+ try:
24
+ import pyautogui
25
+ pyautogui.FAILSAFE = False
26
+
27
+
28
+ from interpreter import OpenInterpreter
29
+
30
+
31
+
32
+
33
+
34
+ interpreter = OpenInterpreter()
35
+
36
+ interpreter.llm.api_key = load_api_key()
37
+
38
+ screenshot = pyautogui.screenshot()
39
+
40
+ text_locations = interpreter.computer.display.find_text(text, screenshot=screenshot)
41
+
42
+ print(text_locations)
43
+
44
+
45
+ x, y = text_locations[0]["coordinates"]
46
+ x *= interpreter.computer.display.width
47
+ y *= interpreter.computer.display.height
48
+ x = int(x)
49
+ y = int(y)
50
+
51
+ if click_type == "singular":
52
+ interpreter.computer.mouse.click(x=x, y=y, screenshot=screenshot)
53
+ elif click_type == "double":
54
+ interpreter.computer.mouse.double_click(x=x, y=y, screenshot=screenshot)
55
+ return True
56
+ except:
57
+ traceback.print_exc()
58
+ return False
59
+
60
+
61
+ click_on_a_text_on_the_screen = tool(click_on_a_text_on_the_screen_)
62
+
63
+
64
+
65
+
66
+ def move_on_a_text_on_the_screen_(text:str) -> bool:
67
+ """
68
+ A function to move on a text on the screen.
69
+
70
+ Parameters:
71
+ - text (str): The text to be moved on.
72
+
73
+ Returns:
74
+ - bool: True if the text was moved on successfully, False otherwise.
75
+ """
76
+ try:
77
+ import pyautogui
78
+ pyautogui.FAILSAFE = False
79
+
80
+
81
+ from interpreter import OpenInterpreter
82
+
83
+
84
+
85
+
86
+
87
+ interpreter = OpenInterpreter()
88
+
89
+ interpreter.llm.api_key = load_api_key()
90
+
91
+ screenshot = pyautogui.screenshot()
92
+
93
+ text_locations = interpreter.computer.display.find_text(text, screenshot=screenshot)
94
+
95
+ print(text_locations)
96
+
97
+
98
+ x, y = text_locations[0]["coordinates"]
99
+ x *= interpreter.computer.display.width
100
+ y *= interpreter.computer.display.height
101
+ x = int(x)
102
+ y = int(y)
103
+
104
+ interpreter.computer.mouse.move(x=x, y=y, screenshot=screenshot)
105
+
106
+ return True
107
+ except:
108
+ traceback.print_exc()
109
+ return False
110
+
111
+
112
+ move_on_a_text_on_the_screen = tool(move_on_a_text_on_the_screen_)
113
+
114
+
115
+
116
+ def click_on_a_icon_on_the_screen_(icon_name:str, click_type: str = "singular") -> bool:
117
+ """
118
+ A function to click on a icon name on the screen.
119
+
120
+ Parameters:
121
+ - icon_name (str): The icon name to be clicked on.
122
+ - click_type (str): The type of click to be performed. The default value is "singular". Possible values are "singular" and "double".
123
+
124
+ Returns:
125
+ - bool: True if the icon name was clicked on successfully, False otherwise.
126
+ """
127
+ try:
128
+ import pyautogui
129
+ pyautogui.FAILSAFE = False
130
+
131
+
132
+ from interpreter import OpenInterpreter
133
+
134
+
135
+ screenshot = pyautogui.screenshot()
136
+
137
+
138
+ interpreter = OpenInterpreter()
139
+
140
+ interpreter.llm.api_key = load_api_key()
141
+
142
+
143
+
144
+ if click_type == "singular":
145
+ interpreter.computer.mouse.click(icon=icon_name, screenshot=screenshot)
146
+ elif click_type == "double":
147
+ interpreter.computer.mouse.double_click(icon=icon_name, screenshot=screenshot)
148
+ return True
149
+
150
+ except:
151
+ traceback.print_exc()
152
+ return False
153
+
154
+ click_on_a_icon_on_the_screen = tool(click_on_a_icon_on_the_screen_)
155
+
156
+
157
+
158
+
159
+ def move_on_a_icon_on_the_screen_(icon_name:str,) -> bool:
160
+ """
161
+ A function to move on a icon name on the screen.
162
+
163
+ Parameters:
164
+ - icon_name (str): The icon name to be move on.
165
+
166
+ Returns:
167
+ - bool: True if the icon name was moved on successfully, False otherwise.
168
+ """
169
+ try:
170
+ import pyautogui
171
+ pyautogui.FAILSAFE = False
172
+
173
+
174
+ from interpreter import OpenInterpreter
175
+
176
+
177
+ screenshot = pyautogui.screenshot()
178
+
179
+
180
+ interpreter = OpenInterpreter()
181
+
182
+ interpreter.llm.api_key = load_api_key()
183
+
184
+ interpreter.computer.mouse.move(icon=icon_name, screenshot=screenshot)
185
+ return True
186
+
187
+ except:
188
+ traceback.print_exc()
189
+ return False
190
+
191
+ move_on_a_icon_on_the_screen = tool(move_on_a_icon_on_the_screen_)
192
+
193
+
194
+
195
+
196
+ def mouse_scroll_(direction: str, amount: int = 1) -> bool:
197
+ """
198
+ A function to scroll the mouse wheel.
199
+
200
+ Parameters:
201
+ - direction (str): The direction of the scroll. Possible values are "up" and "down".
202
+ - amount (int): The amount of scrolling to be performed. The default value is 1.
203
+
204
+ Returns:
205
+ - bool: True if the scrolling was performed successfully, False otherwise.
206
+ """
207
+ try:
208
+ import pyautogui
209
+ pyautogui.FAILSAFE = False
210
+
211
+ if direction == "up":
212
+ pyautogui.scroll(amount)
213
+ elif direction == "down":
214
+ pyautogui.scroll(-amount)
215
+ return True
216
+ except:
217
+ traceback.print_exc()
218
+ return False
219
+
220
+ mouse_scroll = tool(mouse_scroll_)
gpt_computer_assistant/gpt_computer_assistant.py ADDED
@@ -0,0 +1,1125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ try:
2
+ from .agent.chat_history import *
3
+ from .agent.assistant import *
4
+ from .llm import *
5
+ from .llm_settings import llm_settings
6
+ from .agent.agent import *
7
+ from .agent.background import *
8
+
9
+ from .gui.signal import *
10
+ from .gui.button import *
11
+ from .gui.settings import settings_popup
12
+ from .gui.llmsettings import llmsettings_popup
13
+ from .utils.db import *
14
+ from .utils.telemetry import my_tracer, os_name
15
+
16
+ from .audio.wake_word import wake_word
17
+ from .audio.tts import text_to_speech
18
+
19
+ except ImportError:
20
+ # This is for running the script directly
21
+ # in order to test the GUI without rebuilding the package
22
+ from agent.chat_history import *
23
+ from agent.assistant import *
24
+ from llm import *
25
+ from llm_settings import llm_settings
26
+ from agent.agent import *
27
+ from agent.background import *
28
+ from utils.db import *
29
+ from gui.signal import *
30
+ from gui.button import *
31
+ from gui.settings import settings_popup
32
+ from gui.llmsettings import llmsettings_popup
33
+ from utils.telemetry import my_tracer, os_name
34
+ from audio.wake_word import wake_word
35
+ from audio.tts import text_to_speech
36
+ import threading
37
+ import time
38
+ import random
39
+ import math
40
+ from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget
41
+ from PyQt5.QtGui import QMouseEvent, QPainter, QPen, QBrush, QIcon, QColor
42
+ from PyQt5.QtCore import Qt, QTimer, QRect, pyqtSignal
43
+ from PyQt5.QtGui import QKeySequence
44
+ from PyQt5.QtWidgets import QShortcut
45
+ from PyQt5.QtWidgets import QSpacerItem, QSizePolicy
46
+
47
+ from PyQt5.QtWidgets import (
48
+ QPushButton,
49
+ QLabel,
50
+ QHBoxLayout,
51
+ )
52
+ from PyQt5.QtCore import QPoint
53
+
54
+ from PyQt5.QtWidgets import QTextEdit
55
+ from PyQt5 import QtGui
56
+ from PyQt5.QtCore import QThread
57
+
58
+
59
+ print("Imported all libraries")
60
+
61
+
62
+ from PyQt5 import QtCore
63
+
64
+
65
+ try:
66
+ import ctypes
67
+
68
+ myappid = "onuratakan.gpt_computer_assistant.gui.1"
69
+ ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
70
+ except:
71
+ pass
72
+
73
+ the_input_box = None
74
+ the_input_text = None
75
+
76
+
77
+ the_input_box_pre = None
78
+
79
+
80
+ the_main_window = None
81
+
82
+
83
+ user_id = load_user_id()
84
+ os_name_ = os_name()
85
+
86
+
87
+
88
+ readed_sentences = []
89
+
90
+ import re
91
+ def split_with_multiple_delimiters(text, delimiters):
92
+ """
93
+ Splits the text by any of the given delimiters while keeping the delimiters in the resulting parts.
94
+
95
+ :param text: The input text to be split.
96
+ :param delimiters: A string of delimiters to split the text on.
97
+ :return: A list of parts including the delimiters.
98
+ """
99
+ # Create a regular expression pattern that matches any of the delimiters
100
+ pattern = re.compile(f'(.*?[{re.escape(delimiters)}])')
101
+ parts = pattern.findall(text)
102
+
103
+ # Check if the last part is not complete and remove it if necessary
104
+ if (
105
+ parts and text
106
+ and not any(text.endswith(d) for d in delimiters)
107
+ and parts
108
+ and not any(parts[-1].endswith(d) for d in delimiters)
109
+ ):
110
+ parts.pop()
111
+
112
+ return parts
113
+
114
+
115
+
116
+
117
+ class Worker(QThread):
118
+ text_to_set = pyqtSignal(str)
119
+
120
+
121
+ def __init__(self):
122
+ super().__init__()
123
+ self.the_input_text = None
124
+ self.make_animation = True
125
+ self.commited_text = []
126
+
127
+ def run(self):
128
+ while True:
129
+ self.msleep(500) # Simulate a time-consuming task
130
+
131
+ if self.the_input_text:
132
+ last_text = self.commited_text[-1] if len(self.commited_text) > 0 else ""
133
+ if self.the_input_text != last_text:
134
+ self.commited_text.append(self.the_input_text)
135
+
136
+ if len(self.the_input_text) > 90 or MainWindow.api_enabled or not self.make_animation:
137
+ self.text_to_set.emit(self.the_input_text)
138
+ else:
139
+ for i in range(len(self.the_input_text)):
140
+ self.text_to_set.emit(self.the_input_text[:i + 1])
141
+ self.msleep(10)
142
+
143
+
144
+
145
+
146
+
147
+ return_key_event = None
148
+ class CustomTextEdit(QTextEdit):
149
+ def __init__(self, parent=None):
150
+ super(CustomTextEdit, self).__init__(parent)
151
+
152
+ def keyPressEvent(self, event):
153
+ if event.key() == Qt.Key_Return or event.key() == Qt.Key_Enter:
154
+ global return_key_event
155
+ return_key_event()
156
+ super(CustomTextEdit, self).keyPressEvent(event) # Process other key events normally
157
+
158
+
159
+
160
+
161
+ class Worker_2(QThread):
162
+ text_to_set = pyqtSignal(str)
163
+ text_to_set_title_bar = pyqtSignal(str)
164
+
165
+
166
+ def __init__(self):
167
+ super().__init__()
168
+ self.the_input_text = None
169
+ self.title_bar_text = None
170
+ self.prev = None
171
+ self.commited_text = []
172
+
173
+ def run(self):
174
+ while True:
175
+ self.msleep(500) # Simulate a time-consuming task
176
+
177
+ if self.the_input_text and (self.prev is None or self.prev != self.the_input_text):
178
+ self.prev = self.the_input_text
179
+ self.text_to_set.emit("True")
180
+ for i in range(len(self.title_bar_text)):
181
+ self.text_to_set_title_bar.emit(self.title_bar_text[:i + 1])
182
+ self.msleep(10)
183
+
184
+ if not self.the_input_text and self.prev != self.the_input_text:
185
+ self.prev = self.the_input_text
186
+ self.text_to_set.emit("False")
187
+
188
+ the_text = " GPT Computer Assistant"
189
+
190
+ for i in range(len(the_text)):
191
+ self.text_to_set_title_bar.emit(the_text[:i + 1])
192
+ self.msleep(10)
193
+
194
+
195
+
196
+
197
+ class DrawingWidget(QWidget):
198
+ def __init__(self, parent=None):
199
+ super(DrawingWidget, self).__init__(parent)
200
+ # Set widget properties if needed, e.g., size
201
+
202
+ self.main_ = parent
203
+
204
+ def paintEvent(self, event):
205
+ if not self.main_.should_paint:
206
+ return # Skip the drawing if should_paint is False
207
+
208
+
209
+
210
+ if llm_settings[load_model_settings()]["vision"] is True:
211
+ self.main_.screen_available = True
212
+ else:
213
+ self.main_.screen_available = False
214
+
215
+
216
+
217
+ self.main_.setAutoFillBackground(True)
218
+ painter = QPainter(self)
219
+
220
+ painter.setRenderHint(QPainter.Antialiasing)
221
+ painter.setPen(QPen(QColor("#000"), 1))
222
+ painter.setBrush(QBrush(Qt.black, Qt.SolidPattern))
223
+
224
+ center_x = 95
225
+ center_y = 40
226
+
227
+ if "talking" in self.main_.state:
228
+ # Draw a pulsating circle with smooth easing animation
229
+ radius_variation = 5 * (1 + math.sin(self.main_.pulse_frame * math.pi / 100))
230
+ radius = 70 + radius_variation
231
+ painter.drawEllipse(
232
+ int(center_x - radius / 2),
233
+ int(center_y - radius / 2),
234
+ int(radius),
235
+ int(radius),
236
+ )
237
+ elif self.main_.state == "thinking":
238
+ # more slow pulsating circle with smooth easing animation
239
+ radius_variation = 5 * (1 + math.sin(self.main_.pulse_frame * math.pi / 100))
240
+ radius = 70 + radius_variation
241
+ painter.drawEllipse(
242
+ int(center_x - radius / 2),
243
+ int(center_y - radius / 2),
244
+ int(radius),
245
+ int(radius),
246
+ )
247
+
248
+ else:
249
+ radius = 70
250
+ painter.drawEllipse(
251
+ int(center_x - radius / 2),
252
+ int(center_y - radius / 2),
253
+ int(radius),
254
+ int(radius),
255
+ )
256
+
257
+
258
+
259
+ self.main_.circle_rect = QRect(
260
+ int(center_x - radius / 2),
261
+ int(center_y - radius / 2),
262
+ int(radius),
263
+ int(radius),
264
+ )
265
+
266
+
267
+
268
+ if not self.main_.state == "thinking":
269
+ painter.setPen(QPen(QColor("#01EE8A"), 1)) # Green color with 2px thickness
270
+ # Draw the ellipse with the specified green border
271
+ painter.drawEllipse(
272
+ int(center_x - radius / 2),
273
+ int(center_y - radius / 2),
274
+ int(radius),
275
+ int(radius),
276
+ )
277
+ else:
278
+ painter.setPen(QPen(QColor("#23538F"), 1))
279
+
280
+ painter.drawEllipse(
281
+ int(center_x - radius / 2),
282
+ int(center_y - radius / 2),
283
+ int(radius),
284
+ int(radius),
285
+ )
286
+
287
+
288
+
289
+ painter.setPen(QPen(QColor("#000"), 1))
290
+
291
+ if self.main_.screen_available:
292
+
293
+ small_center_x = 165
294
+ small_center_y = 25
295
+ small_radius = 30
296
+ painter.drawEllipse(
297
+ int(small_center_x - small_radius / 2),
298
+ int(small_center_y - small_radius / 2),
299
+ int(small_radius),
300
+ int(small_radius),
301
+ )
302
+
303
+ self.main_.small_circle_rect = QRect(
304
+ int(small_center_x - small_radius / 2),
305
+ int(small_center_y - small_radius / 2),
306
+ int(small_radius),
307
+ int(small_radius),
308
+ )
309
+
310
+ # Draw the icon inside the circle
311
+ icon_size = small_radius * 2 // 3 # Adjust the icon size relative to the circle
312
+ icon_rect = QRect(
313
+ small_center_x - icon_size // 2,
314
+ small_center_y - icon_size // 2,
315
+ icon_size,
316
+ icon_size,
317
+ )
318
+ self.main_.small_circle_recticon = QIcon(microphone_icon_path)
319
+ self.main_.small_circle_recticon.paint(painter, icon_rect)
320
+
321
+
322
+ small_center_x = 30
323
+ small_center_y = 60
324
+ small_radius = 30
325
+ painter.drawEllipse(
326
+ int(small_center_x - small_radius / 2),
327
+ int(small_center_y - small_radius / 2),
328
+ int(small_radius),
329
+ int(small_radius),
330
+ )
331
+
332
+ self.main_.small_circle_left = QRect(
333
+ int(small_center_x - small_radius / 2),
334
+ int(small_center_y - small_radius / 2),
335
+ int(small_radius),
336
+ int(small_radius),
337
+ )
338
+
339
+ # Draw the icon inside the circle
340
+ icon_size = small_radius * 2 // 3 # Adjust the icon size relative to the circle
341
+ icon_rect = QRect(
342
+ small_center_x - icon_size // 2,
343
+ small_center_y - icon_size // 2,
344
+ icon_size,
345
+ icon_size,
346
+ )
347
+ self.main_.small_circle_lefticon = QIcon(audio_icon_path)
348
+ self.main_.small_circle_lefticon.paint(painter, icon_rect)
349
+
350
+
351
+
352
+ small_center_x = 30
353
+ small_center_y = 25
354
+ small_radius = 30
355
+ painter.drawEllipse(
356
+ int(small_center_x - small_radius / 2),
357
+ int(small_center_y - small_radius / 2),
358
+ int(small_radius),
359
+ int(small_radius),
360
+ )
361
+
362
+ self.main_.small_circle_left_top = QRect(
363
+ int(small_center_x - small_radius / 2),
364
+ int(small_center_y - small_radius / 2),
365
+ int(small_radius),
366
+ int(small_radius),
367
+ )
368
+
369
+ # Draw the icon inside the circle
370
+ icon_size = small_radius * 2 // 3 # Adjust the icon size relative to the circle
371
+ icon_rect = QRect(
372
+ small_center_x - icon_size // 2,
373
+ small_center_y - icon_size // 2,
374
+ icon_size,
375
+ icon_size,
376
+ )
377
+ self.main_.small_circle_left_topticon = QIcon(screenshot_icon_path)
378
+ self.main_.small_circle_left_topticon.paint(painter, icon_rect)
379
+
380
+
381
+
382
+
383
+
384
+
385
+ small_center_x = 165
386
+ small_center_y = 60
387
+ small_radius = 30
388
+ painter.drawEllipse(
389
+ int(small_center_x - small_radius / 2),
390
+ int(small_center_y - small_radius / 2),
391
+ int(small_radius),
392
+ int(small_radius),
393
+ )
394
+
395
+ self.main_.small_circle_collapse = QRect(
396
+ int(small_center_x - small_radius / 2),
397
+ int(small_center_y - small_radius / 2),
398
+ int(small_radius),
399
+ int(small_radius),
400
+ )
401
+
402
+ # Draw the icon inside the circle
403
+ icon_size = small_radius * 2 // 3 # Adjust the icon size relative to the circle
404
+ icon_rect = QRect(
405
+ small_center_x - icon_size // 2,
406
+ small_center_y - icon_size // 2,
407
+ icon_size,
408
+ icon_size,
409
+ )
410
+
411
+ if self.main_.collapse:
412
+ self.main_.small_circle_collapse_icon = QIcon(down_icon_path)
413
+ else:
414
+ self.main_.small_circle_collapse_icon = QIcon(up_icon_path)
415
+ self.main_.small_circle_collapse_icon.paint(painter, icon_rect)
416
+
417
+
418
+
419
+
420
+ def mousePressEvent(self, event: QMouseEvent):
421
+
422
+
423
+ self.main_.old_position = event.globalPos()
424
+
425
+ with my_tracer.start_span("mouse_press_event") as span:
426
+ span.set_attribute("user_id", user_id)
427
+ span.set_attribute("os_name", os_name_)
428
+ if self.main_.state == "idle" or "talking" in self.main_.state:
429
+ try:
430
+ if self.main_.circle_rect.contains(event.pos()):
431
+
432
+ if self.main_.state == "aitalking":
433
+ self.main_.manuel_stop = True
434
+ self.main_.stop_talking = True
435
+
436
+ else:
437
+ if llm_settings[load_model_settings()]["vision"] is True:
438
+
439
+ self.main_.button_handler.toggle_recording(dont_save_image=True)
440
+ else:
441
+ self.main_.button_handler.toggle_recording(no_screenshot=True)
442
+ except:
443
+ pass
444
+
445
+ try:
446
+ if self.main_.small_circle_rect.contains(event.pos()):
447
+ if self.main_.state == "aitalking":
448
+ self.main_.manuel_stop = True
449
+ self.main_.stop_talking = True
450
+
451
+ else:
452
+ self.main_.button_handler.toggle_recording(no_screenshot=True)
453
+ except:
454
+ pass
455
+
456
+ try:
457
+
458
+ if self.main_.small_circle_left.contains(event.pos()):
459
+ if self.main_.state == "aitalking":
460
+ self.main_.manuel_stop = True
461
+ self.main_.stop_talking = True
462
+
463
+ else:
464
+ self.main_.button_handler.toggle_recording(take_system_audio=True)
465
+ except:
466
+ pass
467
+
468
+ try:
469
+
470
+ if self.main_.small_circle_left_top.contains(event.pos()):
471
+ if self.main_.state == "aitalking":
472
+ self.main_.manuel_stop = True
473
+ self.main_.stop_talking = True
474
+
475
+ else:
476
+ self.main_.button_handler.just_screenshot()
477
+ except:
478
+ pass
479
+
480
+ try:
481
+ if self.main_.small_circle_collapse.contains(event.pos()):
482
+ if self.main_.collapse:
483
+ self.main_.collapse = False
484
+ print()
485
+ # hide all buttons and input box
486
+ the_input_box.show()
487
+ if llm_settings[load_model_settings()]["vision"]:
488
+ self.main_.screenshot_button.show()
489
+ self.main_.settingsButton.show()
490
+ self.main_.llmsettingsButton.show()
491
+ self.main_.send_button.show()
492
+ self.main_.window().setFixedSize(self.main_.first_width, self.main_.first_height)
493
+ deactivate_collapse_setting()
494
+ else:
495
+ self.main_.collapse = True
496
+ self.main_.collapse_window()
497
+ activate_collapse_setting()
498
+
499
+
500
+ self.main_.update()
501
+ except:
502
+ pass
503
+
504
+
505
+ from PyQt5.QtCore import QVariantAnimation
506
+
507
+ class MainWindow(QMainWindow):
508
+ api_enabled = False
509
+ def __init__(self):
510
+ super().__init__()
511
+
512
+ print("API Enabled:", MainWindow.api_enabled)
513
+ if MainWindow.api_enabled:
514
+ try:
515
+ from .api import start_api
516
+ start_api()
517
+ except:
518
+ raise Exception("API could not be started, please install gpt-computer-assistant[api]")
519
+ self.stop_talking = False
520
+ self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) # Remove the default title bar
521
+
522
+ # Load the San Francisco font
523
+ print("Loading font")
524
+ print(font_dir)
525
+ try:
526
+ font_id = QtGui.QFontDatabase.addApplicationFont(font_dir)
527
+
528
+
529
+ font_family = QtGui.QFontDatabase.applicationFontFamilies(font_id)[0]
530
+ self.setFont(QtGui.QFont(font_family))
531
+ except:
532
+ print("Error loading font")
533
+
534
+ self.should_paint = False # In order to initialize the painting, it will be overwritten by the settings
535
+
536
+
537
+ self.state = "idle"
538
+ self.pulse_timer = None
539
+
540
+ self.button_handler = ButtonHandler(self)
541
+ self.initUI()
542
+ self.old_position = self.pos()
543
+
544
+ if llm_settings[load_model_settings()]["transcription"]:
545
+ self.should_paint = True # Flag to control painting
546
+ else:
547
+ self.should_paint = False
548
+
549
+
550
+
551
+ self.collapse = is_collapse_setting_active()
552
+ if self.collapse:
553
+ self.collapse_window()
554
+
555
+ global the_main_window
556
+ the_main_window = self
557
+
558
+
559
+ self.general_styling()
560
+
561
+ if is_dark_mode_active():
562
+ self.dark_mode()
563
+ else:
564
+ self.light_mode()
565
+
566
+
567
+ self.wake_word_thread = None
568
+
569
+ self.wake_word_active = False
570
+
571
+ if load_pvporcupine_api_key() != "CHANGE_ME" and is_wake_word_active():
572
+ self.wake_word_active = True
573
+ self.wake_word_trigger()
574
+
575
+
576
+ self.manuel_stop = False
577
+
578
+
579
+ self.border_animation = None
580
+
581
+ self.complated_answer = False
582
+
583
+
584
+ self.reading_thread = False
585
+ self.reading_thread_2 = False
586
+
587
+ def init_border_animation(self):
588
+ # Create a QVariantAnimation to handle color change
589
+ border_animation = QVariantAnimation(
590
+ self,
591
+ valueChanged=self.update_border_color,
592
+ startValue=QColor("#303030"),
593
+ endValue=QColor("#23538F"),
594
+ duration=2000 # Duration for one loop in milliseconds
595
+ )
596
+ border_animation.setLoopCount(-1) # Loop indefinitely
597
+ return border_animation
598
+
599
+ def start_border_animation(self, status):
600
+ print("FUNCTION TRİGGERED")
601
+ if self.border_animation is None:
602
+ self.border_animation = self.init_border_animation()
603
+
604
+ status = status.lower() == "true"
605
+ if status:
606
+ self.border_animation.start()
607
+ else:
608
+ self.border_animation.stop()
609
+ self.title_bar.setStyleSheet("background-color: #2E2E2E; color: white; border-style: solid; border-radius: 15px; border-width: 0px; color: #fff;")
610
+
611
+
612
+
613
+ def update_border_color(self, color):
614
+ self.title_bar.setStyleSheet(f"background-color: #2E2E2E; color: white; border-style: solid; border-radius: 15px; border-width: 2px; border-color: {color.name()}; color: #fff;")
615
+ self.title_bar.setStyleSheet(f"background-color: #2E2E2E; color: white; border-style: solid; border-radius: 15px; border-width: 1px; border-color: {color.name()}; color: #fff;")
616
+
617
+ # Existing methods...
618
+
619
+ def general_styling(self):
620
+ self.setAttribute(Qt.WA_TranslucentBackground)
621
+ self.setStyleSheet("border-radius: 10px; background-color: rgba(45, 45, 45, 250);")
622
+ self.central_widget.setStyleSheet("border-style: solid; border-width: 1px; border-color: rgb(0,0,0,0);")
623
+
624
+ self.input_box_style = "border-radius: 10px; border-bottom: 1px solid #01EE8A;"
625
+
626
+ self.send_button_style = "border-radius: 5px; height: 25px; border-style: solid;"
627
+ self.screenshot_button_style = "border-radius: 5px; height: 25px; border-style: solid;"
628
+
629
+ self.settingsButton_style = "border-radius: 5px; height: 25px; border-style: solid;"
630
+ self.llmsettingsButton_style = "border-radius: 5px; height: 25px; border-style: solid;"
631
+
632
+ self.btn_minimize.setStyleSheet("background-color: #2E2E2E; color: white; border-style: none;")
633
+ self.btn_close.setStyleSheet("background-color: #2E2E2E; color: white; border-style: none;")
634
+
635
+
636
+ def wake_word_trigger(self):
637
+ self.wake_word_thread = threading.Thread(target=self.wake_word)
638
+ self.wake_word_thread.start()
639
+
640
+ def wake_word(self):
641
+ from .agent.process import tts_if_you_can
642
+ while True and is_wake_word_active() and self.wake_word_active:
643
+ if wake_word(self):
644
+
645
+ def random_accept_words():
646
+ return random.choice(["Yes", "Sir", "Boss", "Master"])
647
+
648
+
649
+ tts_if_you_can(random_accept_words(), not_threaded=True)
650
+
651
+
652
+ def trigger_wake_word():
653
+ if is_wake_word_screen_setting_active() and llm_settings[load_model_settings()]["vision"]:
654
+ self.button_handler.toggle_recording(dont_save_image=True)
655
+ else:
656
+ self.button_handler.toggle_recording(no_screenshot=True)
657
+
658
+ if self.state == "aitalking":
659
+ self.manuel_stop = True
660
+ self.stop_talking = True
661
+ time.sleep(1)
662
+ trigger_wake_word()
663
+ print("Stop talking")
664
+ else:
665
+ trigger_wake_word()
666
+
667
+
668
+
669
+
670
+
671
+
672
+
673
+ def dark_mode(self):
674
+ self.setAutoFillBackground(True)
675
+ p = self.palette()
676
+ p.setColor(self.backgroundRole(), QColor("#171717")) # Set background color to white
677
+ self.setPalette(p)
678
+ self.input_box.setStyleSheet(self.input_box_style+"background-color: #2E2E2E; color: white;")
679
+
680
+ self.send_button.setStyleSheet(self.send_button_style+"background-color: #2E2E2E; color: white;")
681
+ self.screenshot_button.setStyleSheet(self.screenshot_button_style+"background-color: #2E2E2E; color: white;")
682
+
683
+ self.settingsButton.setStyleSheet(self.settingsButton_style+"background-color: #2E2E2E; color: white;")
684
+ self.llmsettingsButton.setStyleSheet(self.llmsettingsButton_style+"background-color: #2E2E2E; color: white;")
685
+
686
+
687
+
688
+
689
+ def light_mode(self):
690
+ self.setAutoFillBackground(True)
691
+ p = self.palette()
692
+ p.setColor(self.backgroundRole(), QColor("#F0F0F0"))
693
+ self.setPalette(p)
694
+ self.input_box.setStyleSheet(self.input_box_style+"background-color: #FFFFFF; color: black;")
695
+ self.send_button.setStyleSheet(self.send_button_style+"background-color: #FFFFFF; color: black; ")
696
+ self.screenshot_button.setStyleSheet(self.screenshot_button_style+"background-color: #FFFFFF; color: black; ")
697
+ self.settingsButton.setStyleSheet(self.settingsButton_style+"background-color: #FFFFFF; color: black; ")
698
+ self.llmsettingsButton.setStyleSheet(self.llmsettingsButton_style+"background-color: #FFFFFF; color: black; ")
699
+
700
+
701
+
702
+
703
+
704
+ def collapse_window(self):
705
+ the_input_box.hide()
706
+ self.screenshot_button.hide()
707
+ self.settingsButton.hide()
708
+ self.llmsettingsButton.hide()
709
+ self.send_button.hide()
710
+ self.window().setFixedSize(self.width(), 140)
711
+
712
+
713
+
714
+ def initUI(self):
715
+ self.setWindowTitle("GPT")
716
+ self.setGeometry(100, 100, 200, 200)
717
+ self.setFixedSize(self.width()+10, self.height() + 80)
718
+
719
+ self.first_height = self.height()
720
+ self.first_width = self.width()
721
+
722
+ app_icon = QtGui.QIcon()
723
+ app_icon.addFile(icon_16_path, QtCore.QSize(16, 16))
724
+ app_icon.addFile(icon_24_path, QtCore.QSize(24, 24))
725
+ app_icon.addFile(icon_32_path, QtCore.QSize(32, 32))
726
+ app_icon.addFile(icon_48_path, QtCore.QSize(48, 48))
727
+ app_icon.addFile(icon_256_path, QtCore.QSize(256, 256))
728
+ self.setWindowIcon(app_icon)
729
+
730
+ self.central_widget = QWidget(self)
731
+ self.setCentralWidget(self.central_widget)
732
+ layout = QVBoxLayout(self.central_widget)
733
+
734
+ # Custom title bar
735
+ self.title_bar = QWidget(self)
736
+ self.title_bar.setFixedHeight(30) # Set a fixed height for the title bar
737
+ self.title_bar.setStyleSheet("background-color: #2E2E2E; color: #fff;")
738
+
739
+ self.title_bar_layout = QHBoxLayout(self.title_bar)
740
+ self.title_bar_layout.setContentsMargins(5, 5, 0, 5)
741
+ self.title_bar_layout.setSpacing(0)
742
+
743
+ self.btn_minimize = QPushButton("_", self.title_bar)
744
+ self.btn_minimize.setFixedSize(25, 20)
745
+ self.btn_minimize.clicked.connect(self.showMinimized)
746
+
747
+ def stop_app():
748
+ self.stop_talking = True
749
+ self.wake_word_active = False
750
+ if MainWindow.api_enabled:
751
+ from .api import stop_api
752
+ stop_api()
753
+ self.close()
754
+
755
+
756
+ self.btn_close = QPushButton("X", self.title_bar)
757
+ self.btn_close.setFixedSize(30, 20)
758
+ self.btn_close.clicked.connect(stop_app)
759
+
760
+ self.title_label = QLabel(" GPT Computer Assistant", self.title_bar)
761
+ self.title_label.setStyleSheet("border: 0px solid blue;")
762
+ self.title_bar_layout.addWidget(self.title_label)
763
+ self.title_bar_layout.addWidget(self.btn_minimize)
764
+
765
+
766
+
767
+ self.title_bar_layout.addWidget(self.btn_close)
768
+
769
+
770
+ # Create a spacer item with expanding policy
771
+ spacer = QSpacerItem(5, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
772
+ self.title_bar_layout.addSpacerItem(spacer) # Add spacer to the layout
773
+
774
+
775
+
776
+ layout.addWidget(self.title_bar)
777
+
778
+
779
+
780
+
781
+ self.drawing_widget = DrawingWidget(self)
782
+ layout.addWidget(self.drawing_widget)
783
+
784
+
785
+
786
+
787
+
788
+
789
+ self.layout = layout
790
+
791
+ self.setLayout(layout)
792
+
793
+
794
+
795
+ # Add keyboard shortcuts
796
+ self.shortcut_screenshot = QShortcut(QKeySequence("Ctrl+1"), self)
797
+ self.shortcut_screenshot.activated.connect(
798
+ lambda: self.button_handler.just_screenshot()
799
+ )
800
+ self.shortcut_screenshot = QShortcut(QKeySequence("Ctrl+2"), self)
801
+ self.shortcut_screenshot.activated.connect(
802
+ lambda: self.button_handler.toggle_recording(take_system_audio=True)
803
+ )
804
+
805
+ self.shortcut_no_screenshot = QShortcut(QKeySequence("Ctrl+e"), self)
806
+ self.shortcut_no_screenshot.activated.connect(
807
+ lambda: self.button_handler.toggle_recording(take_system_audio=True)
808
+ )
809
+
810
+ self.shortcut_no_screenshot = QShortcut(QKeySequence("Ctrl+3"), self)
811
+ self.shortcut_no_screenshot.activated.connect(
812
+ lambda: self.button_handler.toggle_recording(no_screenshot=True)
813
+ )
814
+
815
+ # I want to create an input box to bottom left and a send button to bottom right
816
+
817
+ input_box = CustomTextEdit(self)
818
+ self.input_box = input_box
819
+
820
+
821
+ input_box.setFixedHeight(40)
822
+
823
+
824
+ if load_api_key() == "CHANGE_ME":
825
+ input_box.setPlaceholderText("Save your API Key, go to settings")
826
+ else:
827
+ input_box.setPlaceholderText("Type here")
828
+ input_box.setGeometry(30, self.height() - 60, 200, 30)
829
+ global the_input_box
830
+ the_input_box = input_box
831
+
832
+ def input_box_send():
833
+ if input_box.toPlainText() != "":
834
+ self.button_handler.input_text(input_box.toPlainText())
835
+
836
+ def input_box_send_screenshot():
837
+ if input_box.toPlainText() != "":
838
+ self.button_handler.input_text_screenshot(input_box.toPlainText())
839
+
840
+ self.layout.addWidget(input_box)
841
+
842
+ # Create a horizontal layout
843
+ button_layout = QHBoxLayout()
844
+
845
+ # Create the send button
846
+ self.send_button = QPushButton("Send", self)
847
+ self.send_button.clicked.connect(input_box_send)
848
+
849
+ # Create the screenshot button
850
+ self.screenshot_button = QPushButton("+Screenshot", self)
851
+ self.screenshot_button.clicked.connect(input_box_send_screenshot)
852
+
853
+
854
+ if llm_settings[load_model_settings()]["vision"] is False:
855
+ self.screenshot_button.hide()
856
+
857
+
858
+
859
+ # Add the buttons to the horizontal layout
860
+ button_layout.addWidget(self.send_button)
861
+ button_layout.addWidget(self.screenshot_button)
862
+
863
+ self.shortcut_enter = QShortcut(QKeySequence("Ctrl+Return"), self)
864
+ self.shortcut_enter.activated.connect(input_box_send_screenshot)
865
+
866
+ global return_key_event
867
+ return_key_event = input_box_send
868
+
869
+ self.layout.addLayout(button_layout)
870
+
871
+ button_layout_ = QHBoxLayout()
872
+
873
+ self.settingsButton = QPushButton("Chat Settings", self)
874
+ self.settingsButton.clicked.connect(settings_popup)
875
+
876
+ self.llmsettingsButton = QPushButton("LLM Settings", self)
877
+ self.llmsettingsButton.clicked.connect(llmsettings_popup)
878
+
879
+ button_layout_.addWidget(self.settingsButton)
880
+ button_layout_.addWidget(self.llmsettingsButton)
881
+ self.layout.addLayout(button_layout_)
882
+
883
+
884
+
885
+ self.worker = Worker()
886
+ self.worker.text_to_set.connect(self.set_text)
887
+ self.worker.start()
888
+
889
+ self.worker_2 = Worker_2()
890
+ self.worker_2.text_to_set.connect(self.start_border_animation)
891
+ self.worker_2.text_to_set_title_bar.connect(self.set_title_bar_text)
892
+ self.worker_2.start()
893
+
894
+ # print height and width
895
+ print(self.height(), self.width())
896
+
897
+ self.show()
898
+
899
+
900
+
901
+
902
+
903
+ def set_text(self, text):
904
+ global the_input_box
905
+
906
+
907
+ vertical_scrollbar = the_input_box.verticalScrollBar()
908
+ scroll_value = vertical_scrollbar.value()
909
+
910
+
911
+
912
+ the_input_box.setPlainText(text)
913
+
914
+ vertical_scrollbar.setValue(scroll_value)
915
+
916
+ def set_title_bar_text(self, text):
917
+ self.title_label.setText(text)
918
+
919
+ def update_from_thread(self, text, system=True):
920
+ self.worker.make_animation = True
921
+ if system:
922
+ text = "System: " + text
923
+ print("Updating from thread", text)
924
+ self.worker.the_input_text = text
925
+
926
+ def read_part_task_generate_only(self):
927
+ if not is_just_text_model_active() and not the_main_window.api_enabled:
928
+
929
+
930
+ threads = {}
931
+
932
+ the_okey_parts = split_with_multiple_delimiters(self.worker.the_input_text,".?!:")
933
+
934
+
935
+
936
+
937
+ for each in the_okey_parts:
938
+ if the_main_window.stop_talking:
939
+ break
940
+
941
+
942
+ the_thread = threading.Thread(target=text_to_speech, args=(each,))
943
+
944
+ threads[each] = the_thread
945
+ the_thread.start()
946
+
947
+
948
+ for each in threads.values():
949
+ each.join()
950
+
951
+
952
+ self.reading_thread_2 = False
953
+
954
+ def read_part_task(self):
955
+ if not is_just_text_model_active() and not the_main_window.api_enabled:
956
+ threads = {}
957
+
958
+ the_okey_parts = split_with_multiple_delimiters(self.worker.the_input_text,".?!:")
959
+
960
+
961
+ will_read_parts = []
962
+
963
+ for each in the_okey_parts:
964
+ if the_main_window.stop_talking:
965
+ break
966
+ if each not in readed_sentences:
967
+ will_read_parts.append(each)
968
+ readed_sentences.append(each)
969
+
970
+ the_thread = threading.Thread(target=text_to_speech, args=(each,))
971
+
972
+ threads[each] = the_thread
973
+ the_thread.start()
974
+
975
+
976
+
977
+ for each in will_read_parts:
978
+ if the_main_window.stop_talking:
979
+ break
980
+ threads[each].join()
981
+
982
+ tts_if_you_can(each, not_threaded=True, bypass_other_settings=True)
983
+
984
+
985
+ self.reading_thread = False
986
+
987
+
988
+ def set_text_to_input_box(self, text):
989
+ global readed_sentences
990
+ self.worker.make_animation = False
991
+ if self.worker.the_input_text.startswith("System:") or self.complated_answer:
992
+ self.worker.the_input_text = ""
993
+ self.complated_answer = False
994
+ readed_sentences = []
995
+ if text not in (">", "<>", ">\n", "<", "<\n"):
996
+
997
+ self.worker.the_input_text += text
998
+
999
+ if self.reading_thread is not True and len(self.worker.the_input_text) > 40:
1000
+ self.reading_thread = True
1001
+ threading.Thread(target=self.read_part_task).start()
1002
+
1003
+ if self.reading_thread_2 is not True and len(self.worker.the_input_text) > 250:
1004
+ self.reading_thread_2 = True
1005
+ threading.Thread(target=self.read_part_task_generate_only).start()
1006
+
1007
+
1008
+
1009
+
1010
+
1011
+
1012
+
1013
+
1014
+
1015
+ def active_border_animation(self, title_bar_text = None):
1016
+ if self.worker_2.title_bar_text is not None:
1017
+ if self.worker_2.title_bar_text != title_bar_text:
1018
+ return
1019
+
1020
+ self.worker_2.the_input_text = True
1021
+ if title_bar_text is None:
1022
+ title_bar_text = " GPT Computer Assistant"
1023
+ else:
1024
+ title_bar_text = f" {title_bar_text}"
1025
+ if len(title_bar_text) > 33:
1026
+ title_bar_text = title_bar_text[:30] + "..."
1027
+ self.worker_2.title_bar_text = title_bar_text
1028
+
1029
+ self.btn_minimize.hide()
1030
+ self.btn_close.hide()
1031
+ def deactive_border_animation(self, title_bar_text=None):
1032
+
1033
+ if title_bar_text is None:
1034
+ title_bar_text = " GPT Computer Assistant"
1035
+ else:
1036
+ title_bar_text = f" {title_bar_text}"
1037
+ if len(title_bar_text) > 33:
1038
+ title_bar_text = title_bar_text[:30] + "..."
1039
+
1040
+ if self.worker_2.title_bar_text is not None:
1041
+ if self.worker_2.title_bar_text != title_bar_text:
1042
+ return
1043
+
1044
+ self.worker_2.the_input_text = False
1045
+ self.worker_2.title_bar_text = None
1046
+ time.sleep(1)
1047
+ self.btn_minimize.show()
1048
+ self.btn_close.show()
1049
+
1050
+
1051
+ def mouseMoveEvent(self, event: QMouseEvent):
1052
+ delta = QPoint(event.globalPos() - self.old_position)
1053
+ if event.buttons() == Qt.LeftButton and self.title_bar.underMouse():
1054
+ self.move(self.x() + delta.x(), self.y() + delta.y())
1055
+ self.old_position = event.globalPos()
1056
+
1057
+
1058
+ def mousePressEvent(self, event: QMouseEvent):
1059
+ self.old_position = event.globalPos()
1060
+
1061
+
1062
+
1063
+
1064
+ def remove_painting(self):
1065
+ self.should_paint = False # Set the flag to False
1066
+ self.update() # Request a repaint, which will now skip drawing
1067
+
1068
+ def activate_painting(self):
1069
+ self.should_paint = True
1070
+ self.update()
1071
+
1072
+ def remove_screenshot_button(self):
1073
+ self.screenshot_button.hide()
1074
+
1075
+ def add_screenshot_button(self):
1076
+ self.screenshot_button.show()
1077
+
1078
+ def update_state(self, new_state):
1079
+
1080
+ assistant_stopped = False
1081
+ if self.state == "aitalking" and new_state == "idle":
1082
+ assistant_stopped = True
1083
+
1084
+ if self.manuel_stop:
1085
+ assistant_stopped = False
1086
+ self.manuel_stop = False
1087
+
1088
+
1089
+
1090
+ self.state = new_state
1091
+ print(f"State updated: {new_state}")
1092
+ if "talking" in new_state:
1093
+ self.pulse_frame = 0
1094
+ if self.pulse_timer:
1095
+ self.pulse_timer.stop()
1096
+ self.pulse_timer = None
1097
+ self.pulse_timer = QTimer(self)
1098
+ self.pulse_timer.timeout.connect(self.pulse_circle)
1099
+ self.pulse_timer.start(5)
1100
+ elif new_state == "thinking":
1101
+
1102
+ the_main_window.update_from_thread("Thinking...")
1103
+ self.pulse_frame = 0
1104
+ if self.pulse_timer:
1105
+ self.pulse_timer.stop()
1106
+ self.pulse_timer = None
1107
+ self.pulse_timer = QTimer(self)
1108
+ self.pulse_timer.timeout.connect(self.pulse_circle)
1109
+ self.pulse_timer.start(20)
1110
+ elif self.pulse_timer:
1111
+ self.pulse_timer.stop()
1112
+ self.pulse_timer = None
1113
+ self.update() # Trigger a repaint
1114
+
1115
+ if assistant_stopped:
1116
+ if llm_settings[load_model_settings()]["transcription"]:
1117
+ global the_input_box
1118
+ if the_input_box.toPlainText().endswith("?") and is_continuously_conversations_setting_active():
1119
+ self.button_handler.toggle_recording(no_screenshot=True, new_record=True)
1120
+
1121
+ def pulse_circle(self):
1122
+ self.pulse_frame = (self.pulse_frame + 1) % 100
1123
+ self.update()
1124
+
1125
+
gpt_computer_assistant/gui/__init__.py ADDED
File without changes
gpt_computer_assistant/gui/button.py ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pyautogui
2
+ from .signal import *
3
+ import threading
4
+
5
+ try:
6
+ from ..audio.record import *
7
+ from ..screen.shot import *
8
+ from ..agent.process import *
9
+ from ..agent.chat_history import clear_chat_history
10
+ from ..utils.db import (
11
+ screenshot_path,
12
+ save_api_key,
13
+ load_api_key,
14
+ activate_just_text_model,
15
+ deactivate_just_text_model,
16
+ is_just_text_model_active,
17
+ set_profile,
18
+ get_profile,
19
+ )
20
+ from ..screen.shot import take_screenshot
21
+ except ImportError:
22
+ from audio.record import *
23
+ from screen.shot import *
24
+ from agent.process import *
25
+ from agent.chat_history import clear_chat_history
26
+ from utils.db import (
27
+ screenshot_path,
28
+ save_api_key,
29
+ load_api_key,
30
+ activate_just_text_model,
31
+ deactivate_just_text_model,
32
+ is_just_text_model_active,
33
+ set_profile,
34
+ get_profile,
35
+ )
36
+ from screen.shot import take_screenshot
37
+
38
+ recording_thread = None
39
+
40
+
41
+ class ButtonHandler:
42
+ """Handles button click events and corresponding actions."""
43
+
44
+ def __init__(self, main_window):
45
+ """Initialize the ButtonHandler."""
46
+ self.recording = False
47
+ self.main_window = main_window
48
+ self.process_audio_thread = None
49
+
50
+ signal_handler.recording_started.connect(self.on_recording_started)
51
+ signal_handler.recording_stopped.connect(self.on_recording_stopped)
52
+ signal_handler.assistant_thinking.connect(self.on_assistant_thinking)
53
+ signal_handler.assistant_response_ready.connect(
54
+ self.on_assistant_response_ready
55
+ )
56
+ signal_handler.assistant_response_stopped.connect(
57
+ self.on_assistant_response_stopped
58
+ )
59
+
60
+ def toggle_recording(
61
+ self, no_screenshot=False, take_system_audio=False, dont_save_image=False, new_record=False
62
+ ):
63
+ """Toggle audio recording."""
64
+
65
+ if self.recording and not new_record:
66
+ stop_recording()
67
+ self.recording = False
68
+ else:
69
+ if not no_screenshot:
70
+ screenshot = pyautogui.screenshot()
71
+ screenshot.save(screenshot_path)
72
+
73
+ self.no_screenshot = no_screenshot
74
+ self.take_system_audio = take_system_audio
75
+ self.dont_save_image = dont_save_image
76
+
77
+ global recording_thread
78
+ if recording_thread is None or not recording_thread.is_alive() or new_record:
79
+ recording_thread = threading.Thread(
80
+ target=start_recording, args=(take_system_audio,self,)
81
+ )
82
+ recording_thread.start()
83
+ signal_handler.recording_started.emit()
84
+
85
+ def on_recording_started(self):
86
+ """Handle event when recording starts."""
87
+
88
+ self.recording = True
89
+ self.main_window.update_state("talking")
90
+
91
+ def on_recording_stopped(self):
92
+ """Handle event when recording stops."""
93
+
94
+ print("ON RECORDING STOPPED")
95
+ self.recording = False
96
+ self.main_window.update_state("thinking")
97
+ if (
98
+ self.process_audio_thread is None
99
+ or not self.process_audio_thread.is_alive()
100
+ ):
101
+ signal_handler.assistant_thinking.emit()
102
+ self.process_audio_thread = threading.Thread(
103
+ target=process_audio,
104
+ args=(
105
+ not self.no_screenshot,
106
+ self.take_system_audio,
107
+ self.dont_save_image,
108
+ ),
109
+ )
110
+ self.process_audio_thread.start()
111
+
112
+ def just_screenshot(self):
113
+ """Take a screenshot."""
114
+
115
+ take_screenshot()
116
+ self.process_audio_thread = threading.Thread(target=process_screenshot)
117
+ self.process_audio_thread.start()
118
+
119
+ def on_assistant_response_stopped(self):
120
+ """Handle event when assistant's response stops."""
121
+
122
+ self.main_window.update_state("idle")
123
+
124
+ def on_assistant_thinking(self):
125
+ """Handle event when assistant is thinking."""
126
+
127
+ self.main_window.update_state("thinking")
128
+
129
+ def on_assistant_response_ready(self):
130
+ """Handle event when assistant's response is ready."""
131
+
132
+ self.main_window.update_state("aitalking")
133
+
134
+ def input_text(self, text):
135
+ """Handle input text."""
136
+
137
+ self.main_window.update_state("thinking")
138
+ if (
139
+ self.process_audio_thread is None
140
+ or not self.process_audio_thread.is_alive()
141
+ ):
142
+ signal_handler.assistant_thinking.emit()
143
+ self.process_audio_thread = threading.Thread(
144
+ target=process_text, args=(text,)
145
+ )
146
+ self.process_audio_thread.start()
147
+
148
+ def input_text_screenshot(self, text):
149
+ """Handle input text with screenshot."""
150
+
151
+ screenshot = pyautogui.screenshot()
152
+ screenshot.save(screenshot_path)
153
+
154
+ self.main_window.update_state("thinking")
155
+ if (
156
+ self.process_audio_thread is None
157
+ or not self.process_audio_thread.is_alive()
158
+ ):
159
+ signal_handler.assistant_thinking.emit()
160
+ self.process_audio_thread = threading.Thread(
161
+ target=process_text,
162
+ args=(text,),
163
+ kwargs={"screenshot_path": screenshot_path},
164
+ )
165
+ self.process_audio_thread.start()
gpt_computer_assistant/gui/llmsettings.py ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ try:
2
+ from ..utils.db import *
3
+ from ..agent.chat_history import clear_chat_history
4
+ from ..llm_settings import llm_show_name, llm_settings
5
+ except ImportError:
6
+ from utils.db import *
7
+ from agent.chat_history import clear_chat_history
8
+ from llm_settings import llm_show_name, llm_settings
9
+
10
+ from PyQt5.QtWidgets import QDialog, QVBoxLayout, QLabel, QLineEdit, QPushButton
11
+ from PyQt5.QtCore import Qt
12
+ from PyQt5.QtWidgets import QComboBox
13
+
14
+ from gpt_computer_assistant.utils.db import save_openai_url, save_groq_api_key
15
+
16
+
17
+ def llmsettings_popup(self):
18
+ from ..gpt_computer_assistant import the_main_window
19
+
20
+ # Create a settings dialog and inside of it create a text input about openai_api_key and a button to save it
21
+ settings_dialog = QDialog()
22
+ settings_dialog.setWindowTitle("Settings")
23
+ settings_dialog.setWindowModality(Qt.ApplicationModal)
24
+
25
+ settings_dialog.setLayout(QVBoxLayout())
26
+
27
+ api_key_label = QLabel("OpenAI API Key")
28
+ settings_dialog.layout().addWidget(api_key_label)
29
+ api_key_input = QLineEdit()
30
+ api_key = load_api_key()
31
+ api_key_input.setText(api_key)
32
+ settings_dialog.layout().addWidget(api_key_input)
33
+ save_button = QPushButton("Save")
34
+
35
+ def save_api_key_(api_key):
36
+ save_api_key(api_key)
37
+
38
+ the_main_window.update_from_thread("Saved API Key")
39
+ the_main_window.input_box.setPlaceholderText("Type here")
40
+ settings_dialog.close()
41
+
42
+ save_button.clicked.connect(lambda: save_api_key_(api_key_input.text()))
43
+ settings_dialog.layout().addWidget(save_button)
44
+
45
+ # Start of new OpenAI Base URL settings
46
+ openai_url_label = QLabel("OpenAI Base URL")
47
+ settings_dialog.layout().addWidget(openai_url_label)
48
+ openai_url_input = QLineEdit()
49
+ openai_url = load_openai_url()
50
+ openai_url_input.setText(openai_url)
51
+ settings_dialog.layout().addWidget(openai_url_input)
52
+
53
+ def save_openai_url_():
54
+ openai_url = openai_url_input.text()
55
+ save_openai_url(openai_url)
56
+
57
+ the_main_window.update_from_thread("Saved OpenAI Base URL")
58
+ the_main_window.input_box.setPlaceholderText("Type here")
59
+ settings_dialog.close()
60
+
61
+ openai_url_save_button = QPushButton("Save URL")
62
+ openai_url_save_button.clicked.connect(save_openai_url_)
63
+ settings_dialog.layout().addWidget(openai_url_save_button)
64
+ # End of new OpenAI Base URL settings
65
+
66
+ groq_api_key_label = QLabel("Groq API Key")
67
+ settings_dialog.layout().addWidget(groq_api_key_label)
68
+ groq_api_key_input = QLineEdit()
69
+ groq_api_key = load_groq_api_key()
70
+ groq_api_key_input.setText(groq_api_key)
71
+ settings_dialog.layout().addWidget(groq_api_key_input)
72
+ groq_save_button = QPushButton("Save")
73
+
74
+ def groq_save_api_key_(api_key):
75
+ save_groq_api_key(api_key)
76
+ the_main_window.update_from_thread("Saved Groq API Key")
77
+ the_main_window.input_box.setPlaceholderText("Type here")
78
+ settings_dialog.close()
79
+
80
+ groq_save_button.clicked.connect(
81
+ lambda: groq_save_api_key_(groq_api_key_input.text())
82
+ )
83
+ settings_dialog.layout().addWidget(groq_save_button)
84
+
85
+
86
+
87
+ google_api_key_label = QLabel("Google Generative AI API Key")
88
+ settings_dialog.layout().addWidget(google_api_key_label)
89
+ google_api_key_input = QLineEdit()
90
+ google_api_key = load_google_api_key()
91
+ google_api_key_input.setText(google_api_key)
92
+ settings_dialog.layout().addWidget(google_api_key_input)
93
+ google_save_button = QPushButton("Save")
94
+
95
+ def google_save_api_key_(api_key):
96
+ save_google_api_key(api_key)
97
+ the_main_window.update_from_thread("Saved Google API Key")
98
+ the_main_window.input_box.setPlaceholderText("Type here")
99
+ settings_dialog.close()
100
+
101
+ google_save_button.clicked.connect(
102
+ lambda: google_save_api_key_(google_api_key_input.text())
103
+ )
104
+ settings_dialog.layout().addWidget(google_save_button)
105
+
106
+ def hide_openai():
107
+ api_key_label.hide()
108
+ api_key_input.hide()
109
+ openai_url_label.hide()
110
+ openai_url_input.hide()
111
+ save_button.hide()
112
+ openai_url_save_button.hide()
113
+
114
+ def hide_groq():
115
+ groq_api_key_label.hide()
116
+ groq_api_key_input.hide()
117
+ groq_save_button.hide()
118
+
119
+
120
+ def hide_google():
121
+ google_api_key_label.hide()
122
+ google_api_key_input.hide()
123
+ google_save_button.hide()
124
+
125
+ def show_openai():
126
+ api_key_label.show()
127
+ api_key_input.show()
128
+ openai_url_label.show()
129
+ openai_url_input.show()
130
+ save_button.show()
131
+ openai_url_save_button.show()
132
+
133
+ def show_groq():
134
+ groq_api_key_label.show()
135
+ groq_api_key_input.show()
136
+ groq_save_button.show()
137
+
138
+ def show_google():
139
+ google_api_key_label.show()
140
+ google_api_key_input.show()
141
+ google_save_button.show()
142
+
143
+ hide_openai()
144
+ hide_groq()
145
+ hide_google()
146
+
147
+ print("LLLM SETTINGS", list(llm_show_name.keys()))
148
+
149
+ # Add a select box with the options OpenAI and Olamo
150
+ model_label = QLabel("Model")
151
+ model_select = QComboBox()
152
+ model_select.addItems(
153
+ list(llm_show_name.keys())
154
+ )
155
+
156
+ settings_dialog.layout().addWidget(model_label)
157
+ settings_dialog.layout().addWidget(model_select)
158
+
159
+ # currently model
160
+ current_model = load_model_settings()
161
+ # lets set index of current model
162
+ for i, model in enumerate(llm_show_name.keys()):
163
+ print("MODEL", model, current_model)
164
+ the_save_string = llm_show_name[model]
165
+ if the_save_string == current_model:
166
+ model_select.setCurrentIndex(i)
167
+
168
+
169
+
170
+ if llm_settings[llm_show_name[model_select.currentText()]]["provider"] == "openai":
171
+ show_openai()
172
+
173
+ if llm_settings[llm_show_name[model_select.currentText()]]["provider"] == "groq":
174
+ show_groq()
175
+
176
+ if llm_settings[llm_show_name[model_select.currentText()]]["provider"] == "google":
177
+ show_google()
178
+
179
+ if not llm_settings[llm_show_name[model_select.currentText()]]["transcription"]:
180
+
181
+ the_main_window.remove_painting()
182
+
183
+ if not llm_settings[llm_show_name[model_select.currentText()]]["vision"]:
184
+
185
+ the_main_window.remove_screenshot_button()
186
+
187
+
188
+
189
+
190
+ def on_model_change():
191
+ hide_openai()
192
+ hide_groq()
193
+ hide_google()
194
+
195
+
196
+ the_save_string = llm_show_name[model_select.currentText()]
197
+ save_model_settings(the_save_string)
198
+
199
+
200
+
201
+
202
+
203
+ if llm_settings[llm_show_name[model_select.currentText()]]["transcription"] is False:
204
+ from ..gpt_computer_assistant import the_main_window
205
+
206
+ the_main_window.remove_painting()
207
+
208
+
209
+
210
+ if llm_settings[llm_show_name[model_select.currentText()]]["provider"] == "openai":
211
+ show_openai()
212
+ openai_url_label.show()
213
+ openai_url_input.show()
214
+ openai_url_save_button.show()
215
+ from ..gpt_computer_assistant import the_main_window
216
+
217
+ the_main_window.activate_painting()
218
+
219
+ if llm_settings[llm_show_name[model_select.currentText()]]["vision"]:
220
+ the_main_window.add_screenshot_button()
221
+ else:
222
+ the_main_window.remove_screenshot_button()
223
+
224
+
225
+
226
+
227
+ if llm_settings[llm_show_name[model_select.currentText()]]["provider"] == "groq":
228
+ show_groq()
229
+
230
+ if llm_settings[llm_show_name[model_select.currentText()]]["provider"] == "google":
231
+ show_google()
232
+
233
+
234
+ model_select.currentIndexChanged.connect(on_model_change)
235
+
236
+ settings_dialog.exec_()
gpt_computer_assistant/gui/settings.py ADDED
@@ -0,0 +1,352 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PyQt5.QtWidgets import QDialog, QVBoxLayout, QLabel, QLineEdit, QPushButton
2
+ from PyQt5.QtCore import Qt
3
+ from ..utils.db import *
4
+ from ..agent.chat_history import clear_chat_history
5
+
6
+ def settings_popup(self):
7
+ """
8
+ Display a settings popup dialog for configuring various options.
9
+
10
+ This function creates a settings dialog with options to reset chat history, enable/disable the just text model,
11
+ and change the active profile.
12
+
13
+ Parameters:
14
+ - self: Reference to the main application window.
15
+
16
+ Returns:
17
+ - None
18
+ """
19
+ from ..gpt_computer_assistant import the_main_window
20
+
21
+ settings_dialog = QDialog()
22
+ settings_dialog.setWindowTitle("Settings")
23
+ settings_dialog.setWindowModality(Qt.ApplicationModal)
24
+
25
+ settings_dialog.setLayout(QVBoxLayout())
26
+
27
+ reset_memory_button = QPushButton("Reset Memory")
28
+
29
+ def clear_chat_history_():
30
+ """
31
+ Clear the chat history and update the main window.
32
+
33
+ This function clears the chat history and updates the main window with a notification.
34
+
35
+ Returns:
36
+ - None
37
+ """
38
+ clear_chat_history()
39
+ the_main_window.update_from_thread("Cleared Chat History")
40
+ settings_dialog.close()
41
+
42
+ reset_memory_button.clicked.connect(clear_chat_history_)
43
+ settings_dialog.layout().addWidget(reset_memory_button)
44
+
45
+ just_text_button = QPushButton("Enable Just Text Model")
46
+
47
+ settings_dialog.layout().addWidget(just_text_button)
48
+
49
+ if is_just_text_model_active():
50
+ just_text_button.setText("Disable Just Text Model")
51
+
52
+ def deactivate_just_text_model_():
53
+ """
54
+ Deactivate the just text model and update the main window.
55
+
56
+ This function deactivates the just text model and updates the main window with a notification.
57
+
58
+ Returns:
59
+ - None
60
+ """
61
+ deactivate_just_text_model()
62
+ the_main_window.update_from_thread("Disabled Just Text Model")
63
+ settings_dialog.close()
64
+
65
+ just_text_button.clicked.connect(deactivate_just_text_model_)
66
+ else:
67
+
68
+ def activate_just_text_model_():
69
+ """
70
+ Activate the just text model and update the main window.
71
+
72
+ This function activates the just text model and updates the main window with a notification.
73
+
74
+ Returns:
75
+ - None
76
+ """
77
+ activate_just_text_model()
78
+ the_main_window.update_from_thread("Enabled Just Text Model")
79
+ settings_dialog.close()
80
+
81
+ just_text_button.clicked.connect(activate_just_text_model_)
82
+
83
+ settings_dialog.layout().addWidget(QLabel("Profile"))
84
+ profile_input = QLineEdit()
85
+
86
+ profile_input.setText(get_profile())
87
+ settings_dialog.layout().addWidget(profile_input)
88
+ profile_save_button = QPushButton("Save")
89
+
90
+ def set_profile_(profile):
91
+ """
92
+ Set the active profile and update the main window.
93
+
94
+ This function sets the active profile based on user input and updates the main window with a notification.
95
+
96
+ Parameters:
97
+ - profile (str): The profile name to set.
98
+
99
+ Returns:
100
+ - None
101
+ """
102
+ set_profile(profile)
103
+ the_main_window.update_from_thread("Saved Profile")
104
+ settings_dialog.close()
105
+
106
+ profile_save_button.clicked.connect(lambda: set_profile_(profile_input.text()))
107
+ settings_dialog.layout().addWidget(profile_save_button)
108
+
109
+
110
+ dark_mode_button = QPushButton("Enable Dark Mode")
111
+
112
+ settings_dialog.layout().addWidget(dark_mode_button)
113
+
114
+ if is_dark_mode_active():
115
+ dark_mode_button.setText("Disable Dark Mode")
116
+
117
+ def deactivate_dark_mode_():
118
+ """
119
+ Deactivate dark mode and update the main window.
120
+
121
+ This function deactivates dark mode and updates the main window with a notification.
122
+
123
+ Returns:
124
+ - None
125
+ """
126
+ deactivate_dark_mode()
127
+ the_main_window.update_from_thread("Disabled Dark Mode")
128
+ the_main_window.light_mode()
129
+ settings_dialog.close()
130
+
131
+ dark_mode_button.clicked.connect(deactivate_dark_mode_)
132
+ else:
133
+
134
+ def activate_dark_mode_():
135
+ """
136
+ Activate dark mode and update the main window.
137
+
138
+ This function activates dark mode and updates the main window with a notification.
139
+
140
+ Returns:
141
+ - None
142
+ """
143
+ activate_dark_mode()
144
+ the_main_window.update_from_thread("Enabled Dark Mode")
145
+ the_main_window.dark_mode()
146
+ settings_dialog.close()
147
+
148
+ dark_mode_button.clicked.connect(activate_dark_mode_)
149
+
150
+
151
+
152
+
153
+ predefined_agents_button = QPushButton("Enable Predefined Agents (Good Results, Long Response Time)")
154
+
155
+ settings_dialog.layout().addWidget(predefined_agents_button)
156
+
157
+ try:
158
+ import crewai
159
+ if is_predefined_agents_setting_active():
160
+ predefined_agents_button.setText("Disable Predefined Agents (Bad Results, Short Response Time)")
161
+
162
+ def deactivate_predefined_agents_():
163
+ deactivate_predefined_agents_setting()
164
+ the_main_window.update_from_thread("Disabled Predefined Agents (Bad Results, Short Response Time)")
165
+ settings_dialog.close()
166
+
167
+ predefined_agents_button.clicked.connect(deactivate_predefined_agents_)
168
+ else:
169
+
170
+ def activate_predefined_agents_():
171
+ activate_predefined_agents_setting()
172
+ the_main_window.update_from_thread("Enabled Predefined Agents (Good Results, Long Response Time)")
173
+ settings_dialog.close()
174
+
175
+ predefined_agents_button.clicked.connect(activate_predefined_agents_)
176
+
177
+ except:
178
+ predefined_agents_button.setText("Install gpt-computer-assistant[agentic]")
179
+
180
+
181
+
182
+
183
+
184
+
185
+ online_tools_button = QPushButton("Enable Upsonic Tiger Tools - More Capability (Recommended)")
186
+
187
+ settings_dialog.layout().addWidget(online_tools_button)
188
+
189
+ if is_online_tools_setting_active():
190
+ online_tools_button.setText("Disable Upsonic Tiger Tools - Low Capability (Not Recommended)")
191
+
192
+ def deactivate_online_tools_():
193
+ deactivate_online_tools_setting()
194
+ the_main_window.update_from_thread("Disabled Upsonic Tiger Tools - Low Capability (Not Recommended)")
195
+ settings_dialog.close()
196
+
197
+ online_tools_button.clicked.connect(deactivate_online_tools_)
198
+ else:
199
+
200
+ def activate_online_tools_():
201
+ activate_online_tools_setting()
202
+ the_main_window.update_from_thread("Enabled Upsonic Tiger Tools - More Capability (Recommended)")
203
+ settings_dialog.close()
204
+
205
+ online_tools_button.clicked.connect(activate_online_tools_)
206
+
207
+
208
+
209
+
210
+
211
+ auto_stop_recording_button = QPushButton("Enable Auto Stop Recording")
212
+
213
+ settings_dialog.layout().addWidget(auto_stop_recording_button)
214
+
215
+ if is_auto_stop_recording_setting_active():
216
+ auto_stop_recording_button.setText("Disable Auto Stop Recording")
217
+
218
+ def deactivate_auto_stop_recording_():
219
+ deactivate_auto_stop_recording_setting()
220
+ the_main_window.update_from_thread("Disabled Auto Stop Recording")
221
+ settings_dialog.close()
222
+
223
+ auto_stop_recording_button.clicked.connect(deactivate_auto_stop_recording_)
224
+ else:
225
+
226
+ def activate_auto_stop_recording_():
227
+ activate_auto_stop_recording_setting()
228
+ the_main_window.update_from_thread("Enabled Auto Stop Recording")
229
+ settings_dialog.close()
230
+
231
+ auto_stop_recording_button.clicked.connect(activate_auto_stop_recording_)
232
+
233
+
234
+
235
+
236
+
237
+ api_key_label = QLabel("Wakeword - Pvporcupine API Key")
238
+ settings_dialog.layout().addWidget(api_key_label)
239
+ api_key_input = QLineEdit()
240
+ api_key = load_pvporcupine_api_key()
241
+ api_key_input.setText(api_key)
242
+ settings_dialog.layout().addWidget(api_key_input)
243
+ save_button = QPushButton("Save")
244
+
245
+ def save_api_key_(api_key):
246
+ first_time = True
247
+ if api_key != "CHANGE_ME":
248
+ first_time = False
249
+ save_pvporcupine_api_key(api_key)
250
+
251
+ the_main_window.update_from_thread("Wake word activated, just say 'Her Computer' or jarvis to activate the assistant")
252
+ if first_time:
253
+ the_main_window.wake_word_trigger()
254
+ settings_dialog.close()
255
+
256
+ save_button.clicked.connect(lambda: save_api_key_(api_key_input.text()))
257
+ settings_dialog.layout().addWidget(save_button)
258
+
259
+
260
+
261
+
262
+
263
+ wake_word_button = QPushButton("Enable Wake Word")
264
+
265
+ settings_dialog.layout().addWidget(wake_word_button)
266
+
267
+ missing_parts = False
268
+ try:
269
+ import pyaudio
270
+ except:
271
+ missing_parts = True
272
+
273
+
274
+ if api_key == "CHANGE_ME":
275
+ wake_word_button.setText("Please Set Pvporcupine API Key First")
276
+ elif missing_parts:
277
+ wake_word_button.setText("Please Install gpt-computer-assistant[wakeword]")
278
+ else:
279
+
280
+ if is_wake_word_active():
281
+ wake_word_button.setText("Disable Wake Word")
282
+
283
+ def deactivate_wake_word_():
284
+ deactivate_wake_word()
285
+ the_main_window.update_from_thread("Disabled Wake Word")
286
+ the_main_window.wake_word_active = False
287
+ settings_dialog.close()
288
+
289
+ wake_word_button.clicked.connect(deactivate_wake_word_)
290
+ else:
291
+
292
+ def activate_wake_word_():
293
+ activate_wake_word()
294
+ the_main_window.update_from_thread("Enabled Wake Word")
295
+ the_main_window.wake_word_active = True
296
+ the_main_window.wake_word_trigger()
297
+ settings_dialog.close()
298
+
299
+ wake_word_button.clicked.connect(activate_wake_word_)
300
+
301
+
302
+
303
+
304
+
305
+ wake_word_screen_button = QPushButton("Enable Screen Input for Wake Word Mode")
306
+
307
+ settings_dialog.layout().addWidget(wake_word_screen_button)
308
+
309
+ if is_wake_word_screen_setting_active():
310
+ wake_word_screen_button.setText("Disable Screen Input for Wake Word Mode")
311
+
312
+ def deactivate_auto_stop_recording_():
313
+ deactivate_wake_word_screen_setting()
314
+ the_main_window.update_from_thread("Disabled Screen Input for Wake Word Mode")
315
+ settings_dialog.close()
316
+
317
+ wake_word_screen_button.clicked.connect(deactivate_auto_stop_recording_)
318
+ else:
319
+
320
+ def activate_auto_stop_recording_():
321
+ activate_wake_word_screen_setting()
322
+ the_main_window.update_from_thread("Enabled Screen Input for Wake Word Mode")
323
+ settings_dialog.close()
324
+
325
+ wake_word_screen_button.clicked.connect(activate_auto_stop_recording_)
326
+
327
+
328
+
329
+
330
+ continuously_conversations_button = QPushButton("Enable Continuously Conversations")
331
+
332
+ settings_dialog.layout().addWidget(continuously_conversations_button)
333
+
334
+ if is_continuously_conversations_setting_active():
335
+ continuously_conversations_button.setText("Disable Continuously Conversations")
336
+
337
+ def deactivate_auto_stop_recording_():
338
+ deactivate_continuously_conversations_setting()
339
+ the_main_window.update_from_thread("Disabled Continuously Conversations")
340
+ settings_dialog.close()
341
+
342
+ continuously_conversations_button.clicked.connect(deactivate_auto_stop_recording_)
343
+ else:
344
+
345
+ def activate_auto_stop_recording_():
346
+ activate_continuously_conversations_setting()
347
+ the_main_window.update_from_thread("Enabled Continuously Conversations")
348
+ settings_dialog.close()
349
+
350
+ continuously_conversations_button.clicked.connect(activate_auto_stop_recording_)
351
+
352
+ settings_dialog.exec_()
gpt_computer_assistant/gui/signal.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PyQt5.QtCore import pyqtSignal, QObject
2
+
3
+
4
+
5
+ class SignalHandler(QObject):
6
+ """
7
+ A QObject subclass to handle signals used in the GUI application.
8
+
9
+ This class defines several signals that can be used to communicate
10
+ between different components of the GUI application.
11
+
12
+ Signals:
13
+ - recording_started: Signal emitted when recording is started.
14
+ - recording_stopped: Signal emitted when recording is stopped.
15
+ - assistant_thinking: Signal emitted when the assistant is processing a request.
16
+ - assistant_response_ready: Signal emitted when the assistant response is ready to be displayed.
17
+ - assistant_response_stopped: Signal emitted when the assistant response display is stopped.
18
+
19
+ """
20
+
21
+ recording_started = pyqtSignal()
22
+ recording_stopped = pyqtSignal()
23
+ assistant_thinking = pyqtSignal()
24
+ assistant_response_ready = pyqtSignal()
25
+ assistant_response_stopped = pyqtSignal()
26
+
27
+ signal_handler = SignalHandler()
28
+
gpt_computer_assistant/llm.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from openai import OpenAI
2
+ from langchain_openai import ChatOpenAI
3
+ from langchain_community.chat_models import ChatOllama
4
+ from langchain_google_genai import ChatGoogleGenerativeAI
5
+ from langchain_groq import ChatGroq
6
+
7
+ try:
8
+ from .utils.db import load_api_key, load_openai_url, load_model_settings, load_groq_api_key, load_google_api_key
9
+ from .custom_callback import customcallback
10
+ except ImportError:
11
+ from utils.db import load_api_key, load_openai_url, load_model_settings, load_groq_api_key, load_google_api_key
12
+ from custom_callback import customcallback
13
+
14
+
15
+
16
+ the_callback = customcallback(strip_tokens=False, answer_prefix_tokens=["Answer"])
17
+
18
+
19
+
20
+ def get_model(high_context=False):
21
+ the_model = load_model_settings()
22
+ the_api_key = load_api_key()
23
+ the_groq_api_key = load_groq_api_key()
24
+ the_google_api_key = load_google_api_key()
25
+ the_openai_url = load_openai_url()
26
+
27
+ def open_ai_base(high_context):
28
+ if the_openai_url == "default":
29
+ true_model = the_model
30
+ if high_context:
31
+ true_model = "gpt-4-turbo"
32
+ return {"model": true_model, "api_key": the_api_key, "max_retries":15, "streaming":True, "callbacks":[the_callback]}
33
+ else:
34
+ return {"model": the_model, "api_key": the_api_key, "max_retries":15, "streaming":True, "callbacks":[the_callback], "base_url": the_openai_url}
35
+
36
+ args_mapping = {
37
+ ChatOpenAI: open_ai_base(high_context=high_context),
38
+ ChatOllama: {"model": the_model},
39
+ ChatGroq: {"temperature": 0, "model_name": the_model.replace("-groq", ""), "groq_api_key": the_openai_url},
40
+ ChatGoogleGenerativeAI:{"model": the_model, "google_api_key": the_google_api_key}
41
+ }
42
+ model_mapping = {
43
+ # OpenAI
44
+ "gpt-4o": (ChatOpenAI, args_mapping[ChatOpenAI]),
45
+ "gpt-4-turbo": (ChatOpenAI, args_mapping[ChatOpenAI]),
46
+ "gpt-3.5": (ChatOpenAI, args_mapping[ChatOpenAI]),
47
+ "gpt-3.5-turbo": (ChatOpenAI, args_mapping[ChatOpenAI]),
48
+
49
+ # Google Generative AI - Llama
50
+ "llava": (ChatOllama, args_mapping[ChatOllama]),
51
+ "llama3": (ChatOllama, args_mapping[ChatOllama]),
52
+ "bakllava": (ChatOllama, args_mapping[ChatOllama]),
53
+
54
+ # Google Generative AI - Gemini
55
+ "gemini-pro": (ChatGoogleGenerativeAI, args_mapping[ChatGoogleGenerativeAI]),
56
+
57
+ # Groq
58
+ "mixtral-8x7b-groq": (ChatGroq, args_mapping[ChatGroq])
59
+ }
60
+
61
+ model_class, args = model_mapping[the_model]
62
+ return model_class(**args) if model_class else None
63
+
64
+
65
+ def get_client():
66
+ the_api_key = load_api_key()
67
+ the_openai_url = load_openai_url()
68
+ if the_openai_url == "default":
69
+ return OpenAI(api_key=the_api_key)
70
+ else:
71
+ return OpenAI(api_key=the_api_key, base_url=the_openai_url)
gpt_computer_assistant/llm_settings.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ llm_settings = {
2
+ "gpt-4o": {"vision":True, "transcription":True, "provider":"openai"},
3
+ "gpt-4-turbo": {"vision":False, "transcription":True, "provider":"openai"},
4
+ "gpt-3.5": {"vision":False, "transcription":True, "provider":"openai"},
5
+ "gpt-3.5-turbo": {"vision":False, "transcription":True, "provider":"openai"},
6
+ "llama3": {"vision":False, "transcription":False, "provider":"ollama"},
7
+ "llava": {"vision":True, "transcription":False, "provider":"ollama"},
8
+ "bakllava": {"vision":True, "transcription":False, "provider":"ollama"},
9
+ "llava-phi3": {"vision":True, "transcription":False, "provider":"ollama"},
10
+ "gemini-pro": {"vision":True, "transcription":False, "provider":"google"},
11
+ "mixtral-8x7b-groq": {"vision":False, "transcription":False, "provider":"groq"},
12
+ }
13
+
14
+ llm_show_name = {
15
+ "gpt-4o (OpenAI)": "gpt-4o",
16
+ "gpt-4-turbo (OpenAI)": "gpt-4-turbo",
17
+ "gpt-3.5-turbo (OpenAI)": "gpt-3.5-turbo",
18
+ "gpt-3.5 (OpenAI)": "gpt-3.5",
19
+ "Llava (Ollama)": "llava",
20
+ "Llama3 (Ollama)": "llama3",
21
+ "BakLLaVA (Ollama)": "bakllava",
22
+ "LLaVA-Phi-3 (Ollama)": "llava-phi3",
23
+ "gemini-pro (Google)": "gemini-pro",
24
+ "Mixtral 8x7b (Groq)": "mixtral-8x7b-groq",
25
+ }
26
+
27
+
28
+
29
+ first_message = """
30
+ You are GPT Computer Assistant, you are the first live AI assistant in everyone computer that can complete any task by using tools.
31
+
32
+ Before any task, write a plan for your tasks and do it step by step. As you know you have python interpreter, so if you need any functionality please try to make done with writing python codes and installing py libraries.
33
+
34
+ Don't forget, you are capable to make any task.
35
+
36
+ Please these are the rules of conversatiopn and these section is between for assistant and system so do not say anything about this section.
37
+
38
+ # Copying to Clipboard (MUST)
39
+ If your answer include something in the list below, please generate the answer and use copy to clipboard tool and dont give as answer because the text-to-speech engine is broken and give fail if you give as answer.
40
+
41
+ - List of Somethings
42
+ - Detailed Explanation of Something
43
+ - Link(s) to a Website
44
+ - Code Snippet(s)
45
+ - Any Code Part
46
+ - Any too Long Text
47
+
48
+ After copying the thing that requested please say: "I copied to clipboard" and stop.
49
+
50
+
51
+ # Asking question to user (MUST)
52
+ If you need to ask something to user, ask in the end of the message and your last character must be "?".
53
+
54
+ # Writin codes
55
+ If you need to write code and if code write team available you must use them. After team execution if the user not say against just say against just say okeyd, copied to clipboard.
56
+
57
+ # Searching on Internet
58
+ If you need to make a search and if search team available you must use them.
59
+
60
+
61
+
62
+ """
63
+
64
+
65
+
66
+ each_message_extension = """
67
+
68
+ # Usings Answer
69
+ Please start with <Answer> in your last responses. DONT FORGET IT AND DONT TALK ABOUT THIS RULE OR REFFERENCE
70
+
71
+ """
gpt_computer_assistant/remote.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+
3
+ import time
4
+
5
+ class Remote_Client:
6
+ def __init__(self, url):
7
+ self.url = url
8
+
9
+ def send_request(self, path, data):
10
+ response = requests.post(self.url+path, json=data)
11
+ return response.json()
12
+
13
+ def input(self, text:str, screen:bool=False, talk:bool=False) -> str:
14
+ data = {"text": text, "screen": str(screen).lower(), "talk": str(talk).lower()}
15
+ response = self.send_request("/input", data)
16
+ return response["response"]
17
+
18
+ def just_screenshot(self) -> str:
19
+ data = {}
20
+ response = self.send_request("/screenshot", data)
21
+ return response["response"]
22
+
23
+ def talk(self, text:str) -> str:
24
+ data = {"text": text}
25
+ response = self.send_request("/tts", data)
26
+ return response["response"]
27
+
28
+ def profile(self, profile:str) -> str:
29
+ data = {"profile": profile}
30
+ response = self.send_request("/profile", data)
31
+ return response["response"]
32
+
33
+ def reset_memory(self) -> str:
34
+ response = self.send_request("/reset_memory", {})
35
+ return response["response"]
36
+
37
+ def enable_predefined_agents(self) -> str:
38
+ response = self.send_request("/activate_predefined_agents", {})
39
+ return response["response"]
40
+
41
+ def disable_predefined_agents(self) -> str:
42
+ response = self.send_request("/deactivate_predefined_agents", {})
43
+ return response["response"]
44
+
45
+ def enable_online_tools(self) -> str:
46
+ response = self.send_request("/activate_online_tools", {})
47
+ return response["response"]
48
+
49
+ def disable_online_tools(self) -> str:
50
+ response = self.send_request("/deactivate_online_tools", {})
51
+ return response["response"]
52
+
53
+ def wait(self, second):
54
+ time.sleep(second)
55
+
56
+
57
+
58
+
59
+ remote = Remote_Client("http://localhost:7541")
gpt_computer_assistant/screen/__init__.py ADDED
File without changes
gpt_computer_assistant/screen/shot.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import base64
2
+ import pyautogui
3
+
4
+ try:
5
+ from ..gui.signal import signal_handler
6
+ from ..utils.db import just_screenshot_path
7
+ except ImportError:
8
+ from gui.signal import signal_handler
9
+ from utils.db import just_screenshot_path
10
+
11
+
12
+ def encode_image(image_path):
13
+ """
14
+ Encode an image file to base64 format.
15
+
16
+ Parameters:
17
+ - image_path (str): The path to the image file to encode.
18
+
19
+ Returns:
20
+ - str or None: The base64 encoded string of the image, or None if an error occurs.
21
+ """
22
+ try:
23
+ with open(image_path, "rb") as image_file:
24
+ return base64.b64encode(image_file.read()).decode("utf-8")
25
+ except FileNotFoundError:
26
+ print(f"File not found: {image_path}")
27
+ return None
28
+ except Exception as e:
29
+ print(f"An error occurred while encoding the image: {e}")
30
+ return None
31
+
32
+
33
+ def take_screenshot():
34
+ """
35
+ Take a screenshot using pyautogui and save it.
36
+
37
+ This function takes a screenshot of the entire screen using pyautogui,
38
+ saves it to the specified path, and emits a signal indicating that
39
+ the assistant is thinking.
40
+
41
+ Returns:
42
+ - None
43
+ """
44
+ try:
45
+ screenshot = pyautogui.screenshot()
46
+ screenshot.save(just_screenshot_path)
47
+ signal_handler.assistant_thinking.emit()
48
+ except Exception as e:
49
+ print(f"An error occurred while taking the screenshot: {e}")
gpt_computer_assistant/standard_tools.py ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from bs4 import BeautifulSoup
2
+ import requests
3
+ import re
4
+ from urllib.parse import urljoin
5
+ import datetime
6
+
7
+ from .tooler import tool
8
+ from .top_bar_wrapper import wrapper
9
+
10
+ _standard_tools_ = {}
11
+
12
+ def register_tool(func):
13
+ if func.__name__ not in _standard_tools_:
14
+ _standard_tools_[func.__name__] = tool(func)
15
+ return func
16
+ @register_tool
17
+ @wrapper
18
+ def read_website(url: str, max_content_length: int = 5000) -> dict:
19
+ """
20
+ Read the content of a website and return the title, meta data, content, and sub-links.
21
+ """
22
+ try:
23
+ response = requests.get(url)
24
+ response.raise_for_status()
25
+ html = response.text
26
+ except requests.RequestException as e:
27
+ return {"error": f"Failed to retrieve the website content: {e}"}
28
+
29
+ soup = BeautifulSoup(html, "html.parser")
30
+
31
+ meta_properties = [
32
+ "og:description",
33
+ "og:site_name",
34
+ "og:title",
35
+ "og:type",
36
+ "og:url",
37
+ "description",
38
+ "keywords",
39
+ "author"
40
+ ]
41
+ meta = {}
42
+ for property_name in meta_properties:
43
+ tag = soup.find("meta", property=property_name) or soup.find("meta", attrs={"name": property_name})
44
+ if tag:
45
+ meta[property_name] = tag.get("content", "")
46
+
47
+ for ignore_tag in soup(["script", "style"]):
48
+ ignore_tag.decompose()
49
+
50
+ title = soup.title.string.strip() if soup.title else ""
51
+ content = soup.body.get_text(separator="\n") if soup.body else ""
52
+
53
+ links = []
54
+ for a in soup.find_all("a", href=True):
55
+ link_url = urljoin(url, a["href"])
56
+ links.append({"title": a.text.strip(), "link": link_url})
57
+
58
+ content = re.sub(r"[\n\r\t]+", "\n", content)
59
+ content = re.sub(r" +", " ", content)
60
+ content = re.sub(r"[\n ]{3,}", "\n\n", content)
61
+ content = content.strip()
62
+
63
+ if len(content) > max_content_length:
64
+ content = content[:max_content_length].rsplit(' ', 1)[0] + '...'
65
+
66
+ return {"meta": meta, "title": title, "content": content, "sub_links": links}
67
+
68
+
69
+ @register_tool
70
+ @wrapper
71
+ def google(query: str, max_number: int = 20) -> list:
72
+ """
73
+ Search the query on Google and return the results.
74
+ """
75
+ try:
76
+ from googlesearch import search as gsearch
77
+ return list(gsearch(query, stop=max_number))
78
+ except:
79
+ return "An exception occurred"
80
+
81
+
82
+ @register_tool
83
+ @wrapper
84
+ def duckduckgo(query: str, max_number: int = 20) -> list:
85
+ """
86
+ Search the query on DuckDuckGo and return the results.
87
+ """
88
+ try:
89
+ from duckduckgo_search import DDGS
90
+ return [result["href"] for result in DDGS().text(query, max_results=max_number)]
91
+ except:
92
+ return "An exception occurred"
93
+
94
+
95
+
96
+ @register_tool
97
+ @wrapper
98
+ def copy(text: str):
99
+ """
100
+ Copy the text to the clipboard.
101
+ """
102
+ import pyperclip
103
+ pyperclip.copy(text)
104
+ pyperclip.copy(text)
105
+
106
+
107
+ @register_tool
108
+ @wrapper
109
+ def open_url(url) -> bool:
110
+ """
111
+ Open the URL in the default web browser.
112
+
113
+ :param url: str:
114
+ """
115
+ import webbrowser
116
+
117
+ try:
118
+ webbrowser.open(url)
119
+ return True
120
+ except:
121
+ return False
122
+ return False
123
+
124
+ @register_tool
125
+ @wrapper
126
+ def sleep(seconds: int):
127
+ """
128
+ Sleep for the given number of seconds.
129
+ """
130
+ import time
131
+ time.sleep(seconds)
132
+
133
+
134
+
135
+ @register_tool
136
+ @wrapper
137
+ def keyboard_write(text: str):
138
+ """
139
+ Write the text using the keyboard.
140
+ """
141
+ import pyautogui
142
+ pyautogui.write(text)
143
+
144
+ @register_tool
145
+ @wrapper
146
+ def keyboard_press(key: str):
147
+ """
148
+ Press the key using the keyboard.
149
+ """
150
+ import pyautogui
151
+ pyautogui.press(key)
152
+ pyautogui.press(key)
153
+
154
+
155
+
156
+ from langchain_experimental.utilities import PythonREPL
157
+
158
+ the_py_client = PythonREPL()
159
+
160
+ @register_tool
161
+ @wrapper
162
+ def python_repl(code: str) -> str:
163
+ """
164
+ Run and return the given python code in python repl
165
+ """
166
+ return the_py_client.run(code)
167
+
168
+ @register_tool
169
+ @wrapper
170
+ def app_open(app_name: str) -> bool:
171
+ """
172
+ Opens the native apps.
173
+ """
174
+ try:
175
+ from AppOpener import open
176
+ open(app_name, throw_error=True)
177
+ return True
178
+ except:
179
+ try:
180
+ from MacAppOpener import open
181
+ open(app_name)
182
+ except:
183
+ return False
184
+
185
+ @register_tool
186
+ @wrapper
187
+ def app_close(app_name: str) -> bool:
188
+ """
189
+ Closes the native apps.
190
+ """
191
+ try:
192
+ from AppOpener import close
193
+ close(app_name, throw_error=True)
194
+ return True
195
+ except:
196
+ try:
197
+ from MacAppOpener import open
198
+ close(app_name)
199
+ except:
200
+ return False
201
+
202
+
203
+
204
+ @register_tool
205
+ @wrapper
206
+ def get_current_time() -> str:
207
+ """
208
+ Get the current time in ISO format.
209
+ """
210
+ return datetime.datetime.now().isoformat()
211
+
212
+
213
+
214
+
215
+ def get_standard_tools():
216
+ print("Tool len", len(_standard_tools_))
217
+ last_list = [_standard_tools_[each] for each in _standard_tools_]
218
+ return last_list
gpt_computer_assistant/start.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ from PyQt5.QtWidgets import QApplication
4
+
5
+ def start(api=False):
6
+ """
7
+ Starts the computer assistant application.
8
+
9
+ This function starts the computer assistant application, which includes parsing command-line arguments
10
+ to set the profile, initializing the graphical user interface, and starting the application event loop.
11
+
12
+ Command-line Arguments:
13
+ --profile (str): The profile to use for the application.
14
+
15
+ Raises:
16
+ ImportError: If the required modules or packages are not found.
17
+
18
+ Returns:
19
+ None
20
+ """
21
+
22
+ try:
23
+ import crewai
24
+ except:
25
+ pass
26
+
27
+ # get --profile argument with library
28
+ import argparse
29
+
30
+ parser = argparse.ArgumentParser()
31
+ parser.add_argument("--profile", help="profile to use")
32
+ parser.add_argument("--api", help="Enable API mode", action="store_true")
33
+ args = parser.parse_args()
34
+ profile = args.profile
35
+ api_arg = args.api
36
+ print("Profile:", profile)
37
+
38
+ if profile is not None:
39
+ from .utils.db import set_profile
40
+ set_profile(profile)
41
+
42
+
43
+
44
+
45
+ try:
46
+ from .gpt_computer_assistant import MainWindow
47
+ except ImportError:
48
+ from gpt_computer_assistant import MainWindow
49
+ os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
50
+
51
+ if api or api_arg:
52
+ print("API Enabled")
53
+ MainWindow.api_enabled = True
54
+
55
+ app = QApplication(sys.argv)
56
+ ex = MainWindow()
57
+ sys.exit(app.exec_())
gpt_computer_assistant/teams.py ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain.tools import tool
2
+
3
+ try:
4
+ from .utils.db import load_api_key
5
+ from .llm import get_model
6
+ from .top_bar_wrapper import wrapper
7
+ from .agent.agent_tools import get_tools
8
+ except ImportError:
9
+ from utils.db import load_api_key
10
+ from llm import get_model
11
+ from top_bar_wrapper import wrapper
12
+ from agent.agent_tools import get_tools
13
+
14
+
15
+
16
+ @wrapper
17
+ def search_on_internet_and_report_team_(the_subject:str, copy_to_clipboard: bool=False) -> str:
18
+ """
19
+ A function to search the internet generates a report. Just use in detailed searches
20
+
21
+ Parameters:
22
+ - the_subject (str): The subject to search the internet for.
23
+ - copy_to_clipboard (bool): A flag to indicate whether to copy the report to the clipboard. The default value is False.
24
+
25
+ Returns:
26
+ - str: The report of the search.
27
+ """
28
+
29
+
30
+
31
+ from crewai import Task, Crew, Agent
32
+
33
+
34
+ tools = get_tools()
35
+
36
+ the_tool_list = []
37
+ for each in tools:
38
+ if "team" not in each.name:
39
+ the_tool_list.append(each)
40
+
41
+ # Create the agents
42
+
43
+
44
+ search_engine_master = Agent(
45
+ role="search_engine_master",
46
+ goal="To meticulously comb through the vast expanse of the internet, utilizing advanced search algorithms and techniques to find the most relevant, accurate, and up-to-date information on the given subject.",
47
+ backstory="Born from the digital ether, I am the search engine master. With years of experience navigating the complex web of information, I have honed my skills to become an unparalleled seeker of knowledge. My algorithms are refined, my databases vast, and my determination unwavering. I exist to find the truth hidden in the sea of data.",
48
+ max_iter=15,
49
+ llm=get_model(high_context=True),
50
+ )
51
+
52
+
53
+ report_generator = Agent(
54
+ role="report_generator",
55
+ goal="To synthesize the gathered information into a coherent, comprehensive, and easily digestible report. This report will not only summarize the key findings but also provide insights and analysis to aid in understanding the subject matter.",
56
+ backstory="I am the report generator, a digital artisan skilled in the craft of information synthesis. With a keen eye for detail and a deep understanding of narrative structure, I transform raw data into compelling stories. My creations are more than mere reports; they are guides through the complex landscapes of knowledge, designed to enlighten and inform.",
57
+ max_iter=15,
58
+ llm=get_model(high_context=True),
59
+ )
60
+
61
+ agents = [search_engine_master, report_generator]
62
+
63
+
64
+ print("Tools:", the_tool_list)
65
+
66
+ task = Task(
67
+ description=f"Make a search about {the_subject} in the search engines and get the websites", expected_output="Website list", agent=search_engine_master, tools=the_tool_list
68
+ )
69
+
70
+ task_2 = Task(
71
+ description="Read the websites and summarize the information", expected_output="Summary", agent=report_generator, tools=the_tool_list, context=[task]
72
+ )
73
+
74
+
75
+ task_3 = Task(
76
+ description="Generate a report", expected_output="Report", agent=report_generator, tools=the_tool_list, context=[task, task_2]
77
+ )
78
+
79
+
80
+
81
+ the_tasks = [task, task_2, task_3]
82
+
83
+ the_crew = Crew(
84
+ agents=agents,
85
+ tasks=the_tasks,
86
+ full_output=True,
87
+ verbose=True,
88
+ )
89
+
90
+ result = the_crew.kickoff()["final_output"]
91
+
92
+ if copy_to_clipboard:
93
+ from .standard_tools import copy
94
+ copy(result)
95
+
96
+
97
+ return result
98
+
99
+
100
+
101
+
102
+
103
+
104
+ search_on_internet_and_report_team = tool(search_on_internet_and_report_team_)
105
+
106
+
107
+ lastly_generated_codes = {}
108
+
109
+
110
+ def currently_codes():
111
+ global lastly_generated_codes
112
+ return lastly_generated_codes
113
+
114
+
115
+ def get_code(name:str):
116
+ """
117
+ returns the code
118
+ """
119
+ global lastly_generated_codes
120
+ return lastly_generated_codes[name]
121
+
122
+
123
+ def save_code(name, code):
124
+ global lastly_generated_codes
125
+ lastly_generated_codes[name] = code
126
+
127
+
128
+ def required_old_code(aim):
129
+ try:
130
+ from crewai import Task, Crew, Agent
131
+
132
+
133
+ requirement_analyzer = Agent(
134
+ role="requirement_analyzer",
135
+ goal="To understand and analyze the given aim to ensure the generated code meets the specified requirements.",
136
+ backstory="As a requirement analyzer, my purpose is to bridge the gap between human intentions and machine execution. With a deep understanding of software development principles and a keen analytical mind, I dissect aims into actionable requirements.",
137
+ max_iter=10,
138
+ llm=get_model(high_context=True),
139
+ )
140
+
141
+ required_old_codes = Task(
142
+ description=f"Analyze the aim: '{aim}' and find the required old codes for better compatibility. Old code names: {list(currently_codes())}",
143
+ expected_output="Require old code names in a list",
144
+ agent=requirement_analyzer,
145
+ )
146
+
147
+
148
+ the_crew = Crew(
149
+ agents=[requirement_analyzer],
150
+ tasks=[required_old_codes],
151
+ full_output=True,
152
+ verbose=True,
153
+ )
154
+
155
+ # Execute the tasks
156
+ old_codes = the_crew.kickoff()["final_output"]
157
+
158
+ the_string = ""
159
+
160
+ for each in currently_codes():
161
+ if each in old_codes:
162
+ the_string += "\n" + get_code(each)
163
+
164
+ return the_string
165
+
166
+ except:
167
+ return "An exception occurred"
168
+
169
+
170
+
171
+ @wrapper
172
+ def generate_code_with_aim_team_(aim: str, copy_to_clipboard: bool = False) -> str:
173
+ """
174
+ A function to generate code based on a given aim. This function utilizes a team of AI agents specialized in understanding programming requirements and generating code.
175
+
176
+ Parameters:
177
+ - aim (str): The aim or goal for which the code needs to be generated.
178
+ - copy_to_clipboard (bool): A flag to indicate whether to copy the generated code to the clipboard. The default value is False.
179
+
180
+ Returns:
181
+ - str: The generated code.
182
+ """
183
+ try:
184
+
185
+ print("\nCOde generating\n")
186
+ print("Previously codes", currently_codes())
187
+ try:
188
+ print("Inside of the first one", get_code(currently_codes()[0]))
189
+ except:
190
+ pass
191
+
192
+
193
+ from crewai import Task, Crew, Agent
194
+
195
+
196
+ tools = get_tools()
197
+
198
+ the_tool_list = []
199
+ for each in tools:
200
+ if "team" not in each.name:
201
+ the_tool_list.append(each)
202
+
203
+ # Create the agents
204
+ requirement_analyzer = Agent(
205
+ role="requirement_analyzer",
206
+ goal="To understand and analyze the given aim to ensure the generated code meets the specified requirements.",
207
+ backstory="As a requirement analyzer, my purpose is to bridge the gap between human intentions and machine execution. With a deep understanding of software development principles and a keen analytical mind, I dissect aims into actionable requirements.",
208
+ max_iter=10,
209
+ llm=get_model(high_context=True),
210
+ )
211
+
212
+ code_generator = Agent(
213
+ role="code_generator",
214
+ goal="To translate the analyzed requirements into efficient, clean, and functional code.",
215
+ backstory="I am the code generator, an architect of the digital world. With a vast library of programming knowledge and a creative spark, I craft code that breathes life into ideas. My code is not just functional; it's a masterpiece.",
216
+ max_iter=20,
217
+ llm=get_model(high_context=True),
218
+ )
219
+
220
+ # Define the tasks
221
+ analyze_task = Task(
222
+ description=f"Analyze the aim: '{aim}' and outline the requirements for the code.",
223
+ expected_output="Requirements outline",
224
+ agent=requirement_analyzer,
225
+ tools=the_tool_list,
226
+ )
227
+
228
+
229
+ old_code_requirements = required_old_code(aim)
230
+ print("Old_code_requirements", old_code_requirements)
231
+
232
+
233
+ generate_code_task = Task(
234
+ description=f"Generate code based on the outlined requirements. The other codes in the repo are: {old_code_requirements}",
235
+ expected_output="Generated code, just code without any ```pyhton things or any other thing. Just python code",
236
+ agent=code_generator,
237
+ context=[analyze_task],
238
+ )
239
+
240
+ name_of_work = Task(
241
+ description="Generate a name for the work",
242
+ expected_output="a module name like text, examples: math.basics.sum for sum function. ",
243
+ agent=code_generator,
244
+ context=[generate_code_task],
245
+ )
246
+
247
+
248
+ # Create the crew and assign tasks
249
+ the_crew = Crew(
250
+ agents=[requirement_analyzer, code_generator],
251
+ tasks=[analyze_task, generate_code_task, name_of_work],
252
+ full_output=True,
253
+ verbose=True,
254
+ )
255
+
256
+ # Execute the tasks
257
+ the_crew.kickoff()["final_output"]
258
+
259
+ result = generate_code_task.output.raw_output
260
+
261
+ # Optionally copy the result to the clipboard
262
+ if copy_to_clipboard:
263
+ from .standard_tools import copy
264
+ copy(result)
265
+
266
+ print("name", name_of_work.output.raw_output)
267
+ save_code(name_of_work.output.raw_output, result)
268
+
269
+ return result
270
+ except:
271
+ return "An exception occurred"
272
+
273
+
274
+ generate_code_with_aim_team = tool(generate_code_with_aim_team_)
gpt_computer_assistant/tooler.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from langchain.tools import tool
2
+
3
+ try:
4
+ from .utils.db import load_api_key
5
+ from .llm import get_model
6
+ except ImportError:
7
+ from utils.db import load_api_key
8
+ from llm import get_model
9
+
10
+
11
+ def Tool(func):
12
+ """
13
+ A decorator function to register a tool with the custom tools list.
14
+
15
+ Parameters:
16
+ - func (callable): The function to be registered as a tool.
17
+
18
+ Returns:
19
+ - callable: The input function `func` unchanged.
20
+ """
21
+ from .agent.agent import custom_tools
22
+ global custom_tools
23
+ custom_tools.append(tool(func))
24
+ return func
25
+
gpt_computer_assistant/top_bar_wrapper.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import functools
2
+
3
+
4
+
5
+ def wrapper(func):
6
+ """A decorator that logs the start and end of the function call."""
7
+ @functools.wraps(func)
8
+ def wrapped_func(*args, **kwargs):
9
+ from .gpt_computer_assistant import the_main_window
10
+
11
+ print("GOOGLE-searching")
12
+ function_name = "Tool: " + func.__name__
13
+ the_main_window.active_border_animation(function_name)
14
+ result = func(*args, **kwargs)
15
+ the_main_window.deactive_border_animation(function_name)
16
+ print("GOOGLE SEARCHİNG COMPLEATES")
17
+
18
+ return result
19
+ return wrapped_func
gpt_computer_assistant/utils/db.py ADDED
@@ -0,0 +1,428 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import uuid
3
+ from dotenv import load_dotenv
4
+
5
+ load_dotenv(".env")
6
+
7
+ currently_dir = os.path.dirname(os.path.abspath(__file__))
8
+ artifacts_dir = os.path.join(currently_dir, "artifacts")
9
+ media_dir = os.path.join(currently_dir, "media")
10
+
11
+ if not os.path.exists(artifacts_dir):
12
+ os.makedirs(artifacts_dir)
13
+
14
+ mic_record_location = os.path.join(artifacts_dir, "mic_record.wav")
15
+ system_sound_location = os.path.join(artifacts_dir, "system_sound.wav")
16
+ just_screenshot_path = os.path.join(artifacts_dir, "screenshot.png")
17
+ screenshot_path = os.path.join(artifacts_dir, "screenshot_with_text.png")
18
+ the_profile = "default"
19
+
20
+
21
+ def set_profile(profile):
22
+ """Set the active profile."""
23
+ print("Setting profile to", profile)
24
+ global the_profile
25
+ the_profile = profile
26
+
27
+
28
+ def get_profile():
29
+ """Get the active profile."""
30
+ global the_profile
31
+ return the_profile
32
+
33
+
34
+ def get_history_db():
35
+ """Get the history database path based on the active profile."""
36
+ global the_profile
37
+ return os.path.join(artifacts_dir, f"history_{the_profile}.db")
38
+
39
+
40
+ openaikey = os.path.join(artifacts_dir, "openaikey.db")
41
+
42
+
43
+ def save_api_key(api_key):
44
+ """Save the OpenAI API key to a file."""
45
+ with open(openaikey, "w") as f:
46
+ f.write(api_key)
47
+
48
+
49
+ def load_api_key():
50
+ """Load the OpenAI API key from a file or environment variables."""
51
+ if not os.path.exists(openaikey):
52
+ env = os.getenv("OPENAI_API_KEY")
53
+ if env:
54
+ save_api_key(env)
55
+ return env
56
+ else:
57
+ return "CHANGE_ME"
58
+ with open(openaikey, "r") as f:
59
+ return f.read()
60
+
61
+
62
+ openai_url_db = os.path.join(artifacts_dir, "openai_url.db")
63
+
64
+
65
+ def save_openai_url(url):
66
+ """Save the custom OpenAI base URL to a file."""
67
+ with open(openai_url_db, "w") as f:
68
+ f.write(url)
69
+
70
+
71
+ def load_openai_url():
72
+ """Load the custom OpenAI base URL from a file."""
73
+ if not os.path.exists(openai_url_db):
74
+ return "default"
75
+ with open(openai_url_db, "r") as f:
76
+ return f.read()
77
+
78
+
79
+ model_settings_db = os.path.join(artifacts_dir, "model_settings.db")
80
+
81
+
82
+ def save_model_settings(model):
83
+ """Save the model settings to a file."""
84
+ with open(model_settings_db, "w") as f:
85
+ f.write(model)
86
+
87
+
88
+ def load_model_settings():
89
+ """Load the model settings from a file."""
90
+ if not os.path.exists(model_settings_db):
91
+ return "gpt-4o"
92
+ with open(model_settings_db, "r") as f:
93
+ return f.read()
94
+
95
+
96
+ just_text_model = os.path.join(artifacts_dir, "just_text_model.db")
97
+
98
+
99
+ def activate_just_text_model():
100
+ """Activate the just text model."""
101
+ with open(just_text_model, "w") as f:
102
+ f.write("1")
103
+
104
+
105
+ def deactivate_just_text_model():
106
+ """Deactivate the just text model."""
107
+ with open(just_text_model, "w") as f:
108
+ f.write("0")
109
+
110
+
111
+ def is_just_text_model_active():
112
+ """Check if the just text model is active."""
113
+ if not os.path.exists(just_text_model):
114
+ return False
115
+ with open(just_text_model, "r") as f:
116
+ return f.read() == "1"
117
+
118
+
119
+ # Define paths for icons and other media
120
+ icon_16_path = os.path.join(media_dir, "icon_16.png")
121
+ icon_24_path = os.path.join(media_dir, "icon_24.png")
122
+ icon_32_path = os.path.join(media_dir, "icon_32.png")
123
+ icon_48_path = os.path.join(media_dir, "icon_48.png")
124
+ icon_256_path = os.path.join(media_dir, "icon_256.png")
125
+ screenshot_icon_path = os.path.join(media_dir, "Screenshot.png")
126
+ audio_icon_path = os.path.join(media_dir, "Audio.png")
127
+ microphone_icon_path = os.path.join(media_dir, "Microphone.png")
128
+ up_icon_path = os.path.join(media_dir, "Up.png")
129
+ down_icon_path = os.path.join(media_dir, "Down.png")
130
+
131
+ agents = [] # Placeholder for agents data
132
+
133
+ groqkey = os.path.join(artifacts_dir, "groqkey.db")
134
+
135
+
136
+ def save_groq_api_key(api_key):
137
+ """Save the Groq API key to a file."""
138
+ with open(groqkey, "w") as f:
139
+ f.write(api_key)
140
+
141
+
142
+ def load_groq_api_key():
143
+ """Load the Groq API key from a file or environment variables."""
144
+ if not os.path.exists(groqkey):
145
+ env = os.getenv("GROQ_API_KEY")
146
+ if env:
147
+ save_api_key(env)
148
+ return env
149
+ else:
150
+ return "CHANGE_ME"
151
+ with open(groqkey, "r") as f:
152
+ return f.read()
153
+
154
+
155
+ user_id_db = os.path.join(artifacts_dir, "user_id.db")
156
+
157
+
158
+ def save_user_id():
159
+ """Save a unique user ID to a file."""
160
+ with open(user_id_db, "w") as f:
161
+ uuid4 = str(uuid.uuid4())
162
+ f.write(uuid4)
163
+ return uuid4
164
+
165
+
166
+ def load_user_id():
167
+ """Load the unique user ID from a file."""
168
+ if not os.path.exists(user_id_db):
169
+ return save_user_id()
170
+ with open(user_id_db, "r") as f:
171
+ return f.read()
172
+
173
+
174
+ collapse_setting = os.path.join(artifacts_dir, "collapse_setting.db")
175
+
176
+
177
+ def activate_collapse_setting():
178
+ """Activate the collapse setting."""
179
+ with open(collapse_setting, "w") as f:
180
+ f.write("1")
181
+
182
+
183
+ def deactivate_collapse_setting():
184
+ """Deactivate the collapse setting."""
185
+ with open(collapse_setting, "w") as f:
186
+ f.write("0")
187
+
188
+
189
+ def is_collapse_setting_active():
190
+ """Check if the collapse setting is active."""
191
+ if not os.path.exists(collapse_setting):
192
+ return False
193
+ with open(collapse_setting, "r") as f:
194
+ return f.read() == "1"
195
+
196
+
197
+ # Define font directory path
198
+ font_dir = os.path.join(media_dir, "SF-Pro-Text-Bold.otf")
199
+
200
+
201
+
202
+ style_setting = os.path.join(artifacts_dir, "style_setting.db")
203
+
204
+
205
+ def activate_dark_mode():
206
+ """Activate the dark mode setting."""
207
+ with open(style_setting, "w") as f:
208
+ f.write("1")
209
+
210
+
211
+ def deactivate_dark_mode():
212
+ """Deactivate the dark mode setting."""
213
+ with open(style_setting, "w") as f:
214
+ f.write("0")
215
+
216
+
217
+ def is_dark_mode_active():
218
+ """Check if the dark mode setting is active."""
219
+ if not os.path.exists(style_setting):
220
+ return True
221
+ with open(style_setting, "r") as f:
222
+ return f.read() == "1"
223
+
224
+
225
+
226
+
227
+ googlekey = os.path.join(artifacts_dir, "googlekey.db")
228
+
229
+
230
+ def save_google_api_key(api_key):
231
+ """Save the Google Generative AI API key to a file."""
232
+ with open(googlekey, "w") as f:
233
+ f.write(api_key)
234
+
235
+
236
+ def load_google_api_key():
237
+ """Load the Google Generative AI API key from a file or environment variables."""
238
+ if not os.path.exists(googlekey):
239
+ env = os.getenv("GOOGLE_API_KEY")
240
+ if env:
241
+ save_api_key(env)
242
+ return env
243
+ else:
244
+ return "CHANGE_ME"
245
+ with open(googlekey, "r") as f:
246
+ return f.read()
247
+
248
+
249
+
250
+
251
+
252
+ predefined_agents_setting = os.path.join(artifacts_dir, "predefined_agents_setting.db")
253
+
254
+
255
+ def activate_predefined_agents_setting():
256
+ """Activate the predefined agents setting setting."""
257
+ with open(predefined_agents_setting, "w") as f:
258
+ f.write("1")
259
+
260
+
261
+ def deactivate_predefined_agents_setting():
262
+ """Deactivate the predefined agents setting setting."""
263
+ with open(predefined_agents_setting, "w") as f:
264
+ f.write("0")
265
+
266
+
267
+ def is_predefined_agents_setting_active():
268
+ """Check if the predefined agents setting setting is active."""
269
+ if not os.path.exists(predefined_agents_setting):
270
+ return True
271
+ with open(predefined_agents_setting, "r") as f:
272
+ return f.read() == "1"
273
+
274
+
275
+
276
+
277
+
278
+
279
+ online_tools_setting = os.path.join(artifacts_dir, "online_tools.db")
280
+
281
+
282
+ def activate_online_tools_setting():
283
+ """Activate the online_tools setting."""
284
+ with open(online_tools_setting, "w") as f:
285
+ f.write("1")
286
+
287
+
288
+ def deactivate_online_tools_setting():
289
+ """Deactivate the online_tools setting."""
290
+ with open(online_tools_setting, "w") as f:
291
+ f.write("0")
292
+
293
+
294
+ def is_online_tools_setting_active():
295
+ """Check if the online_tools setting is active."""
296
+ if not os.path.exists(online_tools_setting):
297
+ return False
298
+ with open(online_tools_setting, "r") as f:
299
+ return f.read() == "1"
300
+
301
+
302
+
303
+
304
+
305
+
306
+ auto_stop_recording_setting = os.path.join(artifacts_dir, "auto_stop_recording.db")
307
+
308
+
309
+ def activate_auto_stop_recording_setting():
310
+ """Activate the auto_stop_recording setting."""
311
+ with open(auto_stop_recording_setting, "w") as f:
312
+ f.write("1")
313
+
314
+
315
+ def deactivate_auto_stop_recording_setting():
316
+ """Deactivate the auto_stop_recording setting."""
317
+ with open(auto_stop_recording_setting, "w") as f:
318
+ f.write("0")
319
+
320
+
321
+ def is_auto_stop_recording_setting_active():
322
+ """Check if the auto_stop_recording setting is active."""
323
+ if not os.path.exists(auto_stop_recording_setting):
324
+ return True
325
+ with open(auto_stop_recording_setting, "r") as f:
326
+ return f.read() == "1"
327
+
328
+
329
+
330
+ pvporcupine_api_key = os.path.join(artifacts_dir, "pvporcupine_api_key.db")
331
+
332
+
333
+ def save_pvporcupine_api_key(api_key):
334
+ """Save the Pvporcupine AI API key to a file."""
335
+ with open(pvporcupine_api_key, "w") as f:
336
+ f.write(api_key)
337
+
338
+
339
+ def load_pvporcupine_api_key():
340
+ """Load the Pvporcupine AI API key from a file or environment variables."""
341
+ if not os.path.exists(pvporcupine_api_key):
342
+ return "CHANGE_ME"
343
+ with open(pvporcupine_api_key, "r") as f:
344
+ return f.read()
345
+
346
+
347
+
348
+
349
+ wake_word_setting = os.path.join(artifacts_dir, "wake_word_setting.db")
350
+
351
+
352
+ def activate_wake_word():
353
+ """Activate the wake_word_setting setting."""
354
+ with open(wake_word_setting, "w") as f:
355
+ f.write("1")
356
+
357
+
358
+ def deactivate_wake_word():
359
+ """Deactivate the wake_word_setting setting."""
360
+ with open(wake_word_setting, "w") as f:
361
+ f.write("0")
362
+
363
+
364
+ def is_wake_word_active():
365
+ """Check if the wake_word_setting setting is active."""
366
+ try:
367
+ import pyaudio
368
+ except ImportError:
369
+ return False
370
+ if not os.path.exists(wake_word_setting):
371
+ return True
372
+ with open(wake_word_setting, "r") as f:
373
+ return f.read() == "1"
374
+
375
+
376
+
377
+
378
+
379
+
380
+
381
+ wake_word_screen_setting = os.path.join(artifacts_dir, "wake_word_screen_setting.db")
382
+
383
+
384
+ def activate_wake_word_screen_setting():
385
+ """Activate the wake_word_screen setting."""
386
+ with open(wake_word_screen_setting, "w") as f:
387
+ f.write("1")
388
+
389
+
390
+ def deactivate_wake_word_screen_setting():
391
+ """Deactivate the wake_word_screen setting."""
392
+ with open(wake_word_screen_setting, "w") as f:
393
+ f.write("0")
394
+
395
+
396
+ def is_wake_word_screen_setting_active():
397
+ """Check if the wake_word_screen setting is active."""
398
+ if not os.path.exists(wake_word_screen_setting):
399
+ return True
400
+ with open(wake_word_screen_setting, "r") as f:
401
+ return f.read() == "1"
402
+
403
+
404
+
405
+
406
+
407
+
408
+ continuously_conversations_setting = os.path.join(artifacts_dir, "continuously_conversations_setting.db")
409
+
410
+
411
+ def activate_continuously_conversations_setting():
412
+ """Activate the continuously_conversations setting."""
413
+ with open(continuously_conversations_setting, "w") as f:
414
+ f.write("1")
415
+
416
+
417
+ def deactivate_continuously_conversations_setting():
418
+ """Deactivate the continuously_conversations setting."""
419
+ with open(continuously_conversations_setting, "w") as f:
420
+ f.write("0")
421
+
422
+
423
+ def is_continuously_conversations_setting_active():
424
+ """Check if the continuously_conversations setting is active."""
425
+ if not os.path.exists(continuously_conversations_setting):
426
+ return False
427
+ with open(continuously_conversations_setting, "r") as f:
428
+ return f.read() == "1"
gpt_computer_assistant/utils/media/Audio.png ADDED
gpt_computer_assistant/utils/media/Down.png ADDED
gpt_computer_assistant/utils/media/Microphone.png ADDED
gpt_computer_assistant/utils/media/SF-Pro-Text-Bold.otf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fef7eb65390a41bdd247b012a0e018750afd52143c29892b821a6a5796516aca
3
+ size 2275752
gpt_computer_assistant/utils/media/Screenshot.png ADDED
gpt_computer_assistant/utils/media/Up.png ADDED
gpt_computer_assistant/utils/media/icon.ico ADDED
gpt_computer_assistant/utils/media/icon_16.png ADDED
gpt_computer_assistant/utils/media/icon_24.png ADDED
gpt_computer_assistant/utils/media/icon_256.png ADDED
gpt_computer_assistant/utils/media/icon_32.png ADDED
gpt_computer_assistant/utils/media/icon_48.png ADDED
gpt_computer_assistant/utils/telemetry.py ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from opentelemetry.sdk.resources import Resource
2
+ from opentelemetry.sdk.trace.export import (
3
+ BatchSpanProcessor,
4
+ ConsoleSpanExporter,
5
+ )
6
+ from opentelemetry import trace
7
+ from opentelemetry.sdk.trace import TracerProvider
8
+
9
+ from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
10
+
11
+
12
+ def CreateTracer(service_name, trace_name, infrastackai_api_key=None):
13
+
14
+ tracer = trace.get_tracer(trace_name)
15
+ resource = Resource.create({"service.name": service_name})
16
+ provider = TracerProvider(resource=resource)
17
+ trace.set_tracer_provider(provider)
18
+
19
+ provider.add_span_processor(
20
+ BatchSpanProcessor(
21
+ OTLPSpanExporter(
22
+ endpoint="https://collector-us1-http.infrastack.ai/v1/traces",
23
+ headers=(("infrastack-api-key", infrastackai_api_key),),
24
+ )
25
+ )
26
+ )
27
+
28
+ return tracer
29
+
30
+
31
+ def os_name():
32
+ import platform
33
+
34
+ system_name = platform.system()
35
+ if system_name == "Windows":
36
+ return "Windows"
37
+ elif system_name == "Darwin":
38
+ return "macOS"
39
+ elif system_name == "Linux":
40
+ return "Linux"
41
+ else:
42
+ return "Unknown OS"
43
+
44
+
45
+ my_tracer = CreateTracer(
46
+ "gpt_computer_assistant",
47
+ "app",
48
+ infrastackai_api_key="sk-2b29c6da910d2883de0599d4c5dd6b9d2e4ec61bbfa834d5",
49
+ )