戒酒的李白

Fixing Streamlit bugs.

"""
Streamlit Web界面
Deep Search Agent提供友好的Web界面
Insight Agent提供友好的Web界面
"""
import os
... ... @@ -19,54 +19,25 @@ from config import DEEPSEEK_API_KEY, KIMI_API_KEY, DB_HOST, DB_USER, DB_PASSWORD
def main():
"""主函数"""
st.set_page_config(
page_title="Deep Search Agent",
page_icon="🔍",
page_title="Insight Agent",
page_icon="",
layout="wide"
)
st.title("Insight Engine Agent")
st.markdown("基于DeepSeek的本地舆情数据库深度分析AI代理")
# 侧边栏配置
with st.sidebar:
st.header("配置")
# 模型选择
llm_provider = st.selectbox("LLM提供商", ["deepseek", "openai", "kimi"])
# 高级配置
st.subheader("高级配置")
max_reflections = st.slider("反思次数", 1, 5, 2)
# 根据选择的模型动态调整默认值
if llm_provider == "kimi":
default_content_length = 500000 # Kimi支持长文本,使用更大的默认值
max_limit = 1000000 # 提高上限
st.info("💡 Kimi模型支持超长文本处理,建议使用更大的内容长度以充分利用其能力")
else:
default_content_length = 200000
max_limit = 500000
max_content_length = st.number_input("最大内容长度", 10000, max_limit, default_content_length)
# 初始化所有可能的变量
openai_key = ""
kimi_key = ""
if llm_provider == "deepseek":
model_name = st.selectbox("DeepSeek模型", ["deepseek-chat"])
elif llm_provider == "openai":
model_name = st.selectbox("OpenAI模型", ["gpt-4o-mini", "gpt-4o"])
openai_key = st.text_input("OpenAI API Key", type="password",
value="")
else: # kimi
model_name = st.selectbox("Kimi模型", ["kimi-k2-0711-preview"])
kimi_key = st.text_input("Kimi API Key", type="password",
value="")
st.title("Insight Agent")
st.markdown("私有舆情数据库深度分析AI代理")
# ----- 配置被硬编码 -----
# 强制使用 Kimi
llm_provider = "kimi"
model_name = "kimi-k2-0711-preview"
# 默认高级配置
max_reflections = 2
max_content_length = 500000 # Kimi支持长文本
# 主界面
col1, col2 = st.columns([2, 1])
with col1:
st.header("研究查询")
query = st.text_area(
... ... @@ -74,21 +45,7 @@ def main():
placeholder="例如:2025年人工智能发展趋势",
height=100
)
# 预设查询示例
st.subheader("示例查询")
example_queries = [
"2025年人工智能发展趋势",
"深度学习在医疗领域的应用",
"区块链技术的最新发展",
"可持续能源技术趋势",
"量子计算的发展现状"
]
selected_example = st.selectbox("选择示例查询", ["自定义"] + example_queries)
if selected_example != "自定义":
query = selected_example
with col2:
st.header("状态信息")
if 'agent' in st.session_state and hasattr(st.session_state.agent, 'state'):
... ... @@ -98,41 +55,36 @@ def main():
st.progress(progress['progress_percentage'] / 100)
else:
st.info("尚未开始研究")
# 执行按钮
col1, col2, col3 = st.columns([1, 1, 1])
with col2:
col1_btn, col2_btn, col3_btn = st.columns([1, 1, 1])
with col2_btn:
start_research = st.button("开始研究", type="primary", use_container_width=True)
# 验证配置
if start_research:
if not query.strip():
st.error("请输入研究查询")
return
if llm_provider == "openai" and not openai_key:
st.error("请提供OpenAI API Key")
return
if llm_provider == "kimi" and not kimi_key and not KIMI_API_KEY:
st.error("请提供Kimi API Key或在配置文件中设置KIMI_API_KEY")
# 由于强制使用Kimi,只检查KIMI_API_KEY
if not KIMI_API_KEY:
st.error("请在您的配置文件(config.py)中设置KIMI_API_KEY")
return
# 自动使用配置文件中的API密钥和数据库配置
deepseek_key = DEEPSEEK_API_KEY
kimi_key_final = kimi_key if kimi_key else KIMI_API_KEY
db_host = DB_HOST
db_user = DB_USER
db_password = DB_PASSWORD
db_name = DB_NAME
db_port = DB_PORT
db_charset = DB_CHARSET
# 创建配置
config = Config(
deepseek_api_key=deepseek_key if llm_provider == "deepseek" else None,
openai_api_key=openai_key if llm_provider == "openai" else None,
kimi_api_key=kimi_key_final if llm_provider == "kimi" else None,
deepseek_api_key=None,
openai_api_key=None,
kimi_api_key=KIMI_API_KEY, # 强制使用配置文件中的Kimi Key
db_host=db_host,
db_user=db_user,
db_password=db_password,
... ... @@ -140,14 +92,14 @@ def main():
db_port=db_port,
db_charset=db_charset,
default_llm_provider=llm_provider,
deepseek_model=model_name if llm_provider == "deepseek" else "deepseek-chat",
openai_model=model_name if llm_provider == "openai" else "gpt-4o-mini",
kimi_model=model_name if llm_provider == "kimi" else "kimi-k2-0711-preview",
deepseek_model="deepseek-chat", # 保留默认值以兼容
openai_model="gpt-4o-mini", # 保留默认值以兼容
kimi_model=model_name,
max_reflections=max_reflections,
max_content_length=max_content_length,
output_dir="insight_engine_streamlit_reports"
)
# 执行研究
execute_research(query, config)
... ... @@ -158,51 +110,51 @@ def execute_research(query: str, config: Config):
# 创建进度条
progress_bar = st.progress(0)
status_text = st.empty()
# 初始化Agent
status_text.text("正在初始化Agent...")
agent = DeepSearchAgent(config)
st.session_state.agent = agent
progress_bar.progress(10)
# 生成报告结构
status_text.text("正在生成报告结构...")
agent._generate_report_structure(query)
progress_bar.progress(20)
# 处理段落
total_paragraphs = len(agent.state.paragraphs)
for i in range(total_paragraphs):
status_text.text(f"正在处理段落 {i+1}/{total_paragraphs}: {agent.state.paragraphs[i].title}")
status_text.text(f"正在处理段落 {i + 1}/{total_paragraphs}: {agent.state.paragraphs[i].title}")
# 初始搜索和总结
agent._initial_search_and_summary(i)
progress_value = 20 + (i + 0.5) / total_paragraphs * 60
progress_bar.progress(int(progress_value))
# 反思循环
agent._reflection_loop(i)
agent.state.paragraphs[i].research.mark_completed()
progress_value = 20 + (i + 1) / total_paragraphs * 60
progress_bar.progress(int(progress_value))
# 生成最终报告
status_text.text("正在生成最终报告...")
final_report = agent._generate_final_report()
progress_bar.progress(90)
# 保存报告
status_text.text("正在保存报告...")
agent._save_report(final_report)
progress_bar.progress(100)
status_text.text("研究完成!")
# 显示结果
display_results(agent, final_report)
except Exception as e:
st.error(f"研究过程中发生错误: {str(e)}")
... ... @@ -210,61 +162,41 @@ def execute_research(query: str, config: Config):
def display_results(agent: DeepSearchAgent, final_report: str):
"""显示研究结果"""
st.header("研究结果")
# 结果标签页
tab1, tab2, tab3 = st.tabs(["最终报告", "详细信息", "下载"])
# 结果标签页(已移除下载选项)
tab1, tab2 = st.tabs(["最终报告", "详细信息"])
with tab1:
st.markdown(final_report)
with tab2:
# 段落详情
st.subheader("段落详情")
for i, paragraph in enumerate(agent.state.paragraphs):
with st.expander(f"段落 {i+1}: {paragraph.title}"):
with st.expander(f"段落 {i + 1}: {paragraph.title}"):
st.write("**预期内容:**", paragraph.content)
st.write("**最终内容:**", paragraph.research.latest_summary[:300] + "..."
if len(paragraph.research.latest_summary) > 300
else paragraph.research.latest_summary)
st.write("**最终内容:**", paragraph.research.latest_summary[:300] + "..."
if len(paragraph.research.latest_summary) > 300
else paragraph.research.latest_summary)
st.write("**搜索次数:**", paragraph.research.get_search_count())
st.write("**反思次数:**", paragraph.research.reflection_iteration)
# 搜索历史
st.subheader("搜索历史")
all_searches = []
for paragraph in agent.state.paragraphs:
all_searches.extend(paragraph.research.search_history)
if all_searches:
for i, search in enumerate(all_searches):
with st.expander(f"搜索 {i+1}: {search.query}"):
with st.expander(f"搜索 {i + 1}: {search.query}"):
st.write("**URL:**", search.url)
st.write("**标题:**", search.title)
st.write("**内容预览:**", search.content[:200] + "..." if len(search.content) > 200 else search.content)
st.write("**内容预览:**",
search.content[:200] + "..." if len(search.content) > 200 else search.content)
if search.score:
st.write("**相关度评分:**", search.score)
with tab3:
# 下载选项
st.subheader("下载报告")
# Markdown下载
st.download_button(
label="下载Markdown报告",
data=final_report,
file_name=f"deep_search_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md",
mime="text/markdown"
)
# JSON状态下载
state_json = agent.state.to_json()
st.download_button(
label="下载状态文件",
data=state_json,
file_name=f"deep_search_state_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
mime="application/json"
)
if __name__ == "__main__":
main()
main()
\ No newline at end of file
... ...
"""
Streamlit Web界面
Deep Search Agent提供友好的Web界面
Media Agent提供友好的Web界面
"""
import os
... ... @@ -19,38 +19,25 @@ from config import DEEPSEEK_API_KEY, BOCHA_Web_Search_API_KEY, GEMINI_API_KEY
def main():
"""主函数"""
st.set_page_config(
page_title="Deep Search Agent",
page_icon="🔍",
page_title="Media Agent",
page_icon="",
layout="wide"
)
st.title("Deep Search Agent")
st.markdown("基于DeepSeek的无框架深度搜索AI代理")
# 侧边栏配置
with st.sidebar:
st.header("配置")
# 高级配置
st.subheader("高级配置")
max_reflections = st.slider("反思次数", 1, 5, 2)
max_content_length = st.number_input("最大内容长度", 1000, 50000, 20000)
# 模型选择
llm_provider = st.selectbox("LLM提供商", ["deepseek", "openai", "gemini"])
openai_key = "" # 初始化变量
if llm_provider == "deepseek":
model_name = st.selectbox("DeepSeek模型", ["deepseek-chat"])
elif llm_provider == "openai":
model_name = st.selectbox("OpenAI模型", ["gpt-4o-mini", "gpt-4o"])
openai_key = st.text_input("OpenAI API Key", type="password", value="")
else: # gemini
model_name = st.selectbox("Gemini模型", ["gemini-2.5-pro"])
st.title("Media Agent")
st.markdown("具备强大多模态能力的AI代理")
# ----- 配置被硬编码 -----
# 强制使用 Gemini
llm_provider = "gemini"
model_name = "gemini-2.5-pro"
# 默认高级配置
max_reflections = 2
max_content_length = 20000
# 主界面
col1, col2 = st.columns([2, 1])
with col1:
st.header("研究查询")
query = st.text_area(
... ... @@ -58,21 +45,7 @@ def main():
placeholder="例如:2025年人工智能发展趋势",
height=100
)
# 预设查询示例
st.subheader("示例查询")
example_queries = [
"2025年人工智能发展趋势",
"深度学习在医疗领域的应用",
"区块链技术的最新发展",
"可持续能源技术趋势",
"量子计算的发展现状"
]
selected_example = st.selectbox("选择示例查询", ["自定义"] + example_queries)
if selected_example != "自定义":
query = selected_example
with col2:
st.header("状态信息")
if 'agent' in st.session_state and hasattr(st.session_state.agent, 'state'):
... ... @@ -82,42 +55,45 @@ def main():
st.progress(progress['progress_percentage'] / 100)
else:
st.info("尚未开始研究")
# 执行按钮
col1, col2, col3 = st.columns([1, 1, 1])
with col2:
col1_btn, col2_btn, col3_btn = st.columns([1, 1, 1])
with col2_btn:
start_research = st.button("开始研究", type="primary", use_container_width=True)
# 验证配置
if start_research:
if not query.strip():
st.error("请输入研究查询")
return
if llm_provider == "openai" and not openai_key:
st.error("请提供OpenAI API Key")
# 由于强制使用Gemini,检查相关的API密钥
if not GEMINI_API_KEY:
st.error("请在您的配置文件(config.py)中设置GEMINI_API_KEY")
return
if not BOCHA_Web_Search_API_KEY:
st.error("请在您的配置文件(config.py)中设置BOCHA_Web_Search_API_KEY")
return
# 自动使用配置文件中的API密钥
deepseek_key = DEEPSEEK_API_KEY
gemini_key = GEMINI_API_KEY # 使用config.py中的Gemini API密钥
gemini_key = GEMINI_API_KEY
bocha_key = BOCHA_Web_Search_API_KEY
# 创建配置
config = Config(
deepseek_api_key=deepseek_key if llm_provider == "deepseek" else None,
openai_api_key=openai_key if llm_provider == "openai" else None,
gemini_api_key=gemini_key if llm_provider == "gemini" else None,
deepseek_api_key=None,
openai_api_key=None,
gemini_api_key=gemini_key,
bocha_api_key=bocha_key,
default_llm_provider=llm_provider,
deepseek_model=model_name if llm_provider == "deepseek" else "deepseek-chat",
openai_model=model_name if llm_provider == "openai" else "gpt-4o-mini",
gemini_model=model_name if llm_provider == "gemini" else "gemini-2.5-pro",
deepseek_model="deepseek-chat", # 保留默认值以兼容
openai_model="gpt-4o-mini", # 保留默认值以兼容
gemini_model=model_name,
max_reflections=max_reflections,
max_content_length=max_content_length,
output_dir="media_engine_streamlit_reports"
)
# 执行研究
execute_research(query, config)
... ... @@ -128,51 +104,51 @@ def execute_research(query: str, config: Config):
# 创建进度条
progress_bar = st.progress(0)
status_text = st.empty()
# 初始化Agent
status_text.text("正在初始化Agent...")
agent = DeepSearchAgent(config)
st.session_state.agent = agent
progress_bar.progress(10)
# 生成报告结构
status_text.text("正在生成报告结构...")
agent._generate_report_structure(query)
progress_bar.progress(20)
# 处理段落
total_paragraphs = len(agent.state.paragraphs)
for i in range(total_paragraphs):
status_text.text(f"正在处理段落 {i+1}/{total_paragraphs}: {agent.state.paragraphs[i].title}")
status_text.text(f"正在处理段落 {i + 1}/{total_paragraphs}: {agent.state.paragraphs[i].title}")
# 初始搜索和总结
agent._initial_search_and_summary(i)
progress_value = 20 + (i + 0.5) / total_paragraphs * 60
progress_bar.progress(int(progress_value))
# 反思循环
agent._reflection_loop(i)
agent.state.paragraphs[i].research.mark_completed()
progress_value = 20 + (i + 1) / total_paragraphs * 60
progress_bar.progress(int(progress_value))
# 生成最终报告
status_text.text("正在生成最终报告...")
final_report = agent._generate_final_report()
progress_bar.progress(90)
# 保存报告
status_text.text("正在保存报告...")
agent._save_report(final_report)
progress_bar.progress(100)
status_text.text("研究完成!")
# 显示结果
display_results(agent, final_report)
except Exception as e:
st.error(f"研究过程中发生错误: {str(e)}")
... ... @@ -180,61 +156,41 @@ def execute_research(query: str, config: Config):
def display_results(agent: DeepSearchAgent, final_report: str):
"""显示研究结果"""
st.header("研究结果")
# 结果标签页
tab1, tab2, tab3 = st.tabs(["最终报告", "详细信息", "下载"])
# 结果标签页(已移除下载选项)
tab1, tab2 = st.tabs(["最终报告", "详细信息"])
with tab1:
st.markdown(final_report)
with tab2:
# 段落详情
st.subheader("段落详情")
for i, paragraph in enumerate(agent.state.paragraphs):
with st.expander(f"段落 {i+1}: {paragraph.title}"):
with st.expander(f"段落 {i + 1}: {paragraph.title}"):
st.write("**预期内容:**", paragraph.content)
st.write("**最终内容:**", paragraph.research.latest_summary[:300] + "..."
if len(paragraph.research.latest_summary) > 300
else paragraph.research.latest_summary)
st.write("**最终内容:**", paragraph.research.latest_summary[:300] + "..."
if len(paragraph.research.latest_summary) > 300
else paragraph.research.latest_summary)
st.write("**搜索次数:**", paragraph.research.get_search_count())
st.write("**反思次数:**", paragraph.research.reflection_iteration)
# 搜索历史
st.subheader("搜索历史")
all_searches = []
for paragraph in agent.state.paragraphs:
all_searches.extend(paragraph.research.search_history)
if all_searches:
for i, search in enumerate(all_searches):
with st.expander(f"搜索 {i+1}: {search.query}"):
with st.expander(f"搜索 {i + 1}: {search.query}"):
st.write("**URL:**", search.url)
st.write("**标题:**", search.title)
st.write("**内容预览:**", search.content[:200] + "..." if len(search.content) > 200 else search.content)
st.write("**内容预览:**",
search.content[:200] + "..." if len(search.content) > 200 else search.content)
if search.score:
st.write("**相关度评分:**", search.score)
with tab3:
# 下载选项
st.subheader("下载报告")
# Markdown下载
st.download_button(
label="下载Markdown报告",
data=final_report,
file_name=f"deep_search_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md",
mime="text/markdown"
)
# JSON状态下载
state_json = agent.state.to_json()
st.download_button(
label="下载状态文件",
data=state_json,
file_name=f"deep_search_state_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
mime="application/json"
)
if __name__ == "__main__":
main()
main()
\ No newline at end of file
... ...
"""
Streamlit Web界面
Deep Search Agent提供友好的Web界面
Query Agent提供友好的Web界面
"""
import os
... ... @@ -19,36 +19,25 @@ from config import DEEPSEEK_API_KEY, TAVILY_API_KEY
def main():
"""主函数"""
st.set_page_config(
page_title="Deep Search Agent",
page_icon="🔍",
page_title="Query Agent",
page_icon="",
layout="wide"
)
st.title("Deep Search Agent")
st.markdown("基于DeepSeek的无框架深度搜索AI代理")
# 侧边栏配置
with st.sidebar:
st.header("配置")
# 高级配置
st.subheader("高级配置")
max_reflections = st.slider("反思次数", 1, 5, 2)
max_content_length = st.number_input("最大内容长度", 1000, 50000, 20000)
# 模型选择
llm_provider = st.selectbox("LLM提供商", ["deepseek", "openai"])
if llm_provider == "deepseek":
model_name = st.selectbox("DeepSeek模型", ["deepseek-chat"])
else:
model_name = st.selectbox("OpenAI模型", ["gpt-4o-mini", "gpt-4o"])
openai_key = st.text_input("OpenAI API Key", type="password",
value="")
st.title("Query Agent")
st.markdown("具备强大网页搜索能力的AI代理")
# ----- 配置被硬编码 -----
# 强制使用 DeepSeek
llm_provider = "deepseek"
model_name = "deepseek-chat"
# 默认高级配置
max_reflections = 2
max_content_length = 20000
# 主界面
col1, col2 = st.columns([2, 1])
with col1:
st.header("研究查询")
query = st.text_area(
... ... @@ -56,21 +45,7 @@ def main():
placeholder="例如:2025年人工智能发展趋势",
height=100
)
# 预设查询示例
st.subheader("示例查询")
example_queries = [
"2025年人工智能发展趋势",
"深度学习在医疗领域的应用",
"区块链技术的最新发展",
"可持续能源技术趋势",
"量子计算的发展现状"
]
selected_example = st.selectbox("选择示例查询", ["自定义"] + example_queries)
if selected_example != "自定义":
query = selected_example
with col2:
st.header("状态信息")
if 'agent' in st.session_state and hasattr(st.session_state.agent, 'state'):
... ... @@ -80,39 +55,43 @@ def main():
st.progress(progress['progress_percentage'] / 100)
else:
st.info("尚未开始研究")
# 执行按钮
col1, col2, col3 = st.columns([1, 1, 1])
with col2:
col1_btn, col2_btn, col3_btn = st.columns([1, 1, 1])
with col2_btn:
start_research = st.button("开始研究", type="primary", use_container_width=True)
# 验证配置
if start_research:
if not query.strip():
st.error("请输入研究查询")
return
if llm_provider == "openai" and not openai_key:
st.error("请提供OpenAI API Key")
# 由于强制使用DeepSeek,检查相关的API密钥
if not DEEPSEEK_API_KEY:
st.error("请在您的配置文件(config.py)中设置DEEPSEEK_API_KEY")
return
if not TAVILY_API_KEY:
st.error("请在您的配置文件(config.py)中设置TAVILY_API_KEY")
return
# 自动使用配置文件中的API密钥
deepseek_key = DEEPSEEK_API_KEY
tavily_key = TAVILY_API_KEY
# 创建配置
config = Config(
deepseek_api_key=deepseek_key if llm_provider == "deepseek" else None,
openai_api_key=openai_key if llm_provider == "openai" else None,
deepseek_api_key=deepseek_key,
openai_api_key=None,
tavily_api_key=tavily_key,
default_llm_provider=llm_provider,
deepseek_model=model_name if llm_provider == "deepseek" else "deepseek-chat",
openai_model=model_name if llm_provider == "openai" else "gpt-4o-mini",
deepseek_model=model_name,
openai_model="gpt-4o-mini", # 保留默认值以兼容
max_reflections=max_reflections,
max_content_length=max_content_length,
output_dir="query_engine_streamlit_reports"
)
# 执行研究
execute_research(query, config)
... ... @@ -123,51 +102,51 @@ def execute_research(query: str, config: Config):
# 创建进度条
progress_bar = st.progress(0)
status_text = st.empty()
# 初始化Agent
status_text.text("正在初始化Agent...")
agent = DeepSearchAgent(config)
st.session_state.agent = agent
progress_bar.progress(10)
# 生成报告结构
status_text.text("正在生成报告结构...")
agent._generate_report_structure(query)
progress_bar.progress(20)
# 处理段落
total_paragraphs = len(agent.state.paragraphs)
for i in range(total_paragraphs):
status_text.text(f"正在处理段落 {i+1}/{total_paragraphs}: {agent.state.paragraphs[i].title}")
status_text.text(f"正在处理段落 {i + 1}/{total_paragraphs}: {agent.state.paragraphs[i].title}")
# 初始搜索和总结
agent._initial_search_and_summary(i)
progress_value = 20 + (i + 0.5) / total_paragraphs * 60
progress_bar.progress(int(progress_value))
# 反思循环
agent._reflection_loop(i)
agent.state.paragraphs[i].research.mark_completed()
progress_value = 20 + (i + 1) / total_paragraphs * 60
progress_bar.progress(int(progress_value))
# 生成最终报告
status_text.text("正在生成最终报告...")
final_report = agent._generate_final_report()
progress_bar.progress(90)
# 保存报告
status_text.text("正在保存报告...")
agent._save_report(final_report)
progress_bar.progress(100)
status_text.text("研究完成!")
# 显示结果
display_results(agent, final_report)
except Exception as e:
st.error(f"研究过程中发生错误: {str(e)}")
... ... @@ -175,61 +154,41 @@ def execute_research(query: str, config: Config):
def display_results(agent: DeepSearchAgent, final_report: str):
"""显示研究结果"""
st.header("研究结果")
# 结果标签页
tab1, tab2, tab3 = st.tabs(["最终报告", "详细信息", "下载"])
# 结果标签页(已移除下载选项)
tab1, tab2 = st.tabs(["最终报告", "详细信息"])
with tab1:
st.markdown(final_report)
with tab2:
# 段落详情
st.subheader("段落详情")
for i, paragraph in enumerate(agent.state.paragraphs):
with st.expander(f"段落 {i+1}: {paragraph.title}"):
with st.expander(f"段落 {i + 1}: {paragraph.title}"):
st.write("**预期内容:**", paragraph.content)
st.write("**最终内容:**", paragraph.research.latest_summary[:300] + "..."
if len(paragraph.research.latest_summary) > 300
else paragraph.research.latest_summary)
st.write("**最终内容:**", paragraph.research.latest_summary[:300] + "..."
if len(paragraph.research.latest_summary) > 300
else paragraph.research.latest_summary)
st.write("**搜索次数:**", paragraph.research.get_search_count())
st.write("**反思次数:**", paragraph.research.reflection_iteration)
# 搜索历史
st.subheader("搜索历史")
all_searches = []
for paragraph in agent.state.paragraphs:
all_searches.extend(paragraph.research.search_history)
if all_searches:
for i, search in enumerate(all_searches):
with st.expander(f"搜索 {i+1}: {search.query}"):
with st.expander(f"搜索 {i + 1}: {search.query}"):
st.write("**URL:**", search.url)
st.write("**标题:**", search.title)
st.write("**内容预览:**", search.content[:200] + "..." if len(search.content) > 200 else search.content)
st.write("**内容预览:**",
search.content[:200] + "..." if len(search.content) > 200 else search.content)
if search.score:
st.write("**相关度评分:**", search.score)
with tab3:
# 下载选项
st.subheader("下载报告")
# Markdown下载
st.download_button(
label="下载Markdown报告",
data=final_report,
file_name=f"deep_search_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md",
mime="text/markdown"
)
# JSON状态下载
state_json = agent.state.to_json()
st.download_button(
label="下载状态文件",
data=state_json,
file_name=f"deep_search_state_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json",
mime="application/json"
)
if __name__ == "__main__":
main()
main()
\ No newline at end of file
... ...
# 深度研究报告
- [深度研究报告](#深度研究报告)
- [1. 事件全景:从5秒抓痒到18亿阅读](#1-事件全景从5秒抓痒到18亿阅读)
- [2. 当事双方:谁在风暴中心](#2-当事双方谁在风暴中心)
- [3. 舆论温度表:数据·声浪·情绪](#3-舆论温度表数据声浪情绪)
- [3.1 平台热度排行榜](#31-平台热度排行榜)
- [3.2 学生集体表情](#32-学生集体表情)
- [4. 现行防治机制:漏洞与鸿沟](#4-现行防治机制漏洞与鸿沟)
- [5. 改革呼声:制度补洞,人心如何补](#5-改革呼声制度补洞人心如何补)
- [5.1 针锋相对的两种方案](#51-针锋相对的两种方案)
- [5.2 学生真实焦虑](#52-学生真实焦虑)
- [6. 结论:当樱花再次飘落](#6-结论当樱花再次飘落)
---
## 1. 事件全景:从5秒抓痒到18亿阅读
| 时间节点 | 关键动作 | 全网热度 |
|---|---|---|
| **2023-07-11** | 肖同学抓痒被拍;杨某媛现场要求手写“道歉” | 校内口口相传 |
| **2023-10-11** | 杨某媛凌晨发布剪辑视频,贴“性骚扰”标签 | 4小时破亿阅读 |
| **2023-10-13** | 学校红头文件:记过处分,取消保研资格 | 微博热搜第一 |
| **2025-07-25** | 法院一审:*“无法认定性骚扰”* | #武大仍未撤销处分# 3.7亿阅读 |
| **2025-07-27** | 杨某媛晒香港浸会大学博士录取 | 小红书3.2万赞“姐姐好飒” |
| **2025-07-31** | 校长回应“等上级安排” | B站弹幕刷屏“青春谁来赔” |
---
## 2. 当事双方:谁在风暴中心
| 维度 | 肖同学(19岁,本科) | 杨某媛(22岁,研二) |
|---|---|---|
| **现实代价** | - PTSD确诊<br>- 爷爷去世<br>- 保研名额归零 | - 获名校录取<br>- 被贴“诬告者”标签<br>- 论文漏洞遭群嘲 |
| **网络处境** | 私信辱骂、家庭住址被曝光 | 小红书“飒姐”人设与“学术妲己”并存 |
| **制度结果** | 记过处分仍挂官网 | 无校纪追责 |
---
## 3. 舆论温度表:数据·声浪·情绪
### 3.1 平台热度排行榜
| 平台 | 主话题阅读量/播放量 | 最高同时在线 |
|---|---|---|
| 微博 | 18.4亿 | 62%情绪为“愤怒” |
| 抖音 | 12.7亿 | “气死了”弹幕 3.7条/10秒 |
| 知乎 | 4.2万条回答 | 热帖“为什么高校举报石沉大海” |
| B站 | 50万+弹幕 | “樱花没开,我们也没脸开”刷屏 |
| 小红书 | 900万+ #我也遇到过# | “恐惧”指数↑12个百分点 |
### 3.2 学生集体表情
- **珞珈山水BBS**:深夜在线4100+,热帖《旧图书馆的猫》2.3万点亮
- **匿名树洞**:“我们不是沉默,是怕成为下一个杨某” 1.1万赞
- **微信群/QQ群**统一刷屏:
> “如果樱花会说话,它会哭吗?”
---
## 4. 现行防治机制:漏洞与鸿沟
| 制度环节 | 学生遭遇 | 舆情高频词 |
|---|---|---|
| **举报入口** | 按钮形同虚设,需“两名证人签字” | “证据链陷阱” |
| **调查流程** | 3个月无书面回复,信息被群发泄露 | “裸奔式举报” |
| **心理支持** | 心理评估报告被质疑“主观” | “二次伤害” |
| **结果反馈** | 多数仅为“谈话提醒” | “息事宁人” |
> “我们怕的不是色狼,而是色狼背后那张‘维护学校声誉’的遮羞布。”
> ——微博高赞留言,转发5.2万次
---
## 5. 改革呼声:制度补洞,人心如何补
### 5.1 针锋相对的两种方案
| 主张方 | 核心观点 | 代表语录 |
|---|---|---|
| **北大法学院教授** | 法院未认定即自动冻结校纪处分 | “行政权不能凌驾司法权” |
| **华东师大性别研究基地** | 建立“司法—校纪”双轨听证 | “让双方都能说话” |
### 5.2 学生真实焦虑
- **问卷数据**:45%选择“说不清”现有措施能否让自己更安心
- **深夜留言**
> “我更怕风吹草动时,第一反应是‘我会不会被二次伤害’。”
---
## 6. 结论:当樱花再次飘落
1. **真相跑不赢情绪**:从5秒抓痒到18亿阅读,网络审判只用了4小时。
2. **制度性缺位**:封闭调查、信息泄露、权力不对等,让学生不敢按下“发送”。
3. **双输结局**:肖同学失去前途与健康,杨某媛背负标签与质疑,学校公信力折损。
4. **改革关键**
- 司法结果与校纪处分**刚性挂钩**
- 建立**第三方独立调查+隐私保护**双保险
- 把“零”从摄像头数量转向**每个人心里的那杆秤**
> 樱花会再次盛开,但落在地上的花瓣提醒我们:
> **如果制度不补洞,明年的风还会吹来新的眼泪。**
\ No newline at end of file
... ...
This diff could not be displayed because it is too large.
# 深度研究报告
- [深度研究报告](#深度研究报告)
- [1. 事件全景:从5秒抓痒到18亿阅读](#1-事件全景从5秒抓痒到18亿阅读)
- [2. 当事双方:谁在风暴中心](#2-当事双方谁在风暴中心)
- [3. 舆论温度表:数据·声浪·情绪](#3-舆论温度表数据声浪情绪)
- [3.1 平台热度排行榜](#31-平台热度排行榜)
- [3.2 学生集体表情](#32-学生集体表情)
- [4. 现行防治机制:漏洞与鸿沟](#4-现行防治机制漏洞与鸿沟)
- [5. 改革呼声:制度补洞,人心如何补](#5-改革呼声制度补洞人心如何补)
- [5.1 针锋相对的两种方案](#51-针锋相对的两种方案)
- [5.2 学生真实焦虑](#52-学生真实焦虑)
- [6. 结论:当樱花再次飘落](#6-结论当樱花再次飘落)
---
## 1. 事件全景:从5秒抓痒到18亿阅读
| 时间节点 | 关键动作 | 全网热度 |
|---|---|---|
| **2023-07-11** | 肖同学抓痒被拍;杨某媛现场要求手写“道歉” | 校内口口相传 |
| **2023-10-11** | 杨某媛凌晨发布剪辑视频,贴“性骚扰”标签 | 4小时破亿阅读 |
| **2023-10-13** | 学校红头文件:记过处分,取消保研资格 | 微博热搜第一 |
| **2025-07-25** | 法院一审:*“无法认定性骚扰”* | #武大仍未撤销处分# 3.7亿阅读 |
| **2025-07-27** | 杨某媛晒香港浸会大学博士录取 | 小红书3.2万赞“姐姐好飒” |
| **2025-07-31** | 校长回应“等上级安排” | B站弹幕刷屏“青春谁来赔” |
---
## 2. 当事双方:谁在风暴中心
| 维度 | 肖同学(19岁,本科) | 杨某媛(22岁,研二) |
|---|---|---|
| **现实代价** | - PTSD确诊<br>- 爷爷去世<br>- 保研名额归零 | - 获名校录取<br>- 被贴“诬告者”标签<br>- 论文漏洞遭群嘲 |
| **网络处境** | 私信辱骂、家庭住址被曝光 | 小红书“飒姐”人设与“学术妲己”并存 |
| **制度结果** | 记过处分仍挂官网 | 无校纪追责 |
---
## 3. 舆论温度表:数据·声浪·情绪
### 3.1 平台热度排行榜
| 平台 | 主话题阅读量/播放量 | 最高同时在线 |
|---|---|---|
| 微博 | 18.4亿 | 62%情绪为“愤怒” |
| 抖音 | 12.7亿 | “气死了”弹幕 3.7条/10秒 |
| 知乎 | 4.2万条回答 | 热帖“为什么高校举报石沉大海” |
| B站 | 50万+弹幕 | “樱花没开,我们也没脸开”刷屏 |
| 小红书 | 900万+ #我也遇到过# | “恐惧”指数↑12个百分点 |
### 3.2 学生集体表情
- **珞珈山水BBS**:深夜在线4100+,热帖《旧图书馆的猫》2.3万点亮
- **匿名树洞**:“我们不是沉默,是怕成为下一个杨某” 1.1万赞
- **微信群/QQ群**统一刷屏:
> “如果樱花会说话,它会哭吗?”
---
## 4. 现行防治机制:漏洞与鸿沟
| 制度环节 | 学生遭遇 | 舆情高频词 |
|---|---|---|
| **举报入口** | 按钮形同虚设,需“两名证人签字” | “证据链陷阱” |
| **调查流程** | 3个月无书面回复,信息被群发泄露 | “裸奔式举报” |
| **心理支持** | 心理评估报告被质疑“主观” | “二次伤害” |
| **结果反馈** | 多数仅为“谈话提醒” | “息事宁人” |
> “我们怕的不是色狼,而是色狼背后那张‘维护学校声誉’的遮羞布。”
> ——微博高赞留言,转发5.2万次
---
## 5. 改革呼声:制度补洞,人心如何补
### 5.1 针锋相对的两种方案
| 主张方 | 核心观点 | 代表语录 |
|---|---|---|
| **北大法学院教授** | 法院未认定即自动冻结校纪处分 | “行政权不能凌驾司法权” |
| **华东师大性别研究基地** | 建立“司法—校纪”双轨听证 | “让双方都能说话” |
### 5.2 学生真实焦虑
- **问卷数据**:45%选择“说不清”现有措施能否让自己更安心
- **深夜留言**
> “我更怕风吹草动时,第一反应是‘我会不会被二次伤害’。”
---
## 6. 结论:当樱花再次飘落
1. **真相跑不赢情绪**:从5秒抓痒到18亿阅读,网络审判只用了4小时。
2. **制度性缺位**:封闭调查、信息泄露、权力不对等,让学生不敢按下“发送”。
3. **双输结局**:肖同学失去前途与健康,杨某媛背负标签与质疑,学校公信力折损。
4. **改革关键**
- 司法结果与校纪处分**刚性挂钩**
- 建立**第三方独立调查+隐私保护**双保险
- 把“零”从摄像头数量转向**每个人心里的那杆秤**
> 樱花会再次盛开,但落在地上的花瓣提醒我们:
> **如果制度不补洞,明年的风还会吹来新的眼泪。**
\ No newline at end of file
... ...
"""
Streamlit Web界面
为DInsight Agent提供友好的Web界面
"""
import os
import sys
import streamlit as st
from datetime import datetime
import json
# 添加src目录到Python路径
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from InsightEngine import DeepSearchAgent, Config
from config import DEEPSEEK_API_KEY, KIMI_API_KEY, DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, DB_PORT, DB_CHARSET
def main():
"""主函数"""
st.set_page_config(
page_title="Insight Agent",
page_icon="",
layout="wide"
)
st.title("Insight Engine")
st.markdown("本地舆情数据库深度分析AI代理")
# ----- 配置被硬编码 -----
# 强制使用 Kimi
llm_provider = "kimi"
model_name = "kimi-k2-0711-preview"
# 默认高级配置
max_reflections = 2
max_content_length = 500000 # Kimi支持长文本
# 主界面
col1, col2 = st.columns([2, 1])
with col1:
st.header("研究查询")
query = st.text_area(
"请输入您要研究的问题",
placeholder="例如:2025年人工智能发展趋势",
height=100
)
with col2:
st.header("状态信息")
if 'agent' in st.session_state and hasattr(st.session_state.agent, 'state'):
progress = st.session_state.agent.get_progress_summary()
st.metric("总段落数", progress['total_paragraphs'])
st.metric("已完成", progress['completed_paragraphs'])
st.progress(progress['progress_percentage'] / 100)
else:
st.info("尚未开始研究")
# 执行按钮
col1_btn, col2_btn, col3_btn = st.columns([1, 1, 1])
with col2_btn:
start_research = st.button("开始研究", type="primary", use_container_width=True)
# 验证配置
if start_research:
if not query.strip():
st.error("请输入研究查询")
return
# 由于强制使用Kimi,只检查KIMI_API_KEY
if not KIMI_API_KEY:
st.error("请在您的配置文件(config.py)中设置KIMI_API_KEY")
return
# 自动使用配置文件中的API密钥和数据库配置
db_host = DB_HOST
db_user = DB_USER
db_password = DB_PASSWORD
db_name = DB_NAME
db_port = DB_PORT
db_charset = DB_CHARSET
# 创建配置
config = Config(
deepseek_api_key=None,
openai_api_key=None,
kimi_api_key=KIMI_API_KEY, # 强制使用配置文件中的Kimi Key
db_host=db_host,
db_user=db_user,
db_password=db_password,
db_name=db_name,
db_port=db_port,
db_charset=db_charset,
default_llm_provider=llm_provider,
deepseek_model="deepseek-chat", # 保留默认值以兼容
openai_model="gpt-4o-mini", # 保留默认值以兼容
kimi_model=model_name,
max_reflections=max_reflections,
max_content_length=max_content_length,
output_dir="insight_engine_streamlit_reports"
)
# 执行研究
execute_research(query, config)
def execute_research(query: str, config: Config):
"""执行研究"""
try:
# 创建进度条
progress_bar = st.progress(0)
status_text = st.empty()
# 初始化Agent
status_text.text("正在初始化Agent...")
agent = DeepSearchAgent(config)
st.session_state.agent = agent
progress_bar.progress(10)
# 生成报告结构
status_text.text("正在生成报告结构...")
agent._generate_report_structure(query)
progress_bar.progress(20)
# 处理段落
total_paragraphs = len(agent.state.paragraphs)
for i in range(total_paragraphs):
status_text.text(f"正在处理段落 {i + 1}/{total_paragraphs}: {agent.state.paragraphs[i].title}")
# 初始搜索和总结
agent._initial_search_and_summary(i)
progress_value = 20 + (i + 0.5) / total_paragraphs * 60
progress_bar.progress(int(progress_value))
# 反思循环
agent._reflection_loop(i)
agent.state.paragraphs[i].research.mark_completed()
progress_value = 20 + (i + 1) / total_paragraphs * 60
progress_bar.progress(int(progress_value))
# 生成最终报告
status_text.text("正在生成最终报告...")
final_report = agent._generate_final_report()
progress_bar.progress(90)
# 保存报告
status_text.text("正在保存报告...")
agent._save_report(final_report)
progress_bar.progress(100)
status_text.text("研究完成!")
# 显示结果
display_results(agent, final_report)
except Exception as e:
st.error(f"研究过程中发生错误: {str(e)}")
def display_results(agent: DeepSearchAgent, final_report: str):
"""显示研究结果"""
st.header("研究结果")
# 结果标签页(已移除下载选项)
tab1, tab2 = st.tabs(["最终报告", "详细信息"])
with tab1:
st.markdown(final_report)
with tab2:
# 段落详情
st.subheader("段落详情")
for i, paragraph in enumerate(agent.state.paragraphs):
with st.expander(f"段落 {i + 1}: {paragraph.title}"):
st.write("**预期内容:**", paragraph.content)
st.write("**最终内容:**", paragraph.research.latest_summary[:300] + "..."
if len(paragraph.research.latest_summary) > 300
else paragraph.research.latest_summary)
st.write("**搜索次数:**", paragraph.research.get_search_count())
st.write("**反思次数:**", paragraph.research.reflection_iteration)
# 搜索历史
st.subheader("搜索历史")
all_searches = []
for paragraph in agent.state.paragraphs:
all_searches.extend(paragraph.research.search_history)
if all_searches:
for i, search in enumerate(all_searches):
with st.expander(f"搜索 {i + 1}: {search.query}"):
st.write("**URL:**", search.url)
st.write("**标题:**", search.title)
st.write("**内容预览:**",
search.content[:200] + "..." if len(search.content) > 200 else search.content)
if search.score:
st.write("**相关度评分:**", search.score)
if __name__ == "__main__":
main()
\ No newline at end of file
... ...
This diff could not be displayed because it is too large.
# 深度研究报告
- [深度研究报告](#深度研究报告)
- [1. 事件全景:从5秒抓痒到18亿阅读](#1-事件全景从5秒抓痒到18亿阅读)
- [2. 当事双方:谁在风暴中心](#2-当事双方谁在风暴中心)
- [3. 舆论温度表:数据·声浪·情绪](#3-舆论温度表数据声浪情绪)
- [3.1 平台热度排行榜](#31-平台热度排行榜)
- [3.2 学生集体表情](#32-学生集体表情)
- [4. 现行防治机制:漏洞与鸿沟](#4-现行防治机制漏洞与鸿沟)
- [5. 改革呼声:制度补洞,人心如何补](#5-改革呼声制度补洞人心如何补)
- [5.1 针锋相对的两种方案](#51-针锋相对的两种方案)
- [5.2 学生真实焦虑](#52-学生真实焦虑)
- [6. 结论:当樱花再次飘落](#6-结论当樱花再次飘落)
---
## 1. 事件全景:从5秒抓痒到18亿阅读
| 时间节点 | 关键动作 | 全网热度 |
|---|---|---|
| **2023-07-11** | 肖同学抓痒被拍;杨某媛现场要求手写“道歉” | 校内口口相传 |
| **2023-10-11** | 杨某媛凌晨发布剪辑视频,贴“性骚扰”标签 | 4小时破亿阅读 |
| **2023-10-13** | 学校红头文件:记过处分,取消保研资格 | 微博热搜第一 |
| **2025-07-25** | 法院一审:*“无法认定性骚扰”* | #武大仍未撤销处分# 3.7亿阅读 |
| **2025-07-27** | 杨某媛晒香港浸会大学博士录取 | 小红书3.2万赞“姐姐好飒” |
| **2025-07-31** | 校长回应“等上级安排” | B站弹幕刷屏“青春谁来赔” |
---
## 2. 当事双方:谁在风暴中心
| 维度 | 肖同学(19岁,本科) | 杨某媛(22岁,研二) |
|---|---|---|
| **现实代价** | - PTSD确诊<br>- 爷爷去世<br>- 保研名额归零 | - 获名校录取<br>- 被贴“诬告者”标签<br>- 论文漏洞遭群嘲 |
| **网络处境** | 私信辱骂、家庭住址被曝光 | 小红书“飒姐”人设与“学术妲己”并存 |
| **制度结果** | 记过处分仍挂官网 | 无校纪追责 |
---
## 3. 舆论温度表:数据·声浪·情绪
### 3.1 平台热度排行榜
| 平台 | 主话题阅读量/播放量 | 最高同时在线 |
|---|---|---|
| 微博 | 18.4亿 | 62%情绪为“愤怒” |
| 抖音 | 12.7亿 | “气死了”弹幕 3.7条/10秒 |
| 知乎 | 4.2万条回答 | 热帖“为什么高校举报石沉大海” |
| B站 | 50万+弹幕 | “樱花没开,我们也没脸开”刷屏 |
| 小红书 | 900万+ #我也遇到过# | “恐惧”指数↑12个百分点 |
### 3.2 学生集体表情
- **珞珈山水BBS**:深夜在线4100+,热帖《旧图书馆的猫》2.3万点亮
- **匿名树洞**:“我们不是沉默,是怕成为下一个杨某” 1.1万赞
- **微信群/QQ群**统一刷屏:
> “如果樱花会说话,它会哭吗?”
---
## 4. 现行防治机制:漏洞与鸿沟
| 制度环节 | 学生遭遇 | 舆情高频词 |
|---|---|---|
| **举报入口** | 按钮形同虚设,需“两名证人签字” | “证据链陷阱” |
| **调查流程** | 3个月无书面回复,信息被群发泄露 | “裸奔式举报” |
| **心理支持** | 心理评估报告被质疑“主观” | “二次伤害” |
| **结果反馈** | 多数仅为“谈话提醒” | “息事宁人” |
> “我们怕的不是色狼,而是色狼背后那张‘维护学校声誉’的遮羞布。”
> ——微博高赞留言,转发5.2万次
---
## 5. 改革呼声:制度补洞,人心如何补
### 5.1 针锋相对的两种方案
| 主张方 | 核心观点 | 代表语录 |
|---|---|---|
| **北大法学院教授** | 法院未认定即自动冻结校纪处分 | “行政权不能凌驾司法权” |
| **华东师大性别研究基地** | 建立“司法—校纪”双轨听证 | “让双方都能说话” |
### 5.2 学生真实焦虑
- **问卷数据**:45%选择“说不清”现有措施能否让自己更安心
- **深夜留言**
> “我更怕风吹草动时,第一反应是‘我会不会被二次伤害’。”
---
## 6. 结论:当樱花再次飘落
1. **真相跑不赢情绪**:从5秒抓痒到18亿阅读,网络审判只用了4小时。
2. **制度性缺位**:封闭调查、信息泄露、权力不对等,让学生不敢按下“发送”。
3. **双输结局**:肖同学失去前途与健康,杨某媛背负标签与质疑,学校公信力折损。
4. **改革关键**
- 司法结果与校纪处分**刚性挂钩**
- 建立**第三方独立调查+隐私保护**双保险
- 把“零”从摄像头数量转向**每个人心里的那杆秤**
> 樱花会再次盛开,但落在地上的花瓣提醒我们:
> **如果制度不补洞,明年的风还会吹来新的眼泪。**
\ No newline at end of file
... ...
"""
Streamlit Web界面
为DInsight Agent提供友好的Web界面
"""
import os
import sys
import streamlit as st
from datetime import datetime
import json
# 添加src目录到Python路径
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from InsightEngine import DeepSearchAgent, Config
from config import DEEPSEEK_API_KEY, KIMI_API_KEY, DB_HOST, DB_USER, DB_PASSWORD, DB_NAME, DB_PORT, DB_CHARSET
def main():
"""主函数"""
st.set_page_config(
page_title="Insight Agent",
page_icon="",
layout="wide"
)
st.title("Insight Engine")
st.markdown("本地舆情数据库深度分析AI代理")
# ----- 配置被硬编码 -----
# 强制使用 Kimi
llm_provider = "kimi"
model_name = "kimi-k2-0711-preview"
# 默认高级配置
max_reflections = 2
max_content_length = 500000 # Kimi支持长文本
# 主界面
col1, col2 = st.columns([2, 1])
with col1:
st.header("研究查询")
query = st.text_area(
"请输入您要研究的问题",
placeholder="例如:2025年人工智能发展趋势",
height=100
)
with col2:
st.header("状态信息")
if 'agent' in st.session_state and hasattr(st.session_state.agent, 'state'):
progress = st.session_state.agent.get_progress_summary()
st.metric("总段落数", progress['total_paragraphs'])
st.metric("已完成", progress['completed_paragraphs'])
st.progress(progress['progress_percentage'] / 100)
else:
st.info("尚未开始研究")
# 执行按钮
col1_btn, col2_btn, col3_btn = st.columns([1, 1, 1])
with col2_btn:
start_research = st.button("开始研究", type="primary", use_container_width=True)
# 验证配置
if start_research:
if not query.strip():
st.error("请输入研究查询")
return
# 由于强制使用Kimi,只检查KIMI_API_KEY
if not KIMI_API_KEY:
st.error("请在您的配置文件(config.py)中设置KIMI_API_KEY")
return
# 自动使用配置文件中的API密钥和数据库配置
db_host = DB_HOST
db_user = DB_USER
db_password = DB_PASSWORD
db_name = DB_NAME
db_port = DB_PORT
db_charset = DB_CHARSET
# 创建配置
config = Config(
deepseek_api_key=None,
openai_api_key=None,
kimi_api_key=KIMI_API_KEY, # 强制使用配置文件中的Kimi Key
db_host=db_host,
db_user=db_user,
db_password=db_password,
db_name=db_name,
db_port=db_port,
db_charset=db_charset,
default_llm_provider=llm_provider,
deepseek_model="deepseek-chat", # 保留默认值以兼容
openai_model="gpt-4o-mini", # 保留默认值以兼容
kimi_model=model_name,
max_reflections=max_reflections,
max_content_length=max_content_length,
output_dir="insight_engine_streamlit_reports"
)
# 执行研究
execute_research(query, config)
def execute_research(query: str, config: Config):
"""执行研究"""
try:
# 创建进度条
progress_bar = st.progress(0)
status_text = st.empty()
# 初始化Agent
status_text.text("正在初始化Agent...")
agent = DeepSearchAgent(config)
st.session_state.agent = agent
progress_bar.progress(10)
# 生成报告结构
status_text.text("正在生成报告结构...")
agent._generate_report_structure(query)
progress_bar.progress(20)
# 处理段落
total_paragraphs = len(agent.state.paragraphs)
for i in range(total_paragraphs):
status_text.text(f"正在处理段落 {i + 1}/{total_paragraphs}: {agent.state.paragraphs[i].title}")
# 初始搜索和总结
agent._initial_search_and_summary(i)
progress_value = 20 + (i + 0.5) / total_paragraphs * 60
progress_bar.progress(int(progress_value))
# 反思循环
agent._reflection_loop(i)
agent.state.paragraphs[i].research.mark_completed()
progress_value = 20 + (i + 1) / total_paragraphs * 60
progress_bar.progress(int(progress_value))
# 生成最终报告
status_text.text("正在生成最终报告...")
final_report = agent._generate_final_report()
progress_bar.progress(90)
# 保存报告
status_text.text("正在保存报告...")
agent._save_report(final_report)
progress_bar.progress(100)
status_text.text("研究完成!")
# 显示结果
display_results(agent, final_report)
except Exception as e:
st.error(f"研究过程中发生错误: {str(e)}")
def display_results(agent: DeepSearchAgent, final_report: str):
"""显示研究结果"""
st.header("研究结果")
# 结果标签页(已移除下载选项)
tab1, tab2 = st.tabs(["最终报告", "详细信息"])
with tab1:
st.markdown(final_report)
with tab2:
# 段落详情
st.subheader("段落详情")
for i, paragraph in enumerate(agent.state.paragraphs):
with st.expander(f"段落 {i + 1}: {paragraph.title}"):
st.write("**预期内容:**", paragraph.content)
st.write("**最终内容:**", paragraph.research.latest_summary[:300] + "..."
if len(paragraph.research.latest_summary) > 300
else paragraph.research.latest_summary)
st.write("**搜索次数:**", paragraph.research.get_search_count())
st.write("**反思次数:**", paragraph.research.reflection_iteration)
# 搜索历史
st.subheader("搜索历史")
all_searches = []
for paragraph in agent.state.paragraphs:
all_searches.extend(paragraph.research.search_history)
if all_searches:
for i, search in enumerate(all_searches):
with st.expander(f"搜索 {i + 1}: {search.query}"):
st.write("**URL:**", search.url)
st.write("**标题:**", search.title)
st.write("**内容预览:**",
search.content[:200] + "..." if len(search.content) > 200 else search.content)
if search.score:
st.write("**相关度评分:**", search.score)
if __name__ == "__main__":
main()
\ No newline at end of file
... ...
This diff could not be displayed because it is too large.