Skip to content

Commit

Permalink
ver0.4.2 修复目前反馈遇到的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
goldfishh committed Apr 25, 2023
1 parent e0c8caa commit fd2d0fe
Show file tree
Hide file tree
Showing 25 changed files with 135 additions and 67 deletions.
6 changes: 3 additions & 3 deletions chatgpt_tool_hub/apps/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from typing import List

from chatgpt_tool_hub.chains.base import Chain
from chatgpt_tool_hub.engine.tool_engine import ToolEngine
from chatgpt_tool_hub.common.log import LOG
from chatgpt_tool_hub.tools.base_tool import BaseTool

Expand All @@ -11,7 +11,7 @@ class App:
_instance = None # 存储单例实例
init_flag = False # 记录是否执行过初始化动作

engine: Chain = None
engine: ToolEngine = None

# 当前已加载工具
tools: set = set()
Expand Down Expand Up @@ -76,4 +76,4 @@ def _check_mandatory_tools(self, use_tools: list) -> bool:
return True

def get_tool_list(self) -> List[str]:
return list(self.tools)
return list(self.engine.get_tool_list())
11 changes: 9 additions & 2 deletions chatgpt_tool_hub/apps/app_factory.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
import os

from rich.console import Console

Expand Down Expand Up @@ -33,10 +34,16 @@ def init_env(self, **kwargs):
else:
self.default_tools_list = ["python", "terminal", "url-get", "meteo-weather"]

# set proxy
# _proxy = get_from_dict_or_env(kwargs, "proxy", "PROXY", "")
# if not _proxy:
# os.environ["http_proxy"] = str(_proxy)
# os.environ["https_proxy"] = str(_proxy)

# dynamic loading tool
dynamic_tool_loader()

def create_app(self, app_type: str = 'victorinox', tools_list: list = None, **kwargs) -> App:
def create_app(self, app_type: str = 'victorinox', tools_list: list = None, console=Console(quiet=True), **kwargs) -> App:
tools_list = tools_list if tools_list else []

self.init_env(**kwargs)
Expand All @@ -58,7 +65,7 @@ def create_app(self, app_type: str = 'victorinox', tools_list: list = None, **kw
if "browser" in tools_list:
tools_list = list(filter(lambda tool: tool != "url-get", tools_list))

app = Victorinox(**build_model_params(kwargs))
app = Victorinox(console, **build_model_params(kwargs))
app.create(tools_list, **kwargs)
return app
else:
Expand Down
5 changes: 3 additions & 2 deletions chatgpt_tool_hub/bots/chat_bot/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def _extract_tool_and_input(self, llm_output: str) -> Optional[Tuple[str, str]]:

if action.lower() != "answer-user":
self.console.print(f"√ 我在用 [bold cyan]{action}[/] 工具...")
# todo

LOG.info(f"执行Tool: {action}中...")
return action.strip(), action_input.strip()

Expand Down Expand Up @@ -223,7 +223,8 @@ def parse_reply_json(self, assistant_reply) -> dict:
title=f"{self.ai_prefix.upper()}的内心独白",
highlight=True, style='dim'))
# it's useful for avoid splitting Panel
self.console.print("\n")
LOG.info(f"{self.ai_prefix.upper()}的内心独白: {thoughts_text}")

return assistant_reply_json
except json.decoder.JSONDecodeError as e:
call_stack = traceback.format_exc()
Expand Down
2 changes: 1 addition & 1 deletion chatgpt_tool_hub/bots/chat_bot/prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"speak": "thoughts summary to say to {human_prefix}",
}}}},
"tool": {{{{
"name": "the tool to use, You must use one of the tools from the list: [{tool_names}]",
"name": "the tool to use, You must use one of the tools from the list: [{tool_names}, answer-user]",
"input": "the input to the tool"
}}}}
}}}}
Expand Down
14 changes: 12 additions & 2 deletions chatgpt_tool_hub/chains/api/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from pydantic import BaseModel, Field, root_validator
from rich.console import Console
from rich.panel import Panel

from chatgpt_tool_hub.chains.api.prompt import API_RESPONSE_PROMPT, API_URL_PROMPT
from chatgpt_tool_hub.chains.base import Chain
Expand Down Expand Up @@ -69,12 +70,21 @@ def _call(self, inputs: Dict[str, str]) -> Dict[str, str]:
api_url = self.api_request_chain.predict(
question=question, api_docs=self.api_docs
)
LOG.debug(f"[API] generate url: {str(api_url)}")
self.console.print(Panel(f"{str(api_url)}",
title=f"[bright_magenta]URL 构造[/]",
highlight=True))

LOG.info(f"URL 构造: {str(api_url)}")
self.callback_manager.on_text(
api_url, color="green", end="\n", verbose=self.verbose
)
api_response = self.requests_wrapper.get(api_url)
LOG.debug(f"[API] response: {str(api_response)}")

self.console.print(Panel(f"{repr(api_response)}",
title=f"[bright_magenta]API 响应[/]",
highlight=True))

LOG.info(f"API 响应: {repr(api_response)}")
self.callback_manager.on_text(
api_response, color="yellow", end="\n", verbose=self.verbose
)
Expand Down
3 changes: 1 addition & 2 deletions chatgpt_tool_hub/common/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@

def _get_logger(level: int = LOGGING_LEVEL):
logger = logging.getLogger("tool")
logger.setLevel(level)

ch = logging.StreamHandler(sys.stdout)
ch.setLevel(level)
ch.setFormatter(logging.Formatter(LOGGING_FMT, datefmt=LOGGING_DATEFMT))

fh = logging.FileHandler(f'{os.getcwd()}/tool.log', encoding='utf-8')
fh.setLevel(logging.DEBUG)
fh.setFormatter(logging.Formatter(LOGGING_FMT, datefmt=LOGGING_DATEFMT))

logger.addHandler(ch)
Expand Down
4 changes: 2 additions & 2 deletions chatgpt_tool_hub/database/chat_memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ def save_context(self, inputs: Dict[str, Any], outputs: Dict[str, str]) -> None:
output_key = list(outputs.keys())[0]
else:
output_key = self.output_key
self.chat_memory.add_user_message(inputs[prompt_input_key])
self.chat_memory.add_ai_message(outputs[output_key])
self.chat_memory.add_user_message(repr(inputs[prompt_input_key]))
self.chat_memory.add_ai_message(repr(outputs[output_key]))

def clear(self) -> None:
"""Clear memory contents."""
Expand Down
2 changes: 1 addition & 1 deletion chatgpt_tool_hub/engine/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def _crop_full_input(self, inputs: str) -> str:
try:
os.remove(file_path)
except Exception as e:
LOG.info(f"remove {file_path} failed... error_info: {repr(e)}")
LOG.debug(f"remove {file_path} failed... error_info: {repr(e)}")

return _input

Expand Down
18 changes: 12 additions & 6 deletions chatgpt_tool_hub/engine/tool_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ def _take_next_step(
self.console.print(Panel(f"{output.tool_input}",
title=f"我将给工具 [bright_magenta]{output.tool}[/] 发送如下信息",
highlight=True))
self.console.print("\n")


LOG.info(f"我将给工具发送如下信息: \n{output.tool_input}")
tool = name_to_tool_map[output.tool]
return_direct = tool.return_direct
# color = color_mapping[output.tool]
Expand All @@ -146,8 +146,8 @@ def _take_next_step(
)
else:
self.console.print(f"× 该工具 [bright_magenta]{output.tool}[/] 无效")
self.console.print("\n")


LOG.info(f"该工具 {output.tool} 无效")
observation = InvalidTool().run(
output.tool,
verbose=self.verbose,
Expand All @@ -159,8 +159,8 @@ def _take_next_step(
self.console.print(Panel(observation + "\n",
title=f"工具 [bright_magenta]{output.tool}[/] 返回内容",
highlight=True, style='dim'))
self.console.print("\n")


LOG.info(f"工具 {output.tool} 返回内容: {observation}")
return output, observation

def _call(self, inputs: Dict[str, str]) -> Dict[str, Any]:
Expand Down Expand Up @@ -321,3 +321,9 @@ async def _areturn(
if self.return_intermediate_steps:
final_output["intermediate_steps"] = intermediate_steps
return final_output

def get_tool_list(self) -> List[str]:
_tool_list = []
for tool in self.tools:
_tool_list.extend(tool.get_tool_list())
return _tool_list
4 changes: 2 additions & 2 deletions chatgpt_tool_hub/tools/arxiv_search/api_prompt.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
ARXIV_PROMPT = """
You are a converter from natural language to json to search research papers in arxiv api.
You are a converter from natural language to json to search research papers by arxiv api.
You should only respond in JSON format as described below.
Response Format:
Expand All @@ -10,7 +10,7 @@
"sort_order": "descending"
}}
json note:
search_query: an arXiv query string. I will show you how to generate a search_query
search_query: an arXiv query string. I will teach you how to generate a search_query below.
max_results: int, range: 1~20
sort_by: The sort criterion for results: "relevance", "lastUpdatedDate", or "submittedDate"
sort_order: The sort order for results: "descending" or "ascending"
Expand Down
23 changes: 22 additions & 1 deletion chatgpt_tool_hub/tools/arxiv_search/tool.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import os
import tempfile
from typing import Any

from rich.console import Console

from chatgpt_tool_hub.chains import LLMChain
from chatgpt_tool_hub.common.log import LOG
from chatgpt_tool_hub.common.utils import get_from_dict_or_env
from chatgpt_tool_hub.models import build_model_params
from chatgpt_tool_hub.models.model_factory import ModelFactory
from chatgpt_tool_hub.prompts import PromptTemplate
from chatgpt_tool_hub.tools.all_tool_list import main_tool_register
from chatgpt_tool_hub.tools.arxiv_search.api_prompt import ARXIV_PROMPT
from chatgpt_tool_hub.tools.arxiv_search.wrapper import ArxivAPIWrapper
from chatgpt_tool_hub.tools.base_tool import BaseTool
from chatgpt_tool_hub.tools.summary import SummaryTool

default_tool_name = "arxiv"

Expand All @@ -32,6 +36,7 @@ def __init__(self, console: Console = Console(), **tool_kwargs: Any):
super().__init__(console=console, return_direct=True)

self.api_wrapper = ArxivAPIWrapper(**tool_kwargs)
self.arxiv_summary = get_from_dict_or_env(tool_kwargs, "arxiv_summary", "ARXIV_SUMMARY", True)

llm = ModelFactory().create_llm_model(**build_model_params(tool_kwargs))
prompt = PromptTemplate(
Expand All @@ -46,7 +51,23 @@ def _run(self, query: str) -> str:
_llm_response = self.bot.run(query)
LOG.info(f"[arxiv]: search_query: {_llm_response}")

return self.api_wrapper.run(_llm_response)
_api_response = self.api_wrapper.run(_llm_response)

if not self.arxiv_summary:
return _api_response

temp_file = tempfile.mkstemp()
file_path = temp_file[1]
with open(file_path, "w") as f:
f.write(_api_response + "\n")

_input = SummaryTool(max_segment_length=2400).run(f"{str(file_path)}, 0")
try:
os.remove(file_path)
except Exception as e:
LOG.debug(f"remove {file_path} failed... error_info: {repr(e)}")

return _input

async def _arun(self, query: str) -> str:
"""Use the Arxiv tool asynchronously."""
Expand Down
3 changes: 3 additions & 0 deletions chatgpt_tool_hub/tools/base_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,6 @@ async def arun(
observation, verbose=verbose, color=color, **kwargs
)
return observation

def get_tool_list(self):
return [self.name]
2 changes: 1 addition & 1 deletion chatgpt_tool_hub/tools/meteo/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class MeteoWeatherTool(BaseTool):
def __init__(self, console: Console = Console(), **tool_kwargs):
super().__init__(console=console, return_direct=False)
llm = ModelFactory().create_llm_model(**build_model_params(tool_kwargs))
self.api_chain = APIChain.from_llm_and_api_docs(llm, OPEN_METEO_DOCS)
self.api_chain = APIChain.from_llm_and_api_docs(llm, OPEN_METEO_DOCS, console=console)

def _run(self, query: str) -> str:
"""Use the tool."""
Expand Down
2 changes: 1 addition & 1 deletion chatgpt_tool_hub/tools/news/morning_news/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def _run(self, query: str) -> str:
_news_content = "\n".join(_return_data.get("news"))
_weiyu = _return_data.get('weiyu')
_image_url = _return_data.get('image')
return f"\n今日日期:{_date}\n今日早报:{_news_content}\n今日微语:{_weiyu}\nURL: {_image_url}"
return f"\n今日日期:{_date}\n\n今日早报:{_news_content}\n\n今日微语:{_weiyu}\n\nURL: {_image_url}"
else:
return f"[{default_tool_name}] api error, error_info: {_response_json.get('msg')}"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
This endpoint is great for retrieving headlines for use with news tickers or similar.
Request parameters
country | The 2-letter ISO 3166-1 code of the country you want to get headlines for. Possible options: ae ar at au be bg br ca ch cn co cu cz de eg fr gb gr hk hu id ie il in it jp kr lt lv ma mx my ng nl no nz ph pl pt ro rs ru sa se sg si sk th tr tw ua us ve za. Note: you can't mix this param with the sources param.
category | The category you want to get headlines for. Possible options: business entertainment general health science sports technology. Note: you can't mix this param with the sources param.
sources | A comma-seperated string of identifiers for the news sources or blogs you want headlines from. Use the /top-headlines/sources endpoint to locate these programmatically or look at the sources index. Note: you can't mix this param with the country or category params.
Expand All @@ -28,7 +27,11 @@
publishedAt | string | The date and time that the article was published, in UTC (+000)
content | string | The unformatted content of the article, where available. This is truncated to 200 chars.
Use page size: 2
The endpoint and prefix of the document are absolutely correct, and that other URL prefixes should not be fabricated.
the url must not contain apiKey param
"""
Pay attention:
1. page size: 5
2. You should only use the parameters described in this document
to construct the API URL, and should not make up parameters.
3. The endpoint and top headlines of the document are absolutely correct,
any other URL prefixes should not be fabricated.
URL: """
4 changes: 2 additions & 2 deletions chatgpt_tool_hub/tools/news/news_api/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from chatgpt_tool_hub.models.model_factory import ModelFactory
from chatgpt_tool_hub.tools.base_tool import BaseTool
from chatgpt_tool_hub.tools.news import news_tool_register
from chatgpt_tool_hub.tools.news.news_api.docs_prompts import NEWS_DOCS
from chatgpt_tool_hub.tools.news.news_api.docs_prompt import NEWS_DOCS

default_tool_name = "news-api"

Expand All @@ -29,7 +29,7 @@ def __init__(self, console: Console = Console(), **tool_kwargs: Any):
llm = ModelFactory().create_llm_model(**build_model_params(tool_kwargs))

self.api_chain = APIChain.from_llm_and_api_docs(
llm, NEWS_DOCS, headers={"X-Api-Key": news_api_key}
llm, NEWS_DOCS, console=console, headers={"X-Api-Key": news_api_key}
)

def _run(self, query: str) -> str:
Expand Down
10 changes: 7 additions & 3 deletions chatgpt_tool_hub/tools/news/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
class NewsTool(BaseTool):
name: str = default_tool_name
description: str = (
"Useful when you want to get information about current news stories, "
"such as financial news, daily morning reports and any other news. "
"The input should be a description of your needs in natural language."
"当你想要获取实时新闻资讯时可以使用该工具,你能获取任何与新闻有关的信息。"
"该工具包含了金融、早报和news-api三个子工具,访问这些工具前你需要先访问本工具。"
"工具输入:你目前了解到的所有信息的总结 和 用户想获取的新闻内容。"
)
engine: ToolEngine = Any

Expand All @@ -30,6 +30,7 @@ def __init__(self, console: Console = Console(), **tool_kwargs: Any):
tools = load_tools(news_tool_register.get_registered_tool_names(), news_tool_register, console, **tool_kwargs)
llm = ModelFactory().create_llm_model(**build_model_params(tool_kwargs))

# subtool 思考深度暂时固定为2
self.engine = init_tool_engine(tools, llm, bot="qa-bot", verbose=True, console=self.console,
max_iterations=2, early_stopping_method="force")

Expand All @@ -47,5 +48,8 @@ async def _arun(self, query: str) -> str:
"""Use the tool asynchronously."""
raise NotImplementedError("NewsTool does not support async")

def get_tool_list(self):
return news_tool_register.get_registered_tool_names()


main_tool_register.register_tool(default_tool_name, lambda console, kwargs: NewsTool(console, **kwargs), [])
15 changes: 10 additions & 5 deletions chatgpt_tool_hub/tools/summary/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,6 @@ def _run(self, tool_input: str) -> str:
map_text_list = asyncio.run(self._acall(self.map_bot, _clip_text_list))
map_text = _clipper.seperator.join(map_text_list)

self.console.print(Panel(f"{map_text}",
title=f"=[bright_magenta]Summary tool[/] 总结",
highlight=True))
self.console.print("\n")

LOG.debug(f"[summary] round:{ctn}, map_list: {map_text}")
# reduce
_clip_summary_list = _clipper.clip(map_text, self.message_num)
Expand All @@ -164,6 +159,16 @@ def _run(self, tool_input: str) -> str:
reduce_text = _clipper.seperator.join(reduce_text_list)
LOG.debug(f"[summary] round:{ctn}, reduce_list: {reduce_text}")
_text = reduce_text

self.console.print(Panel(f"{_text}",
title=f"[bright_magenta]Summary tool[/] 第{ctn}轮总结",
highlight=True))

if ctn > 2:
self.console.print(Panel(f"{_text}",
title=f"[bright_magenta]Summary tool[/] 最终总结",
highlight=True))

return _text

async def _arun(self, file_path: str) -> str:
Expand Down
2 changes: 1 addition & 1 deletion chatgpt_tool_hub/tools/web_requests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def filter_text(html: str) -> str:
try:
os.remove(file_path)
except Exception as e:
LOG.info(f"remove {file_path} failed... error_info: {repr(e)}")
LOG.debug(f"remove {file_path} failed... error_info: {repr(e)}")

return _summary.encode('utf-8').decode()

Expand Down
Loading

0 comments on commit fd2d0fe

Please sign in to comment.