戒酒的李白

Fixing Streamlit bugs.

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