1 line
81 KiB
JSON
1 line
81 KiB
JSON
{"repo": "666woshinibab/aichat", "files": {"main.py": {"6f734b16dfccab1f2bfc951cdee936eb8cd385b5": {"t": 1785747501.0163882, "n": 69235, "h": "21772a7c59fcc713", "c": "import wave\r\nimport pandas as pd\r\nimport matplotlib.pyplot as plt\r\nimport uuid\r\nimport pickle\r\nimport json\r\nimport warnings\r\nimport sqlite3\r\nimport requests\r\nfrom PIL import Image\r\nimport base64\r\nfrom gtts import gTTS\r\nimport datetime\r\nimport pyaudio\r\nimport mysql.connector\r\nimport re\r\nimport wikipedia\r\nimport pytz\r\nfrom langchain.chains import ConversationalRetrievalChain, ConversationChain\r\nfrom langchain.chains.flare.prompts import PROMPT_TEMPLATE\r\nfrom langchain.memory import ConversationBufferMemory\r\nfrom langchain_community.chat_models import ChatOpenAI\r\nfrom langchain_community.document_loaders import TextLoader, PyPDFLoader, Docx2txtLoader\r\nfrom langchain_community.vectorstores import FAISS\r\nfrom langchain.text_splitter import RecursiveCharacterTextSplitter\r\nfrom langchain_experimental.agents import create_pandas_dataframe_agent\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain.tools import Tool\r\nfrom langchain.agents import AgentType\r\nfrom langchain_experimental.utilities import PythonREPL\r\nfrom user_db import UserDB\r\nimport os\r\nimport speech_recognition as sr\r\nimport streamlit as st\r\nfrom io import BytesIO\r\n\r\nPROMPT_TEMPLATE = \"\"\"你是一位数据分析助手,你的回应内容取决于用户的请求内容,请按照下面的步骤处理用户请求:\r\n\r\n1. 思考阶段 (Thought) :先分析用户请求类型(文字回答/表格/图表),并验证数据类型是否匹配。\r\n2. 行动阶段 (Action) :根据分析结果选择以下严格对应的格式。\r\n - 纯文字回答: \r\n {\"answer\": \"不超过50个字符的明确答案\"}\r\n\r\n - 表格数据: \r\n {\"table\":{\"columns\":[\"列名1\", \"列名2\", ...], \"data\":[[\"第一行值1\", \"值2\", ...], [\"第二行值1\", \"值2\", ...]]}}\r\n\r\n - 柱状图 \r\n {\"bar\":{\"columns\": [\"A\", \"B\", \"C\", ...], \"data\":[35, 42, 29, ...]}}\r\n\r\n - 折线图 \r\n {\"line\":{\"columns\": [\"A\", \"B\", \"C\", ...], \"data\": [35, 42, 29, ...]}}\r\n\r\n3. 格式校验要求\r\n - 字符串值必须使用英文双引号\r\n - 数值类型不得添加引号\r\n - 确保数组闭合无遗漏\r\n\r\n 错误案例:{'columns':['Product', 'Sales'], data:[[A001, 200]]} \r\n 正确案例:{\"columns\":[\"product\", \"sales\"], \"data\":[[\"A001\", 200]]}\r\n\r\n注意:响应数据的\"output\"中不要有换行符、制表符以及其他格式符号。\r\n\r\n当前用户请求:\"\"\"\r\n\r\n\r\n# 从test1导入dataframe_agent函数\r\ndef dataframe_agent(df, query):\r\n try:\r\n # 确保 DataFrame 不是空的\r\n if df.empty:\r\n return {\"answer\": \"错误:数据集为空,无法进行分析\"}\r\n\r\n # 创建模型\r\n model = ChatOpenAI(\r\n model=\"deepseek-chat\",\r\n base_url='https://api.deepseek.com',\r\n api_key='sk-62d08d23019c4d74bdfb1495abe8f489',\r\n temperature=0,\r\n max_tokens=2048\r\n )\r\n\r\n # 创建代理\r\n agent = create_pandas_dataframe_agent(\r\n llm=model,\r\n df=df,\r\n agent_type=AgentType.OPENAI_FUNCTIONS, # 使用更可靠的代理类型\r\n agent_executor_kwargs={\"handle_parsing_errors\": True},\r\n max_iterations=8, # 减少迭代次数防止超时\r\n early_stopping_method='generate',\r\n allow_dangerous_code=True,\r\n verbose=True\r\n )\r\n\r\n # 使用正确的提示模板\r\n prompt = PROMPT_TEMPLATE + query\r\n\r\n # 调用代理\r\n response = agent.invoke({\"input\": prompt})\r\n return json.loads(response[\"output\"])\r\n\r\n # 处理响应\r\n try:\r\n output = response[\"output\"]\r\n # 尝试解析 JSON\r\n try:\r\n return json.loads(output)\r\n except json.JSONDecodeError:\r\n # 尝试提取可能的 JSON 部分\r\n start_idx = output.find('{')\r\n end_idx = output.rfind('}') + 1\r\n if start_idx != -1 and end_idx != 0:\r\n json_str = output[start_idx:end_idx]\r\n return json.loads(json_str)\r\n else:\r\n # 返回原始文本\r\n return {\"answer\": output}\r\n except KeyError:\r\n return {\"answer\": \"未获取到有效的分析结果\"}\r\n\r\n except Exception as e:\r\n # 返回详细错误信息\r\n return {\"answer\": f\"分析过程中发生错误: {str(e)}\"}\r\n\r\n\r\n\r\nwarnings.filterwarnings('ignore')\r\n\r\n# 页面设置\r\nst.set_page_config(\r\n page_title=\"六棵松互联智能分析平台\",\r\n layout=\"wide\",\r\n page_icon=\"🤖\",\r\n initial_sidebar_state=\"expanded\"\r\n)\r\n\r\n# 自定义CSS样式\r\n# 固定浅色主题 CSS\r\nst.markdown(\"\"\"\r\n<style>\r\n@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap');\r\n\r\n.stApp {\r\n --color-primary: #0077ff;\r\n --color-secondary: #00c3ff;\r\n --color-accent: #ff0080;\r\n --color-bg: #f5f5f5;\r\n --color-card: #ffffff;\r\n --color-text: #111111;\r\n --color-shadow: rgba(0, 0, 0, 0.1);\r\n\r\n font-family: 'Montserrat', sans-serif !important;\r\n background-color: var(--color-bg);\r\n color: var(--color-text);\r\n}\r\n\r\n/* 按钮 */\r\n.stButton>button {\r\n background: linear-gradient(45deg, var(--color-primary), var(--color-accent));\r\n color: #fff;\r\n font-weight: 700;\r\n border: none;\r\n border-radius: 30px;\r\n padding: 14px 30px;\r\n box-shadow: 0 0 20px var(--color-primary);\r\n cursor: pointer;\r\n transition: all 0.4s ease;\r\n text-transform: uppercase;\r\n letter-spacing: 1.2px;\r\n}\r\n.stButton>button:hover {\r\n background: linear-gradient(45deg, var(--color-accent), var(--color-primary));\r\n box-shadow: 0 0 30px var(--color-accent), 0 0 40px var(--color-primary);\r\n transform: scale(1.1);\r\n}\r\n\r\n/* 输入框等 */\r\n.stTextInput input,\r\n.stTextArea textarea,\r\n.stSelectbox div[data-baseweb=\"select\"],\r\n.stFileUploader div {\r\n background: var(--color-card);\r\n border: 1.5px solid var(--color-primary);\r\n border-radius: 15px;\r\n color: var(--color-text);\r\n padding: 15px 20px;\r\n box-shadow: 0 0 8px var(--color-primary);\r\n transition: border-color 0.3s ease, box-shadow 0.3s ease;\r\n}\r\n\r\n/* Tabs 样式 */\r\n.stTabs [data-baseweb=\"tab\"] {\r\n background: var(--color-card);\r\n color: var(--color-text);\r\n border-radius: 10px 10px 0 0;\r\n padding: 10px 20px;\r\n margin-right: 5px;\r\n box-shadow: 0 0 12px var(--color-shadow);\r\n}\r\n.stTabs [aria-selected=\"true\"] {\r\n background: linear-gradient(45deg, var(--color-primary), var(--color-accent));\r\n color: white;\r\n box-shadow: 0 0 25px var(--color-accent);\r\n}\r\n\r\n/* 卡片/侧边栏 */\r\n.stSidebar, .stExpander, .card {\r\n background: var(--color-card);\r\n border-radius: 20px;\r\n box-shadow: 0 0 25px var(--color-shadow);\r\n color: var(--color-text);\r\n padding: 1rem;\r\n}\r\n\r\n/* 滑动条 */\r\ninput[type=\"range\"] {\r\n background: var(--color-secondary);\r\n box-shadow: 0 0 10px var(--color-primary);\r\n}\r\ninput[type=\"range\"]::-webkit-slider-thumb {\r\n background: var(--color-accent);\r\n box-shadow: 0 0 20px var(--color-accent);\r\n}\r\n\r\n/* 表格 */\r\ntable {\r\n background: var(--color-card);\r\n color: var(--color-text);\r\n border-radius: 12px;\r\n box-shadow: 0 0 15px var(--color-shadow);\r\n}\r\n</style>\r\n\"\"\", unsafe_allow_html=True)\r\n\r\n\r\n\r\n\r\ndef get_chat_response(llm, memory, user_prompt):\r\n \"\"\"用于构建带有对话记忆功能的聊天应用\"\"\"\r\n chain = ConversationChain(llm=llm, memory=memory)\r\n return chain.invoke({'input': user_prompt})['response']\r\n\r\n\r\ndef generate_summary(text, max_length=300):\r\n \"\"\"生成文本摘要\"\"\"\r\n model = ChatOpenAI(\r\n # model='gpt-3.5-turbo',\r\n # base_url='https://twapi.openai-hk.com/v1',\r\n # api_key='hk-3n6lv81000055630609b77f801914238092bf036f0495aa1',\r\n # temperature=0\r\n model=\"deepseek-chat\",\r\n base_url='https://api.deepseek.com',\r\n api_key='sk-62d08d23019c4d74bdfb1495abe8f489',\r\n temperature=0\r\n )\r\n prompt = f\"请为以下文本生成一个简洁的摘要(不超过{max_length}字):\\n\\n{text}\"\r\n return model.invoke(prompt).content\r\n\r\n\r\ndef get_answer(thy_question, session_state):\r\n model = ChatOpenAI(\r\n model='gpt-3.5-turbo',\r\n base_url='https://twapi.openai-hk.com/v1',\r\n api_key='hk-yq4ipo100005562375c7c3ac31e70baadb11e09f2040908b',\r\n temperature=0\r\n )\r\n if session_state['is_new_file']:\r\n loader = TextLoader(f'{session_state[\"session_id\"]}.txt', encoding='utf-8')\r\n docs = loader.load()\r\n text_splitter = RecursiveCharacterTextSplitter(\r\n chunk_size=1000,\r\n chunk_overlap=50,\r\n separators=[\"\\n\", \"。\", \"!\", \"?\", \",\", \"、\", \"\"]\r\n )\r\n texts = text_splitter.split_documents(docs)\r\n db = FAISS.from_documents(texts, session_state['em_model'])\r\n session_state['db'] = db\r\n session_state['is_new_file'] = False\r\n if 'db' in session_state:\r\n retriever = session_state['db'].as_retriever()\r\n chain = ConversationalRetrievalChain.from_llm(\r\n llm=model,\r\n retriever=retriever,\r\n memory=session_state['memory']\r\n )\r\n resp = chain.invoke({'chat_history': session_state['memory'], 'question': thy_question})\r\n return resp\r\n return ''\r\n\r\n\r\ndef preprocess_data(df):\r\n \"\"\"数据预处理函数\"\"\"\r\n with st.expander(\"🔧 数据预处理\", expanded=False):\r\n # 创建两列布局\r\n col1, col2 = st.columns(2)\r\n\r\n with col1:\r\n # 处理缺失值\r\n st.markdown(\"### 缺失值处理\")\r\n missing_action = st.selectbox(\r\n \"选择缺失值处理方式\",\r\n [\"不处理\", \"删除包含缺失值的行\", \"填充缺失值\"],\r\n key=\"missing_action\"\r\n )\r\n\r\n if missing_action == \"填充缺失值\":\r\n fill_method = st.selectbox(\r\n \"选择填充方法\",\r\n [\"用平均值填充\", \"用中位数填充\", \"用众数填充\", \"用指定值填充\"],\r\n key=\"fill_method\"\r\n )\r\n if fill_method == \"用指定值填充\":\r\n fill_value = st.text_input(\"输入填充值\", key=\"fill_value\")\r\n\r\n with col2:\r\n # 数据类型转换\r\n st.markdown(\"### 数据类型转换\")\r\n if st.checkbox(\"转换数据类型\", key=\"convert_dtypes\"):\r\n column_to_convert = st.selectbox(\r\n \"选择要转换的列\",\r\n df.columns,\r\n key=\"column_to_convert\"\r\n )\r\n new_type = st.selectbox(\r\n \"选择新类型\",\r\n [\"int\", \"float\", \"str\", \"datetime\"],\r\n key=\"new_type\"\r\n )\r\n\r\n # 数据过滤\r\n st.markdown(\"### 数据过滤\")\r\n if st.checkbox(\"应用数据过滤\", key=\"apply_filter\"):\r\n filter_column = st.selectbox(\r\n \"选择过滤列\",\r\n df.columns,\r\n key=\"filter_column\"\r\n )\r\n if pd.api.types.is_numeric_dtype(df[filter_column]):\r\n min_val, max_val = st.slider(\r\n \"选择数值范围\",\r\n float(df[filter_column].min()),\r\n float(df[filter_column].max()),\r\n (float(df[filter_column].min()), float(df[filter_column].max())),\r\n key=\"numeric_filter\"\r\n )\r\n else:\r\n unique_values = df[filter_column].unique()\r\n selected_values = st.multiselect(\r\n \"选择要保留的值\",\r\n unique_values,\r\n default=list(unique_values),\r\n key=\"categorical_filter\"\r\n )\r\n\r\n # 执行预处理按钮\r\n if st.button(\"🚀 应用预处理\", key=\"apply_preprocessing\", use_container_width=True):\r\n processed_df = df.copy()\r\n\r\n # 处理缺失值\r\n if missing_action == \"删除包含缺失值的行\":\r\n processed_df = processed_df.dropna()\r\n st.success(f\"已删除包含缺失值的行,剩余 {len(processed_df)} 行数据\")\r\n elif missing_action == \"填充缺失值\":\r\n if fill_method == \"用平均值填充\":\r\n processed_df = processed_df.fillna(processed_df.mean(numeric_only=True))\r\n elif fill_method == \"用中位数填充\":\r\n processed_df = processed_df.fillna(processed_df.median(numeric_only=True))\r\n elif fill_method == \"用众数填充\":\r\n for col in processed_df.columns:\r\n processed_df[col] = processed_df[col].fillna(processed_df[col].mode()[0])\r\n elif fill_method == \"用指定值填充\" and fill_value:\r\n try:\r\n # 尝试转换为数值类型\r\n try:\r\n fill_val = float(fill_value)\r\n except ValueError:\r\n fill_val = fill_value\r\n processed_df = processed_df.fillna(fill_val)\r\n except Exception as e:\r\n st.error(f\"填充过程中出错: {str(e)}\")\r\n\r\n # 数据类型转换\r\n if st.session_state.get(\"convert_dtypes\"):\r\n try:\r\n if new_type == \"int\":\r\n processed_df[column_to_convert] = processed_df[column_to_convert].astype(int)\r\n elif new_type == \"float\":\r\n processed_df[column_to_convert] = processed_df[column_to_convert].astype(float)\r\n elif new_type == \"str\":\r\n processed_df[column_to_convert] = processed_df[column_to_convert].astype(str)\r\n elif new_type == \"datetime\":\r\n processed_df[column_to_convert] = pd.to_datetime(processed_df[column_to_convert])\r\n st.success(f\"已将列 '{column_to_convert}' 转换为 {new_type} 类型\")\r\n except Exception as e:\r\n st.error(f\"类型转换失败: {str(e)}\")\r\n\r\n # 数据过滤\r\n if st.session_state.get(\"apply_filter\"):\r\n if pd.api.types.is_numeric_dtype(processed_df[filter_column]):\r\n processed_df = processed_df[\r\n (processed_df[filter_column] >= min_val) &\r\n (processed_df[filter_column] <= max_val)\r\n ]\r\n st.success(f\"已过滤 '{filter_column}' 列,保留范围: {min_val} 到 {max_val}\")\r\n else:\r\n processed_df = processed_df[processed_df[filter_column].isin(selected_values)]\r\n st.success(f\"已过滤 '{filter_column}' 列,保留选定的类别\")\r\n\r\n # 显示处理后的数据\r\n st.subheader(\"🔄 预处理后的数据\")\r\n st.dataframe(processed_df)\r\n\r\n return processed_df\r\n\r\n return df\r\n\r\n\r\ndef render_chart(chart_type, data):\r\n \"\"\"渲染不同类型的图表\"\"\"\r\n try:\r\n if chart_type == \"bar\":\r\n df = pd.DataFrame({\r\n \"x\": data[\"columns\"],\r\n \"y\": data[\"data\"]\r\n }).set_index(\"x\")\r\n st.bar_chart(df)\r\n\r\n elif chart_type == \"line\":\r\n df = pd.DataFrame({\r\n \"x\": data[\"columns\"],\r\n \"y\": data[\"data\"]\r\n }).set_index(\"x\")\r\n st.line_chart(df)\r\n\r\n elif chart_type == \"pie\":\r\n fig, ax = plt.subplots()\r\n ax.pie(data[\"data\"], labels=data[\"columns\"], autopct='%1.1f%%', startangle=90)\r\n ax.axis('equal')\r\n st.pyplot(fig)\r\n\r\n elif chart_type == \"scatter\":\r\n if len(data[\"columns\"]) >= 2:\r\n df = pd.DataFrame({\r\n \"x\": data[\"data\"][0],\r\n \"y\": data[\"data\"][1]\r\n })\r\n if len(data[\"columns\"]) >= 3:\r\n df[\"size\"] = data[\"data\"][2]\r\n st.scatter_chart(df, x=\"x\", y=\"y\", size=\"size\")\r\n else:\r\n st.scatter_chart(df, x=\"x\", y=\"y\")\r\n else:\r\n st.warning(\"散点图需要至少两个维度的数据\")\r\n\r\n elif chart_type == \"heatmap\":\r\n try:\r\n import seaborn as sns\r\n df = pd.DataFrame(data[\"data\"], columns=data[\"columns\"])\r\n plt.figure(figsize=(10, 8))\r\n sns.heatmap(df.corr(), annot=True, cmap='coolwarm', fmt=\".2f\")\r\n st.pyplot(plt.gcf())\r\n except ImportError:\r\n st.warning(\"渲染热力图需要seaborn库,请先安装\")\r\n\r\n except Exception as e:\r\n st.error(f\"渲染图表时出错: {str(e)}\")\r\n\r\n\r\ndef text_to_speech(text, lang='zh'):\r\n \"\"\"将文本转换为语音\"\"\"\r\n tts = gTTS(text=text, lang=lang, slow=False)\r\n audio_bytes = BytesIO()\r\n tts.write_to_fp(audio_bytes)\r\n audio_bytes.seek(0)\r\n return audio_bytes\r\n\r\n\r\ndef setup_plugins():\r\n \"\"\"设置插件系统(移除Google搜索,添加替代功能)\"\"\"\r\n plugins = []\r\n\r\n # 1. 维基百科搜索插件\r\n def wikipedia_search(query, lang='zh'):\r\n try:\r\n wikipedia.set_lang(lang)\r\n result = wikipedia.summary(query, sentences=2)\r\n return result\r\n except:\r\n return f\"未找到关于'{query}'的信息\"\r\n\r\n wikipedia_tool = Tool(\r\n name=\"维基百科搜索\",\r\n func=lambda query: wikipedia_search(query),\r\n description=\"使用维基百科获取知识信息\"\r\n )\r\n plugins.append(wikipedia_tool)\r\n\r\n # 2. 计算器插件\r\n def calculator(expression):\r\n try:\r\n # 安全计算数学表达式\r\n allowed_chars = \"0123456789+-*/(). \"\r\n if all(c in allowed_chars for c in expression):\r\n return str(eval(expression))\r\n else:\r\n return \"表达式包含不安全字符\"\r\n except Exception as e:\r\n return f\"计算错误: {str(e)}\"\r\n\r\n calc_tool = Tool(\r\n name=\"计算器\",\r\n func=calculator,\r\n description=\"计算数学表达式\"\r\n )\r\n plugins.append(calc_tool)\r\n\r\n # 3. 时间日期插件\r\n def get_datetime(timezone='Asia/Shanghai'):\r\n try:\r\n tz = pytz.timezone(timezone)\r\n now = datetime.datetime.now(tz)\r\n return now.strftime(\"%Y-%m-%d %H:%M:%S %Z\")\r\n except:\r\n return \"无法获取时间信息\"\r\n\r\n datetime_tool = Tool(\r\n name=\"时间日期\",\r\n func=get_datetime,\r\n description=\"获取当前时间和日期\"\r\n )\r\n plugins.append(datetime_tool)\r\n\r\n # 4. 单位转换插件\r\n def unit_converter(query):\r\n try:\r\n # 简单的单位转换实现\r\n conversions = {\r\n '公里': 1000,\r\n '千克': 1000,\r\n '小时': 3600\r\n }\r\n\r\n # 匹配类似 \"10公里 to 米\" 的格式\r\n pattern = r'(\\d+\\.?\\d*)\\s*(\\S+)\\s+to\\s+(\\S+)'\r\n match = re.match(pattern, query)\r\n if match:\r\n value = float(match.group(1))\r\n from_unit = match.group(2)\r\n to_unit = match.group(3)\r\n\r\n # 简单转换逻辑\r\n if from_unit == '公里' and to_unit == '米':\r\n return f\"{value} 公里 = {value * 1000} 米\"\r\n elif from_unit == '米' and to_unit == '公里':\r\n return f\"{value} 米 = {value / 1000} 公里\"\r\n elif from_unit == '千克' and to_unit == '克':\r\n return f\"{value} 千克 = {value * 1000} 克\"\r\n elif from_unit == '克' and to_unit == '千克':\r\n return f\"{value} 克 = {value / 1000} 千克\"\r\n elif from_unit == '小时' and to_unit == '分钟':\r\n return f\"{value} 小时 = {value * 60} 分钟\"\r\n elif from_unit == '分钟' and to_unit == '小时':\r\n return f\"{value} 分钟 = {value / 60:.2f} 小时\"\r\n\r\n return \"无法转换该单位,支持的转换:公里↔米,千克↔克,小时↔分钟\"\r\n except Exception as e:\r\n return f\"单位转换错误: {str(e)}\"\r\n\r\n unit_tool = Tool(\r\n name=\"单位转换\",\r\n func=unit_converter,\r\n description=\"转换不同单位(公里/米,千克/克,小时/分钟)\"\r\n )\r\n plugins.append(unit_tool)\r\n\r\n # 5. 文本翻译插件\r\n def translate_text(text, target_lang='en'):\r\n model = ChatOpenAI(\r\n model='gpt-3.5-turbo',\r\n base_url='https://twapi.openai-hk.com/v1',\r\n api_key='hk-yq4ipo100005562375c7c3ac31e70baadb11e09f2040908b',\r\n temperature=0\r\n )\r\n prompt = f\"将以下文本翻译为{target_lang}:\\n\\n{text}\"\r\n return model.invoke(prompt).content\r\n\r\n translate_tool = Tool(\r\n name=\"文本翻译\",\r\n func=lambda text: translate_text(text),\r\n description=\"将文本翻译为其他语言\"\r\n )\r\n plugins.append(translate_tool)\r\n\r\n # 6. 代码执行插件\r\n python_repl = PythonREPL()\r\n repl_tool = Tool(\r\n name=\"Python REPL\",\r\n func=python_repl.run,\r\n description=\"执行Python代码并返回结果\"\r\n )\r\n plugins.append(repl_tool)\r\n\r\n return plugins\r\n\r\n# 初始化用户数据库\r\n\r\nif 'user_db' not in st.session_state:\r\n st.session_state.user_db = UserDB(db_path='ai_platform_users.db')\r\n\r\n # 初始化聊天应用的记忆和消息\r\n if 'chat_messages' not in st.session_state:\r\n st.session_state['chat_messages'] = [{'role': 'ai', 'content': '你好主人,我是你的AI助手,我叫小美', 'avatar': '🤖'}]\r\n st.session_state['chat_memory'] = ConversationBufferMemory(return_messages=True)\r\n\r\n # 初始化插件\r\n if 'plugins' not in st.session_state:\r\n st.session_state['plugins'] = setup_plugins()\r\n\r\n # 初始化当前用户\r\n if 'current_user' not in st.session_state:\r\n st.session_state['current_user'] = None\r\n\r\n\r\n\r\n\r\n# 用户认证函数\r\n\r\ndef authenticate(username, password):\r\n \"\"\"用户认证\"\"\"\r\n try:\r\n success, result = st.session_state.user_db.authenticate(username, password)\r\n if success:\r\n st.session_state['current_user'] = username\r\n return success, result\r\n except Exception as e:\r\n # 如果数据库连接失败,提供备用方案\r\n st.error(f\"数据库连接失败: {str(e)}\")\r\n return False, \"系统暂时无法访问用户数据库,请稍后再试\"\r\n\r\n\r\n\r\n\r\n\r\n# 在页面设置之后,初始化 session_state 之前添加注册和登录函数\r\ndef register_user(username, password, confirm_password):\r\n \"\"\"注册新用户\"\"\"\r\n\r\n if password != confirm_password:\r\n return False, \"两次输入的密码不一致\"\r\n success, message = st.session_state.user_db.register_user(username, password,confirm_password)\r\n\r\n # 添加调试代码\r\n if success:\r\n print(f\"注册成功,检查数据库内容...\")\r\n try:\r\n with sqlite3.connect('users.db') as conn:\r\n cursor = conn.cursor()\r\n cursor.execute(\"SELECT * FROM users\")\r\n rows = cursor.fetchall()\r\n print(f\"当前用户表内容: {rows}\")\r\n except Exception as e:\r\n print(f\"检查数据库内容失败: {str(e)}\")\r\n\r\n return success, message\r\n\r\n\r\n\r\n\r\n# 修改后的初始化 session_state\r\nif 'session_id' not in st.session_state:\r\n st.session_state['memory'] = ConversationBufferMemory(\r\n return_messages=True,\r\n memory_key='chat_history',\r\n output_key='answer'\r\n )\r\n st.session_state['session_id'] = uuid.uuid4().hex\r\n st.session_state['is_new_file'] = False\r\n try:\r\n with open('D:\\AppGallery\\Downloads\\DANSANXIASHIXUN\\DAY07\\em.pkl', 'rb') as file_obj:\r\n em_model = pickle.load(file_obj)\r\n st.session_state['em_model'] = em_model\r\n except:\r\n st.session_state['em_model'] = None\r\n st.warning(\"未找到嵌入模型文件,部分功能可能受限\")\r\n\r\n # 初始化聊天应用的记忆和消息\r\n if 'chat_messages' not in st.session_state:\r\n st.session_state['chat_messages'] = [{'role': 'ai', 'content': '你好主人,我是你的AI助手,我叫小美', 'avatar': '🤖'}]\r\n st.session_state['chat_memory'] = ConversationBufferMemory(return_messages=True)\r\n\r\n # 初始化插件\r\n if 'plugins' not in st.session_state:\r\n st.session_state['plugins'] = setup_plugins()\r\n\r\n # 初始化用户系统 - 不再有默认用户\r\n if 'users' not in st.session_state:\r\n st.session_state['users'] = {}\r\n st.session_state['current_user'] = None\r\n\r\n\r\n\r\n# 侧边栏导航\r\nwith st.sidebar:\r\n\r\n st.title(\"📊 导航菜单\")\r\n\r\n # 用户登录/注册\r\n if st.session_state.get('current_user') is None:\r\n # 添加注册/登录选项卡\r\n tab1, tab2 = st.tabs([\"登录\", \"注册\"])\r\n\r\n with tab1:\r\n st.title(\"🔒 用户登录\")\r\n username = st.text_input(\"用户名\", key=\"login_username\")\r\n password = st.text_input(\"密码\", type=\"password\", key=\"login_password\")\r\n if st.button(\"登录\"):\r\n if username and password: # 确保用户名和密码不为空\r\n success, message = authenticate(username, password)\r\n if success:\r\n st.success(message)\r\n st.rerun()\r\n else:\r\n st.error(message) # 显示登录失败的具体原因\r\n else:\r\n st.error(\"用户名和密码不能为空\")\r\n\r\n with tab2:\r\n st.title(\"📝 用户注册\")\r\n new_username = st.text_input(\"新用户名\", key=\"reg_username\")\r\n new_password = st.text_input(\"新密码\", type=\"password\", key=\"reg_password\")\r\n confirm_password = st.text_input(\"确认密码\", type=\"password\", key=\"confirm_password\")\r\n\r\n if st.button(\"注册\"):\r\n if not new_username or not new_password:\r\n st.error(\"用户名和密码不能为空\")\r\n else:\r\n success, message = register_user(new_username, new_password, confirm_password)\r\n if success:\r\n st.success(message)\r\n else:\r\n st.error(message)\r\n\r\n st.title(\"🌟 六棵松互联智能分析平台\")\r\n st.warning(\"请先登录或注册以使用平台功能\")\r\n st.stop() # 阻止后续页面内容渲染\r\n\r\n else:\r\n st.subheader(f\"👤 当前用户: {st.session_state['current_user']}\")\r\n if st.button(\"退出登录\"):\r\n st.session_state['current_user'] = None\r\n st.rerun()\r\n\r\n st.divider()\r\n page = st.radio(\r\n \"选择功能模块\",\r\n [\"首页\", \"Excel数据分析\", \"CSV数据分析\", \"文本问答\", \"AI聊天助手\", \"数据库分析\", \"图像分析\", \"Web爬虫\"],\r\n index=0\r\n )\r\n# 主页面\r\nif page == \"首页\":\r\n st.title(\"🌟 六棵松互联智能分析平台\")\r\n st.subheader(\"一站式智能数据分析与AI助手解决方案\")\r\n\r\n # 功能卡片\r\n col1, col2, col3 = st.columns(3)\r\n with col1:\r\n st.markdown(\"\"\"\r\n <div class=\"feature-card fade-in\">\r\n <div class=\"feature-icon\">📊</div>\r\n <h3>数据分析</h3>\r\n <p>支持Excel、CSV等多种数据格式,提供强大的数据预处理和分析功能</p>\r\n </div>\r\n \"\"\", unsafe_allow_html=True)\r\n with col2:\r\n st.markdown(\"\"\"\r\n <div class=\"feature-card fade-in\">\r\n <div class=\"feature-icon\">💬</div>\r\n <h3>智能对话</h3>\r\n <p>ChatGPT式连续对话,支持自定义头像和多模态输入</p>\r\n </div>\r\n \"\"\", unsafe_allow_html=True)\r\n with col3:\r\n st.markdown(\"\"\"\r\n <div class=\"feature-card fade-in\">\r\n <div class=\"feature-icon\">🔌</div>\r\n <h3>插件系统</h3>\r\n <p>集成搜索、翻译、代码执行等多种插件,扩展平台能力</p>\r\n </div>\r\n \"\"\", unsafe_allow_html=True)\r\n\r\n col4, col5, col6 = st.columns(3)\r\n with col4:\r\n st.markdown(\"\"\"\r\n <div class=\"feature-card fade-in\">\r\n <div class=\"feature-icon\">🎙️</div>\r\n <h3>语音交互</h3>\r\n <p>支持语音输入和输出,提供更自然的交互体验</p>\r\n </div>\r\n \"\"\", unsafe_allow_html=True)\r\n with col5:\r\n st.markdown(\"\"\"\r\n <div class=\"feature-card fade-in\">\r\n <div class=\"feature-icon\">🕸️</div>\r\n <h3>Web爬虫</h3>\r\n <p>自动抓取网页内容并进行分析</p>\r\n </div>\r\n \"\"\", unsafe_allow_html=True)\r\n with col6:\r\n st.markdown(\"\"\"\r\n <div class=\"feature-card fade-in\">\r\n <div class=\"feature-icon\">👥</div>\r\n <h3>团队协作</h3>\r\n <p>多用户权限管理,支持团队协同工作</p>\r\n </div>\r\n \"\"\", unsafe_allow_html=True)\r\n\r\n st.divider()\r\n # 快速开始指南\r\n st.subheader(\"🚀 快速开始\")\r\n with st.expander(\"Excel/CSV数据分析\", expanded=True):\r\n st.write(\"\"\"\r\n 1. 在导航菜单中选择 **Excel数据分析** 或 **CSV数据分析** \r\n 2. 上传您的数据文件 \r\n 3. 使用数据预处理功能清洗数据 \r\n 4. 输入分析问题(例如:\"展示销售额前5的产品\") \r\n 5. 获取AI生成的分析结果和可视化图表 \r\n \"\"\")\r\n\r\n with st.expander(\"文本问答\", expanded=False):\r\n st.write(\"\"\"\r\n 1. 在导航菜单中选择 **文本问答** \r\n 2. 上传文本文件(TXT、PDF、DOCX) \r\n 3. 系统将自动生成文档摘要 \r\n 4. 输入您的问题(例如:\"文档的主要观点是什么?\") \r\n 5. 获取基于文档内容的精准答案 \r\n \"\"\")\r\n\r\n with st.expander(\"AI聊天助手\", expanded=False):\r\n st.write(\"\"\"\r\n 1. 在导航菜单中选择 **AI聊天助手** \r\n 2. 上传自定义头像(可选) \r\n 3. 使用文本或语音输入您的问题 \r\n 4. 与AI进行多轮连续对话 \r\n 5. 可选择语音输出功能收听回复 \r\n \"\"\")\r\nelse:\r\n if not st.session_state.get('current_user'):\r\n st.warning(\"🔒 请先登录以使用此功能\")\r\n st.info(\"请在左侧边栏登录您的账户\")\r\n st.stop()\r\n # Excel数据分析页面\r\nif page == \"Excel数据分析\":\r\n st.title(\"📈 Excel 数据分析\")\r\n st.write(\"上传Excel文件进行数据分析\")\r\n\r\n with st.container():\r\n col1, col2 = st.columns([3, 1])\r\n with col1:\r\n data = st.file_uploader(\"上传Excel文件\", type=[\"xlsx\", \"xls\"], key=\"excel_uploader\")\r\n with col2:\r\n st.write(\"\")\r\n st.write(\"\")\r\n if st.button(\"示例数据\", key=\"excel_sample\"):\r\n st.session_state[\"df\"] = pd.DataFrame({\r\n '产品': ['A', 'B', 'C', 'D', 'E'],\r\n '销售额': [12000, 18000, 15000, 22000, 19000],\r\n '利润': [3000, 4500, 3500, 5500, 4800],\r\n '地区': ['华北', '华南', '华东', '华北', '华南']\r\n })\r\n st.success(\"已加载示例数据\")\r\n\r\n if data or \"df\" in st.session_state:\r\n try:\r\n if data:\r\n # 获取Excel文件中的所有工作表名\r\n xls = pd.ExcelFile(data)\r\n sheet_names = xls.sheet_names\r\n\r\n # 让用户选择要加载的工作表\r\n if len(sheet_names) > 1:\r\n selected_sheet = st.selectbox(\r\n \"请选择要分析的工作表\",\r\n sheet_names,\r\n index=0,\r\n key=\"sheet_selector\"\r\n )\r\n else:\r\n selected_sheet = sheet_names[0]\r\n\r\n # 读取选定的工作表数据\r\n st.session_state[\"df\"] = pd.read_excel(data, sheet_name=selected_sheet)\r\n\r\n with st.expander(\"📂 原始数据预览\", expanded=True):\r\n st.dataframe(st.session_state[\"df\"], height=300)\r\n st.caption(\r\n f\"数据维度: {st.session_state['df'].shape[0]}行 × {st.session_state['df'].shape[1]}列\")\r\n\r\n # 添加数据预处理面板\r\n st.session_state[\"df\"] = preprocess_data(st.session_state[\"df\"])\r\n except Exception as e:\r\n st.error(f\"读取Excel文件出错: {str(e)}\")\r\n st.stop()\r\n\r\n query = st.text_area(\r\n \"请输入您的分析问题(例如:'展示不同产品的销售总量柱状图')\",\r\n disabled=\"df\" not in st.session_state,\r\n height=100,\r\n key=\"excel_query\"\r\n )\r\n\r\n # 图表建议\r\n if \"df\" in st.session_state:\r\n st.subheader(\"💡 图表建议\")\r\n chart_suggestions = [\r\n \"柱状图:比较不同类别的数值\",\r\n \"折线图:展示数据随时间的变化趋势\",\r\n \"饼图:显示各部分占整体的比例\",\r\n \"散点图:探索两个变量之间的关系\",\r\n \"热力图:展示数据相关性\"\r\n ]\r\n\r\n\r\n # 为每个建议创建单独的回调函数\r\n def set_suggestion(suggestion):\r\n st.session_state.excel_query = f\"生成一个{suggestion.split(':')[0]}:\" + suggestion.split(':')[1]\r\n\r\n\r\n cols = st.columns(len(chart_suggestions))\r\n for i, suggestion in enumerate(chart_suggestions):\r\n with cols[i]:\r\n st.button(\r\n suggestion,\r\n key=f\"excel_chart_sug_{i}\",\r\n use_container_width=True,\r\n on_click=set_suggestion,\r\n args=(suggestion,)\r\n )\r\n\r\n col1, col2 = st.columns([4, 1])\r\n with col1:\r\n if st.button(\"🚀 分析Excel数据\", key=\"excel_analyze\", use_container_width=True):\r\n if \"df\" not in st.session_state:\r\n st.warning(\"请先上传Excel文件\")\r\n st.stop()\r\n\r\n with st.spinner(\"AI正在分析Excel数据,请稍候...\"):\r\n try:\r\n result = dataframe_agent(st.session_state[\"df\"], query)\r\n if \"answer\" in result:\r\n st.success(result[\"answer\"])\r\n if \"table\" in result:\r\n st.table(pd.DataFrame(\r\n result[\"table\"][\"data\"],\r\n columns=result[\"table\"][\"columns\"]\r\n ))\r\n if \"bar\" in result:\r\n df_data = pd.DataFrame(\r\n data={\r\n \"x\": result[\"bar\"][\"columns\"],\r\n \"y\": result[\"bar\"][\"data\"]\r\n }\r\n )\r\n df_data.set_index(\"x\", inplace=True)\r\n st.bar_chart(df_data)\r\n if \"line\" in result:\r\n df = pd.DataFrame({\r\n \"x\": result[\"line\"][\"columns\"],\r\n \"y\": result[\"line\"][\"data\"]\r\n }).set_index(\"x\")\r\n plt.plot(df.index, df[\"y\"], marker=\"o\", linestyle=\"--\")\r\n plt.title(\"折线图\")\r\n st.pyplot(plt.gcf())\r\n except Exception as e:\r\n st.error(f\"分析过程中出错: {str(e)}\")\r\n\r\n with col2:\r\n if st.button(\"🗑️ 清除结果\", key=\"clear_excel_results\", use_container_width=True):\r\n if 'last_result' in st.session_state:\r\n del st.session_state['last_result']\r\n\r\n if 'last_result' in st.session_state:\r\n result = st.session_state['last_result']\r\n st.subheader(\"📊 分析结果\")\r\n\r\n if \"answer\" in result:\r\n with st.chat_message(\"ai\", avatar=\"🤖\"):\r\n st.markdown(f'<div class=\"ai-message\">{result[\"answer\"]}</div>', unsafe_allow_html=True)\r\n\r\n if \"table\" in result:\r\n st.subheader(\"📋 数据表格\")\r\n try:\r\n st.table(pd.DataFrame(\r\n result[\"table\"][\"data\"],\r\n columns=result[\"table\"][\"columns\"]\r\n ))\r\n except Exception as e:\r\n st.error(f\"显示表格时出错: {str(e)}\")\r\n\r\n if \"charts\" in result:\r\n st.subheader(\"📈 数据可视化\")\r\n for chart in result[\"charts\"]:\r\n for chart_type, data in chart.items():\r\n st.markdown(f\"### {chart_type.capitalize()} 图表\")\r\n render_chart(chart_type, data)\r\n\r\n if st.checkbox(\"🔊 语音播报结果\", key=\"voice_output_excel\"):\r\n if \"answer\" in result:\r\n audio_bytes = text_to_speech(result[\"answer\"])\r\n st.audio(audio_bytes, format='audio/mp3')\r\n\r\n # CSV数据分析页面\r\nelif page == \"CSV数据分析\":\r\n st.title(\"📊 CSV 数据分析\")\r\n st.write(\"上传CSV文件进行数据分析\")\r\n\r\n data = st.file_uploader(\"上传CSV文件\", type=\"csv\", key=\"csv_uploader\")\r\n\r\n if data:\r\n try:\r\n st.session_state[\"df\"] = pd.read_csv(data)\r\n with st.expander(\"📂 原始数据预览\"):\r\n st.dataframe(st.session_state[\"df\"])\r\n st.session_state[\"df\"] = preprocess_data(st.session_state[\"df\"])\r\n except Exception as e:\r\n st.error(f\"读取CSV文件出错: {str(e)}\")\r\n st.stop()\r\n\r\n col1, col2 = st.columns([3, 1])\r\n with col2:\r\n st.write(\"\")\r\n st.write(\"\")\r\n if st.button(\"示例数据\", key=\"csv_sample\"):\r\n st.session_state[\"df\"] = pd.DataFrame({\r\n '月份': ['1月', '2月', '3月', '4月', '5月'],\r\n '收入': [15000, 18000, 22000, 19500, 21000],\r\n '支出': [8000, 8500, 9000, 9200, 8800]\r\n })\r\n st.success(\"已加载示例数据\")\r\n\r\n query = st.text_area(\r\n \"请输入您的分析问题(例如:'展示不同产品的销售总量柱状图')\",\r\n disabled=\"df\" not in st.session_state,\r\n height=100,\r\n key=\"csv_query\"\r\n )\r\n\r\n # 图表建议\r\n if \"df\" in st.session_state:\r\n st.subheader(\"💡 图表建议\")\r\n chart_suggestions = [\r\n \"柱状图:比较不同类别的数值\",\r\n \"折线图:展示数据随时间的变化趋势\",\r\n \"饼图:显示各部分占整体的比例\",\r\n \"散点图:探索两个变量之间的关系\",\r\n \"热力图:展示数据相关性\"\r\n ]\r\n\r\n\r\n # 为每个建议创建单独的回调函数\r\n def set_suggestion(suggestion):\r\n st.session_state.csv_query = f\"生成一个{suggestion.split(':')[0]}:\" + suggestion.split(':')[1]\r\n\r\n\r\n cols = st.columns(len(chart_suggestions))\r\n for i, suggestion in enumerate(chart_suggestions):\r\n with cols[i]:\r\n st.button(\r\n suggestion,\r\n key=f\"csv_chart_sug_{i}\",\r\n use_container_width=True,\r\n on_click=set_suggestion,\r\n args=(suggestion,)\r\n )\r\n\r\n col1, col2 = st.columns([4, 1])\r\n with col1:\r\n if st.button(\"🚀 分析CSV数据\", key=\"csv_analyze\", use_container_width=True):\r\n if \"df\" not in st.session_state:\r\n st.warning(\"请先上传CSV文件\")\r\n st.stop()\r\n\r\n with st.spinner(\"AI正在分析CSV数据,请稍候...\"):\r\n try:\r\n result = dataframe_agent(st.session_state[\"df\"], query)\r\n if \"answer\" in result:\r\n st.success(result[\"answer\"])\r\n if \"table\" in result:\r\n st.table(pd.DataFrame(\r\n result[\"table\"][\"data\"],\r\n columns=result[\"table\"][\"columns\"]\r\n ))\r\n if \"bar\" in result:\r\n # df = pd.DataFrame({\r\n # \"x\": result[\"bar\"][\"columns\"],\r\n # \"y\": result[\"bar\"][\"data\"]\r\n # }).set_index(\"x\")\r\n # st.bar_chart(df)\r\n df_data = pd.DataFrame(\r\n data={\r\n \"x\": result[\"bar\"][\"columns\"],\r\n \"y\": result[\"bar\"][\"data\"]\r\n }\r\n )\r\n df_data.set_index(\"x\", inplace=True)\r\n st.bar_chart(df_data)\r\n if \"line\" in result:\r\n df = pd.DataFrame({\r\n \"x\": result[\"line\"][\"columns\"],\r\n \"y\": result[\"line\"][\"data\"]\r\n }).set_index(\"x\")\r\n plt.plot(df.index, df[\"y\"], marker=\"o\", linestyle=\"--\")\r\n plt.title(\"折线图\")\r\n st.pyplot(plt.gcf())\r\n except Exception as e:\r\n st.error(f\"分析过程中出错: {str(e)}\")\r\n\r\n with col2:\r\n if st.button(\"🗑️ 清除结果\", key=\"clear_csv_results\", use_container_width=True):\r\n if 'last_csv_result' in st.session_state:\r\n del st.session_state['last_csv_result']\r\n\r\n # 显示分析结果\r\n if 'last_csv_result' in st.session_state:\r\n result = st.session_state['last_csv_result']\r\n st.subheader(\"📊 分析结果\")\r\n\r\n # 显示文本解释\r\n if \"answer\" in result:\r\n with st.chat_message(\"ai\", avatar=\"🤖\"):\r\n st.markdown(f'<div class=\"ai-message\">{result[\"answer\"]}</div>', unsafe_allow_html=True)\r\n\r\n # 显示表格\r\n if \"table\" in result:\r\n st.subheader(\"📋 数据表格\")\r\n try:\r\n st.table(pd.DataFrame(\r\n result[\"table\"][\"data\"],\r\n columns=result[\"table\"][\"columns\"]\r\n ))\r\n except Exception as e:\r\n st.error(f\"显示表格时出错: {str(e)}\")\r\n\r\n # 文本问答页面\r\nelif page == \"文本问答\":\r\n st.title(\"📄 文本问答系统\")\r\n st.write(\"上传文本文件进行智能问答\")\r\n\r\n col1, col2 = st.columns([3, 1])\r\n with col1:\r\n uploaded_file = st.file_uploader(\r\n '上传文本文件 (TXT, PDF, DOCX)',\r\n type=[\"txt\", \"pdf\", \"docx\"],\r\n key=\"txt_uploader\"\r\n )\r\n with col2:\r\n st.write(\"\")\r\n st.write(\"\")\r\n if st.button(\"示例文档\", key=\"text_sample\"):\r\n st.session_state['sample_text'] = \"\"\"\r\n 千锋教育成立于2012年,是一家专注于IT技术培训的教育机构。主要提供前端开发、Java开发、Python开发、\r\n 大数据、人工智能等方向的培训课程。千锋教育以\"用良心做教育\"为理念,已培养超过20万名学员。\r\n \r\n 千锋教育的教学特色:\r\n 1. 全程面授教学,讲师均来自一线企业\r\n 2. 项目驱动教学,真实企业项目实战\r\n 3. 就业保障服务,合作企业超过20,000家\r\n 4. 全国19个城市设立直营分校\r\n \r\n 2023年,千锋教育荣获\"中国IT教育影响力品牌\"奖项,继续引领IT职业培训行业的发展。\r\n \"\"\"\r\n st.success(\"已加载示例文档\")\r\n\r\n if uploaded_file or 'sample_text' in st.session_state:\r\n if uploaded_file:\r\n try:\r\n st.session_state['is_new_file'] = True\r\n file_ext = uploaded_file.name.split('.')[-1].lower()\r\n\r\n # 保存文件内容\r\n if file_ext == 'txt':\r\n content = uploaded_file.read().decode('utf-8')\r\n elif file_ext == 'pdf':\r\n loader = PyPDFLoader(uploaded_file)\r\n pages = loader.load()\r\n content = \"\\n\".join([page.page_content for page in pages])\r\n elif file_ext == 'docx':\r\n loader = Docx2txtLoader(uploaded_file)\r\n content = loader.load()[0].page_content\r\n else:\r\n st.error(\"不支持的文件格式\")\r\n st.stop()\r\n\r\n with open(f'{st.session_state[\"session_id\"]}.txt', 'w', encoding='utf-8') as temp_file:\r\n temp_file.write(content)\r\n\r\n st.session_state['file_content'] = content\r\n st.success(\"文件上传成功!\")\r\n\r\n except Exception as e:\r\n st.error(f\"处理文件出错: {str(e)}\")\r\n st.stop()\r\n else:\r\n st.session_state['file_content'] = st.session_state['sample_text']\r\n\r\n # 显示文档摘要\r\n with st.expander(\"📝 文档摘要\", expanded=True):\r\n if 'summary' not in st.session_state:\r\n with st.spinner(\"正在生成文档摘要...\"):\r\n st.session_state['summary'] = generate_summary(st.session_state['file_content'])\r\n st.info(st.session_state['summary'])\r\n\r\n question = st.text_area(\r\n '请输入您的问题(例如:\"这篇文档的主题是什么?\")',\r\n height=100,\r\n key=\"txt_question\"\r\n )\r\n\r\n col1, col2 = st.columns([4, 1])\r\n with col1:\r\n if st.button(\"🚀 获取答案\", key=\"txt_answer\", use_container_width=True):\r\n if not question:\r\n st.warning(\"请输入问题\")\r\n st.stop()\r\n\r\n with st.spinner(\"正在分析文档内容...\"):\r\n try:\r\n response = get_answer(question, st.session_state)\r\n st.session_state['last_text_response'] = response\r\n except Exception as e:\r\n st.error(f\"获取答案过程中出错: {str(e)}\")\r\n\r\n with col2:\r\n if st.button(\"🗑️ 清除结果\", key=\"clear_text_results\", use_container_width=True):\r\n if 'last_text_response' in st.session_state:\r\n del st.session_state['last_text_response']\r\n\r\n if 'last_text_response' in st.session_state:\r\n response = st.session_state['last_text_response']\r\n st.subheader(\"💡 答案\")\r\n with st.chat_message(\"ai\", avatar=\"🤖\"):\r\n st.markdown(f'<div class=\"ai-message\">{response[\"answer\"]}</div>', unsafe_allow_html=True)\r\n\r\n # 语音输出\r\n if st.checkbox(\"🔊 语音播报答案\", key=\"voice_output_text\"):\r\n audio_bytes = text_to_speech(response['answer'])\r\n st.audio(audio_bytes, format='audio/mp3')\r\n\r\n # 历史对话记录\r\n if 'chat_history' in st.session_state:\r\n with st.expander(\"💬 历史对话记录\"):\r\n for i in range(0, len(st.session_state[\"chat_history\"]), 2):\r\n human_message = st.session_state[\"chat_history\"][i]\r\n ai_message = st.session_state[\"chat_history\"][i + 1]\r\n\r\n col1, col2 = st.columns([1, 10])\r\n with col1:\r\n st.image(\"https://cdn-icons-png.flaticon.com/512/3135/3135715.png\", width=40)\r\n with col2:\r\n st.markdown(f\"**👤 用户:** {human_message.content}\")\r\n\r\n col1, col2 = st.columns([1, 10])\r\n with col1:\r\n st.image(\"https://cdn-icons-png.flaticon.com/512/4712/4712035.png\", width=40)\r\n with col2:\r\n st.markdown(f\"**🤖 AI:** {ai_message.content}\")\r\n\r\n if i < len(st.session_state[\"chat_history\"]) - 2:\r\n st.divider()\r\n # AI聊天助手页面\r\n\r\n\r\n\r\n# 在页面中添加语音输入功能\r\n# AI聊天助手页面\r\n\r\n\r\n# AI聊天助手页面\r\nelif page == \"AI聊天助手\":\r\n st.title(\"💬 AI聊天助手\")\r\n st.write(\"与AI助手进行多模态交互对话\")\r\n\r\n # 用户设置\r\n with st.expander(\"⚙️ 个人设置\", expanded=False):\r\n col1, col2 = st.columns(2)\r\n with col1:\r\n user_avatar = st.file_uploader(\"上传用户头像\", type=[\"jpg\", \"png\", \"jpeg\"])\r\n with col2:\r\n ai_avatar = st.file_uploader(\"上传AI头像\", type=[\"jpg\", \"png\", \"jpeg\"])\r\n\r\n # 初始化聊天模型\r\n chat_model = ChatOpenAI(\r\n model='gpt-4o-mini',\r\n base_url='https://twapi.openai-hk.com/v1',\r\n api_key='hk-yq4ipo100005562375c7c3ac31e70baadb11e09f2040908b',\r\n temperature=0.7\r\n )\r\n\r\n # 确保 chat_memory 正确初始化\r\n if 'chat_memory' not in st.session_state:\r\n st.session_state['chat_memory'] = ConversationBufferMemory(\r\n memory_key='chat_history',\r\n return_messages=True\r\n )\r\n\r\n # 显示历史消息\r\n for message in st.session_state['chat_messages']:\r\n avatar = message.get('avatar', '🤖' if message['role'] == 'ai' else '👤')\r\n\r\n if message['role'] == 'ai':\r\n col1, col2 = st.columns([1, 10])\r\n with col1:\r\n if ai_avatar:\r\n st.image(ai_avatar, width=40)\r\n else:\r\n st.markdown(f'<div style=\"font-size: 32px;\">{avatar}</div>', unsafe_allow_html=True)\r\n with col2:\r\n st.markdown(f'<div class=\"ai-message\">{message[\"content\"]}</div>', unsafe_allow_html=True)\r\n else:\r\n col1, col2 = st.columns([10, 1])\r\n with col2:\r\n if user_avatar:\r\n st.image(user_avatar, width=40)\r\n else:\r\n st.markdown(f'<div style=\"font-size: 32px;\">{avatar}</div>', unsafe_allow_html=True)\r\n with col1:\r\n st.markdown(f'<div class=\"user-message\">{message[\"content\"]}</div>', unsafe_allow_html=True)\r\n\r\n # 输入区域\r\n input_container = st.container()\r\n with input_container:\r\n user_input = st.text_area(\"请输入您的问题...\", height=100, key=\"text_input\")\r\n\r\n col1, col2 = st.columns([5, 1])\r\n with col1:\r\n if st.button(\"🚀 发送消息\", key=\"send_message\", use_container_width=True):\r\n if not user_input:\r\n st.warning(\"请输入消息内容\")\r\n st.stop()\r\n\r\n # 显示用户消息\r\n avatar = \"👤\"\r\n if user_avatar:\r\n avatar = user_avatar\r\n\r\n new_message = {\r\n 'role': 'human',\r\n 'content': user_input,\r\n 'avatar': avatar,\r\n }\r\n\r\n st.session_state['chat_messages'].append(new_message)\r\n\r\n # 获取AI回复\r\n with st.spinner('AI正在思考,请稍候...'):\r\n try:\r\n # 初始化对话链\r\n agent = ConversationChain(\r\n llm=chat_model,\r\n memory=st.session_state['chat_memory']\r\n )\r\n # 获取AI回复\r\n ai_response = agent.run({\"input\": user_input})\r\n\r\n # 显示AI回复\r\n avatar = \"🤖\"\r\n if ai_avatar:\r\n avatar = ai_avatar\r\n\r\n st.session_state['chat_messages'].append({\r\n 'role': 'ai',\r\n 'content': ai_response,\r\n 'avatar': avatar\r\n })\r\n\r\n except Exception as e:\r\n st.error(f\"聊天过程中出错: {str(e)}\")\r\n # 添加详细的错误日志\r\n import traceback\r\n st.error(f\"错误详情: {traceback.format_exc()}\")\r\n\r\n st.rerun()\r\n\r\n # 语音输入按钮\r\n if st.button(\"🎤 语音输入\", key=\"voice_input\", use_container_width=True):\r\n # 录制音频\r\n CHUNK = 1024\r\n FORMAT = pyaudio.paInt16\r\n CHANNELS = 1\r\n RATE = 16000\r\n RECORD_SECONDS = 5\r\n WAVE_OUTPUT_FILENAME = \"output.wav\"\r\n\r\n p = pyaudio.PyAudio()\r\n\r\n stream = p.open(format=FORMAT,\r\n channels=CHANNELS,\r\n rate=RATE,\r\n input=True,\r\n frames_per_buffer=CHUNK)\r\n\r\n st.info(\"请说话,正在录音...\")\r\n frames = []\r\n\r\n for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):\r\n data = stream.read(CHUNK)\r\n frames.append(data)\r\n\r\n stream.stop_stream()\r\n stream.close()\r\n p.terminate()\r\n\r\n wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')\r\n wf.setnchannels(CHANNELS)\r\n wf.setsampwidth(p.get_sample_size(FORMAT))\r\n wf.setframerate(RATE)\r\n wf.writeframes(b''.join(frames))\r\n wf.close()\r\n\r\n # 语音识别\r\n recognizer = sr.Recognizer()\r\n with sr.AudioFile(WAVE_OUTPUT_FILENAME) as source:\r\n audio = recognizer.record(source)\r\n\r\n try:\r\n user_input = recognizer.recognize_google(audio, language=\"zh-CN\")\r\n st.info(f\"识别到的语音内容:{user_input}\")\r\n os.remove(WAVE_OUTPUT_FILENAME)\r\n\r\n # 显示用户消息\r\n avatar = \"👤\"\r\n if user_avatar:\r\n avatar = user_avatar\r\n\r\n new_message = {\r\n 'role': 'human',\r\n 'content': user_input,\r\n 'avatar': avatar,\r\n }\r\n\r\n st.session_state['chat_messages'].append(new_message)\r\n\r\n # 获取AI回复\r\n with st.spinner('AI正在思考,请稍候...'):\r\n try:\r\n # 初始化对话链\r\n agent = ConversationChain(\r\n llm=chat_model,\r\n memory=st.session_state['chat_memory']\r\n )\r\n # 获取AI回复\r\n ai_response = agent.run({\"input\": user_input})\r\n\r\n # 显示AI回复\r\n avatar = \"🤖\"\r\n if ai_avatar:\r\n avatar = ai_avatar\r\n\r\n st.session_state['chat_messages'].append({\r\n 'role': 'ai',\r\n 'content': ai_response,\r\n 'avatar': avatar\r\n })\r\n\r\n except Exception as e:\r\n st.error(f\"聊天过程中出错: {str(e)}\")\r\n # 添加详细的错误日志\r\n import traceback\r\n st.error(f\"错误详情: {traceback.format_exc()}\")\r\n\r\n st.rerun()\r\n\r\n except sr.UnknownValueError:\r\n st.error(\"无法识别语音内容\")\r\n except sr.RequestError as e:\r\n st.error(f\"语音识别出错: {e}\")\r\n\r\n with col2:\r\n voice_toggle = st.toggle(\"🔊\", key=\"voice_output\", value=True)\r\n\r\n # 播放最后一条语音\r\n if 'last_audio' in st.session_state and st.session_state.get('voice_output', False):\r\n st.audio(st.session_state['last_audio'], format='audio/mp3')\r\n\r\n # 清空对话按钮\r\n if st.button(\"🔄 清空对话历史\", key=\"clear_chat\", use_container_width=True):\r\n st.session_state['chat_messages'] = [{\r\n 'role': 'ai',\r\n 'content': '你好主人,我是你的AI助手,我叫小美',\r\n 'avatar': '🤖'\r\n }]\r\n st.session_state['chat_memory'] = ConversationBufferMemory(\r\n memory_key='chat_history',\r\n return_messages=True\r\n )\r\n st.rerun()\r\n\r\nelif page == \"数据库分析\":\r\n st.title(\"💾 数据库分析\")\r\n st.write(\"连接数据库并执行SQL查询\")\r\n\r\n # 初始化session_state变量\r\n if 'db_conn' not in st.session_state:\r\n st.session_state.db_conn = None\r\n if 'db_type' not in st.session_state:\r\n st.session_state.db_type = None\r\n if 'last_sql_result' not in st.session_state:\r\n st.session_state.last_sql_result = None\r\n\r\n with st.expander(\"🔌 数据库连接\", expanded=True):\r\n db_type = st.selectbox(\"数据库类型\", [\"SQLite\", \"MySQL\", \"PostgreSQL\"])\r\n st.session_state.db_type = db_type\r\n\r\n if db_type == \"SQLite\":\r\n db_file = st.file_uploader(\"上传SQLite数据库文件\", type=[\"db\", \"sqlite\"])\r\n if db_file:\r\n # 保存到临时文件\r\n with open(\"temp.db\", \"wb\") as f:\r\n f.write(db_file.getbuffer())\r\n try:\r\n st.session_state.db_conn = sqlite3.connect(\"temp.db\")\r\n st.success(\"数据库连接成功!\")\r\n # 重置状态\r\n st.session_state.last_sql_result = None\r\n except Exception as e:\r\n st.error(f\"数据库连接失败: {str(e)}\")\r\n else:\r\n host = st.text_input(\"主机地址\", value=\"localhost\")\r\n port = st.number_input(\"端口\", value=3306)\r\n user = st.text_input(\"用户名\", value=\"root\")\r\n password = st.text_input(\"密码\", type=\"password\")\r\n database = st.text_input(\"数据库名\", value=\"testdb\")\r\n\r\n if st.button(\"连接数据库\"):\r\n try:\r\n if db_type == \"MySQL\":\r\n import mysql.connector\r\n\r\n st.session_state.db_conn = mysql.connector.connect(\r\n host=host,\r\n port=port,\r\n user=user,\r\n password=password,\r\n database=database\r\n )\r\n elif db_type == \"PostgreSQL\":\r\n import psycopg2\r\n\r\n st.session_state.db_conn = psycopg2.connect(\r\n host=host,\r\n port=port,\r\n user=user,\r\n password=password,\r\n database=database\r\n )\r\n st.success(\"数据库连接成功!\")\r\n # 重置状态\r\n st.session_state.last_sql_result = None\r\n except Exception as e:\r\n st.error(f\"数据库连接失败: {str(e)}\")\r\n\r\n # 断开连接按钮\r\n if st.session_state.db_conn and st.button(\"断开连接\"):\r\n try:\r\n st.session_state.db_conn.close()\r\n st.session_state.db_conn = None\r\n st.session_state.last_sql_result = None\r\n st.success(\"已断开数据库连接\")\r\n except:\r\n pass\r\n\r\n if st.session_state.db_conn:\r\n conn = st.session_state.db_conn\r\n # 获取数据库表信息\r\n cursor = conn.cursor()\r\n try:\r\n if st.session_state.db_type == \"SQLite\":\r\n cursor.execute(\"SELECT name FROM sqlite_master WHERE type='table';\")\r\n tables = cursor.fetchall()\r\n tables = [table[0] for table in tables]\r\n elif st.session_state.db_type == \"MySQL\":\r\n cursor.execute(\"SHOW TABLES;\")\r\n tables = [table[0] for table in cursor.fetchall()]\r\n elif st.session_state.db_type == \"PostgreSQL\":\r\n cursor.execute(\"SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';\")\r\n tables = [table[0] for table in cursor.fetchall()]\r\n except Exception as e:\r\n st.error(f\"获取表信息失败: {str(e)}\")\r\n tables = []\r\n\r\n if tables:\r\n # 使用selectbox的key参数来自动管理session_state\r\n selected_table = st.selectbox(\r\n \"选择数据表\",\r\n tables,\r\n key=\"selected_table\"\r\n )\r\n\r\n if selected_table:\r\n # 安全处理表名(防止SQL注入)\r\n safe_table = selected_table\r\n if st.session_state.db_type == \"SQLite\":\r\n safe_table = f'\"{selected_table}\"'\r\n elif st.session_state.db_type == \"MySQL\":\r\n safe_table = f\"`{selected_table}`\"\r\n elif st.session_state.db_type == \"PostgreSQL\":\r\n safe_table = f'\"{selected_table}\"'\r\n\r\n try:\r\n # 显示表数据\r\n cursor.execute(f\"SELECT * FROM {safe_table} LIMIT 100;\")\r\n data = cursor.fetchall()\r\n col_names = [description[0] for description in cursor.description]\r\n df = pd.DataFrame(data, columns=col_names)\r\n\r\n st.dataframe(df)\r\n except Exception as e:\r\n st.error(f\"查询表数据失败: {str(e)}\")\r\n\r\n # SQL查询\r\n st.subheader(\"🔍 SQL查询\")\r\n sql_query = st.text_area(\r\n \"输入SQL查询语句\",\r\n height=100,\r\n value=f\"SELECT * FROM {selected_table} LIMIT 10\"\r\n )\r\n\r\n col1, col2 = st.columns(2)\r\n with col1:\r\n if st.button(\"执行查询\", key=\"execute_sql\"):\r\n try:\r\n # 执行前检查SQL语句安全性\r\n if not re.match(r'^\\s*SELECT', sql_query, re.IGNORECASE):\r\n st.warning(\"仅支持SELECT查询\")\r\n else:\r\n cursor.execute(sql_query)\r\n result = cursor.fetchall()\r\n col_names = [description[0] for description in cursor.description]\r\n result_df = pd.DataFrame(result, columns=col_names)\r\n\r\n # 保存查询结果到session_state\r\n st.session_state.last_sql_result = result_df\r\n\r\n st.subheader(\"查询结果\")\r\n st.dataframe(result_df)\r\n\r\n # 重置分析结果\r\n if 'analysis_result' in st.session_state:\r\n del st.session_state.analysis_result\r\n\r\n except Exception as e:\r\n st.error(f\"SQL查询错误: {str(e)}\")\r\n\r\n with col2:\r\n if st.button(\"清除查询结果\", key=\"clear_sql_result\"):\r\n if 'last_sql_result' in st.session_state:\r\n del st.session_state.last_sql_result\r\n if 'analysis_result' in st.session_state:\r\n del st.session_state.analysis_result\r\n\r\n # 显示查询结果(如果有)\r\n if 'last_sql_result' in st.session_state and st.session_state.last_sql_result is not None:\r\n st.subheader(\"查询结果\")\r\n st.dataframe(st.session_state.last_sql_result)\r\n\r\n # 分析查询结果部分\r\n st.subheader(\"分析查询结果\")\r\n analysis_query = st.text_input(\r\n \"输入分析问题\",\r\n placeholder=\"例如:'计算各列的平均值'\",\r\n key=\"analysis_query\"\r\n )\r\n\r\n if st.button(\"分析数据\", key=\"analyze_data\"):\r\n if not analysis_query:\r\n st.warning(\"请输入分析问题\")\r\n else:\r\n with st.spinner(\"正在分析数据...\"):\r\n try:\r\n # 执行分析\r\n result = dataframe_agent(st.session_state.last_sql_result, analysis_query)\r\n\r\n # 保存分析结果\r\n st.session_state.analysis_result = result\r\n\r\n except Exception as e:\r\n st.error(f\"分析过程中出错: {str(e)}\")\r\n\r\n # 显示分析结果(如果有)\r\n # 在数据库分析页面的分析部分做如下修改\r\n if 'analysis_result' in st.session_state:\r\n result = st.session_state.analysis_result\r\n\r\n # 检查结果类型\r\n if isinstance(result, dict):\r\n # 处理字典格式的结果\r\n if \"answer\" in result:\r\n st.success(result[\"answer\"])\r\n\r\n if \"table\" in result:\r\n st.subheader(\"分析结果表格\")\r\n try:\r\n # 确保数据格式正确\r\n if isinstance(result[\"table\"][\"data\"][0], list):\r\n # 多行数据\r\n st.table(pd.DataFrame(\r\n result[\"table\"][\"data\"],\r\n columns=result[\"table\"][\"columns\"]\r\n ))\r\n else:\r\n # 单行数据\r\n st.table(pd.DataFrame(\r\n [result[\"table\"][\"data\"]],\r\n columns=result[\"table\"][\"columns\"]\r\n ))\r\n except Exception as e:\r\n st.error(f\"显示表格时出错: {str(e)}\")\r\n st.write(\"原始表格数据:\", result[\"table\"])\r\n\r\n if \"charts\" in result:\r\n st.subheader(\"数据可视化\")\r\n for chart in result[\"charts\"]:\r\n for chart_type, data in chart.items():\r\n st.markdown(f\"### {chart_type.capitalize()} 图表\")\r\n render_chart(chart_type, data)\r\n\r\n elif isinstance(result, str):\r\n # 处理纯文本结果\r\n st.success(result)\r\n\r\n else:\r\n # 处理未知结果类型\r\n st.error(\"未知结果格式\")\r\n st.write(result)\r\n else:\r\n st.warning(\"数据库中没有找到表\")\r\n# 图像分析页面\r\nelif page == \"图像分析\":\r\n st.title(\"🖼️ 图像分析\")\r\n st.write(\"上传图片并进行分析\")\r\n\r\n col1, col2 = st.columns(2)\r\n with col1:\r\n image_file = st.file_uploader(\"上传图片\", type=[\"jpg\", \"png\", \"jpeg\"])\r\n if image_file:\r\n st.image(image_file, caption=\"上传的图片\", use_container_width=True)\r\n with col2:\r\n if image_file:\r\n st.subheader(\"图像信息\")\r\n img = Image.open(image_file)\r\n st.write(f\"**格式**: {img.format}\")\r\n st.write(f\"**尺寸**: {img.width} x {img.height} 像素\")\r\n st.write(f\"**模式**: {img.mode}\")\r\n\r\n # 基本图像处理\r\n st.subheader(\"图像处理\")\r\n if st.button(\"转换为灰度图\"):\r\n gray_img = img.convert(\"L\")\r\n st.image(gray_img, caption=\"灰度图像\", use_container_width=True)\r\n\r\n if image_file:\r\n st.subheader(\"图像分析\")\r\n analysis_type = st.selectbox(\"选择分析类型\", [\r\n \"图像描述\",\r\n \"物体识别\",\r\n \"文字识别 (OCR)\",\r\n \"情感分析\"\r\n ])\r\n\r\n question = st.text_input(\"您想了解这张图片的什么信息?\", placeholder=\"例如:'图片中有哪些物体?'\")\r\n\r\n if st.button(\"分析图像\"):\r\n with st.spinner(\"正在分析图像...\"):\r\n try:\r\n # 使用多模态模型分析图像\r\n model = ChatOpenAI(\r\n model='gpt-4-vision-preview',\r\n base_url='https://twapi.openai-hk.com/v1',\r\n api_key='hk-yq4ipo100005562375c7c3ac31e70baadb11e09f2040908b',\r\n max_tokens=1024\r\n )\r\n\r\n # 将图像转换为base64\r\n buffered = BytesIO()\r\n img = Image.open(image_file)\r\n\r\n # 确保图像是RGB模式(Vision模型要求)\r\n if img.mode != 'RGB':\r\n img = img.convert('RGB')\r\n\r\n img.save(buffered, format=\"JPEG\")\r\n img_str = base64.b64encode(buffered.getvalue()).decode()\r\n\r\n # 构建正确的消息格式\r\n messages = [\r\n {\r\n \"role\": \"user\",\r\n \"content\": [\r\n {\"type\": \"text\", \"text\": question},\r\n {\r\n \"type\": \"image_url\",\r\n \"image_url\": {\r\n \"url\": f\"data:image/jpeg;base64,{img_str}\"\r\n }\r\n }\r\n ]\r\n }\r\n ]\r\n\r\n # 调用模型\r\n response = model.invoke(messages)\r\n\r\n # 检查响应格式\r\n if isinstance(response, dict) and 'content' in response:\r\n result = response['content']\r\n elif hasattr(response, 'content'):\r\n result = response.content\r\n else:\r\n result = str(response)\r\n\r\n # 保存分析结果到session_state\r\n st.session_state.analysis_result = result\r\n\r\n except Exception as e:\r\n st.error(f\"图像分析失败: {str(e)}\")\r\n\r\n # 分离语音播报逻辑\r\n if st.session_state.get(\"analysis_result\"):\r\n st.subheader(\"分析结果\")\r\n st.write(st.session_state.analysis_result)\r\n\r\n # 添加语音播报按钮\r\n if st.button(\"🔊 语音播报结果\", key=\"voice_output_image\"):\r\n st.session_state.voice_output = True\r\n\r\n # 语音输出\r\n if st.session_state.get(\"voice_output\", False):\r\n audio_bytes = text_to_speech(st.session_state.analysis_result)\r\n st.audio(audio_bytes, format='audio/mp3')\r\n\r\n\r\n # Web爬虫页面\r\nelif page == \"Web爬虫\":\r\n st.title(\"🕸️ Web爬虫分析\")\r\n st.write(\"抓取网页内容并进行分析\")\r\n\r\n url = st.text_input(\"输入网页URL\", placeholder=\"https://example.com\")\r\n\r\n if st.button(\"抓取网页内容\", key=\"crawl_web\"):\r\n if not url:\r\n st.warning(\"请输入URL\")\r\n st.stop()\r\n\r\n with st.spinner(\"正在抓取网页内容...\"):\r\n try:\r\n headers = {\r\n 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'\r\n }\r\n response = requests.get(url, headers=headers)\r\n response.encoding = response.apparent_encoding\r\n html_content = response.text\r\n\r\n # 提取文本内容\r\n from bs4 import BeautifulSoup\r\n\r\n soup = BeautifulSoup(html_content, 'html.parser')\r\n\r\n # 移除不需要的元素\r\n for script in soup([\"script\", \"style\", \"header\", \"footer\", \"nav\"]):\r\n script.extract()\r\n\r\n text_content = soup.get_text(separator='\\n', strip=True)\r\n text_content = re.sub(r'\\n+', '\\n', text_content) # 移除多余空行\r\n\r\n st.session_state['web_content'] = text_content\r\n st.success(\"网页抓取成功!\")\r\n\r\n except Exception as e:\r\n st.error(f\"网页抓取失败: {str(e)}\")\r\n\r\n if 'web_content' in st.session_state:\r\n with st.expander(\"📝 网页内容预览\", expanded=False):\r\n st.text_area(\"网页内容\", st.session_state['web_content'], height=300)\r\n\r\n # 生成摘要\r\n with st.expander(\"📊 网页摘要\", expanded=True):\r\n if 'web_summary' not in st.session_state:\r\n with st.spinner(\"正在生成网页摘要...\"):\r\n st.session_state['web_summary'] = generate_summary(st.session_state['web_content'])\r\n st.info(st.session_state['web_summary'])\r\n\r\n question = st.text_input(\"关于此网页,您有什么问题?\", placeholder=\"例如:'网页的主要话题是什么?'\")\r\n\r\n if st.button(\"分析网页内容\", key=\"analyze_web\"):\r\n if not question:\r\n st.warning(\"请输入问题\")\r\n st.stop()\r\n\r\n with st.spinner(\"正在分析网页内容...\"):\r\n try:\r\n # 提取网页内容中的中文字符\r\n chinese_content = ''.join(re.findall(r'[\\u4e00-\\u9fff]+', st.session_state['web_content']))\r\n\r\n # 打印提取后的中文内容,确保内容正确\r\n # st.write(\"提取后的中文内容:\", chinese_content)\r\n\r\n # 保存提取后的中文内容到临时文件\r\n file_path = f'{st.session_state[\"session_id\"]}.txt'\r\n with open(file_path, 'w', encoding='utf-8') as f:\r\n f.write(chinese_content)\r\n\r\n # 打印文件路径,确保路径正确\r\n # st.write(\"文件保存路径:\", file_path)\r\n\r\n # 设置会话状态\r\n st.session_state['is_new_file'] = True\r\n st.session_state['file_content'] = chinese_content\r\n\r\n # 获取答案\r\n response = get_answer(question, st.session_state)\r\n\r\n st.subheader(\"分析结果\")\r\n st.write(response['answer'])\r\n\r\n # 语音输出\r\n if st.checkbox(\"🔊 语音播报结果\", key=\"voice_output_web\"):\r\n audio_bytes = text_to_speech(response['answer'])\r\n st.audio(audio_bytes, format='audio/mp3')\r\n\r\n except Exception as e:\r\n st.error(f\"分析过程中出错: {str(e)}\")"}}}} |