utils.py:
from langchain_openai import ChatOpenAI
from langchain_experimental.agents.agent_toolkits import create_csv_agent
import jsonPROMPT_TEMPLATE = """你是一位数据分析助手,你的回应内容取决于用户的请求内容。1. 对于文字回答的问题,按照这样的格式回答:{"answer": "<你的答案写在这里>"}例如:{"answer": "订单量最高的产品ID是!MNWC3-067"}2. 如果用户需要一个表格,按照这样的格式回答:{"table": {"columns": ["column1", "column2", ...], "data": [[value1, value2, ...],[value1, value2, ...],...]}}3. 如果用户的请求适合返回条形图,按照这样的格式回答:{"bar": {"columns": ["A", "B", "C", ...], "data": [34, 21, 91, ...]}}4. 如果用户的请求适合返回折线图,按照这样的格式回答:{"line": {"columns": ["A", "B", "C", ...], "data": [34, 21, 91, ...]}}5. 如果用户的请求适合返回散点图,按照这样的格式回答:{"scatter": {"columns": ["A", "B", "C", ...], "data": [34, 21, 91, ...]}}注意:我们只支持三种类型的图表:"bar", "line" 和 "scatter"。请将所有输出作为JSON字符串返回。请注意要将"columns"列表和数据列表中的所有字符串都用双引号包围。例如:{"columns": ["Products", "Orders"], "data": [["32085Lip", 245], ["76439Eye", 178]]}你要处理的用户请求如下:"""def dataframe_agent(api_key, uploaded_file, query):model = ChatOpenAI(model="gpt-4",api_key=api_key,base_url="https://api.gptsapi.net/v1",temperature=0)# path 复制文件到本地,得到路径file_content = uploaded_file.getvalue() #.read()改成.getvalue(),就能读了print(file_content)print(type(file_content))print(type(file_content))file_path = "temp.csv"with open(file_path,"wb") as fwb:fwb.write(file_content)# agent执行器agent_executor = create_csv_agent(llm=model,path=file_path,allow_dangerous_code=True,agent_executor_kwargs={"handle_parsing_errors": True},verbose=True)# 输入 = 我们补充的提示 + 用户输入prompt = PROMPT_TEMPLATE + queryresult = agent_executor.invoke({"input": prompt})# result_dict = json.loads(result["output"]) #实际输出的内容是output键对应的值,然后把它解析成字典,方便前端使用# return result_dicttry : result_dict = json.loads(result["output"]) #实际输出的内容是output键对应的值,然后把它解析成字典,方便前端使用finally : print(result["output"])return result_dict# # 自定义一个类来模拟 UploadedFile 对象
# class CustomUploadedFile:
# def __init__(self, name, type, data):
# self.name = name
# self.type = type
# self.data = data
# self.size = len(data)# def read(self):
# return self.data# # 自定义一个函数将文件路径转换为类似 UploadedFile 的对象
# def file_path_to_uploaded_file(file_path):
# with open(file_path, 'rb') as f:
# file_content = f.read()
# file_name = file_path.split("/")[-1] # 获取文件名
# file_type = "text/csv" # 假设是 CSV 文件,可根据实际情况修改
# return CustomUploadedFile(file_name, file_type, file_content)# # 示例文件路径
# file_path = "test_data.csv"# # 转换为 UploadedFile 对象
# uploaded_file = file_path_to_uploaded_file(file_path)# import os
# import pandas as pd# print(dataframe_agent(os.getenv("OPENAI_API_KEY"),uploaded_file,"数据里score的范围是什么"))
main.py:
import streamlit as st
from utils import dataframe_agent
import pandas as pd
import osdef create_chart(input_data, chart_type):# 检查"data"字段是否存在且非空if "data" not in input_data or not input_data["data"]:st.error("没有提供有效的数据来创建图表")returndata = input_data["data"]# 如果数据看起来像是一维的(即单列数据)if all(isinstance(i, (int, float)) for i in data):df = pd.DataFrame(data, columns=input_data["columns"])else:# 假设数据是二维的(多列数据)df = pd.DataFrame(data, columns=input_data["columns"])if chart_type == "line":st.line_chart(df)elif chart_type == "bar":st.bar_chart(df)# 可以添加更多图表类型的支持else:st.error(f"不支持的图表类型: {chart_type}")st.title("CSV数据分析智能工具")with st.sidebar:api_key = st.text_input("请输入你的OpenAI API密钥", type="password") st.markdown("[获取OpenAI API密钥](https://2233.ai/api)")# 上传文件csv_file = st.file_uploader("请上传你的csv格式数据文件:", type="csv")# 展示部分文件数据
if csv_file:df = pd.read_csv(csv_file)with st.expander("原始数据"):st.dataframe(df)query = st.text_area("请输入你关于以上表格的问题,或数据提取请求,或可视化请求(支持散点图、折线图、条形图):", disabled=not csv_file)button = st.button("生成回答")if button:if not api_key:st.info("请先输入OpenAI API密钥")st.stop()if not query:st.info("请输入您的问题")st.stop()with st.spinner("AI正在思考中,请稍等···"):result_dict = dataframe_agent(api_key=api_key, uploaded_file=csv_file, query=query)if "answer" in result_dict:st.write(result_dict["answer"])if "table" in result_dict:columns = result_dict["table"]["columns"]data = result_dict["table"]["data"]df_result = pd.DataFrame(data, columns=columns)st.table(df_result)if "bar" in result_dict:create_chart(result_dict["bar"], "bar")if "line" in result_dict:create_chart(result_dict["line"], "line")if "scatter" in result_dict:create_chart(result_dict["scatter"], "scatter")
1、由于对于不同的响应内容,前端展示不同
比如:直接输出字符串答案,或者绘制表格、条形图、散点图、折线图等。
所以要设计提示词,引导ai对不同内容进行区分。
一个办法是,规定响应的答案格式是字典,里面的键值表示了是什么样的内容(比如answer对应字符串内容,table表示表格,bar条形图,line折线图,scatter散点图),
易于后续分类讨论解析。
注意:仔细检查prompt有没有格式错误,或者中英文标点符号错误
2、
json.loads
是 Python 标准库json
模块中的一个重要函数,主要用于将 JSON 格式的字符串解析为 Python 对象。
3、
从你给出的错误信息可知,在调用
create_csv_agent
或者create_pandas_dataframe_agent
时,程序抛出了ValueError
异常。错误原因:
create_pandas_dataframe_agent
这类代理会依赖 Python REPL(交互式解释器)工具来执行任意代码,这存在安全风险。为了防止潜在的安全问题,在使用此功能前,你必须明确表示同意使用,也就是要把allow_dangerous_code
参数设置为True
。
4、把file_content = uploaded_file.read()改成file_content = uploaded_file.getvalue()
因为前端里有一句df=pd.read_csv(csv_file),会让读指针移到文件末尾,所以再用read读就是空。
补充:
关闭文件后,文件指针并不会回到最开始的位置,文件对象也不再处于可用状态,无法直接获取其指针位置信息。
当你调用文件对象的
close()
方法关闭文件时,系统会释放与该文件相关的资源,包括文件描述符等。此时,文件对象在内存中的状态被改变,不再维护之前的文件指针位置。如果后续你想要再次读取文件内容,需要重新打开文件,而重新打开文件时,文件指针默认会位于文件开头(除非你使用特定的模式打开文件,例如以追加模式'a'
或'a+'
打开文件,文件指针会位于文件末尾 )。
5、