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
|
#! /bin/bash
|
||||||
|
|
||||||
poetry remove langchain
|
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
|
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 endpoints import router as endpoints_router
|
||||||
from list import router as list_router
|
from list import router as list_router
|
||||||
from signature import router as signatures_router
|
from signature import router as signatures_router
|
||||||
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
"""Create the FastAPI app and include the router."""
|
"""Create the FastAPI app and include the router."""
|
||||||
app = FastAPI()
|
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(endpoints_router)
|
||||||
app.include_router(list_router)
|
app.include_router(list_router)
|
||||||
app.include_router(signatures_router)
|
app.include_router(signatures_router)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ AGENT_TYPE = "conversational-react-description"
|
||||||
|
|
||||||
@router.get("/")
|
@router.get("/")
|
||||||
def get_all():
|
def get_all():
|
||||||
tools = list.list_tools()
|
# tools = list.list_tools()
|
||||||
return {
|
return {
|
||||||
"chains": {chain: signature.chain(chain) for chain in list.list_chains()},
|
"chains": {chain: signature.chain(chain) for chain in list.list_chains()},
|
||||||
"agents": {agent: signature.agent(agent) for agent in list.list_agents()},
|
"agents": {agent: signature.agent(agent) for agent in list.list_agents()},
|
||||||
|
|
@ -41,13 +41,19 @@ def get_all():
|
||||||
# },
|
# },
|
||||||
# "vectorstores": {"template": {}},
|
# "vectorstores": {"template": {}},
|
||||||
# "docstores": {"template": {}},
|
# "docstores": {"template": {}},
|
||||||
"tools": {
|
# "tools": {
|
||||||
tool: {"template": signature.tool(tool), **values}
|
# tool: {"template": signature.tool(tool), **values}
|
||||||
for tool, values in tools.items()
|
# 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")
|
# @router.get("/chain")
|
||||||
# def get_chain():
|
# def get_chain():
|
||||||
# llm = OpenAI(temperature=0)
|
# 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 document_loaders
|
||||||
from langchain import vectorstores
|
from langchain import vectorstores
|
||||||
from langchain import docstore
|
from langchain import docstore
|
||||||
from langchain.agents.load_tools import (
|
from langchain.agents.load_tools import get_all_tool_names
|
||||||
_BASE_TOOLS,
|
|
||||||
_LLM_TOOLS,
|
|
||||||
_EXTRA_LLM_TOOLS,
|
|
||||||
_EXTRA_OPTIONAL_TOOLS,
|
|
||||||
)
|
|
||||||
import util
|
import util
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -106,11 +101,4 @@ def list_memories():
|
||||||
def list_tools():
|
def list_tools():
|
||||||
"""List all load tools"""
|
"""List all load tools"""
|
||||||
|
|
||||||
merged_dict = {
|
return get_all_tool_names()
|
||||||
**_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()}
|
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,6 @@ router = APIRouter(
|
||||||
tags=["signatures"],
|
tags=["signatures"],
|
||||||
)
|
)
|
||||||
|
|
||||||
KEYS_TO_REMOVE = ["name", "default_factory"]
|
|
||||||
|
|
||||||
|
|
||||||
def build_template_from_function(name: str, dict: dict):
|
def build_template_from_function(name: str, dict: dict):
|
||||||
classes = [item.__annotations__["return"].__name__ for item in dict.values()]
|
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:
|
if name not in classes:
|
||||||
raise Exception(f"{name} not found.")
|
raise Exception(f"{name} not found.")
|
||||||
|
|
||||||
for k, v in dict.items():
|
for _type, v in dict.items():
|
||||||
if v.__annotations__["return"].__name__ == name:
|
if v.__annotations__["return"].__name__ == name:
|
||||||
_type = k
|
|
||||||
_class = v.__annotations__["return"]
|
_class = v.__annotations__["return"]
|
||||||
|
|
||||||
docs = util.get_class_doc(_class)
|
docs = util.get_class_doc(_class)
|
||||||
|
|
||||||
variables = {}
|
variables = {"_type": _type}
|
||||||
for name, value in _class.__fields__.items():
|
for name, value in _class.__fields__.items():
|
||||||
|
if name in ["callback_manager", "requests_wrapper"]:
|
||||||
|
continue
|
||||||
variables[name] = {}
|
variables[name] = {}
|
||||||
for name_, value_ in value.__repr_args__():
|
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][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 {
|
return {
|
||||||
"template": util.format_dict(variables),
|
"template": util.format_dict(variables),
|
||||||
"_type": _type,
|
|
||||||
"description": docs["Description"],
|
"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):
|
def build_template_from_class(name: str, dict: dict):
|
||||||
classes = [item.__name__ for item in dict.values()]
|
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:
|
if name not in classes:
|
||||||
raise Exception(f"{name} not found.")
|
raise Exception(f"{name} not found.")
|
||||||
|
|
||||||
for k, v in dict.items():
|
for _type, v in dict.items():
|
||||||
if v.__name__ == name:
|
if v.__name__ == name:
|
||||||
_type = k
|
|
||||||
_class = v
|
_class = v
|
||||||
|
|
||||||
docs = util.get_class_doc(_class)
|
docs = util.get_class_doc(_class)
|
||||||
|
|
||||||
variables = {}
|
variables = {"_type": _type}
|
||||||
for name, value in _class.__fields__.items():
|
for name, value in _class.__fields__.items():
|
||||||
|
if name in ["callback_manager"]:
|
||||||
|
continue
|
||||||
variables[name] = {}
|
variables[name] = {}
|
||||||
for name_, value_ in value.__repr_args__():
|
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][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 {
|
return {
|
||||||
"template": util.format_dict(variables),
|
"template": util.format_dict(variables),
|
||||||
"_type": _type,
|
|
||||||
"description": docs["Description"],
|
"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")
|
@router.get("/chain")
|
||||||
def chain(name: str):
|
def chain(name: str):
|
||||||
|
|
@ -193,6 +184,16 @@ def tool(name: str):
|
||||||
params = extra_keys
|
params = extra_keys
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
"template": {
|
||||||
param: (type_dict[param] if param == "llm" else type_dict["str"])
|
param: (type_dict[param] if param == "llm" else type_dict["str"])
|
||||||
for param in params
|
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()}
|
||||||
|
|
|
||||||
107
src/util.py
107
src/util.py
|
|
@ -1,5 +1,47 @@
|
||||||
import ast
|
import ast
|
||||||
import inspect
|
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):
|
def get_tool_params(func):
|
||||||
|
|
@ -69,61 +111,15 @@ def get_class_doc(class_name):
|
||||||
current_section = line[:-1]
|
current_section = line[:-1]
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if current_section == "Description":
|
if current_section in ["Description", "Example"]:
|
||||||
data[current_section] += line
|
|
||||||
elif current_section == "Example":
|
|
||||||
data[current_section] += line
|
data[current_section] += line
|
||||||
else:
|
else:
|
||||||
try:
|
|
||||||
param, desc = line.split(":")
|
param, desc = line.split(":")
|
||||||
except:
|
|
||||||
param, desc = "", ""
|
|
||||||
data[current_section][param.strip()] = desc.strip()
|
data[current_section][param.strip()] = desc.strip()
|
||||||
|
|
||||||
return data
|
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):
|
def format_dict(d):
|
||||||
"""
|
"""
|
||||||
Formats a dictionary by removing certain keys and modifying the values of other keys.
|
Formats a dictionary by removing certain keys and modifying the values of other keys.
|
||||||
|
|
@ -134,12 +130,11 @@ def format_dict(d):
|
||||||
Returns:
|
Returns:
|
||||||
A new dictionary with the desired modifications applied.
|
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
|
# Process remaining keys
|
||||||
for key, value in d.items():
|
for key, value in d.items():
|
||||||
|
if key == "_type":
|
||||||
|
continue
|
||||||
_type = value["type"]
|
_type = value["type"]
|
||||||
|
|
||||||
# Remove 'Optional' wrapper
|
# Remove 'Optional' wrapper
|
||||||
|
|
@ -157,18 +152,22 @@ def format_dict(d):
|
||||||
if "Mapping" in _type:
|
if "Mapping" in _type:
|
||||||
_type = _type.replace("Mapping", "dict")
|
_type = _type.replace("Mapping", "dict")
|
||||||
|
|
||||||
value["type"] = _type
|
value["type"] = "Tool" if key == "allowed_tools" else _type
|
||||||
|
|
||||||
# Show if required
|
# Show if required
|
||||||
value["show"] = bool(
|
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
|
# Replace default value with actual value
|
||||||
if _type == "str":
|
if _type in ["str", "bool"]:
|
||||||
value["value"] = value.get("default", "")
|
value["value"] = value.get("default", "")
|
||||||
if "default" in value:
|
if "default" in value:
|
||||||
value.pop("default")
|
value.pop("default")
|
||||||
|
|
||||||
# Filter out keys that should not be shown
|
# 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