feat: all types working
This commit is contained in:
parent
c0ad9a383f
commit
04ac50e9ef
6 changed files with 131 additions and 121 deletions
|
|
@ -1,5 +1,5 @@
|
|||
#! /bin/bash
|
||||
|
||||
poetry remove langchain
|
||||
docker build -t ibiscp/expert:v0.0.6 . && docker push ibiscp/expert:v0.0.6
|
||||
docker build -t ibiscp/expert:v0.0.11 . && docker push ibiscp/expert:v0.0.11
|
||||
poetry add --editable ../langchain
|
||||
|
|
|
|||
16
src/app.py
16
src/app.py
|
|
@ -2,11 +2,27 @@ from fastapi import FastAPI
|
|||
from endpoints import router as endpoints_router
|
||||
from list import router as list_router
|
||||
from signature import router as signatures_router
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
|
||||
def create_app():
|
||||
"""Create the FastAPI app and include the router."""
|
||||
app = FastAPI()
|
||||
|
||||
origins = [
|
||||
"http://localhost",
|
||||
"http://localhost:8080",
|
||||
"http://localhost:3000",
|
||||
]
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=origins,
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
app.include_router(endpoints_router)
|
||||
app.include_router(list_router)
|
||||
app.include_router(signatures_router)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ AGENT_TYPE = "conversational-react-description"
|
|||
|
||||
@router.get("/")
|
||||
def get_all():
|
||||
tools = list.list_tools()
|
||||
# tools = list.list_tools()
|
||||
return {
|
||||
"chains": {chain: signature.chain(chain) for chain in list.list_chains()},
|
||||
"agents": {agent: signature.agent(agent) for agent in list.list_agents()},
|
||||
|
|
@ -41,13 +41,19 @@ def get_all():
|
|||
# },
|
||||
# "vectorstores": {"template": {}},
|
||||
# "docstores": {"template": {}},
|
||||
"tools": {
|
||||
tool: {"template": signature.tool(tool), **values}
|
||||
for tool, values in tools.items()
|
||||
},
|
||||
# "tools": {
|
||||
# tool: {"template": signature.tool(tool), **values}
|
||||
# for tool, values in tools.items()
|
||||
# },
|
||||
"tools": {tool: signature.tool(tool) for tool in list.list_tools()},
|
||||
}
|
||||
|
||||
|
||||
@router.post("/load")
|
||||
def get_load(data: dict[str, str]) -> str:
|
||||
return "Hello Otávio!"
|
||||
|
||||
|
||||
# @router.get("/chain")
|
||||
# def get_chain():
|
||||
# llm = OpenAI(temperature=0)
|
||||
|
|
|
|||
16
src/list.py
16
src/list.py
|
|
@ -9,12 +9,7 @@ from langchain.chains.conversation import memory as memories
|
|||
from langchain import document_loaders
|
||||
from langchain import vectorstores
|
||||
from langchain import docstore
|
||||
from langchain.agents.load_tools import (
|
||||
_BASE_TOOLS,
|
||||
_LLM_TOOLS,
|
||||
_EXTRA_LLM_TOOLS,
|
||||
_EXTRA_OPTIONAL_TOOLS,
|
||||
)
|
||||
from langchain.agents.load_tools import get_all_tool_names
|
||||
import util
|
||||
|
||||
|
||||
|
|
@ -106,11 +101,4 @@ def list_memories():
|
|||
def list_tools():
|
||||
"""List all load tools"""
|
||||
|
||||
merged_dict = {
|
||||
**_BASE_TOOLS,
|
||||
**_LLM_TOOLS,
|
||||
**{k: v[0] for k, v in _EXTRA_LLM_TOOLS.items()},
|
||||
**{k: v[0] for k, v in _EXTRA_OPTIONAL_TOOLS.items()},
|
||||
}
|
||||
|
||||
return {k: util.get_tool_params(v) for k, v in merged_dict.items()}
|
||||
return get_all_tool_names()
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ router = APIRouter(
|
|||
tags=["signatures"],
|
||||
)
|
||||
|
||||
KEYS_TO_REMOVE = ["name", "default_factory"]
|
||||
|
||||
|
||||
def build_template_from_function(name: str, dict: dict):
|
||||
classes = [item.__annotations__["return"].__name__ for item in dict.values()]
|
||||
|
|
@ -34,41 +32,38 @@ def build_template_from_function(name: str, dict: dict):
|
|||
if name not in classes:
|
||||
raise Exception(f"{name} not found.")
|
||||
|
||||
for k, v in dict.items():
|
||||
for _type, v in dict.items():
|
||||
if v.__annotations__["return"].__name__ == name:
|
||||
_type = k
|
||||
_class = v.__annotations__["return"]
|
||||
|
||||
docs = util.get_class_doc(_class)
|
||||
|
||||
variables = {}
|
||||
variables = {"_type": _type}
|
||||
for name, value in _class.__fields__.items():
|
||||
if name in ["callback_manager", "requests_wrapper"]:
|
||||
continue
|
||||
variables[name] = {}
|
||||
for name_, value_ in value.__repr_args__():
|
||||
if name_ not in KEYS_TO_REMOVE:
|
||||
if name_ == "default_factory":
|
||||
try:
|
||||
variables[name]["default"] = util.get_default_factory(
|
||||
module=_class.__base__.__module__, function=value_
|
||||
)
|
||||
except:
|
||||
variables[name]["default"] = None
|
||||
elif name_ not in ["name"]:
|
||||
variables[name][name_] = value_
|
||||
variables[name]["placeholder"] = docs["Attributes"][name] if name in docs["Attributes"] else ""
|
||||
|
||||
variables[name]["placeholder"] = (
|
||||
docs["Attributes"][name] if name in docs["Attributes"] else ""
|
||||
)
|
||||
|
||||
return {
|
||||
"template": util.format_dict(variables),
|
||||
"_type": _type,
|
||||
"description": docs["Description"],
|
||||
"base_classes": util.get_base_classes(_class),
|
||||
}
|
||||
|
||||
# return {
|
||||
# "template": util.format_dict(
|
||||
# {
|
||||
# name: {
|
||||
# name: value
|
||||
# for (name, value) in value.__repr_args__()
|
||||
# if name not in KEYS_TO_REMOVE
|
||||
# }
|
||||
# for name, value in _class.__fields__.items()
|
||||
# }
|
||||
# ),
|
||||
# "_type": _type,
|
||||
# "description": _class.__doc__,
|
||||
# }
|
||||
|
||||
|
||||
def build_template_from_class(name: str, dict: dict):
|
||||
classes = [item.__name__ for item in dict.values()]
|
||||
|
|
@ -77,42 +72,38 @@ def build_template_from_class(name: str, dict: dict):
|
|||
if name not in classes:
|
||||
raise Exception(f"{name} not found.")
|
||||
|
||||
for k, v in dict.items():
|
||||
for _type, v in dict.items():
|
||||
if v.__name__ == name:
|
||||
_type = k
|
||||
_class = v
|
||||
|
||||
docs = util.get_class_doc(_class)
|
||||
|
||||
variables = {}
|
||||
variables = {"_type": _type}
|
||||
for name, value in _class.__fields__.items():
|
||||
if name in ["callback_manager"]:
|
||||
continue
|
||||
variables[name] = {}
|
||||
for name_, value_ in value.__repr_args__():
|
||||
if name_ not in KEYS_TO_REMOVE:
|
||||
if name_ == "default_factory":
|
||||
try:
|
||||
variables[name]["default"] = util.get_default_factory(
|
||||
module=_class.__base__.__module__, function=value_
|
||||
)
|
||||
except:
|
||||
variables[name]["default"] = None
|
||||
elif name_ not in ["name"]:
|
||||
variables[name][name_] = value_
|
||||
variables[name]["placeholder"] = docs["Attributes"][name] if name in docs["Attributes"] else ""
|
||||
|
||||
variables[name]["placeholder"] = (
|
||||
docs["Attributes"][name] if name in docs["Attributes"] else ""
|
||||
)
|
||||
|
||||
return {
|
||||
"template": util.format_dict(variables),
|
||||
"_type": _type,
|
||||
"description": docs["Description"],
|
||||
"base_classes": util.get_base_classes(_class),
|
||||
}
|
||||
|
||||
# return {
|
||||
# "template": util.format_dict(
|
||||
# {
|
||||
# name: {
|
||||
# name: value
|
||||
# for (name, value) in value.__repr_args__()
|
||||
# if name not in KEYS_TO_REMOVE
|
||||
# }
|
||||
# for name, value in _class.__fields__.items()
|
||||
# }
|
||||
# ),
|
||||
# "_type": _type,
|
||||
# "description": _class.__doc__,
|
||||
# }
|
||||
|
||||
|
||||
@router.get("/chain")
|
||||
def chain(name: str):
|
||||
|
|
@ -193,6 +184,16 @@ def tool(name: str):
|
|||
params = extra_keys
|
||||
|
||||
return {
|
||||
param: (type_dict[param] if param == "llm" else type_dict["str"])
|
||||
for param in params
|
||||
"template": {
|
||||
param: (type_dict[param] if param == "llm" else type_dict["str"])
|
||||
for param in params
|
||||
},
|
||||
**util.get_tool_params(util.get_tools_dict(name)),
|
||||
"base_classes": ["Tool"],
|
||||
}
|
||||
|
||||
|
||||
# {"template": signature.tool(tool), **values}
|
||||
# for tool, values in tools.items()
|
||||
# }
|
||||
# return {k: util.get_tool_params(v) for k, v in merged_dict.items()}
|
||||
|
|
|
|||
109
src/util.py
109
src/util.py
|
|
@ -1,5 +1,47 @@
|
|||
import ast
|
||||
import inspect
|
||||
import re
|
||||
import importlib
|
||||
from langchain.agents.load_tools import (
|
||||
_BASE_TOOLS,
|
||||
_LLM_TOOLS,
|
||||
_EXTRA_LLM_TOOLS,
|
||||
_EXTRA_OPTIONAL_TOOLS,
|
||||
)
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def get_base_classes(cls):
|
||||
bases = cls.__bases__
|
||||
if not bases:
|
||||
return []
|
||||
else:
|
||||
result = []
|
||||
for base in bases:
|
||||
if any(type in base.__module__ for type in ["pydantic", "abc"]):
|
||||
continue
|
||||
result.append(base.__name__)
|
||||
result.extend(get_base_classes(base))
|
||||
return result
|
||||
|
||||
|
||||
def get_default_factory(module: str, function: str):
|
||||
pattern = r"<function (\w+)>"
|
||||
|
||||
if match := re.search(pattern, function):
|
||||
module = importlib.import_module(module)
|
||||
return getattr(module, match[1])()
|
||||
return None
|
||||
|
||||
|
||||
def get_tools_dict(name: Optional[str] = None):
|
||||
tools = {
|
||||
**_BASE_TOOLS,
|
||||
**_LLM_TOOLS,
|
||||
**{k: v[0] for k, v in _EXTRA_LLM_TOOLS.items()},
|
||||
**{k: v[0] for k, v in _EXTRA_OPTIONAL_TOOLS.items()},
|
||||
}
|
||||
return tools[name] if name else tools
|
||||
|
||||
|
||||
def get_tool_params(func):
|
||||
|
|
@ -69,61 +111,15 @@ def get_class_doc(class_name):
|
|||
current_section = line[:-1]
|
||||
continue
|
||||
|
||||
if current_section == "Description":
|
||||
data[current_section] += line
|
||||
elif current_section == "Example":
|
||||
if current_section in ["Description", "Example"]:
|
||||
data[current_section] += line
|
||||
else:
|
||||
try:
|
||||
param, desc = line.split(":")
|
||||
except:
|
||||
param, desc = "", ""
|
||||
param, desc = line.split(":")
|
||||
data[current_section][param.strip()] = desc.strip()
|
||||
|
||||
return data
|
||||
|
||||
|
||||
# def format_dict(d):
|
||||
# # Remove from keys
|
||||
# keys_to_remove = ["callback_manager"]
|
||||
# for key in keys_to_remove:
|
||||
# if key in d:
|
||||
# d.pop(key)
|
||||
|
||||
# for key, value in d.items():
|
||||
# _type = value["type"]
|
||||
|
||||
# # Add optional parameter
|
||||
# if "Optional" in _type:
|
||||
# _type = _type.replace("Optional[", "")[:-1]
|
||||
|
||||
# # Add list parameter
|
||||
# if "List" in _type:
|
||||
# _type = _type.replace("List[", "")[:-1]
|
||||
# value["list"] = True
|
||||
# else:
|
||||
# value["list"] = False
|
||||
|
||||
# if "Mapping" in _type:
|
||||
# _type = _type.replace("Mapping", "dict")
|
||||
|
||||
# value["type"] = _type
|
||||
|
||||
# # Show if required
|
||||
# if value["required"] or key in ["allowed_tools", "verbose", "Memory"]:
|
||||
# value["show"] = True
|
||||
# else:
|
||||
# value["show"] = False
|
||||
|
||||
# # If default, change to value
|
||||
# if value['type'] == 'str':
|
||||
# value["value"] = value["default"] if 'default' in value else ''
|
||||
# if 'default' in value:
|
||||
# value.pop("default")
|
||||
|
||||
# return {key: value for key, value in d.items() if value["show"]}
|
||||
|
||||
|
||||
def format_dict(d):
|
||||
"""
|
||||
Formats a dictionary by removing certain keys and modifying the values of other keys.
|
||||
|
|
@ -134,12 +130,11 @@ def format_dict(d):
|
|||
Returns:
|
||||
A new dictionary with the desired modifications applied.
|
||||
"""
|
||||
# Remove keys to exclude
|
||||
keys_to_exclude = ["callback_manager"]
|
||||
d = {key: value for key, value in d.items() if key not in keys_to_exclude}
|
||||
|
||||
# Process remaining keys
|
||||
for key, value in d.items():
|
||||
if key == "_type":
|
||||
continue
|
||||
_type = value["type"]
|
||||
|
||||
# Remove 'Optional' wrapper
|
||||
|
|
@ -157,18 +152,22 @@ def format_dict(d):
|
|||
if "Mapping" in _type:
|
||||
_type = _type.replace("Mapping", "dict")
|
||||
|
||||
value["type"] = _type
|
||||
value["type"] = "Tool" if key == "allowed_tools" else _type
|
||||
|
||||
# Show if required
|
||||
value["show"] = bool(
|
||||
value["required"] or key in ["allowed_tools", "verbose", "Memory"]
|
||||
(value["required"] and key not in ["input_variables"])
|
||||
or key in ["allowed_tools", "verbose", "Memory", "memory", "prefix"]
|
||||
or "api_key" in key
|
||||
)
|
||||
|
||||
# Replace default value with actual value
|
||||
if _type == "str":
|
||||
if _type in ["str", "bool"]:
|
||||
value["value"] = value.get("default", "")
|
||||
if "default" in value:
|
||||
value.pop("default")
|
||||
|
||||
# Filter out keys that should not be shown
|
||||
return {key: value for key, value in d.items() if value["show"]}
|
||||
return (
|
||||
d # {key: value for key, value in d.items() if key == "_type" or value["show"]}
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue