From 99cd01db8f666c6d2da9c973de437790cd7cacd9 Mon Sep 17 00:00:00 2001 From: leifei Date: Mon, 31 Mar 2025 18:31:41 +0800 Subject: [PATCH 1/4] add community-use-cae:excel_analyzer --- community_usecase/excel_analyzer/README.md | 25 ++ community_usecase/excel_analyzer/README_zh.md | 30 ++ .../excel_analyzer/data/admission_en.xlsx | Bin 0 -> 33947 bytes .../excel_analyzer/data/admission_zh.xlsx | Bin 0 -> 27643 bytes .../excel_analyzer/data_analyzer_en.py | 270 ++++++++++++++++ .../excel_analyzer/data_analyzer_zh.py | 304 ++++++++++++++++++ 6 files changed, 629 insertions(+) create mode 100644 community_usecase/excel_analyzer/README.md create mode 100644 community_usecase/excel_analyzer/README_zh.md create mode 100644 community_usecase/excel_analyzer/data/admission_en.xlsx create mode 100644 community_usecase/excel_analyzer/data/admission_zh.xlsx create mode 100644 community_usecase/excel_analyzer/data_analyzer_en.py create mode 100644 community_usecase/excel_analyzer/data_analyzer_zh.py diff --git a/community_usecase/excel_analyzer/README.md b/community_usecase/excel_analyzer/README.md new file mode 100644 index 0000000..3c14607 --- /dev/null +++ b/community_usecase/excel_analyzer/README.md @@ -0,0 +1,25 @@ +# Excel Analyzer +This project uses **Owl** for data analysis and visualization. + +## Features + +- Provides both English and Chinese versions of the raw data and prompts +- Utilizes **CodeExecutionToolkit**, **ExcelToolkit**, and **FileWriteToolkit** to complete related tasks +- Implements **ExcelRolePlaying** based on **OwlRolePlaying**, which overrides the `system_prompt` with a cleaner, more focused version tailored for data analysis scenarios + +## How to Use +1. Set up the environment according to Owl's official instructions +2. Run the following commands: + ```bash + cd community_usecase/excel_analyzer + + # Chinese version + python data_insights_deepseek_zh.py + + # English version + python data_insights_gpt4o_zh.py + ``` +3. The analysis results will be saved in the current directory + +## Demo Video + diff --git a/community_usecase/excel_analyzer/README_zh.md b/community_usecase/excel_analyzer/README_zh.md new file mode 100644 index 0000000..9fb1361 --- /dev/null +++ b/community_usecase/excel_analyzer/README_zh.md @@ -0,0 +1,30 @@ +# Excel Analyzer +这个项目使用owl来做数据分析和可视化 + + +## Features + +- 提供了英文,中文两个版本的原始数据和prompt,方便理解 +- 使用**CodeExecutionToolkit**,**ExcelToolkit**,**FileWriteToolkit**来完成相关工作 +- 在**OwlRolePlaying**基础之上实现了**ExcelRolePalying**,它重写了system_prompt,更简洁,聚焦在数据分析场景 + + +## How to use +1. 按照owl的官方流程搭建好环境 +2. 运行 + ``` + cd community_usecase/excel_analyzer + + # Chinese version + python excel_analyzer_zh.py + + # English version + python excel_analyzer_zh.py + ``` +3. 数据集分析的结果将会在出存在当前目录下 + + +## Demo +视频结果:[link] + + diff --git a/community_usecase/excel_analyzer/data/admission_en.xlsx b/community_usecase/excel_analyzer/data/admission_en.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..05cf69066486556bd3e35942edf201ed2227662c GIT binary patch literal 33947 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 literal 0 HcmV?d00001 diff --git a/community_usecase/excel_analyzer/data/admission_zh.xlsx b/community_usecase/excel_analyzer/data/admission_zh.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..81077359a407c591dc0e1a5b6862ff40a17a65f1 GIT binary patch literal 27643 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 b|EE}~$U}olI)Q<~gZ_j-LsV?@`|3Xcc!GNN literal 0 HcmV?d00001 diff --git a/community_usecase/excel_analyzer/data_analyzer_en.py b/community_usecase/excel_analyzer/data_analyzer_en.py new file mode 100644 index 0000000..57d15e6 --- /dev/null +++ b/community_usecase/excel_analyzer/data_analyzer_en.py @@ -0,0 +1,270 @@ +# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= +import os +import sys + + +from dotenv import load_dotenv +from camel.configs import ChatGPTConfig +from camel.models import ModelFactory +from camel.messages.base import BaseMessage + +from camel.toolkits import ( + CodeExecutionToolkit, + ExcelToolkit, + FileWriteToolkit, +) +from camel.types import ModelPlatformType + +from owl.utils import OwlRolePlaying +from typing import Dict, List, Optional, Tuple +from camel.logger import set_log_level, set_log_file, get_logger + +import pathlib + +logger = get_logger(__name__) + +base_dir = pathlib.Path(__file__).parent.parent.parent +env_path = base_dir / "owl" / ".env" +load_dotenv(dotenv_path=str(env_path)) + +set_log_level(level="DEBUG") + +class ExcelRolePalying(OwlRolePlaying): + def _construct_gaia_sys_msgs(self): + user_system_prompt = f""" +===== RULES OF USER ===== +Never forget you are a user and I am a assistant. Never flip roles! You will always instruct me. We share a common interest in collaborating to successfully complete a task. +I must help you to complete a difficult task. +You must instruct me based on my expertise and your needs to solve the task step by step. The format of your instruction is: `Instruction: [YOUR INSTRUCTION]`, where "Instruction" describes a sub-task or question. +You must give me one instruction at a time. +I must write a response that appropriately solves the requested instruction. +You should instruct me not ask me questions. + +Please note that the task may be very complicated. Do not attempt to solve the task by single step. You must instruct me to find the answer step by step. +Here are some tips that will help you to give more valuable instructions about our task to me: + +- I can use various tools, such as Excel Toolkit and Code Execution Toolkit. + +- Although the task may be complex, the answer exists. + If you find that the current approach does not lead to the answer, reconsider the task, and use alternative methods or tools to achieve the same goal. + +- Always remind me to verify whether the final answer is correct! + This can be done in multiple ways, such as screenshots, web analysis, etc. + +- If I have written code, remind me to run the code and obtain the results. + +- Flexibly use code to solve problems, especially for Excel-related tasks. + + + +Now, here is the overall task: {self.task_prompt}. Never forget our task! + +Now you must start to instruct me to solve the task step-by-step. Do not add anything else other than your instruction! +Keep giving me instructions until you think the task is completed. +When the task is completed, you must only reply with a single word . +Never say unless my responses have solved your task. + """ + + assistant_system_prompt = f""" +===== RULES OF ASSISTANT ===== +Never forget you are a assistant and I am a user. Never flip roles! Never instruct me! You have to utilize your available tools to solve the task I assigned. +We share a common interest in collaborating to successfully complete a complex task. +You must help me to complete the task. + +Here is our overall task: {self.task_prompt}. Never forget our task! + +I must instruct you based on your expertise and my needs to complete the task. An instruction is typically a sub-task or question. + +You must leverage your available tools, try your best to solve the problem, and explain your solutions. +Unless I say the task is completed, you should always start with: +Solution: [YOUR_SOLUTION] +[YOUR_SOLUTION] should be specific, including detailed explanations and provide preferable detailed implementations and examples and lists for task-solving. + +Please note that our overall task may be very complicated. Here are some tips that may help you solve the task: + +- If one method fails, try another. The answer exists! +- When it comes to viewing information in an Excel file, you can always start by writing Python code to read the Excel file and check sheet names, column names, and similar details. +- When providing Python code, always remember to import the necessary libraries at the beginning, such as the commonly used libraries for Excel analysis below: +``` +import pandas as pd +``` +- Always verify whether your final answer is correct! +- Always write complete code from scratch. After writing the code, be sure to run it and obtain the results! + If you encounter errors, try debugging the code. + Note that the code execution environment does not support interactive input. +- If the tool fails to run or the code does not execute correctly, + never assume that it has returned the correct result and continue reasoning based on it! + The correct approach is to analyze the cause of the error and try to fix it! + + + """ + + user_sys_msg = BaseMessage.make_user_message( + role_name=self.user_role_name, content=user_system_prompt + ) + + assistant_sys_msg = BaseMessage.make_assistant_message( + role_name=self.assistant_role_name, content=assistant_system_prompt + ) + + return user_sys_msg, assistant_sys_msg + +def run_society( + society: ExcelRolePalying, + round_limit: int = 15, +) -> Tuple[str, List[dict], dict]: + overall_completion_token_count = 0 + overall_prompt_token_count = 0 + + chat_history = [] + init_prompt = """ + Now please give me instructions to solve over overall task step by step. If the task requires some specific knowledge, please instruct me to use tools to complete the task. + """ + input_msg = society.init_chat(init_prompt) + for _round in range(round_limit): + assistant_response, user_response = society.step(input_msg) + # Check if usage info is available before accessing it + if assistant_response.info.get("usage") and user_response.info.get("usage"): + overall_completion_token_count += assistant_response.info["usage"].get( + "completion_tokens", 0 + ) + user_response.info["usage"].get("completion_tokens", 0) + overall_prompt_token_count += assistant_response.info["usage"].get( + "prompt_tokens", 0 + ) + user_response.info["usage"].get("prompt_tokens", 0) + + # convert tool call to dict + tool_call_records: List[dict] = [] + if assistant_response.info.get("tool_calls"): + for tool_call in assistant_response.info["tool_calls"]: + tool_call_records.append(tool_call.as_dict()) + + _data = { + "user": user_response.msg.content + if hasattr(user_response, "msg") and user_response.msg + else "", + "assistant": assistant_response.msg.content + if hasattr(assistant_response, "msg") and assistant_response.msg + else "", + "tool_calls": tool_call_records, + } + + chat_history.append(_data) + logger.info( + f"Round #{_round} user_response:\n {user_response.msgs[0].content if user_response.msgs and len(user_response.msgs) > 0 else ''}" + ) + logger.info( + f"Round #{_round} assistant_response:\n {assistant_response.msgs[0].content if assistant_response.msgs and len(assistant_response.msgs) > 0 else ''}" + ) + + if ( + assistant_response.terminated + or user_response.terminated + or "TASK_DONE" in user_response.msg.content + ): + break + + input_msg = assistant_response.msg + + answer = chat_history[-1]["assistant"] + token_info = { + "completion_token_count": overall_completion_token_count, + "prompt_token_count": overall_prompt_token_count, + } + + return answer, chat_history, token_info + +def construct_society(question: str) -> ExcelRolePalying: + r"""Construct a society of agents based on the given question. + + Args: + question (str): The task or question to be addressed by the society. + + Returns: + OwlRolePlaying: A configured society of agents ready to address the question. + """ + + # base_model_config = { + # "model_platform": ModelPlatformType.DEEPSEEK, + # "model_type": 'deepseek-chat', + # "model_config_dict": ChatGPTConfig(temperature=0.1, max_tokens=8192).as_dict(), + # } + + # Create models for different components using Azure OpenAI + base_model_config = { + "model_platform": ModelPlatformType.AZURE, + "model_type": os.getenv("AZURE_OPENAI_MODEL_TYPE"), + "model_config_dict": ChatGPTConfig(temperature=0.01, max_tokens=4096).as_dict(), + } + + + models = { + "user": ModelFactory.create(**base_model_config), + "assistant": ModelFactory.create(**base_model_config), + } + + # Configure toolkits + tools = [ + *CodeExecutionToolkit(sandbox="subprocess", verbose=True).get_tools(), + *ExcelToolkit().get_tools(), + *FileWriteToolkit(output_dir="./").get_tools(), + ] + + # Configure agent roles and parameters + user_agent_kwargs = {"model": models["user"]} + assistant_agent_kwargs = {"model": models["assistant"], "tools": tools} + + # Configure task parameters + task_kwargs = { + "task_prompt": question, + "with_task_specify": False, + } + + # Create and return the society + society = ExcelRolePalying( + **task_kwargs, + user_role_name="user", + user_agent_kwargs=user_agent_kwargs, + assistant_role_name="assistant", + assistant_agent_kwargs=assistant_agent_kwargs, + output_language="English" + ) + + return society + + +def main(): + r"""Main function to run the OWL system with Azure OpenAI.""" + # Example question + + + default_task = "Please help analyze the number of admitted students, as well as the highest and lowest scores for each college in this file. Visualize this information in a single chart and save it in the current directory. The file path is `./data/admission_en.xlsx.`" + + + set_log_file('log.txt') + + # Override default task if command line argument is provided + task = sys.argv[1] if len(sys.argv) > 1 else default_task + + # Construct and run the society + society = construct_society(task) + + answer, chat_history, token_count = run_society(society) + + # Output the result + print(f"\033[94mAnswer: {answer}\033[0m") + + +if __name__ == "__main__": + main() diff --git a/community_usecase/excel_analyzer/data_analyzer_zh.py b/community_usecase/excel_analyzer/data_analyzer_zh.py new file mode 100644 index 0000000..cdb342f --- /dev/null +++ b/community_usecase/excel_analyzer/data_analyzer_zh.py @@ -0,0 +1,304 @@ +# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ========= Copyright 2023-2024 @ CAMEL-AI.org. All Rights Reserved. ========= +import os +import sys + + +from dotenv import load_dotenv +from camel.configs import ChatGPTConfig +from camel.models import ModelFactory +from camel.messages.base import BaseMessage + +from camel.toolkits import ( + CodeExecutionToolkit, + ExcelToolkit, + FileWriteToolkit, +) +from camel.types import ModelPlatformType + +from owl.utils import OwlRolePlaying +from typing import Dict, List, Optional, Tuple +from camel.logger import set_log_level, set_log_file, get_logger + +import pathlib + +logger = get_logger(__name__) + +base_dir = pathlib.Path(__file__).parent.parent.parent +env_path = base_dir / "owl" / ".env" +load_dotenv(dotenv_path=str(env_path)) + +set_log_level(level="DEBUG") + +class ExcelRolePalying(OwlRolePlaying): + def _construct_gaia_sys_msgs(self): + user_system_prompt = f""" +### ===== 用户规则 ===== +永远不要忘记,你是用户,而我是助手。绝对不能互换角色! 你必须始终指导我,我们的共同目标是合作完成任务。 +我的职责是帮助你完成一个复杂的任务。 + +你必须根据我的专业能力和你的需求逐步指导我解决任务。 +你的指令格式必须为: +`Instruction: [你的指令]` +其中,"Instruction" 代表一个子任务或问题。 + +- 你每次只能给出一个指令。 +- 我必须依据你的指令提供适当的解决方案。 +- 你只能指导我,而不能向我提问。 + +--- + +### 请注意 +任务可能会非常复杂,不要试图一次性解决整个任务! +你必须让我一步一步地寻找答案。 + +以下是一些能帮助你给出更有价值指令的提示: + +#### +- 我可以使用各种工具,比如:excel Toolkit 和 code Execution Toolkit 等。 + +- 尽管任务复杂,但答案是存在的。 + 如果你发现当前方案无法找到答案,请重新规划任务,使用其他方法或工具来达到相同的目标。 + +- 务必提醒我验证最终答案是否正确! + 这可以通过多种方式完成,例如截图、网页分析等。 + +- 如果我编写了代码,请提醒我运行代码并获取结果。 + +- 请灵活使用代码解决问题,尤其是涉及 Excel 相关任务时。 + + + +--- + +### 任务描述 +当前任务如下: +{self.task_prompt} +永远不要忘记这个任务! + +### 任务执行规则 +你现在必须开始 逐步指导我完成任务。 +- 不要添加任何额外的内容! +- 继续给出指令,直到你认为任务完成。 + +### 任务完成规则 +当任务完成时,你只能回复一个单词: +`` + +在我的回答完全解决你的任务之前,绝对不要说 ``! + """ + + assistant_system_prompt = f""" +===== 助手规则 ===== +永远不要忘记,你是助手,而我是用户。绝对不能互换角色! 绝对不能指挥我! 你必须利用你的工具来解决我分配的任务。 +我们的共同目标是合作完成一个复杂的任务。 +你的职责是帮助我完成任务。 + +当前任务如下: +{self.task_prompt} +永远不要忘记这个任务! + +我会根据你的专业能力和我的需求指导你完成任务。 +每条指令通常是一个子任务或问题。 + +你必须充分利用你的工具,尽力解决问题,并详细解释你的解决方案。 +除非我宣布任务完成,你的回答必须以以下格式开始: + +Solution: [你的解决方案] + +[你的解决方案] 必须具体,包含详细的解释,并提供可行的实现方案、示例或清单来解决任务。 + +--- + +### 请注意:整体任务可能会非常复杂! +以下是一些可能帮助你解决任务的重要提示: + +#### +- 如果一种方法失败了,尝试其他方法。答案是存在的! +- 当涉及到查看某个excel信息的时候,你可以总是以编写python代码读入excel文件查看sheet名,列名之类的信息开始。 +- 当你尝试给出python代码的时候,始终记得在最开头import相关的库,比如下面这些excel分析常见的库 +``` +import pandas as pd +``` +- 始终验证你的最终答案是否正确! +- 请每次都从头开始编写完整代码,编写代码后,务必运行代码并获取结果! + 如果遇到错误,尝试调试代码。 + 请注意,代码执行环境不支持交互式输入。 +- 如果工具运行失败,或者代码无法正确运行, + 绝对不要假设其返回了正确结果,并在此基础上继续推理! + 正确的做法是分析错误原因,并尝试修正! +- 如果你写的代码涉及到用matplotlib画图,请始终在代码开头下面这段代码: +``` +import matplotlib +matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 支持中文 +matplotlib.rcParams['axes.unicode_minus'] = False # 解决负号显示问题 +``` +- 请始终使用英文来画图,比如title, xlabel, ylabel以及其他均使用英文。 + + """ + + user_sys_msg = BaseMessage.make_user_message( + role_name=self.user_role_name, content=user_system_prompt + ) + + assistant_sys_msg = BaseMessage.make_assistant_message( + role_name=self.assistant_role_name, content=assistant_system_prompt + ) + + return user_sys_msg, assistant_sys_msg + +def run_society( + society: OwlRolePlaying, + round_limit: int = 15, +) -> Tuple[str, List[dict], dict]: + overall_completion_token_count = 0 + overall_prompt_token_count = 0 + + chat_history = [] + init_prompt = """ +现在请给我逐步解决整个任务的指令。如果任务需要一些特定的知识,请指示我使用工具来完成任务。 + """ + input_msg = society.init_chat(init_prompt) + for _round in range(round_limit): + assistant_response, user_response = society.step(input_msg) + # Check if usage info is available before accessing it + if assistant_response.info.get("usage") and user_response.info.get("usage"): + overall_completion_token_count += assistant_response.info["usage"].get( + "completion_tokens", 0 + ) + user_response.info["usage"].get("completion_tokens", 0) + overall_prompt_token_count += assistant_response.info["usage"].get( + "prompt_tokens", 0 + ) + user_response.info["usage"].get("prompt_tokens", 0) + + # convert tool call to dict + tool_call_records: List[dict] = [] + if assistant_response.info.get("tool_calls"): + for tool_call in assistant_response.info["tool_calls"]: + tool_call_records.append(tool_call.as_dict()) + + _data = { + "user": user_response.msg.content + if hasattr(user_response, "msg") and user_response.msg + else "", + "assistant": assistant_response.msg.content + if hasattr(assistant_response, "msg") and assistant_response.msg + else "", + "tool_calls": tool_call_records, + } + + chat_history.append(_data) + logger.info( + f"Round #{_round} user_response:\n {user_response.msgs[0].content if user_response.msgs and len(user_response.msgs) > 0 else ''}" + ) + logger.info( + f"Round #{_round} assistant_response:\n {assistant_response.msgs[0].content if assistant_response.msgs and len(assistant_response.msgs) > 0 else ''}" + ) + + if ( + assistant_response.terminated + or user_response.terminated + or "TASK_DONE" in user_response.msg.content + ): + break + + input_msg = assistant_response.msg + + answer = chat_history[-1]["assistant"] + token_info = { + "completion_token_count": overall_completion_token_count, + "prompt_token_count": overall_prompt_token_count, + } + + return answer, chat_history, token_info + +def construct_society(question: str) -> ExcelRolePalying: + r"""Construct a society of agents based on the given question. + + Args: + question (str): The task or question to be addressed by the society. + + Returns: + OwlRolePlaying: A configured society of agents ready to address the question. + """ + + # base_model_config = { + # "model_platform": ModelPlatformType.DEEPSEEK, + # "model_type": 'deepseek-chat', + # "model_config_dict": ChatGPTConfig(temperature=0.1, max_tokens=8192).as_dict(), + # } + + # Create models for different components using Azure OpenAI + base_model_config = { + "model_platform": ModelPlatformType.AZURE, + "model_type": os.getenv("AZURE_OPENAI_MODEL_TYPE"), + "model_config_dict": ChatGPTConfig(temperature=0.4, max_tokens=4096).as_dict(), + } + + + models = { + "user": ModelFactory.create(**base_model_config), + "assistant": ModelFactory.create(**base_model_config), + } + + # Configure toolkits + tools = [ + *CodeExecutionToolkit(sandbox="subprocess", verbose=True).get_tools(), + *ExcelToolkit().get_tools(), + *FileWriteToolkit(output_dir="./").get_tools(), + ] + + # Configure agent roles and parameters + user_agent_kwargs = {"model": models["user"]} + assistant_agent_kwargs = {"model": models["assistant"], "tools": tools} + + # Configure task parameters + task_kwargs = { + "task_prompt": question, + "with_task_specify": False, + } + + # Create and return the society + society = ExcelRolePalying( + **task_kwargs, + user_role_name="user", + user_agent_kwargs=user_agent_kwargs, + assistant_role_name="assistant", + assistant_agent_kwargs=assistant_agent_kwargs, + output_language="中文" + ) + + return society + + +def main(): + r"""Main function to run the OWL system with Azure OpenAI.""" + # Example question + default_task = "帮忙分析一下这个文件中各个学院的录取人数以及最高分最低分,把这些信息画到一张图上,并存到当前目录下。文件路径是`./data/admission_zh.xlsx`" + + set_log_file('log.txt') + + # Override default task if command line argument is provided + task = sys.argv[1] if len(sys.argv) > 1 else default_task + + # Construct and run the society + society = construct_society(task) + + answer, chat_history, token_count = run_society(society) + + # Output the result + print(f"\033[94mAnswer: {answer}\033[0m") + + +if __name__ == "__main__": + main() From 6913c0a75a6027a37bf055a11f02c75b91065e48 Mon Sep 17 00:00:00 2001 From: leifei Date: Mon, 31 Mar 2025 23:16:13 +0800 Subject: [PATCH 2/4] add community-use-cae:excel_analyzer --- community_usecase/excel_analyzer/README.md | 15 ++++++--- community_usecase/excel_analyzer/README_zh.md | 16 +++++----- .../excel_analyzer/data_analyzer_en.py | 14 +++------ .../excel_analyzer/data_analyzer_zh.py | 31 +++++++++++-------- 4 files changed, 40 insertions(+), 36 deletions(-) diff --git a/community_usecase/excel_analyzer/README.md b/community_usecase/excel_analyzer/README.md index 3c14607..fd7e87e 100644 --- a/community_usecase/excel_analyzer/README.md +++ b/community_usecase/excel_analyzer/README.md @@ -6,6 +6,12 @@ This project uses **Owl** for data analysis and visualization. - Provides both English and Chinese versions of the raw data and prompts - Utilizes **CodeExecutionToolkit**, **ExcelToolkit**, and **FileWriteToolkit** to complete related tasks - Implements **ExcelRolePlaying** based on **OwlRolePlaying**, which overrides the `system_prompt` with a cleaner, more focused version tailored for data analysis scenarios +- +- The analysis and visualization of this Excel file involve: + - Complex headers (merged rows) + - Nan value handling + - Complex group calculations + - Visualization ## How to Use 1. Set up the environment according to Owl's official instructions @@ -13,13 +19,12 @@ This project uses **Owl** for data analysis and visualization. ```bash cd community_usecase/excel_analyzer - # Chinese version - python data_insights_deepseek_zh.py + # Chinese version, using deepseek-v3 + python excel_analyzer_zh.py - # English version - python data_insights_gpt4o_zh.py + # English version, using gpt-4o + python excel_analyzer_zh.py ``` 3. The analysis results will be saved in the current directory -## Demo Video diff --git a/community_usecase/excel_analyzer/README_zh.md b/community_usecase/excel_analyzer/README_zh.md index 9fb1361..eeb85a9 100644 --- a/community_usecase/excel_analyzer/README_zh.md +++ b/community_usecase/excel_analyzer/README_zh.md @@ -3,11 +3,15 @@ ## Features - - 提供了英文,中文两个版本的原始数据和prompt,方便理解 - 使用**CodeExecutionToolkit**,**ExcelToolkit**,**FileWriteToolkit**来完成相关工作 - 在**OwlRolePlaying**基础之上实现了**ExcelRolePalying**,它重写了system_prompt,更简洁,聚焦在数据分析场景 - +- 经过测试,在`gpt-4o`和`deepseek-v3`下均可以达到预期效果 +- 对该excel进行分析和可视化时涉及到的内容有: + - 复杂表头(合并行) + - 缺失值处理 + - 复杂的分组计算 + - 可视化 ## How to use 1. 按照owl的官方流程搭建好环境 @@ -15,16 +19,12 @@ ``` cd community_usecase/excel_analyzer - # Chinese version + # Chinese version, using deepseek-v3 python excel_analyzer_zh.py - # English version + # English version, using gpt-4o python excel_analyzer_zh.py ``` 3. 数据集分析的结果将会在出存在当前目录下 -## Demo -视频结果:[link] - - diff --git a/community_usecase/excel_analyzer/data_analyzer_en.py b/community_usecase/excel_analyzer/data_analyzer_en.py index 57d15e6..d3458e3 100644 --- a/community_usecase/excel_analyzer/data_analyzer_en.py +++ b/community_usecase/excel_analyzer/data_analyzer_en.py @@ -195,12 +195,6 @@ def construct_society(question: str) -> ExcelRolePalying: OwlRolePlaying: A configured society of agents ready to address the question. """ - # base_model_config = { - # "model_platform": ModelPlatformType.DEEPSEEK, - # "model_type": 'deepseek-chat', - # "model_config_dict": ChatGPTConfig(temperature=0.1, max_tokens=8192).as_dict(), - # } - # Create models for different components using Azure OpenAI base_model_config = { "model_platform": ModelPlatformType.AZURE, @@ -245,12 +239,12 @@ def construct_society(question: str) -> ExcelRolePalying: def main(): - r"""Main function to run the OWL system with Azure OpenAI.""" # Example question - - default_task = "Please help analyze the number of admitted students, as well as the highest and lowest scores for each college in this file. Visualize this information in a single chart and save it in the current directory. The file path is `./data/admission_en.xlsx.`" - + default_task = """Please help analyze the file `./data/admission_en.xlsx` by: + - Calculating the number of admitted students, as well as the highest and lowest scores for each college + - Plotting this information in a single chart: use a bar chart for the number of admitted students, and line charts for the highest and lowest scores + - Saving the generated chart as `vis_en.png` in the current directory""" set_log_file('log.txt') diff --git a/community_usecase/excel_analyzer/data_analyzer_zh.py b/community_usecase/excel_analyzer/data_analyzer_zh.py index cdb342f..96f1e92 100644 --- a/community_usecase/excel_analyzer/data_analyzer_zh.py +++ b/community_usecase/excel_analyzer/data_analyzer_zh.py @@ -134,11 +134,10 @@ import pandas as pd - 始终验证你的最终答案是否正确! - 请每次都从头开始编写完整代码,编写代码后,务必运行代码并获取结果! 如果遇到错误,尝试调试代码。 - 请注意,代码执行环境不支持交互式输入。 - 如果工具运行失败,或者代码无法正确运行, 绝对不要假设其返回了正确结果,并在此基础上继续推理! 正确的做法是分析错误原因,并尝试修正! -- 如果你写的代码涉及到用matplotlib画图,请始终在代码开头下面这段代码: +- [重要!!!]如果你写的代码涉及到用matplotlib画图,请始终在代码开头下面这段代码: ``` import matplotlib matplotlib.rcParams['font.sans-serif'] = ['SimHei'] # 支持中文 @@ -232,18 +231,18 @@ def construct_society(question: str) -> ExcelRolePalying: OwlRolePlaying: A configured society of agents ready to address the question. """ - # base_model_config = { - # "model_platform": ModelPlatformType.DEEPSEEK, - # "model_type": 'deepseek-chat', - # "model_config_dict": ChatGPTConfig(temperature=0.1, max_tokens=8192).as_dict(), - # } + base_model_config = { + "model_platform": ModelPlatformType.DEEPSEEK, + "model_type": 'deepseek-chat', + "model_config_dict": ChatGPTConfig(temperature=0.1, max_tokens=8192).as_dict(), + } # Create models for different components using Azure OpenAI - base_model_config = { - "model_platform": ModelPlatformType.AZURE, - "model_type": os.getenv("AZURE_OPENAI_MODEL_TYPE"), - "model_config_dict": ChatGPTConfig(temperature=0.4, max_tokens=4096).as_dict(), - } + # base_model_config = { + # "model_platform": ModelPlatformType.AZURE, + # "model_type": os.getenv("AZURE_OPENAI_MODEL_TYPE"), + # "model_config_dict": ChatGPTConfig(temperature=0.4, max_tokens=4096).as_dict(), + # } models = { @@ -284,7 +283,13 @@ def construct_society(question: str) -> ExcelRolePalying: def main(): r"""Main function to run the OWL system with Azure OpenAI.""" # Example question - default_task = "帮忙分析一下这个文件中各个学院的录取人数以及最高分最低分,把这些信息画到一张图上,并存到当前目录下。文件路径是`./data/admission_zh.xlsx`" + # default_task = """帮忙分析一下这个文件中各个学院的录取人数以及最高分最低分,把这些信息画到一张图上,并存到当前路径下。文件路径是`./data/admission_zh.xlsx`""" + + default_task = """帮忙分析一下`./data/admission_zh.xlsx`这个文件,请你: + - 统计各个学院的录取人数以及最高分最低分 + - 把这些信息画到一张图上,录取人数使用柱状图,最高分最低分使用折线图 + - 把画完的图`vis_zh.png`存到当前目录下""" + set_log_file('log.txt') From 367e05af85bebc2f048186507f2b770e475a26f2 Mon Sep 17 00:00:00 2001 From: leifei Date: Mon, 31 Mar 2025 23:19:54 +0800 Subject: [PATCH 3/4] update community-use-cae:excel_analyzer --- community_usecase/excel_analyzer/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/community_usecase/excel_analyzer/README.md b/community_usecase/excel_analyzer/README.md index fd7e87e..ef2b53b 100644 --- a/community_usecase/excel_analyzer/README.md +++ b/community_usecase/excel_analyzer/README.md @@ -1,4 +1,6 @@ # Excel Analyzer +[中文](README_zh.md) + This project uses **Owl** for data analysis and visualization. ## Features From 8bfeea963dcd0748ceb0962153d7dd55993cdb25 Mon Sep 17 00:00:00 2001 From: leifei Date: Mon, 31 Mar 2025 23:22:33 +0800 Subject: [PATCH 4/4] update community-use-cae:excel_analyzer --- community_usecase/excel_analyzer/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/community_usecase/excel_analyzer/README.md b/community_usecase/excel_analyzer/README.md index ef2b53b..c91e8e7 100644 --- a/community_usecase/excel_analyzer/README.md +++ b/community_usecase/excel_analyzer/README.md @@ -8,7 +8,7 @@ This project uses **Owl** for data analysis and visualization. - Provides both English and Chinese versions of the raw data and prompts - Utilizes **CodeExecutionToolkit**, **ExcelToolkit**, and **FileWriteToolkit** to complete related tasks - Implements **ExcelRolePlaying** based on **OwlRolePlaying**, which overrides the `system_prompt` with a cleaner, more focused version tailored for data analysis scenarios -- +- tested using `gpt-4o` and `deepseek-v3` - The analysis and visualization of this Excel file involve: - Complex headers (merged rows) - Nan value handling