Skip to content

Commit

Permalink
Feat/add tools icon (#51)
Browse files Browse the repository at this point in the history
* feat:tool manager to simplify builtin tool code

* feat:tool icon form svg

* feat:tool node and panel icon

* fix:tool bind bug

* feat: add tool display_name

* feat: tools icon frontend
  • Loading branch information
Onelevenvy authored Sep 26, 2024
1 parent bf71d0d commit f2bb046
Show file tree
Hide file tree
Showing 39 changed files with 1,047 additions and 390 deletions.
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

0 comments on commit f2bb046

Please sign in to comment.