From 0417b369dca9457f0dddd6e40cb01b5d0f1acf9f Mon Sep 17 00:00:00 2001 From: jinno Date: Mon, 6 May 2024 14:47:15 +0900 Subject: [PATCH] fix: update for GuiAgentInterpreterChatResponse --- server.py | 168 +++++++++++++++++++----------- src/codeinterpreterapi/session.py | 109 +++++++++++++++++-- 2 files changed, 210 insertions(+), 67 deletions(-) diff --git a/server.py b/server.py index 4e36cd1e..6fb22499 100644 --- a/server.py +++ b/server.py @@ -1,64 +1,112 @@ -from codeinterpreterapi import CodeInterpreterSession - -model = "claude-3-haiku-20240307" -model = "gemini-1.5-pro-latest" -session = CodeInterpreterSession(model=model) - -try: - message = """SVG画像を自動生成するプログラムの要件を以下のように定義します。 - -目的: - -電子書籍のヘッダ画像を自動生成すること -別のコンテンツ生成プログラムが出力したSVGファイルを入力として受け取ること -入力SVGファイルを指定の要件に従って加工し、新たなSVGファイルとして出力すること -機能要件: - -グリッドレイアウト機能の実装 - -指定したグリッドサイズ(行数、列数)に基づいて要素を配置できるようにする -グリッドの各セルに対して要素を割り当てられるようにする -グリッドのサイズや間隔を柔軟に設定できるようにする -SVG要素の配置と編集 +import traceback -グリッド上の指定した位置にSVG要素(テキスト、図形、画像など)を配置できるようにする -配置する要素の属性(サイズ、色、フォントなど)を柔軟に設定できるようにする -既存のSVG要素を削除、移動、変更できるようにする -外部画像ファイルの読み込みと配置 +from gui_agent_loop_core.gui_agent_loop_core import GuiAgentLoopCore +from gui_agent_loop_core.schema.schema import ( + GuiAgentInterpreterBase, + GuiAgentInterpreterChatMessage, + GuiAgentInterpreterChatMessages, + GuiAgentInterpreterChatResponse, + GuiAgentInterpreterChatResponseAny, +) -PNGやJPEGなどの外部画像ファイルを読み込んでSVGファイルに埋め込めるようにする -読み込んだ画像をグリッド上の指定した位置に配置できるようにする -画像のサイズを変更できるようにする -SVGファイルの入出力 - -SVGファイルを入力として読み込み、加工後のSVGファイルを出力できるようにする -出力ファイルのファイル名やパスを指定できるようにする -非機能要件: - -Python3とsvgwriteライブラリを使用して実装すること -コードはモジュール化し、再利用性と保守性を高めること -エラーハンドリングを適切に行い、ログ出力を行うこと -コードにはコメントを付けて可読性を高めること -実装の進め方: - -svgwriteを使ったSVGファイルの基本的な読み込み、編集、出力の機能を実装する -グリッドレイアウト機能を実装し、要素を配置できるようにする -外部画像ファイルの読み込みと配置機能を実装する -入力SVGファイルを読み込んで、指定の要件に従って加工し、新たなSVGファイルを出力する一連の処理を実装する -細かい仕様について検討し、機能を拡張する -テストを行い、不具合を修正する -ドキュメントを整備し、コードをリファクタリングする -まずはこの要件定義に基づいて、各機能の実装に着手してください。実装方法や詳細な手順は、要件に合わせて適宜ご判断ください。 - - - -作業フォルダは/app/workを使ってください。 +from codeinterpreterapi import CodeInterpreterSession -全ての処理は自動で実施して結果とプログラムだけ報告してください。 - """ - status = session.start_local() - result = session.generate_response(message) - result.show() -except Exception as e: - print(e) +class CodeInterpreter(GuiAgentInterpreterBase): + def __init__(self): + model = "claude-3-haiku-20240307" + model = "gemini-1.5-pro-latest" + self.session = CodeInterpreterSession(model=model) + self.status = self.session.start_local() + + def chat( + self, + message: GuiAgentInterpreterChatMessages, + display: bool = False, + stream: bool = False, + blocking: bool = False, + ) -> GuiAgentInterpreterChatResponseAny: + try: + message = """SVG画像を自動生成するプログラムの要件を以下のように定義します。 + + 目的: + + 電子書籍のヘッダ画像を自動生成すること + 別のコンテンツ生成プログラムが出力したSVGファイルを入力として受け取ること + 入力SVGファイルを指定の要件に従って加工し、新たなSVGファイルとして出力すること + 機能要件: + + グリッドレイアウト機能の実装 + + 指定したグリッドサイズ(行数、列数)に基づいて要素を配置できるようにする + グリッドの各セルに対して要素を割り当てられるようにする + グリッドのサイズや間隔を柔軟に設定できるようにする + SVG要素の配置と編集 + + グリッド上の指定した位置にSVG要素(テキスト、図形、画像など)を配置できるようにする + 配置する要素の属性(サイズ、色、フォントなど)を柔軟に設定できるようにする + 既存のSVG要素を削除、移動、変更できるようにする + 外部画像ファイルの読み込みと配置 + + PNGやJPEGなどの外部画像ファイルを読み込んでSVGファイルに埋め込めるようにする + 読み込んだ画像をグリッド上の指定した位置に配置できるようにする + 画像のサイズを変更できるようにする + SVGファイルの入出力 + + SVGファイルを入力として読み込み、加工後のSVGファイルを出力できるようにする + 出力ファイルのファイル名やパスを指定できるようにする + 非機能要件: + + Python3とsvgwriteライブラリを使用して実装すること + コードはモジュール化し、再利用性と保守性を高めること + エラーハンドリングを適切に行い、ログ出力を行うこと + コードにはコメントを付けて可読性を高めること + 実装の進め方: + + svgwriteを使ったSVGファイルの基本的な読み込み、編集、出力の機能を実装する + グリッドレイアウト機能を実装し、要素を配置できるようにする + 外部画像ファイルの読み込みと配置機能を実装する + 入力SVGファイルを読み込んで、指定の要件に従って加工し、新たなSVGファイルを出力する一連の処理を実装する + 細かい仕様について検討し、機能を拡張する + テストを行い、不具合を修正する + ドキュメントを整備し、コードをリファクタリングする + まずはこの要件定義に基づいて、各機能の実装に着手してください。実装方法や詳細な手順は、要件に合わせて適宜ご判断ください。 + + + + 作業フォルダは/app/workを使ってください。 + + 全ての処理は自動で実施して結果とプログラムだけ報告してください。 + + """ + + is_stream = False + if is_stream: + # ChainExecutorのエラーが出て動かない + """ + process_messages_gradio response_chunks= + llm stream start + server chat chunk_response= type= role= content="Error in CodeInterpreterSession: AttributeError - 'ChainExecutor' object has no attribute 'stream'" format='' code='' start=False end=False + process_messages_gradio response= type= role= content="Error in CodeInterpreterSession: AttributeError - 'ChainExecutor' object has no attribute 'stream'" format='' code='' start=False end=False + memory.save_context full_response= Error in CodeInterpr + """ + for chunk_str in self.session.generate_response_stream(message): + chunk_response = GuiAgentInterpreterChatResponse() + chunk_response.content = chunk_str + print("server chat chunk_response=", chunk_response) + yield chunk_response + else: + response = self.session.generate_response(message) + print("server chat response(no stream)=", response) + yield response + + except Exception as e: + print(e) + traceback.print_exc() + error_response = {"role": GuiAgentInterpreterChatMessage.Role.ASSISTANT, "content": str(e)} + yield error_response + + +interpreter = CodeInterpreter() +core = GuiAgentLoopCore() +core.launch_server(interpreter) diff --git a/src/codeinterpreterapi/session.py b/src/codeinterpreterapi/session.py index d7b5611a..2df16dc4 100644 --- a/src/codeinterpreterapi/session.py +++ b/src/codeinterpreterapi/session.py @@ -10,6 +10,15 @@ from codeboxapi import CodeBox # type: ignore from codeboxapi.schema import CodeBoxOutput # type: ignore +from gui_agent_loop_core.schema.schema import ( + GuiAgentInterpreterChatMessage, + GuiAgentInterpreterChatMessageList, + GuiAgentInterpreterChatResponse, + GuiAgentInterpreterChatResponseGenerator, + GuiAgentInterpreterChatResponseStr, + GuiAgentInterpreterManagerBase, + InterpreterState, +) from langchain.agents import AgentExecutor from langchain.callbacks.base import Callbacks from langchain_community.chat_message_histories.in_memory import ChatMessageHistory @@ -391,22 +400,33 @@ def generate_response( # response = self.agent_executor.invoke(input=user_request.content) response = self.supervisor.invoke(input=user_request.content) # ======= ↑↑↑↑ LLM invoke ↑↑↑↑ #======= + print("response(type)=", type(response)) + print("response=", response) output = response["output"] - print("agent_executor.invoke output=", output) - return self._output_handler(output) + print("generate_response agent_executor.invoke output=", output) + inner_response = self._output_handler(output) + final_response = GuiAgentInterpreterChatResponse() + final_response.content = str(inner_response) + return final_response except Exception as e: if self.verbose: traceback.print_exc() if settings.DETAILED_ERROR: - return CodeInterpreterResponse( - content="Error in CodeInterpreterSession: " f"{e.__class__.__name__} - {e}" + inner_response = CodeInterpreterResponse( + content="Error in CodeInterpreterSession(generate_response): " f"{e.__class__.__name__} - {e}" ) + final_response = GuiAgentInterpreterChatResponse() + final_response.content = str(inner_response) + return final_response else: - return CodeInterpreterResponse( + inner_response = CodeInterpreterResponse( content="Sorry, something went while generating your response." "Please try again or restart the session." ) + final_response = GuiAgentInterpreterChatResponse() + final_response.content = str(inner_response) + return final_response async def agenerate_response( self, @@ -424,14 +444,14 @@ async def agenerate_response( # ======= ↑↑↑↑ LLM invoke ↑↑↑↑ #======= output = response["output"] - print("agent_executor.invoke output=", output) + print("agenerate_response agent_executor.ainvoke output=", output) return await self._aoutput_handler(output) except Exception as e: if self.verbose: traceback.print_exc() if settings.DETAILED_ERROR: return CodeInterpreterResponse( - content="Error in CodeInterpreterSession: " f"{e.__class__.__name__} - {e}" + content="Error in CodeInterpreterSession(agenerate_response): " f"{e.__class__.__name__} - {e}" ) else: return CodeInterpreterResponse( @@ -439,6 +459,81 @@ async def agenerate_response( "Please try again or restart the session." ) + def generate_response_stream( + self, + user_msg: str, + files: list[File] = None, + ) -> GuiAgentInterpreterChatResponseStr: + """Generate a Code Interpreter response based on the user's input.""" + if files is None: + files = [] + user_request = UserRequest(content=user_msg, files=files) + try: + self._input_handler(user_request) + assert self.agent_executor, "Session not initialized." + print("llm stream start") + # ======= ↓↓↓↓ LLM invoke ↓↓↓↓ #======= + response = self.agent_executor.stream(input=user_request.content) + # ======= ↑↑↑↑ LLM invoke ↑↑↑↑ #======= + print("llm stream response(type)=", type(response)) + print("llm stream response=", response) + + full_output = "" + for chunk in response: + yield chunk + full_output += chunk["output"] + + print("generate_response_stream agent_executor.stream full_output=", full_output) + self._aoutput_handler(full_output) + except Exception as e: + if self.verbose: + traceback.print_exc() + if settings.DETAILED_ERROR: + yield "Error in CodeInterpreterSession(generate_response_stream): " f"{e.__class__.__name__} - {e}" + else: + yield "Sorry, something went while generating your response." + "Please try again or restart the session." + + async def agenerate_response_stream( + self, + user_msg: str, + files: list[File] = None, + ) -> CodeInterpreterResponse: + """Generate a Code Interpreter response based on the user's input.""" + if files is None: + files = [] + user_request = UserRequest(content=user_msg, files=files) + try: + await self._ainput_handler(user_request) + assert self.agent_executor, "Session not initialized." + + print("llm astream start") + # ======= ↓↓↓↓ LLM invoke ↓↓↓↓ #======= + response = self.agent_executor.astream(input=user_request.content) + # ======= ↑↑↑↑ LLM invoke ↑↑↑↑ #======= + print("llm astream response(type)=", type(response)) + print("llm astream response=", response) + + full_output = "" + async for chunk in response: + yield chunk + full_output += chunk["output"] + + print("agent_executor.astream full_output=", full_output) + await self._aoutput_handler(full_output) + except Exception as e: + if self.verbose: + traceback.print_exc() + if settings.DETAILED_ERROR: + yield CodeInterpreterResponse( + content="Error in CodeInterpreterSession(agenerate_response_stream): " + f"{e.__class__.__name__} - {e}" + ) + else: + yield CodeInterpreterResponse( + content="Sorry, something went while generating your response." + "Please try again or restart the session." + ) + def is_running(self) -> bool: return self.codebox.status() == "running"