AutoSTAT / prompt_engineer /sec1_call_llm.py
ElvisWang111's picture
Upload folder using huggingface_hub
495d32d verified
import re
import streamlit as st
from typing import IO, List
from prompt_engineer.call_llm import LLMClient
class DataLoadingAgent(LLMClient):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.file_name = []
self.user_input = None
self.par_content = ""
self.dfs = None
self.abstract=None
self.full = None
self.finish_auto_task = False
def finish_auto(self):
self.finish_auto_task = True
def save_file_name(self, file_name):
self.file_name.append(file_name)
def load_file_name(self):
return self.file_name
def save_dfs(self, dfs):
self.dfs = (dfs)
def load_dfs(self):
return self.dfs
def clear_file_name(self):
self.file_name = []
def read_names_from_file(self, uploaded_names_file, df_head):
"""
从上传的 .names/.arff 文件中提取属性名。
优先使用 LLM 识别 @attribute 行中的属性名;如果 LLM 调用失败,退回到正则解析。
"""
raw = uploaded_names_file.read().decode('utf-8', errors='ignore')
try:
uploaded_names_file.seek(0)
except Exception:
pass
prompt = (
"下面是上传的 names 和 df_head 文件内容,请仅以 Python 列表格式返回与df_head一一对应的所有属性(attribute)名称,"
"并保持顺序,不要添加多余文字,请注意,你只需要返回一个列表,不要出现任何markdown语法:\n```\n"
f"name文件:{raw}\n```"
f"df_head:{df_head}\n```"
)
try:
response = self.call(prompt)
names_list = eval(response.strip())
if isinstance(names_list, list) and all(isinstance(n, str) for n in names_list):
col_names = names_list
else:
raise ValueError("LLM 输出格式不正确")
except Exception:
col_names = []
attr_re = re.compile(
r"""^@attribute\s+
['"]?([^'"\s]+)['"]?
\s+.+
""",
re.IGNORECASE | re.VERBOSE
)
for line in raw.splitlines():
line = line.strip()
if not line:
continue
if line.lower().startswith('@data'):
break
m = attr_re.match(line)
if m:
col_names.append(m.group(1))
counts: dict[str, int] = {}
unique_names: List[str] = []
for name in col_names:
if name in counts:
counts[name] += 1
unique_names.append(f"{name}_{counts[name]}")
else:
counts[name] = 0
unique_names.append(name)
return unique_names
def do_data_description(self, df, user_input=None, memory_limit=6):
recent_memory = self.memory[-memory_limit:] if self.memory else []
if recent_memory:
formatted_memory = "\n".join(
f"{m['role']}: {m['content']}" for m in recent_memory
)
memory_block = f"{formatted_memory}"
else:
memory_block = ""
prompt = (
"你是一名专业的数据分析助手,负责解释数据结构与业务含义。\n"
f"- 数据维度:{df.shape[0]} 行 × {df.shape[1]} 列\n"
f"- 列名和数据类型:{dict(zip(df.columns.tolist(), df.dtypes.astype(str).tolist()))}\n"
f"- 前 5 行样本:\n{df.head().to_dict(orient='list')}\n\n"
f"""- 数据解释聊天对话:
--- 开始聊天记录 ---
{memory_block}
--- 结束聊天记录 ---"""
)
if user_input is not None:
prompt += f"""
请严格依据用户需求“{user_input}”,对当前数据进行深入、系统的分析。
要求:
1. 分析内容必须与该需求完全对应,不能添加无关推断。
2. 结论要具体、清晰,可直接支持后续报告撰写或建模步骤。
3. 分析语言应专业、简洁,不使用模糊或情绪化表述。
"""
else:
prompt += """
以下是一个数据集的基本概览。请帮助我分析它的性质和结构,并回答以下问题:
1. 该数据集可能来源于什么业务或研究场景?
2. 各主要字段分别代表什么含义?若能判断,请说明其单位或数值含义。
3. 数据中是否存在明显异常、异常分布或需要注意的特征?
输出要求:
- 使用自然、流畅的中文描述;
- 采用清晰的分条结构(1、2、3);
- 语言客观简洁,不使用“可能”“也许”“似乎”等模糊词;
- 重点突出数据结构、含义与潜在问题。
"""
if st.session_state.preference_select:
prompt += f"以下是用户的分析偏好设置:{st.session_state.preference_select}”。\n\n"
if st.session_state.additional_preference:
prompt += f"用户提供了以下建模目的与特殊需求:{st.session_state.additional_preference}”。\n\n"
desc = self.call(prompt)
return desc
def summary_html(self):
df = self.load_df()
df_head = df.head()
dtype_info = df.dtypes.astype(str)
prompt = f"""
你正在撰写一份数据分析报告的第一章——《数据概览与数据含义分析》。
请根据以下输入内容,整理关键信息并进行分析说明:
数据格式:
{dtype_info}
前五行数据:
{df_head}
数据解释聊天对话:
--- 开始聊天记录 ---
{self.memory}
--- 结束聊天记录 ---
额外要求:
1. 要用流畅的自然语言
2. 不要滥用形容词和副词,尽量用简单的动词和名词表达意思
3. 不用"可能""也许""似乎""微妙"等模糊表述
""".strip()
desc = self.call(prompt)
summary = {
"title": "数据导入",
"df": df_head,
"desc": desc,
}
return summary
def summary_word(self):
return self.summary_html()
def check_abstract(self):
if self.abstract is None:
df = self.load_df()
df_head = df.head()
dtype_info = df.dtypes.astype(str)
prompt = f"""
这是数据分析的数据导入阶段
数据格式:
{dtype_info}
前五行数据:
{df_head}
数据解释聊天对话:
--- 开始聊天记录 ---
{self.memory}
--- 结束聊天记录 ---
要求:
请基于上述数据与对话内容,生成一段简洁、准确的综合摘要。
摘要需完整呈现核心信息,便于后续自动判断该内容在报告撰写中是否需要被引用。
""".strip()
desc = self.call(prompt)
self.abstract = desc
return self.abstract
def check_full(self):
if self.full is None:
df = self.load_df()
df_head = df.head()
dtype_info = df.dtypes.astype(str)
self.full = (
f"【阶段说明】这是数据分析流程中的数据导入阶段。\n"
f"【数据格式】{dtype_info}\n"
f"【样本预览】\n{df_head}\n"
f"【分析对话记录】\n{self.memory}"
)
return self.full