Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Feat/tools icon #51

Merged
merged 6 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions backend/app/alembic/versions/7bb637385f51_modify_skills_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""modify skills table

Revision ID: 7bb637385f51
Revises: b5d6291d6db9
Create Date: 2024-09-26 13:41:33.595237

"""
from alembic import op
import sqlalchemy as sa
import sqlmodel.sql.sqltypes


# revision identifiers, used by Alembic.
revision = '7bb637385f51'
down_revision = 'b5d6291d6db9'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('skill', sa.Column('display_name', sqlmodel.sql.sqltypes.AutoString(), nullable=True))
op.drop_column('skill', 'icon')
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('skill', sa.Column('icon', sa.VARCHAR(), autoincrement=False, nullable=True))
op.drop_column('skill', 'display_name')
# ### end Alembic commands ###
5 changes: 3 additions & 2 deletions backend/app/core/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,20 @@ def init_db(session: Session) -> None:

if (
existing_skill.description != skill_info.description
or existing_skill.icon != skill_info.icon
or existing_skill.display_name != skill_info.display_name
):

# Update the existing skill's description
existing_skill.description = skill_info.description
existing_skill.icon = skill_info.icon
existing_skill.display_name = skill_info.display_name
session.add(existing_skill) # Mark the modified object for saving
else:
new_skill = Skill(
name=skill_name,
description=skill_info.description,
managed=True,
owner_id=user.id,
display_name=skill_info.display_name
)
session.add(new_skill) # Prepare new skill for addition to the database

Expand Down
16 changes: 13 additions & 3 deletions backend/app/core/graph/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ def convert_chatbot_chatrag_team_to_dict(
member = members[0]
assert member.id is not None, "member.id is unexpectedly None"
tools: list[GraphSkill | GraphUpload]
if workflow_type == "ragbot" or workflow_type == "chatbot":
if workflow_type == "ragbot":
tools = [
GraphUpload(
name=upload.name,
Expand All @@ -233,7 +233,16 @@ def convert_chatbot_chatrag_team_to_dict(
if upload.owner_id is not None
]
elif workflow_type == "chatbot":
tools += [
tools = [
GraphUpload(
name=upload.name,
description=upload.description,
owner_id=upload.owner_id,
upload_id=cast(int, upload.id),
)
for upload in member.uploads
if upload.owner_id is not None
] + [
GraphSkill(
name=skill.name,
managed=skill.managed,
Expand Down Expand Up @@ -445,7 +454,7 @@ def create_hierarchical_graph(
build.set_entry_point(leader_name)
build.set_finish_point("FinalAnswer")
graph = build.compile(
checkpointer=checkpointer, interrupt_before=interrupt_member_names
checkpointer=checkpointer, interrupt_before=interrupt_member_names, debug=True
)

# try:
Expand Down Expand Up @@ -819,6 +828,7 @@ async def generator(
formatted_output = f"data: {response.model_dump_json()}\n\n"
yield formatted_output
snapshot = await root.aget_state(config)

if snapshot.next:
# Interrupt occured
message = snapshot.values["messages"][-1]
Expand Down
90 changes: 2 additions & 88 deletions backend/app/core/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -1,89 +1,3 @@
import os
from .tool_manager import ToolInfo, managed_tools

from langchain.pydantic_v1 import BaseModel
from langchain.tools import BaseTool
from langchain_community.tools import DuckDuckGoSearchRun, WikipediaQueryRun
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_community.tools.yahoo_finance_news import YahooFinanceNewsTool
from langchain_community.utilities import WikipediaAPIWrapper

from .calculator import calculator
from .google_translate import google_tanslate
from .human_tool import AskHuman
from .open_weather import open_weather_search

# Add more tools here


class ToolInfo(BaseModel):
description: str
tool: BaseTool
icon: str = "🔧"


managed_tools: dict[str, ToolInfo] = {
"duckduckgo-search": ToolInfo(
description="Searches the web using DuckDuckGo",
tool=DuckDuckGoSearchRun(),
icon="🔍",
),
"wikipedia": ToolInfo(
description="Searches Wikipedia",
tool=WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper()),
icon="📖", # type: ignore[call-arg]
),
"yahoo-finance": ToolInfo(
description="Get information from Yahoo Finance News",
tool=YahooFinanceNewsTool(),
icon="💰",
),
"tavilysearch": ToolInfo(
description="tavily search useful when searching for information on the internet",
tool=TavilySearchResults(max_results=1), # type: ignore[call-arg]
icon="🔍",
),
"calculator": ToolInfo(
description=calculator.description, tool=calculator, icon="🧮"
),
"openweather-search": ToolInfo(
description=open_weather_search.description,
tool=open_weather_search,
icon="🌞",
),
"ask-human": ToolInfo(description=AskHuman.description, tool=AskHuman, icon="📖"),
"google-translate": ToolInfo(
description=google_tanslate.description,
tool=google_tanslate,
icon="📖",
),
}


# from .tool_manager import managed_skills

# # You can still import specific tools if needed
# from .calculator import calculator
# from .open_weather import open_weather_search
# from .human_tool import AskHuman
# from .google_translate import google_tanslate

# # Add any additional imports or configurations here
# ├── __init__.py
# ├── tool_manager.py
# ├── calculator/
# │ ├── __init__.py
# │ ├── calculator.py
# │ └── icon.svg
# ├── open_weather/
# │ ├── __init__.py
# │ ├── open_weather.py
# │ └── icon.svg
# ├── human_tool/
# │ ├── __init__.py
# │ ├── human_tool.py
# │ └── icon.svg
# ├── google_translate/
# │ ├── __init__.py
# │ ├── google_translate.py
# │ └── icon.svg
# └── ...
__all__ = ["managed_tools", "ToolInfo"]
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@


@tool
def AskHuman(query: Annotated[str, "query to ask the human"]) -> None:
def ask_human(query: Annotated[str, "query to ask the human"]) -> None:
"""Ask the human a question to gather additional inputs"""
23 changes: 0 additions & 23 deletions backend/app/core/tools/calculator.py

This file was deleted.

37 changes: 0 additions & 37 deletions backend/app/core/tools/google_translate.py

This file was deleted.

38 changes: 38 additions & 0 deletions backend/app/core/tools/googletranslate/googletranslate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import requests
from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools import StructuredTool


class GoogleTranslateInput(BaseModel):
"""Input for the googleTranslate tool."""

content: str = Field(description="The text content you need to translate")
dest: str = Field(description="The destination language you want to translate")


def google_translate_invoke(content: str, dest: str) -> str:
try:
# url = "https://translate.googleapis.com/translate_a/single"
# params = {"client": "gtx", "sl": "auto", "tl": dest, "dt": "t", "q": content}

# headers = {
# "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko)"
# " Chrome/91.0.4472.124 Safari/537.36"
# }

# response_json = requests.get(url, params=params, headers=headers).json()
# result = response_json[0]
# translated_text = "".join([item[0] for item in result if item[0]])
# return str(translated_text)
return "aaaaaa"
except Exception as e:
return str(e)


googletranslate = StructuredTool.from_function(
func=google_translate_invoke,
name="Google Translate",
description="Useful for when you neet to translate text",
args_schema=GoogleTranslateInput,
return_direct=True,
)
28 changes: 28 additions & 0 deletions backend/app/core/tools/math/math.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# This is an example showing how to create a simple calculator skill

from langchain.pydantic_v1 import BaseModel, Field
from langchain.tools import StructuredTool
import numexpr as ne


class MathInput(BaseModel):
expression: str = Field(description="Math Expression")


def math_cal(expression: str) -> str:
try:
result = ne.evaluate(expression)
result_str = str(result)
return f"{result_str}"
except Exception as e:

return f"Error evaluating expression: {expression}"


math = StructuredTool.from_function(
func=math_cal,
name="Math Calculator",
description=" A tool for evaluating an math expression, calculated locally with NumExpr.",
args_schema=MathInput,
return_direct=True,
)
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class WeatherSearchInput(BaseModel):
city: str = Field(description="city name")


def openweather(
def open_weather_qry(
city: str,
appid: str = os.environ.get("OPEN_WEATHER_API_KEY", ""),
units: str = "metric",
Expand Down Expand Up @@ -51,10 +51,12 @@ def openweather(
return json.dumps(f"Openweather API Key is invalid. {e}")


open_weather_search = StructuredTool.from_function(
func=openweather,
name="openweather",
openweather = StructuredTool.from_function(
func=open_weather_qry,
name="Open Weather",
description="Useful for when you neet to get weather information. Please provide city name in English.",
args_schema=WeatherSearchInput,
return_direct=True,
)


Loading
Loading