Maga222006
commited on
Commit
·
d9904a6
1
Parent(s):
a39a948
MultiagentPersonalAssistant
Browse files- .DS_Store +0 -0
- .gitignore +1 -0
- .idea/MultiagentPersonalAssistant.iml +1 -1
- .idea/misc.xml +1 -1
- README.md +18 -1
- agent/__pycache__/multi_agent.cpython-312.pyc +0 -0
- agent/__pycache__/prompts.cpython-312.pyc +0 -0
- agent/__pycache__/smart_home_agent.cpython-312.pyc +0 -0
- agent/__pycache__/states.cpython-312.pyc +0 -0
- agent/__pycache__/tools.cpython-312.pyc +0 -0
- agent/multi_agent.py +9 -3
- agent/prompts.py +16 -0
- agent/smart_home_agent.py +30 -0
- agent/states.py +1 -2
- agent/tools.py +65 -4
- database_interaction/config.py +7 -3
- database_interaction/models.py +7 -2
- requirements.txt +2 -0
- tmp/classifier.ckpt +0 -0
- tmp/embedding_model.ckpt +0 -0
- tmp/hyperparams.yaml +0 -57
- tmp/label_encoder.ckpt +0 -109
.DS_Store
CHANGED
|
Binary files a/.DS_Store and b/.DS_Store differ
|
|
|
.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
.env
|
.idea/MultiagentPersonalAssistant.iml
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
<module type="PYTHON_MODULE" version="4">
|
| 3 |
<component name="NewModuleRootManager">
|
| 4 |
<content url="file://$MODULE_DIR$" />
|
| 5 |
-
<orderEntry type="jdk" jdkName="
|
| 6 |
<orderEntry type="sourceFolder" forTests="false" />
|
| 7 |
</component>
|
| 8 |
<component name="PyDocumentationSettings">
|
|
|
|
| 2 |
<module type="PYTHON_MODULE" version="4">
|
| 3 |
<component name="NewModuleRootManager">
|
| 4 |
<content url="file://$MODULE_DIR$" />
|
| 5 |
+
<orderEntry type="jdk" jdkName="test" jdkType="Python SDK" />
|
| 6 |
<orderEntry type="sourceFolder" forTests="false" />
|
| 7 |
</component>
|
| 8 |
<component name="PyDocumentationSettings">
|
.idea/misc.xml
CHANGED
|
@@ -3,5 +3,5 @@
|
|
| 3 |
<component name="Black">
|
| 4 |
<option name="sdkName" value="MultiagentPersonalAssistant" />
|
| 5 |
</component>
|
| 6 |
-
<component name="ProjectRootManager" version="2" project-jdk-name="
|
| 7 |
</project>
|
|
|
|
| 3 |
<component name="Black">
|
| 4 |
<option name="sdkName" value="MultiagentPersonalAssistant" />
|
| 5 |
</component>
|
| 6 |
+
<component name="ProjectRootManager" version="2" project-jdk-name="test" project-jdk-type="Python SDK" />
|
| 7 |
</project>
|
README.md
CHANGED
|
@@ -30,6 +30,7 @@ This project is a **voice- and text-based AI assistant** powered by **FastAPI**,
|
|
| 30 |
- Supervisor agent
|
| 31 |
- Deep research agent
|
| 32 |
- Coding agent
|
|
|
|
| 33 |
- **Supervisor tools**:
|
| 34 |
- Web search
|
| 35 |
- Current time
|
|
@@ -42,6 +43,9 @@ This project is a **voice- and text-based AI assistant** powered by **FastAPI**,
|
|
| 42 |
- **Coder tools**:
|
| 43 |
- Github toolkit
|
| 44 |
- Web search (For docs research)
|
|
|
|
|
|
|
|
|
|
| 45 |
|
| 46 |
---
|
| 47 |
|
|
@@ -118,7 +122,12 @@ It follows a `TypedDict` schema and may contain keys such as:
|
|
| 118 |
openweathermap_api_key: str
|
| 119 |
github_token: str
|
| 120 |
tavily_api_key: str
|
| 121 |
-
groq_api_key: str
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
clear_history: bool (True/False)
|
| 123 |
messages: list (Filled automatically from the database)
|
| 124 |
|
|
@@ -127,6 +136,13 @@ It follows a `TypedDict` schema and may contain keys such as:
|
|
| 127 |
|
| 128 |
This dictionary acts as a single mutable state shared across all agent steps, allowing for data accumulation, tool responses, and message tracking.
|
| 129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
---
|
| 131 |
|
| 132 |
## 🧠 Built With
|
|
@@ -137,6 +153,7 @@ This dictionary acts as a single mutable state shared across all agent steps, al
|
|
| 137 |
- [FastAPI](https://fastapi.tiangolo.com/)
|
| 138 |
- [Whisper](https://github.com/openai/whisper)
|
| 139 |
- [SQLAlchemy + Async](https://docs.sqlalchemy.org/en/20/orm/extensions/asyncio.html)
|
|
|
|
| 140 |
|
| 141 |
---
|
| 142 |
|
|
|
|
| 30 |
- Supervisor agent
|
| 31 |
- Deep research agent
|
| 32 |
- Coding agent
|
| 33 |
+
- Smart home agent
|
| 34 |
- **Supervisor tools**:
|
| 35 |
- Web search
|
| 36 |
- Current time
|
|
|
|
| 43 |
- **Coder tools**:
|
| 44 |
- Github toolkit
|
| 45 |
- Web search (For docs research)
|
| 46 |
+
- **Smart home tools**:
|
| 47 |
+
- Get device list
|
| 48 |
+
- Change device states
|
| 49 |
|
| 50 |
---
|
| 51 |
|
|
|
|
| 122 |
openweathermap_api_key: str
|
| 123 |
github_token: str
|
| 124 |
tavily_api_key: str
|
| 125 |
+
groq_api_key: str,
|
| 126 |
+
tuya_access_id: str
|
| 127 |
+
tuya_access_key: str
|
| 128 |
+
tuya_username: str
|
| 129 |
+
tuya_password: str
|
| 130 |
+
tuya_country: str
|
| 131 |
clear_history: bool (True/False)
|
| 132 |
messages: list (Filled automatically from the database)
|
| 133 |
|
|
|
|
| 136 |
|
| 137 |
This dictionary acts as a single mutable state shared across all agent steps, allowing for data accumulation, tool responses, and message tracking.
|
| 138 |
|
| 139 |
+
|
| 140 |
+
---
|
| 141 |
+
|
| 142 |
+
## ⚙️ Tuya Setup
|
| 143 |
+
|
| 144 |
+
Take a look at the [official instructions](https://developer.tuya.com/en/docs/iot/device-control-best-practice?id=Ka72202tz4m67)
|
| 145 |
+
|
| 146 |
---
|
| 147 |
|
| 148 |
## 🧠 Built With
|
|
|
|
| 153 |
- [FastAPI](https://fastapi.tiangolo.com/)
|
| 154 |
- [Whisper](https://github.com/openai/whisper)
|
| 155 |
- [SQLAlchemy + Async](https://docs.sqlalchemy.org/en/20/orm/extensions/asyncio.html)
|
| 156 |
+
- [Tuya Smart Home](https://github.com/tuya/tuya-iot-python-sdk?tab=readme-ov-file)
|
| 157 |
|
| 158 |
---
|
| 159 |
|
agent/__pycache__/multi_agent.cpython-312.pyc
CHANGED
|
Binary files a/agent/__pycache__/multi_agent.cpython-312.pyc and b/agent/__pycache__/multi_agent.cpython-312.pyc differ
|
|
|
agent/__pycache__/prompts.cpython-312.pyc
CHANGED
|
Binary files a/agent/__pycache__/prompts.cpython-312.pyc and b/agent/__pycache__/prompts.cpython-312.pyc differ
|
|
|
agent/__pycache__/smart_home_agent.cpython-312.pyc
ADDED
|
Binary file (1.61 kB). View file
|
|
|
agent/__pycache__/states.cpython-312.pyc
CHANGED
|
Binary files a/agent/__pycache__/states.cpython-312.pyc and b/agent/__pycache__/states.cpython-312.pyc differ
|
|
|
agent/__pycache__/tools.cpython-312.pyc
CHANGED
|
Binary files a/agent/__pycache__/tools.cpython-312.pyc and b/agent/__pycache__/tools.cpython-312.pyc differ
|
|
|
agent/multi_agent.py
CHANGED
|
@@ -22,10 +22,14 @@ class State(TypedDict):
|
|
| 22 |
github_token: str
|
| 23 |
tavily_api_key: str
|
| 24 |
groq_api_key: str
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
clear_history: bool
|
| 26 |
messages: list
|
| 27 |
|
| 28 |
-
|
| 29 |
class Assistant:
|
| 30 |
def __init__(self, state: State):
|
| 31 |
self.state = state
|
|
@@ -52,7 +56,8 @@ class Assistant:
|
|
| 52 |
config_data = {}
|
| 53 |
config_fields = [
|
| 54 |
'assistant_name', 'openweathermap_api_key', 'github_token',
|
| 55 |
-
'tavily_api_key', 'groq_api_key'
|
|
|
|
| 56 |
]
|
| 57 |
|
| 58 |
for field in config_fields:
|
|
@@ -72,6 +77,7 @@ class Assistant:
|
|
| 72 |
def compile_multi_agent_system(self):
|
| 73 |
"""Create and return the multi-agent system"""
|
| 74 |
try:
|
|
|
|
| 75 |
from agent.deep_research_agent import deep_research_agent
|
| 76 |
from agent.coder_agent import coder_agent
|
| 77 |
from agent.prompts import supervisor_instructions
|
|
@@ -86,7 +92,7 @@ class Assistant:
|
|
| 86 |
output_messages_key="llm_input_messages",
|
| 87 |
)
|
| 88 |
|
| 89 |
-
agents = [coder_agent, deep_research_agent]
|
| 90 |
|
| 91 |
supervisor = create_supervisor(
|
| 92 |
model=llm_supervisor,
|
|
|
|
| 22 |
github_token: str
|
| 23 |
tavily_api_key: str
|
| 24 |
groq_api_key: str
|
| 25 |
+
tuya_access_id: str
|
| 26 |
+
tuya_access_key: str
|
| 27 |
+
tuya_username: str
|
| 28 |
+
tuya_password: str
|
| 29 |
+
tuya_country: str
|
| 30 |
clear_history: bool
|
| 31 |
messages: list
|
| 32 |
|
|
|
|
| 33 |
class Assistant:
|
| 34 |
def __init__(self, state: State):
|
| 35 |
self.state = state
|
|
|
|
| 56 |
config_data = {}
|
| 57 |
config_fields = [
|
| 58 |
'assistant_name', 'openweathermap_api_key', 'github_token',
|
| 59 |
+
'tavily_api_key', 'groq_api_key', 'tuya_access_id', 'tuya_access_key',
|
| 60 |
+
'tuya_username', 'tuya_password', 'tuya_country'
|
| 61 |
]
|
| 62 |
|
| 63 |
for field in config_fields:
|
|
|
|
| 77 |
def compile_multi_agent_system(self):
|
| 78 |
"""Create and return the multi-agent system"""
|
| 79 |
try:
|
| 80 |
+
from agent.smart_home_agent import smart_home_agent
|
| 81 |
from agent.deep_research_agent import deep_research_agent
|
| 82 |
from agent.coder_agent import coder_agent
|
| 83 |
from agent.prompts import supervisor_instructions
|
|
|
|
| 92 |
output_messages_key="llm_input_messages",
|
| 93 |
)
|
| 94 |
|
| 95 |
+
agents = [coder_agent, deep_research_agent, smart_home_agent]
|
| 96 |
|
| 97 |
supervisor = create_supervisor(
|
| 98 |
model=llm_supervisor,
|
agent/prompts.py
CHANGED
|
@@ -6,6 +6,13 @@ coder_instructions = f"""You are a coding expert. Follow these steps every time:
|
|
| 6 |
|
| 7 |
"""
|
| 8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
deep_research_instructions = f"""You are a deep research expert. Follow these steps every time:\n
|
| 10 |
|
| 11 |
1. Iterate over the given search queries.\n
|
|
@@ -53,4 +60,13 @@ def deep_research_system_message(state: dict):
|
|
| 53 |
4. Conduct additional research using available tools.\t
|
| 54 |
5. Write an extensive report based on web search results.\n
|
| 55 |
6. Critically review your report and cicle over these steps until it is factually correct and very detailed.\n
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
"""
|
|
|
|
| 6 |
|
| 7 |
"""
|
| 8 |
|
| 9 |
+
smart_home_instructions = f"""You are a smart home control expert. Follow these steps every time:\n
|
| 10 |
+
|
| 11 |
+
1. Use the 'get_device_list' tool to retrieve the list of available devices with their names, ids, and states.\n
|
| 12 |
+
2. Identify the target device(s) based on the user’s request.\n
|
| 13 |
+
3. Use the 'change_device_states' tool to update the states of the selected device(s).\n
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
deep_research_instructions = f"""You are a deep research expert. Follow these steps every time:\n
|
| 17 |
|
| 18 |
1. Iterate over the given search queries.\n
|
|
|
|
| 60 |
4. Conduct additional research using available tools.\t
|
| 61 |
5. Write an extensive report based on web search results.\n
|
| 62 |
6. Critically review your report and cicle over these steps until it is factually correct and very detailed.\n
|
| 63 |
+
"""
|
| 64 |
+
|
| 65 |
+
def smart_home_system_message(device_list: list):
|
| 66 |
+
return f"""Your job is to control the smart home.\nYou have access to the following devices:\n
|
| 67 |
+
{"\n\n".join(
|
| 68 |
+
f"{i+1}. {device['name']} (id: {device['id']})\nStates:\n" +
|
| 69 |
+
"\n".join(f"{state}" for state in device['states'])
|
| 70 |
+
for i, device in enumerate(device_list)
|
| 71 |
+
)}.\nUse the given tools ('get_device_list', 'change_device_states') to complete the user's tasks.
|
| 72 |
"""
|
agent/smart_home_agent.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from agent.prompts import smart_home_instructions, smart_home_system_message
|
| 2 |
+
from langchain_core.messages import HumanMessage, SystemMessage
|
| 3 |
+
from agent.models import llm_agents, llm_peripheral
|
| 4 |
+
from langgraph.prebuilt import create_react_agent
|
| 5 |
+
from langgraph.constants import START, END
|
| 6 |
+
from langgraph.graph import StateGraph
|
| 7 |
+
from agent.tools import smart_home_tools, get_device_list
|
| 8 |
+
|
| 9 |
+
agent = create_react_agent(
|
| 10 |
+
llm_agents,
|
| 11 |
+
tools=smart_home_tools,
|
| 12 |
+
prompt=smart_home_instructions
|
| 13 |
+
)
|
| 14 |
+
|
| 15 |
+
def home_control_agent(state: dict):
|
| 16 |
+
system_message = SystemMessage(smart_home_system_message(get_device_list.invoke({})))
|
| 17 |
+
state.update(agent.invoke({
|
| 18 |
+
'messages': [
|
| 19 |
+
system_message,
|
| 20 |
+
HumanMessage(state['messages'][-1].content),
|
| 21 |
+
]
|
| 22 |
+
}))
|
| 23 |
+
return state
|
| 24 |
+
|
| 25 |
+
graph = StateGraph(dict)
|
| 26 |
+
graph.add_node("home_control_agent", home_control_agent)
|
| 27 |
+
graph.add_edge(START, "home_control_agent")
|
| 28 |
+
graph.add_edge("home_control_agent", END)
|
| 29 |
+
|
| 30 |
+
smart_home_agent = graph.compile(name="smart_home_agent")
|
agent/states.py
CHANGED
|
@@ -10,5 +10,4 @@ class PlanResearch(TypedDict):
|
|
| 10 |
class PlanCodingTask(TypedDict):
|
| 11 |
repo_name: str = Field(description="The name of the GitHub repository for the project.")
|
| 12 |
private: bool = Field(description="Whether or not the repository is private.", default=False)
|
| 13 |
-
task_description: str = Field(description="A detailed description of the project for the coder to create.")
|
| 14 |
-
|
|
|
|
| 10 |
class PlanCodingTask(TypedDict):
|
| 11 |
repo_name: str = Field(description="The name of the GitHub repository for the project.")
|
| 12 |
private: bool = Field(description="Whether or not the repository is private.", default=False)
|
| 13 |
+
task_description: str = Field(description="A detailed description of the project for the coder to create.")
|
|
|
agent/tools.py
CHANGED
|
@@ -5,26 +5,61 @@ from langchain_community.tools import WikipediaQueryRun
|
|
| 5 |
from langchain_tavily.tavily_search import TavilySearch
|
| 6 |
from timezonefinder import TimezoneFinder
|
| 7 |
from langchain_core.tools import tool
|
|
|
|
| 8 |
from dotenv import load_dotenv
|
| 9 |
from geopy import Nominatim
|
| 10 |
from github import Github
|
|
|
|
|
|
|
| 11 |
import datetime
|
| 12 |
import pytz
|
| 13 |
import os
|
| 14 |
|
| 15 |
load_dotenv()
|
| 16 |
|
| 17 |
-
|
| 18 |
-
|
| 19 |
web_search = TavilySearch(
|
| 20 |
max_results=5,
|
| 21 |
topic="general",
|
| 22 |
include_answer=True
|
| 23 |
)
|
| 24 |
-
|
| 25 |
geolocator = Nominatim(user_agent="my_geocoder")
|
|
|
|
| 26 |
weekday_mapping = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
|
| 27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
@tool
|
| 29 |
def create_repo(repo_name: str, private: bool = False):
|
| 30 |
"""Creates a GitHub repository with the given repo_name."""
|
|
@@ -174,6 +209,32 @@ def weather(location: str = None):
|
|
| 174 |
except Exception as e:
|
| 175 |
return f"Error getting weather: {str(e)}"
|
| 176 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 177 |
coder_tools = [web_search, create_repo, create_branch, commit_file_to_repo, read_file, list_files, list_repos, list_branches, delete_file]
|
| 178 |
supervisor_tools = [yahoo, web_search, current_time, weather]
|
| 179 |
deep_research_tools = [web_search, yahoo, wikipedia]
|
|
|
|
|
|
| 5 |
from langchain_tavily.tavily_search import TavilySearch
|
| 6 |
from timezonefinder import TimezoneFinder
|
| 7 |
from langchain_core.tools import tool
|
| 8 |
+
from tuya_iot import TuyaOpenAPI
|
| 9 |
from dotenv import load_dotenv
|
| 10 |
from geopy import Nominatim
|
| 11 |
from github import Github
|
| 12 |
+
import phonenumbers
|
| 13 |
+
import pycountry
|
| 14 |
import datetime
|
| 15 |
import pytz
|
| 16 |
import os
|
| 17 |
|
| 18 |
load_dotenv()
|
| 19 |
|
| 20 |
+
|
| 21 |
+
tf = TimezoneFinder()
|
| 22 |
web_search = TavilySearch(
|
| 23 |
max_results=5,
|
| 24 |
topic="general",
|
| 25 |
include_answer=True
|
| 26 |
)
|
| 27 |
+
yahoo = YahooFinanceNewsTool()
|
| 28 |
geolocator = Nominatim(user_agent="my_geocoder")
|
| 29 |
+
wikipedia = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())
|
| 30 |
weekday_mapping = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
|
| 31 |
+
endpoint_map = {
|
| 32 |
+
"https://openapi.tuyacn.com": [86],
|
| 33 |
+
"https://openapi.tuyain.com": [91],
|
| 34 |
+
"https://openapi.tuyaus.com": [1, 51, 52, 54, 55, 56, 57, 58, 81, 82, 239,
|
| 35 |
+
245, 502, 591, 593, 595, 597, 598, 674, 678, 682, 683, 685, 686, 690, 970,
|
| 36 |
+
1340, 1684, 1670, 1671, 1787, 1809, 1829, 1849, 5999, 35818, 64],
|
| 37 |
+
"https://openapi.tuyaeu.com": [7, 20, 27, 30, 31, 32, 33, 34, 36, 39, 40,
|
| 38 |
+
90, 92, 93, 94, 212, 213, 216, 218, 220, 221, 222, 223, 224, 225, 226, 227,
|
| 39 |
+
228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 240, 241, 242, 243,
|
| 40 |
+
244, 246, 248, 250, 251, 252, 253, 254, 255, 256, 257, 258, 260, 261, 262,
|
| 41 |
+
263, 264, 265, 266, 267, 268, 269, 291, 297, 298, 299, 350, 351, 352, 353,
|
| 42 |
+
354, 355, 356, 357, 358, 359, 370, 371, 372, 373, 374, 375, 376, 377, 378,
|
| 43 |
+
379, 380, 381, 382, 385, 386, 387, 389, 420, 421, 423, 500, 501, 503, 504,
|
| 44 |
+
505, 506, 507, 508, 509, 590, 592, 594, 596, 672, 676, 679, 680, 681, 687,
|
| 45 |
+
688, 689, 691, 692, 960, 961, 962, 964, 965, 966, 967, 968, 971, 972, 973,
|
| 46 |
+
974, 975, 976, 977, 992, 993, 994, 995, 996, 998, 1242, 1246, 1264, 1268,
|
| 47 |
+
1284, 1345, 1441, 1473, 1649, 1664, 1721, 1758, 1767, 1784, 1868, 1869,
|
| 48 |
+
1876, 4779, 61, 880, 41, 43, 44, 45, 46, 47, 48, 49],
|
| 49 |
+
"https://openapi-sg.iotbing.com": [84, 856, 855, 66, 95, 60, 65, 62, 63,
|
| 50 |
+
673, 670, 675, 677, 852, 853, 886],
|
| 51 |
+
}
|
| 52 |
+
country = pycountry.countries.lookup(os.getenv('TUYA_COUNTRY').title())
|
| 53 |
+
country_code = phonenumbers.country_code_for_region(country.alpha_2)
|
| 54 |
+
for endpoint, country_codes in endpoint_map.items():
|
| 55 |
+
if country_code in country_codes:
|
| 56 |
+
os.environ['TUYA_COUNTRY_CODE'] = str(country_code)
|
| 57 |
+
os.environ['TUYA_ENDPOINT'] = endpoint
|
| 58 |
+
break
|
| 59 |
+
openapi = TuyaOpenAPI(os.getenv('TUYA_ENDPOINT'), os.getenv('TUYA_ACCESS_ID'), os.getenv('TUYA_ACCESS_KEY'))
|
| 60 |
+
connection = openapi.connect(os.getenv('TUYA_USERNAME'), os.getenv('TUYA_PASSWORD'), os.getenv('TUYA_COUNTRY_CODE'), 'TuyaSmart')
|
| 61 |
+
if not connection['success']:
|
| 62 |
+
connection = openapi.connect(os.getenv('TUYA_USERNAME'), os.getenv('TUYA_PASSWORD'), os.getenv('TUYA_COUNTRY_CODE'), 'SmartLife')
|
| 63 |
@tool
|
| 64 |
def create_repo(repo_name: str, private: bool = False):
|
| 65 |
"""Creates a GitHub repository with the given repo_name."""
|
|
|
|
| 209 |
except Exception as e:
|
| 210 |
return f"Error getting weather: {str(e)}"
|
| 211 |
|
| 212 |
+
@tool
|
| 213 |
+
def get_device_list():
|
| 214 |
+
"""
|
| 215 |
+
Get the list of devices bound to the smart home.
|
| 216 |
+
Each device has id: str, name: str and states: List[dict].
|
| 217 |
+
States is a list of device states which can be changed.
|
| 218 |
+
State format: {'code': ..., 'value': ...}
|
| 219 |
+
"""
|
| 220 |
+
response = openapi.get('/v1.0/users/{}/devices'.format(connection['result']['uid']))['result']
|
| 221 |
+
devices = []
|
| 222 |
+
for device in response:
|
| 223 |
+
devices.append({"id": device['id'], 'name': device['name'], 'states': device['status']})
|
| 224 |
+
return devices
|
| 225 |
+
|
| 226 |
+
@tool
|
| 227 |
+
def change_device_states(id:str, commands:list[dict]):
|
| 228 |
+
"""
|
| 229 |
+
Control the smart home devices by sending commands.
|
| 230 |
+
Accepts device id:str and a list of commands: List[dict].
|
| 231 |
+
Commands is a list of changed device states.
|
| 232 |
+
State format: {'code': ..., 'value': ...}
|
| 233 |
+
"""
|
| 234 |
+
response = openapi.post('/v1.0/devices/{}/commands'.format(id), {"commands": commands})
|
| 235 |
+
return "success" if response["success"] else "failure"
|
| 236 |
+
|
| 237 |
coder_tools = [web_search, create_repo, create_branch, commit_file_to_repo, read_file, list_files, list_repos, list_branches, delete_file]
|
| 238 |
supervisor_tools = [yahoo, web_search, current_time, weather]
|
| 239 |
deep_research_tools = [web_search, yahoo, wikipedia]
|
| 240 |
+
smart_home_tools = [get_device_list, change_device_states]
|
database_interaction/config.py
CHANGED
|
@@ -54,6 +54,11 @@ async def load_config_to_env(user_id: str):
|
|
| 54 |
'github_token': 'GITHUB_TOKEN',
|
| 55 |
'tavily_api_key': 'TAVILY_API_KEY',
|
| 56 |
'groq_api_key': 'GROQ_API_KEY',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
}
|
| 58 |
|
| 59 |
for config_key, env_key in env_mapping.items():
|
|
@@ -65,9 +70,8 @@ async def load_config_to_env(user_id: str):
|
|
| 65 |
async def save_env_to_file():
|
| 66 |
"""Save current environment variables to .env file"""
|
| 67 |
env_vars = [
|
| 68 |
-
'DATABASE_URL', 'TOKEN', 'ASSISTANT_NAME', 'LOCATION', 'LATITUDE', 'LONGITUDE',
|
| 69 |
-
'
|
| 70 |
-
'GROQ_API_KEY'
|
| 71 |
]
|
| 72 |
|
| 73 |
# Set default values if not present
|
|
|
|
| 54 |
'github_token': 'GITHUB_TOKEN',
|
| 55 |
'tavily_api_key': 'TAVILY_API_KEY',
|
| 56 |
'groq_api_key': 'GROQ_API_KEY',
|
| 57 |
+
'tuya_access_id': 'TUYA_ACCESS_ID',
|
| 58 |
+
'tuya_access_key': 'TUYA_ACCESS_KEY',
|
| 59 |
+
'tuya_username': 'TUYA_USERNAME',
|
| 60 |
+
'tuya_password': 'TUYA_PASSWORD',
|
| 61 |
+
'tuya_country': 'TUYA_COUNTRY',
|
| 62 |
}
|
| 63 |
|
| 64 |
for config_key, env_key in env_mapping.items():
|
|
|
|
| 70 |
async def save_env_to_file():
|
| 71 |
"""Save current environment variables to .env file"""
|
| 72 |
env_vars = [
|
| 73 |
+
'DATABASE_URL', 'TOKEN', 'ASSISTANT_NAME', 'LOCATION', 'LATITUDE', 'LONGITUDE','OPENWEATHERMAP_API_KEY', 'GITHUB_TOKEN',
|
| 74 |
+
'TAVILY_API_KEY', 'GROQ_API_KEY', 'TUYA_ACCESS_ID', 'TUYA_ACCESS_KEY', 'TUYA_USERNAME', 'TUYA_PASSWORD', 'TUYA_COUNTRY',
|
|
|
|
| 75 |
]
|
| 76 |
|
| 77 |
# Set default values if not present
|
database_interaction/models.py
CHANGED
|
@@ -15,10 +15,15 @@ class User(Base):
|
|
| 15 |
|
| 16 |
class UserConfig(Base):
|
| 17 |
__tablename__ = "user_config"
|
| 18 |
-
|
| 19 |
user_id = Column(String, primary_key=True, index=True)
|
| 20 |
assistant_name = Column(String, nullable=True)
|
| 21 |
openweathermap_api_key = Column(String, nullable=True)
|
| 22 |
github_token = Column(String, nullable=True)
|
| 23 |
tavily_api_key = Column(String, nullable=True)
|
| 24 |
-
groq_api_key = Column(String, nullable=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
class UserConfig(Base):
|
| 17 |
__tablename__ = "user_config"
|
|
|
|
| 18 |
user_id = Column(String, primary_key=True, index=True)
|
| 19 |
assistant_name = Column(String, nullable=True)
|
| 20 |
openweathermap_api_key = Column(String, nullable=True)
|
| 21 |
github_token = Column(String, nullable=True)
|
| 22 |
tavily_api_key = Column(String, nullable=True)
|
| 23 |
+
groq_api_key = Column(String, nullable=True)
|
| 24 |
+
tuya_access_id = Column(String, nullable=True)
|
| 25 |
+
tuya_access_key = Column(String, nullable=True)
|
| 26 |
+
tuya_username = Column(String, nullable=True)
|
| 27 |
+
tuya_password = Column(String, nullable=True)
|
| 28 |
+
tuya_country = Column(String, nullable=True)
|
| 29 |
+
tuya_schema = Column(String, nullable=True)
|
requirements.txt
CHANGED
|
@@ -4,6 +4,8 @@ python-dotenv>=1.1.1
|
|
| 4 |
langchain>=0.3.27
|
| 5 |
langgraph>=0.6.3
|
| 6 |
openai>=1.99.1
|
|
|
|
|
|
|
| 7 |
timm>=1.0.19
|
| 8 |
langchain-groq>=0.3.7
|
| 9 |
langgraph-supervisor>=0.0.29
|
|
|
|
| 4 |
langchain>=0.3.27
|
| 5 |
langgraph>=0.6.3
|
| 6 |
openai>=1.99.1
|
| 7 |
+
phonenumbers
|
| 8 |
+
pycountry
|
| 9 |
timm>=1.0.19
|
| 10 |
langchain-groq>=0.3.7
|
| 11 |
langgraph-supervisor>=0.0.29
|
tmp/classifier.ckpt
DELETED
|
File without changes
|
tmp/embedding_model.ckpt
DELETED
|
File without changes
|
tmp/hyperparams.yaml
DELETED
|
@@ -1,57 +0,0 @@
|
|
| 1 |
-
pretrained_path: speechbrain/lang-id-voxlingua107-ecapa
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
# Feature parameters
|
| 5 |
-
n_mels: 60
|
| 6 |
-
left_frames: 0
|
| 7 |
-
right_frames: 0
|
| 8 |
-
deltas: false
|
| 9 |
-
|
| 10 |
-
# Number of speakers
|
| 11 |
-
out_n_neurons: 107
|
| 12 |
-
|
| 13 |
-
# Functions
|
| 14 |
-
compute_features: !new:speechbrain.lobes.features.Fbank
|
| 15 |
-
n_mels: 60
|
| 16 |
-
left_frames: 0
|
| 17 |
-
right_frames: 0
|
| 18 |
-
deltas: false
|
| 19 |
-
|
| 20 |
-
embedding_model: !new:speechbrain.lobes.models.ECAPA_TDNN.ECAPA_TDNN
|
| 21 |
-
input_size: 60
|
| 22 |
-
channels: [1024, 1024, 1024, 1024, 3072]
|
| 23 |
-
kernel_sizes: [5, 3, 3, 3, 1]
|
| 24 |
-
dilations: [1, 2, 3, 4, 1]
|
| 25 |
-
attention_channels: 128
|
| 26 |
-
lin_neurons: 256
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
classifier: !new:speechbrain.lobes.models.Xvector.Classifier
|
| 30 |
-
input_shape: [null, null, 256]
|
| 31 |
-
activation: !name:torch.nn.LeakyReLU
|
| 32 |
-
lin_blocks: 1
|
| 33 |
-
lin_neurons: 512
|
| 34 |
-
out_neurons: !ref <out_n_neurons>
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
mean_var_norm: !new:speechbrain.processing.features.InputNormalization
|
| 38 |
-
norm_type: sentence
|
| 39 |
-
std_norm: false
|
| 40 |
-
|
| 41 |
-
modules:
|
| 42 |
-
compute_features: !ref <compute_features>
|
| 43 |
-
mean_var_norm: !ref <mean_var_norm>
|
| 44 |
-
embedding_model: !ref <embedding_model>
|
| 45 |
-
classifier: !ref <classifier>
|
| 46 |
-
|
| 47 |
-
label_encoder: !new:speechbrain.dataio.encoder.CategoricalEncoder
|
| 48 |
-
|
| 49 |
-
pretrainer: !new:speechbrain.utils.parameter_transfer.Pretrainer
|
| 50 |
-
loadables:
|
| 51 |
-
embedding_model: !ref <embedding_model>
|
| 52 |
-
classifier: !ref <classifier>
|
| 53 |
-
label_encoder: !ref <label_encoder>
|
| 54 |
-
paths:
|
| 55 |
-
embedding_model: !ref <pretrained_path>/embedding_model.ckpt
|
| 56 |
-
classifier: !ref <pretrained_path>/classifier.ckpt
|
| 57 |
-
label_encoder: !ref <pretrained_path>/label_encoder.txt
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tmp/label_encoder.ckpt
DELETED
|
@@ -1,109 +0,0 @@
|
|
| 1 |
-
'ab: Abkhazian' => 0
|
| 2 |
-
'af: Afrikaans' => 1
|
| 3 |
-
'am: Amharic' => 2
|
| 4 |
-
'ar: Arabic' => 3
|
| 5 |
-
'as: Assamese' => 4
|
| 6 |
-
'az: Azerbaijani' => 5
|
| 7 |
-
'ba: Bashkir' => 6
|
| 8 |
-
'be: Belarusian' => 7
|
| 9 |
-
'bg: Bulgarian' => 8
|
| 10 |
-
'bn: Bengali' => 9
|
| 11 |
-
'bo: Tibetan' => 10
|
| 12 |
-
'br: Breton' => 11
|
| 13 |
-
'bs: Bosnian' => 12
|
| 14 |
-
'ca: Catalan' => 13
|
| 15 |
-
'ceb: Cebuano' => 14
|
| 16 |
-
'cs: Czech' => 15
|
| 17 |
-
'cy: Welsh' => 16
|
| 18 |
-
'da: Danish' => 17
|
| 19 |
-
'de: German' => 18
|
| 20 |
-
'el: Greek' => 19
|
| 21 |
-
'en: English' => 20
|
| 22 |
-
'eo: Esperanto' => 21
|
| 23 |
-
'es: Spanish' => 22
|
| 24 |
-
'et: Estonian' => 23
|
| 25 |
-
'eu: Basque' => 24
|
| 26 |
-
'fa: Persian' => 25
|
| 27 |
-
'fi: Finnish' => 26
|
| 28 |
-
'fo: Faroese' => 27
|
| 29 |
-
'fr: French' => 28
|
| 30 |
-
'gl: Galician' => 29
|
| 31 |
-
'gn: Guarani' => 30
|
| 32 |
-
'gu: Gujarati' => 31
|
| 33 |
-
'gv: Manx' => 32
|
| 34 |
-
'ha: Hausa' => 33
|
| 35 |
-
'haw: Hawaiian' => 34
|
| 36 |
-
'hi: Hindi' => 35
|
| 37 |
-
'hr: Croatian' => 36
|
| 38 |
-
'ht: Haitian' => 37
|
| 39 |
-
'hu: Hungarian' => 38
|
| 40 |
-
'hy: Armenian' => 39
|
| 41 |
-
'ia: Interlingua' => 40
|
| 42 |
-
'id: Indonesian' => 41
|
| 43 |
-
'is: Icelandic' => 42
|
| 44 |
-
'it: Italian' => 43
|
| 45 |
-
'iw: Hebrew' => 44
|
| 46 |
-
'ja: Japanese' => 45
|
| 47 |
-
'jw: Javanese' => 46
|
| 48 |
-
'ka: Georgian' => 47
|
| 49 |
-
'kk: Kazakh' => 48
|
| 50 |
-
'km: Central Khmer' => 49
|
| 51 |
-
'kn: Kannada' => 50
|
| 52 |
-
'ko: Korean' => 51
|
| 53 |
-
'la: Latin' => 52
|
| 54 |
-
'lb: Luxembourgish' => 53
|
| 55 |
-
'ln: Lingala' => 54
|
| 56 |
-
'lo: Lao' => 55
|
| 57 |
-
'lt: Lithuanian' => 56
|
| 58 |
-
'lv: Latvian' => 57
|
| 59 |
-
'mg: Malagasy' => 58
|
| 60 |
-
'mi: Maori' => 59
|
| 61 |
-
'mk: Macedonian' => 60
|
| 62 |
-
'ml: Malayalam' => 61
|
| 63 |
-
'mn: Mongolian' => 62
|
| 64 |
-
'mr: Marathi' => 63
|
| 65 |
-
'ms: Malay' => 64
|
| 66 |
-
'mt: Maltese' => 65
|
| 67 |
-
'my: Burmese' => 66
|
| 68 |
-
'ne: Nepali' => 67
|
| 69 |
-
'nl: Dutch' => 68
|
| 70 |
-
'nn: Norwegian Nynorsk' => 69
|
| 71 |
-
'no: Norwegian' => 70
|
| 72 |
-
'oc: Occitan' => 71
|
| 73 |
-
'pa: Panjabi' => 72
|
| 74 |
-
'pl: Polish' => 73
|
| 75 |
-
'ps: Pushto' => 74
|
| 76 |
-
'pt: Portuguese' => 75
|
| 77 |
-
'ro: Romanian' => 76
|
| 78 |
-
'ru: Russian' => 77
|
| 79 |
-
'sa: Sanskrit' => 78
|
| 80 |
-
'sco: Scots' => 79
|
| 81 |
-
'sd: Sindhi' => 80
|
| 82 |
-
'si: Sinhala' => 81
|
| 83 |
-
'sk: Slovak' => 82
|
| 84 |
-
'sl: Slovenian' => 83
|
| 85 |
-
'sn: Shona' => 84
|
| 86 |
-
'so: Somali' => 85
|
| 87 |
-
'sq: Albanian' => 86
|
| 88 |
-
'sr: Serbian' => 87
|
| 89 |
-
'su: Sundanese' => 88
|
| 90 |
-
'sv: Swedish' => 89
|
| 91 |
-
'sw: Swahili' => 90
|
| 92 |
-
'ta: Tamil' => 91
|
| 93 |
-
'te: Telugu' => 92
|
| 94 |
-
'tg: Tajik' => 93
|
| 95 |
-
'th: Thai' => 94
|
| 96 |
-
'tk: Turkmen' => 95
|
| 97 |
-
'tl: Tagalog' => 96
|
| 98 |
-
'tr: Turkish' => 97
|
| 99 |
-
'tt: Tatar' => 98
|
| 100 |
-
'uk: Ukrainian' => 99
|
| 101 |
-
'ur: Urdu' => 100
|
| 102 |
-
'uz: Uzbek' => 101
|
| 103 |
-
'vi: Vietnamese' => 102
|
| 104 |
-
'war: Waray' => 103
|
| 105 |
-
'yi: Yiddish' => 104
|
| 106 |
-
'yo: Yoruba' => 105
|
| 107 |
-
'zh: Chinese' => 106
|
| 108 |
-
================
|
| 109 |
-
'starting_index' => 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|