创建一家网站如何创/天津企业seo

创建一家网站如何创,天津企业seo,wordpress登陆页文件,dell网站的设计特色从零搭建大模型问答系统-GradioOllamaQwen2.5实现全流程(一) 前言一、界面设计(计划)二、模块设计1.登录模块2.注册模块3. 主界面模块4. 历史记录模块 三、相应的接口(前后端交互)四、实现前端界面的设计co…

从零搭建大模型问答系统-Gradio+Ollama+Qwen2.5实现全流程(一)

  • 前言
  • 一、界面设计(计划)
  • 二、模块设计
    • 1.登录模块
    • 2.注册模块
    • 3. 主界面模块
    • 4. 历史记录模块
  • 三、相应的接口(前后端交互)
  • 四、实现前端界面的设计
    • config.py
    • History_g1.py
    • Login.py
    • Main.py
    • Register.py
    • App.py
  • 五、效果展示

压抑的气氛,疲惫的身躯,干涩的眼眶,闲暇的周末~
不甘沉浸在打瓦与go学长的对抗较量,不愿沉迷于开麦与队友间的加密通信,
我便默默地打开电脑,选择换个活法度过周末。

前言

随着人工智能 AI 的快速发展,基于大语言模型(LLM)的应用逐渐成为软件开发中的热点。今天就学习一下如何设计和实现一个前后端交互的问答系统。在这里先进行需求分析,从以下三个角度去考虑:
技术需求 :

  • 前端使用 Gradio 构建用户界面
  • 后端使用 Ollama(本地化模型部署工具)
  • 框架调用 Qwen2.5 大模型
  • 通信协议选择RESTful API(JSON格式)

通过初始设计,我们需要从需求分析开始入手,再去系统实现,最后完成开发的整个过程。
功能需求 :

  • 用户可以通过前端界面输入问题。
  • 系统能够基于大模型生成准确的回答。
  • 支持多轮对话。
  • 提供简单的用户操作反馈(如加载状态、错误提示等)。

非功能性需求 :

  • 系统响应时间控制在合理范围内。
  • 界面简洁直观,用户体验友好。

通信流程图

通信流程
用户->>+前端: 输入问题
前端->>+后端: POST /api/generate
后端->>+Ollama: 模型调用请求
Ollama->>-后端: 生成响应
后端->>-前端: JSON响应
前端->>-用户: 显示回答

一、界面设计(计划)

在设计的时候将预期的功能都设计出来,之后再逐个去实现,往往设计的太简单,当后续需添加功能的时候,前端界面的布局反复修改也比较麻烦。先照葫芦画瓢,根据deepseek以及kimi等问答系统的界面进行模仿学习,修改设计。
这里登录方式分为三种 : 一种是微信扫码,手机号登录,账号密码登录。在实现过程中,暂时计划实现一种登录方式即可,完成整个项目的逻辑。

  1. 界面1 ,登陆界面

| 验证码登录 | 密码登录 |
————————————
这块就使用到我们前面学习到的多页面布局
还有Row 和 Column的组合拳
在这里插入图片描述
在这里插入图片描述

  1. 界面2 ,注册界面

  2. 界面3,主界面

在这里插入图片描述

4.历史记录界面

在这里插入图片描述
界面设计不用太细节有个草图模样就行,重点还是需要理解如何使用容器来布局这些设计,以及添加组件,绑定什么事件。你也可以自己设计一些更加丰富多彩的界面,有的设计在gradio中要想完美的显示,还是需要费很大的功夫(别问为什么)。

二、模块设计

预期有以下四个界面,先将每个界面写出来,再去考虑整合在一块。

1.登录模块

核心功能
发送验证码 :

用户输入手机号或邮箱后,点击“发送验证码”按钮。
前端调用后端接口 /send_verification_code 发送验证码。
如果输入格式错误(如手机号不是11位数字),前端会直接提示错误信息。

验证码登录验证 :

用户输入验证码后,点击“登录”按钮。
前端调用后端接口 /verify_code_login 验证验证码是否正确。
如果验证成功,返回“登录成功”;否则提示错误信息。

密码登录验证 :

用户输入用户名和密码后,点击“登录”按钮。
前端调用后端接口 /login 进行密码验证。
如果验证成功,返回用户ID和成功信息;否则提示错误信息。

用户注册 :

用户输入用户名和密码后,点击“注册”按钮。
前端调用后端接口 /register 提交注册信息。
如果注册成功,提示用户“注册成功,请登录”。

忘记密码 :

提示用户联系管理员重置密码。

界面设计

使用 Gradio 的 Tabs 组件实现验证码登录和密码登录的切换。
左侧为扫码登录区域,右侧为登录选项卡区域。
提供清晰的输入框、按钮和状态提示。

2.注册模块

核心功能
发送验证码 :

用户输入手机号后,点击“获取验证码”按钮。
前端调用后端接口 /send-code 发送验证码。
如果手机号格式错误或发送失败,前端会提示错误信息。

用户注册 :

用户输入手机号、验证码、用户名、密码和确认密码后,点击“立即注册”按钮。
前端调用后端接口 /register 提交注册信息。
如果注册成功,提示用户“注册成功!”;否则提示错误信息。

返回登录 :

提供“返回登录”按钮,用户可以跳转回登录界面。

界面设计

提供清晰的输入框和按钮。
实时显示状态提示(如验证码发送成功或失败)。

3. 主界面模块

核心功能
用户输入处理 :

用户输入问题后,点击“提交”按钮或按 Enter 键。
前端调用后端接口 /chat 获取模型的回答。
将用户输入和模型回答更新到聊天历史记录中。

新建对话 :

用户点击“开启新对话”按钮。
前端调用后端接口 /save_conversation 保存当前对话记录,并清空聊天历史。

切换侧边栏 :

用户可以点击“切换侧边栏”按钮展开或收起侧边栏。

二维码窗口 :

用户点击“手机端下载”按钮,显示二维码窗口。
点击关闭按钮隐藏二维码窗口。

快捷问题 :

提供三个快捷问题按钮,用户点击后自动填充到输入框。

4. 历史记录模块

核心功能

获取历史记录 : 前端调用后端接口 /get_conversation 获取历史记录。
如果后端不可用,使用本地模拟数据。

动态更新 :

用户选择时间范围或输入搜索关键词后,前端动态更新历史记录。

返回主界面 :

提供“返回主界面”按钮,用户可以跳转回主界面。

界面设计

提供时间范围选择器和搜索框。 使用 HTML 动态生成历史记录列表。

三、相应的接口(前后端交互)

在接口设计的过程中,一定要设计好请求参数相应参数,如果未确定好请求响应的参数,在与后端交互的时候会有很多不必要的麻烦。以下是我设计的相关参数,读者也可以自己去设计添加更多的参数以优化自己系统的功能。
接口概览表

模块接口地址请求方法功能说明调用位置
登录模块/send_verification_codePOST发送验证码登录界面发送按钮
/verify_code_loginPOST验证码登录验证码登录按钮
/loginPOST密码登录密码登录按钮
注册界面/send-codePOST发送注册验证码注册界面发送按钮
/registerPOST提交注册信息注册按钮
主界面/chatPOST处理用户提问聊天消息提交
/save_conversationPOST保存对话记录新建对话按钮
历史记录/get_conversationPOST获取历史对话历史记录页面加载
  1. 登录模块
    1.1 发送验证码
    请求地址

/send_verification_code
请求参数

{"phone_email": "用户输入的手机号或邮箱"}

响应示例

{"message": "验证码已发送,请查收!"}
{ "detail": "错误信息(如手机号格式错误)"}

1.2 验证码登录
请求地址

/verify_code_login

请求参数

{"phone_email": "用户输入的手机号或邮箱","code": "用户输入的验证码"
}

响应示例

{"status": "success","message": "登录成功!"
}
{"status": "error","detail": "验证码错误,请重新输入!"
}

1.3 密码登录
请求地址

/login

请求参数

{"username": "用户名","password": "密码"
}

响应示例

{"status": "success","message": "登录成功!","user_id": 12345
}
{"status": "error","detail": "用户名或密码错误!"
}
  1. 注册模块
    2.1 发送注册验证码
    请求地址

/send-code

请求参数

{"phone_number": "用户输入的手机号"}

响应示例

# 成功
{ "message": "验证码已发送至 {phone_number}"}
# 失败
{"message": "发送失败:错误信息"}

2.2 提交注册
请求地址

/register

请求参数

{"username": "用户名","password": "密码"
}

响应示例

# 成功
{ "message": "注册成功!"}
# 失败
{ "message": "注册失败:错误信息"}
  1. 主界面

3.1 处理用户提问
请求地址

/chat

请求参数

{"user_input": "用户输入的问题","chat_history": [{"role": "user", "content": "用户输入"},{"role": "assistant", "content": "模型回答"}]
}

响应示例

# 成功
{"status": "success","response": "模型生成的回答","chat_history": [{"role": "user", "content": "用户输入"},{"role": "assistant", "content": "模型回答"}]
}
# 失败
{"status": "error","detail": "无法处理请求,请稍后再试!"
}

3.2 保存对话记录
请求地址

/save_conversation

请求参数

{"user_id": "用户ID","conversation": [{"user_input": "用户输入"},{"bot_response": "模型回答"}]
}

响应示例

# 成功
{ "message": "对话记录保存成功"}
# 失败
{"message": "保存失败:错误信息"}
  1. 历史记录模块

4.1 获取历史对话
请求地址

/get_conversation

请求参数

{"user_id": "用户ID","time_period": "时间范围(本周/本月/本年/全部)","search_query": "搜索关键词"
}

响应示例

# 成功
{"status": "success","chat_history": [{"title": "会话标题","content": "会话内容","date": "会话日期"},...]
}
# 失败
{"status": "error","detail": "无法获取历史记录,请稍后再试!"
}

四、实现前端界面的设计

当确定好接口,设计好界面,我们就可以进行编程了。
这是文件目录:
在这里插入图片描述

config.py

# config.py# 后端 API 地址
BASE_URL = "http://localhost:8000"

History_g1.py

import gradio as gr
import requests
import json
from config import BASE_URLdef fetch_history(user_id, time_period="全部", search_query=""):"""从后端接口或 mock_history_data 获取历史记录。:param user_id: 用户的唯一标识:param time_period: 时间范围("本周", "本月", "本年", "全部":param search_query: 搜索关键词:return: 历史记录数据"""try:# 构造请求数据payload = {"user_id": user_id,"time_period": time_period,"search_query": search_query,}# 发送 POST 请求到后端 APIresponse = requests.post(f"{BASE_URL}/get_conversation", json=payload)# 检查响应状态码if response.status_code == 200:# 解析后端返回的数据history_data = response.json().get("chat_history", [])# 数据适配:确保返回的是嵌套列表,每个元素是一个字典formatted_data = []for index, item in enumerate(history_data):# print(f"处理第 {index + 1} 条记录: {item}")  # 输出当前处理的记录if isinstance(item, list):  # 判断是否为嵌套列表valid_conversation = []for record in item:# print(f"  当前记录: {record}, 类型: {type(record)}")  # 输出当前记录及其类型# 如果记录是字符串形式的 JSON,尝试解析为 Python 对象if isinstance(record, str) and (record.startswith("[") or record.startswith("{")):try:record = json.loads(record.replace("'", '"'))  # 替换单引号为双引号# print(f"    成功解析字符串 JSON: {record}")except json.JSONDecodeError:# print(f"    无法解析字符串 JSON: {record}")continue# 如果解析后的对象是列表,则遍历其中的每个元素if isinstance(record, list):for sub_record in record:if isinstance(sub_record, dict):  # 判断是否为字典# print(f"      子记录字典内容: {sub_record.keys()}")  # 输出子记录字典的键if "user_input" in sub_record or "bot_response" in sub_record:# 添加默认 date 字段sub_record.setdefault("date", "未知日期")valid_conversation.append(sub_record)else:print(f"      非字典子记录: {sub_record}")elif isinstance(record, dict):  # 判断是否为字典# print(f"    字典内容: {record.keys()}")  # 输出字典的键if "user_input" in record or "bot_response" in record:# 添加默认 date 字段record.setdefault("date", "未知日期")valid_conversation.append(record)else:print(f"    非字典记录: {record}")if valid_conversation:  # 只保留有效的对话记录formatted_data.append(valid_conversation)else:print(f"非嵌套列表记录: {item}")print(f"后端返回的原始数据: {history_data}")print(f"格式化后的数据: {formatted_data}")return formatted_dataelse:print(f"后端错误: {response.status_code}")raise Exception("后端返回错误状态码")except Exception as e:# 如果后端调用失败,回退到本地模拟数据print(f"调用后端接口失败: {str(e)}")def update_history(user_id, time_period="全部", search_query=""):"""根据时间范围和搜索关键词动态更新历史记录。:param user_id: 用户的唯一标识:param time_period: 时间范围("本周", "本月", "本年", "全部":param search_query: 搜索关键词:return: 历史记录 HTML 内容"""# 获取所有历史记录all_conversations = fetch_history(user_id, time_period, search_query)# 构造 HTML 输出内容if not all_conversations:return "<div style='color: gray;'>暂无历史记录</div>"html_content = []for conversation in all_conversations:# 第一条提问作为超链接标题first_user_input = conversation[0].get("user_input", "无标题")first_date = conversation[0].get("date", "未知日期")# 超链接部分html_content.append(f'''<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;"><button style="background: none; border: none; color: blue; text-decoration: underline; cursor: pointer;" onclick="handleButtonClick('{first_user_input}')">{first_user_input}</button><span style="margin-left: 10px; color: gray;">{first_date}</span></div>''')return "\n".join(html_content)def show_conversation_details(conversation_title, user_id, time_period="全部", search_query=""):"""根据超链接标题显示对应对话的详细信息。:param conversation_title: 对话标题(第一条提问的内容):param user_id: 用户的唯一标识:param time_period: 时间范围("本周", "本月", "本年", "全部":param search_query: 搜索关键词:return: 对话详细信息的 HTML 内容"""# 获取所有历史记录all_conversations = fetch_history(user_id, time_period, search_query)# 找到对应标题的对话for conversation in all_conversations:if conversation[0].get("user_input") == conversation_title:html_content = []for record in conversation:if "user_input" in record:content = f"用户提问: {record['user_input']}"elif "bot_response" in record:content = f"机器人回复: {record['bot_response']}"html_content.append(f'<div style="margin-left: 20px;">{content} <span style="margin-left: 10px; color: gray;">{record["date"]}</span></div>')return "<br>".join(html_content)return "<div style='color: gray;'>未找到相关对话</div>"def history_interface(user_id_state):"""历史记录界面的封装函数"""with gr.Column() as history_content:gr.Markdown("# 历史会话")with gr.Row(elem_classes="highlight-border"):# 添加返回按钮back_to_main_btn = gr.Button("返回主界面", elem_classes="send-btn4", elem_id="back-to-main-btn")change_btn = gr.Button("刷新", elem_classes="send-btn4", elem_id="change_btn")# 时间范围选择器with gr.Row(elem_classes="highlight-border"):time_period_dropdown = gr.Dropdown(choices=["本周", "本月", "本年", "全部"],label="选择时间范围",value="全部")# 搜索框with gr.Row(elem_classes="highlight-border"):search_box = gr.Textbox(label="搜索历史会话", placeholder="输入关键词搜索")# 历史记录展示区域with gr.Group(elem_classes="highlight-border"):history_output = gr.HTML()# # 隐藏的 Textbox 用于触发事件# click_event_trigger = gr.Textbox(visible=False)# 刷新按钮事件change_btn.click(fn=update_history,inputs=[user_id_state, time_period_dropdown, search_box],outputs=[history_output])# 动态生成按钮并绑定事件def on_link_click(link_text):detailed_info = show_conversation_details(link_text, user_id_state.value, "全部", "")return detailed_info# 获取历史记录并动态生成按钮all_conversations = fetch_history(user_id_state.value, "全部", "")buttons = []for conversation in all_conversations:first_user_input = conversation[0].get("user_input", "无标题")button = gr.Button(first_user_input, elem_classes="history-button",style="background: none; border: none; color: blue; text-decoration: underline; cursor: pointer;")button.click(fn=on_link_click,inputs=[gr.State(first_user_input)],  # 使用 State 传递按钮的文本outputs=[history_output])buttons.append(button)return history_content, back_to_main_btn, change_btn, history_output, search_box, time_period_dropdown

Login.py

import gradio as gr
import requests
from config import BASE_URL
import global_vars# 后端 API 地址# 发送验证码
def send_verification_code(phone_email):"""发送验证码到后端"""if len(phone_email) != 11 or not phone_email.isdigit():return "手机号格式错误,请输入11位数字!"url = f"{BASE_URL}/send_verification_code"response = requests.post(url, json={"phone_email": phone_email})if response.status_code == 200:return response.json().get("message", "验证码已发送,请查收!")else:return response.json().get("detail", "没链接呢")# 验证码登录验证
def login_with_code(phone_email, code):"""验证码登录验证"""url = f"{BASE_URL}/verify_code_login"response = requests.post(url, json={"phone_email": phone_email, "code": code})if response.status_code == 200:return "登录成功!"else:return response.json().get("detail", "验证码错误,请重新输入!")
# 密码登录验证
'''
返回结果:
{"status": "success","message": "登录成功!","user_id": 12345
}
{"status": "error","detail": "用户名或密码错误!"
}
'''
def login_handler(username, password):"""密码登录验证的前端逻辑"""if not username or not password:return "用户名和密码不能为空!", False  # 返回错误信息和跳转标志# 打印调试信息(可选)print(f"正在验证:用户名={username}, 密码={password[:4]}")# 调用后端接口进行验证url = f"{BASE_URL}/login"response = requests.post(url, json={"username": username, "password": password})if response.status_code == 200:data = response.json()if data.get("status") == "success":user_id = data.get("user_id", "")global_vars.user_id_state = usernamereturn "登录成功!", True  # 返回成功信息和跳转标志else:return data.get("detail", "登录失败!"), False  # 返回错误信息和跳转标志else:return response.json().get("detail", "服务器错误!"), False  # 返回错误信息和跳转标志# 用户注册
def register_handler(username, password):"""用户注册的前端逻辑"""if not username or not password:return "用户名和密码不能为空!"# 打印调试信息(可选)print(f"正在注册:用户名={username}, 密码={password[:4]}****")# 调用后端接口进行注册url = f"{BASE_URL}/register"response = requests.post(url, json={"username": username, "password": password})if response.status_code == 200:return "注册成功,请登录!"else:return response.json().get("detail", "注册失败!")def forgot_password():return "请联系管理员重置密码!"def login_interface():"""登录界面的封装函数"""with gr.Column() as login_content:  # 使用 Column 而不是 Blocksgr.Markdown("# logo+名称", elem_classes="centered-containerL")with gr.Row(elem_classes="gradio-containerL"):# 左侧扫码登录区域with gr.Column(scale=1,elem_classes="highlight-border"):gr.Markdown("""<h1 style="font-size: 20px; color: #007BFF; text-align: center;">微信扫码 快速登录</h1>""")gr.Markdown("""<h1 style="font-size: 20px; color: #000000; text-align: center;">——————————————</h1>""")image = gr.Image("WX.jpg", elem_id="custom-image", height=300)# 验证码登录选项卡with gr.TabItem("验证码登录",elem_classes="highlight-border"):phone_email = gr.Textbox(label="手机号/邮箱",placeholder="请输入手机号或邮箱",info="区分大小写,不含空格",elem_classes="input-field",)code = gr.Textbox(show_label=False,placeholder="输入验证码",)send_btn = gr.Button("发送验证码",elem_classes="send-btnL",)send_status = gr.Markdown(value="", elem_classes="status-text")login_code_button = gr.Button("登录", variant="primary", elem_id="login-confirm-btn")login_result = gr.Textbox(label="操作结果", interactive=False)# 密码登录选项卡with gr.TabItem("密码登录",elem_classes="highlight-border"):username = gr.Textbox(show_label=False,placeholder="用户名",info="区分大小写,不含空格",elem_classes="input-field",)password = gr.Textbox(show_label=False,type="password",placeholder="输入密码",)forgot_btn = gr.Button("忘记密码?")login_pwd_button = gr.Button("登录", variant="primary", elem_id="login-confirm-btn")register_button = gr.Button("注册",  elem_id="register-btn")login_result = gr.Textbox(label="操作结果", interactive=False) # interactive=False 无法编辑should_redirect = gr.State(False)send_btn.click(send_verification_code,inputs=[phone_email],outputs=[send_status])login_code_button.click(login_with_code,inputs=[phone_email, code],outputs=[login_result])# 绑定登录按钮事件login_pwd_button.click(login_handler,inputs=[username, password],outputs=[login_result, should_redirect])forgot_btn.click(forgot_password,inputs=[],outputs=[login_result])register_button.click(register_handler,inputs=[username, password],outputs=[login_result])return login_content, register_button, login_code_button, login_pwd_button,should_redirect,login_result,username

Main.py

import gradio as gr
import requestsfrom global_vars import user_id_state
from config import BASE_URL
from copy import deepcopy'''
后端返回的类型:正确{"status": "success","response": "你好!有什么可以帮您的吗?","chat_history": [{"role": "user", "content": "你好"},{"role": "assistant", "content": "你好!有什么可以帮您的吗?"}{"role": "user", "content": "你好"},{"role": "assistant", "content": "你好!有什么可以帮您的吗?"}]
错误:{"status": "error","detail": "无法处理请求,请稍后再试!"}
'''#之前的
# def process_user_input(user_input, chat_history):
#     """处理用户输入并更新聊天记录。"""
#     try:
#         #chat_history 发送格式 List[Dict[str, str]]
#         formatted_chat_history = chat_history if isinstance(chat_history, list) else []
#         formatted_chat_history.append({"role": "user", "content": user_input})
#
#         # 构造请求数据
#         payload = {
#             "user_input": user_input,
#             "chat_history": formatted_chat_history  # 发送 JSON 格式正确的 chat_history
#         }
#         # 发送 POST 请求到后端 API
#         response = requests.post(f"{BASE_URL}/chat", json=payload)
#
#         # 检查响应状态码
#         if response.status_code == 200:
#             data = response.json()
#             if data.get("status") == "success":
#                 bot_response = data.get("response", "后端未返回有效数据")
#                 #返回 Gradio Chatbot 需要 List[Dict[str, str]]
#                 chat_history.append({"role": "assistant", "content": bot_response})
#             else:
#                 error_message = data.get("detail", "后端返回无效数据")
#                 chat_history.append({"role": "assistant", "content": error_message})
#         else:
#             error_message = f"后端错误: {response.status_code}"
#             chat_history.append({"role": "assistant", "content": error_message})
#     except Exception as e:
#         error_message = f"通信失败: {str(e)}"
#         chat_history.append({"role": "assistant", "content": error_message})
#
#     return "", chat_historydef process_user_input(user_input, chat_history):"""处理用户输入并更新聊天记录。"""try:# 构造请求数据payload = {"user_input": user_input,"chat_history": chat_history  # 发送 JSON 格式正确的 chat_history}# 发送 POST 请求到后端 APIresponse = requests.post(f"{BASE_URL}/chat", json=payload)# 检查响应状态码if response.status_code == 200:data = response.json()if data.get("status") == "success":bot_response = data.get("response", "后端未返回有效数据")chat_history.append({"role": "assistant", "content": bot_response})else:error_message = data.get("detail", "后端返回无效数据")chat_history.append({"role": "assistant", "content": error_message})else:error_message = f"后端错误: {response.status_code}"chat_history.append({"role": "assistant", "content": error_message})except Exception as e:error_message = f"通信失败: {str(e)}"chat_history.append({"role": "assistant", "content": error_message})return "", chat_historydef toggle_sidebar(expand):"""切换侧边栏处理"""if expand:return gr.update(visible=True), gr.update(visible=False)else:return gr.update(visible=False), gr.update(visible=True)def toggle_qrcode(show_qrcode):"""显示或隐藏二维码窗口。"""return gr.update(visible=show_qrcode)def fill_input(text, user_input):return textdef update_and_scroll(user_input, chat_history):"""更新聊天记录并模拟滚动到底部"""# Step 1: 立即更新用户输入到聊天记录中if not chat_history:chat_history = []chat_history.append({"role": "user", "content": user_input})# 返回清空的输入框和更新后的聊天记录(显示用户输入)yield "", chat_history# Step 2: 异步处理后端请求_, updated_chat_history = process_user_input(user_input, chat_history)# 返回最终结果(包含后端响应)yield "", updated_chat_history# def update_and_scroll(user_input, chat_history):
#
#     # Step 1: 立即更新用户输入到聊天记录中
#     if not chat_history:
#         chat_history = []
#     chat_history.append({"role": "user", "content": user_input})
#
#     # 返回清空的输入框和更新后的聊天记录(显示用户输入)
#     yield "", deepcopy(chat_history)
#
#     # Step 2: 异步处理后端请求
#     _, updated_chat_history = process_user_input(user_input, deepcopy(chat_history))
#
#     # 返回最终结果(包含后端响应)
#     yield "", deepcopy(updated_chat_history)#调用后端
def save_and_clear_conversation(chat_history,user_id_state):"""新建对话功能事件1.保存当前对话记录到后端,并清空聊天记录。:param chat_history: 当前的聊天记录(List[Dict[str, str]] 格式):param user_id_state: 用户 ID(用于标识用户):return: 清空后的聊天记录"""try:# 将 chat_history 转换为后端所需的格式formatted_conversation = []for entry in chat_history:role = entry.get("role", "")content = entry.get("content", "")if role == "user":formatted_conversation.append({"user_input": content})elif role == "assistant":formatted_conversation.append({"bot_response": content})# 构造请求数据payload = {"user_id": user_id_state,"conversation": formatted_conversation}# 发送 POST 请求到后端 APIresponse = requests.post(f"{BASE_URL}/save_conversation", json=payload)# 检查响应状态码if response.status_code == 200:print("对话记录保存成功")else:print(f"后端错误: {response.status_code}")except Exception as e:print(f"通信失败: {str(e)}")# 清空聊天记录return []# # 定义全局变量用于存储聊天记录状态
# chat_history_state = gr.State([])
def main_interface(user_id_state):"""主界面的封装函数"""with gr.Column() as register_content:# 插入自定义 CSSgr.HTML("""<style>.custom-button {width:50px;height: 40px;font-size: 14px;}/* 自定义 Chatbot 样式 */.chatbot-wrap {max-height: 1000px; /* 设置最大高度 */overflow-y: auto; /* 启用垂直滚动条 */border: 1px solid #ccc; /* 添加边框 */padding: 10px; /* 内边距 */border-radius: 8px; /* 圆角 */}/* 二维码窗口样式 */.qrcode-window {position: fixed; /* 固定定位 */top: 20px;right: 20px;width: 250px;background-color: white;border: 1px solid #ccc;padding: 15px;box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);z-index: 1000; /* 确保在最上层 */}.qrcode-window h3 {margin-top: 0;}.qrcode-close-btn {float: right;cursor: pointer;color: red;}</style>""")with gr.Row(elem_classes="highlight-border"):with gr.Row(elem_classes="highlight-border"):# toggle_button = gr.Button("切换侧边栏", elem_classes="send-btn2")# 添加返回按钮back_tologin_btn = gr.Button("退出", elem_classes="send-btn4", elem_id="back-to-login-btn")with gr.Column(min_width=200, scale=1, visible=True,elem_classes="highlight-border") as sidebar_expanded:# gr.Markdown("侧边栏展开")gr.Image(value="panda.jpg", elem_classes="highlight-border")new_chat_button = gr.Button("开启新对话", elem_classes="send-btn")history_btn = gr.Button("历史记录", elem_classes="send-btn")more_features_button = gr.Button("更多功能", elem_classes="send-btn")favorites_button = gr.Button("收藏对话", elem_classes="send-btn")settings_button = gr.Button("个人设置", elem_classes="send-btn")mobile_download_button = gr.Button("手机端下载", elem_classes="send-btn")desktop_download_button = gr.Button("电脑端下载", elem_classes="send-btn")with gr.Column(min_width=100, scale=1, visible=False,elem_classes="highlight-border") as sidebar_collapsed:gr.Markdown("缩小")gr.Image(value="panda.jpg" ,elem_classes="highlight-border")gr.Button("新对话", elem_classes="send-btn")# 添加跳转按钮history_button = gr.Button("查看历史记录", elem_id="history-btn")gr.Button("更多", elem_classes="send-btn")gr.Button("收藏", elem_classes="send-btn")gr.Button("设置", elem_classes="send-btn")gr.Button("手载", elem_classes="send-btn")gr.Button("电载", elem_classes="send-btn")# toggle_button.click(lambda: toggle_sidebar(True), outputs=[sidebar_expanded, sidebar_collapsed])# toggle_button.click(lambda: toggle_sidebar(False), outputs=[sidebar_expanded, sidebar_collapsed])with gr.Column(scale=4,elem_classes="highlight-border"):gr.Markdown("""<h1 style="font-size: 60px; color: #007BFF; text-align: center;">我是小希,很高兴与您交流</h1><p style="font-size: 24px; color: #333; text-align: center;">我可以帮你写代码、读文件、写作各种创意内容,请把你的任务交给我吧~</p>""")# 聊天历史记录组件chat_history = gr.Chatbot(label="聊天框", elem_classes="chatbot-wrap",type="messages")user_input = gr.Textbox(label="请输入您的问题", placeholder="宇宙超强大脑小希为您解忧消愁,摆脱一切烦恼!")with gr.Row(elem_classes="highlight-border"):# 左侧占位(可留空)gr.HTML("")gr.HTML("")gr.HTML("")gr.HTML("")gr.HTML("")submit_button = gr.Button("提交", elem_classes="send-btn3")# 创建一个隐藏的文本框用于存储问题hidden_textbox = gr.Textbox(visible=False)# 使用 gr.Row 将三个按钮放在一行展示with gr.Row(elem_classes="highlight-border"):weather_question = gr.Button("贷款流程是什么?", elem_classes="send-btn2")guide_question = gr.Button("贷款材料需要什么",elem_classes="send-btn2")click_answer = gr.Button("点击就可解答",elem_classes="send-btn2")weather_question.click(lambda: fill_input("贷款流程是什么?", hidden_textbox), outputs=hidden_textbox)guide_question.click(lambda: fill_input("贷款材料需要什么", hidden_textbox), outputs=hidden_textbox)click_answer.click(lambda: fill_input("点击就可解答", hidden_textbox), outputs=hidden_textbox)# 将隐藏文本框的内容复制到用户输入框hidden_textbox.change(lambda x: x, inputs=hidden_textbox, outputs=user_input)# 手机端下载二维码窗口(悬浮窗口)with gr.Column(visible=False, elem_classes="highlight-border") as qrcode_window:gr.Markdown("### 扫码下载")close_button = gr.Button("×", elem_classes="qrcode-close-btn")gr.Image(value="WX.jpg", label="手机端下载二维码")# 按钮绑定事件mobile_download_button.click(lambda: toggle_qrcode(True), outputs=[qrcode_window])close_button.click(lambda: toggle_qrcode(False), outputs=[qrcode_window])# desktop_download_button.click(lambda: show_page("desktop_download"), outputs=[register_content, desktop_download_page])# back_to_home_button.click(lambda: show_page("home"), outputs=[register_content, desktop_download_page])# 其他按钮事件# 在 main_interface 函数中绑定 new_chat_button 的事件new_chat_button.click(save_and_clear_conversation,inputs=[chat_history,user_id_state],outputs=[chat_history])history_button.click()history_btn.click()more_features_button.click()favorites_button.click()settings_button.click()# 将按钮和 Textbox 的 Enter 键绑定到同一个回调函数submit_button.click(update_and_scroll,inputs=[user_input, chat_history],outputs=[user_input, chat_history])# 监听 Enter 键事件user_input.submit(update_and_scroll,inputs=[user_input, chat_history],outputs=[user_input, chat_history])return register_content, history_btn, history_button, back_tologin_btn

Register.py

import gradio as gr
import requests
from config import BASE_URLdef send_verification_code(phone_number, status_text):"""调用后端发送验证码接口"""if not phone_number.isdigit() or len(phone_number) != 11:return gr.update(value="⚠️ 手机号格式不正确"), status_texttry:# 模拟调用后端发送验证码接口response = requests.post(f"{BASE_URL}/send-code",  # 使用 BACKEND_URLjson={"phone_number": phone_number})if response.status_code == 200:# 返回成功消息return gr.update(value=f"✅ 验证码已发送至 {phone_number}"), status_textelse:# 返回错误消息error_message = response.json().get("message", "未知错误")return gr.update(value=f"❌ 发送失败:{error_message}"), status_textexcept Exception as e:# 捕获网络错误return gr.update(value=f"❌ 网络错误:{str(e)}"), status_textdef register_user(phone, code, username, password, confirm_pwd, status_text):"""调用后端注册接口"""# 验证密码一致性if password != confirm_pwd:return gr.update(value="⚠️ 两次输入的密码不一致"), status_texttry:# 调用后端注册接口response = requests.post(f"{BASE_URL}/register",  # 使用 BACKEND_URLjson={# "phone_number": phone,# "code": code,"username": username,"password": password,# "confirm_password": confirm_pwd})if response.status_code == 200:# 注册成功return gr.update(value="🎉 注册成功!"), status_textelse:# 注册失败,返回错误信息error_message = response.json().get("message", "注册失败")return gr.update(value=f"❌ {error_message}"), status_textexcept Exception as e:# 捕获网络错误return gr.update(value=f"❌ 网络错误:{str(e)}"), status_textdef register_interface():"""注册界面的封装函数"""with gr.Column() as register_content:  # 移除 css 参数gr.Markdown("# 用户注册", elem_classes="centered-containerR")with gr.Column(elem_classes="gradio-containerR"):with gr.Row(elem_classes="highlight-border"):gr.Button("手机号注册", variant="secondary")with gr.Row(elem_classes="highlight-border"):username = gr.Textbox(label="用户名(必填)", placeholder="请输入用户名")with gr.Row(elem_classes="highlight-border"):phone = gr.Textbox(label="+86(中国) 手机号", placeholder="请输入手机号")password = gr.Textbox(label="密码(必填)", type="password", placeholder="请输入密码")with gr.Row(elem_classes="highlight-border"):code_input = gr.Textbox(label="短信验证码", placeholder="请输入收到的6位验证码")confirm_password = gr.Textbox(label="确认密码(必填)", type="password", placeholder="请确认密码")with gr.Row(elem_classes="highlight-border"):send_code_btn = gr.Button("获取验证码", variant="primary", elem_classes="send-btn3")with gr.Row(elem_classes="highlight-border"):gr.Markdown("已有账号,[去登录](#) 返回到初始界面", elem_classes="centered-containerR")register_btn = gr.Button("立即注册", variant="success")# 添加返回按钮back_to_login_btn = gr.Button("返回登录", elem_id="back-to-login-btn")status_text = gr.Textbox(label="状态提示",interactive=False)# # 绑定发送验证码事件# send_code_btn.click(#     send_verification_code,#     inputs=[phone, status_text],#     outputs=[status_text]# )# 绑定注册事件register_btn.click(register_user,inputs=[phone, code_input, username, password, confirm_password, status_text],outputs=[status_text])return register_content, send_code_btn, register_btn, back_to_login_btn

App.py

# 主文件,负责整合所有界面
import gradio as gr
from Login import login_interface
from Register import register_interface
from Main import main_interface
from History import history_interface,fetch_history
import global_vars'''
通用返回值设计形式:
{"status": "success/error",  // 请求状态"message": "操作成功的描述信息",  // 成功时的提示信息"data": {                   // 成功时的附加数据(可选)"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","user_id": 12345},"detail": "失败时的具体原因"  // 错误时的详细信息
}
'''
# 定义全局变量用于跟踪当前界面
current_page = "login"# 定义跳转逻辑
def navigate_to_register():"""从登录界面跳转到注册界面"""return gr.update(visible=False), gr.update(visible=True), gr.update(visible=False), gr.update(visible=False)def navigate_to_login():"""从注册界面跳转到登录界面"""return gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)def navigate_to_main2():"""从登录界面跳转到主界面"""return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)def navigate_to_main1(login_result, should_redirect):"""根据登录结果决定是否跳转到主界面。"""if should_redirect:return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)else:return gr.update(), gr.update()  # 不跳转,保持当前界面def navigate_to_history():"""从主界面跳转到历史记录界面"""# print(global_vars.user_id_state)# # update_history(user_id_state)# user_id_state.value = global_vars.user_id_state# # history_content,back_to_main_btn,change_btn,history_output, search_box= history_interface(user_id_state)# # print(global_vars.user_id_state)# print(f"history_context: {history_content}")# print(f"history_output: {history_output}")# # history_context = "123456"return gr.update(visible=False), gr.update(visible=False), gr.update(visible=False), gr.update(visible=True),gr.update(value=history_output.value)def navigate_to_main_from_history():"""从历史记录界面跳转到主界面"""return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True), gr.update(visible=False)def updateA_history(user_id_state):history_data = fetch_history(user_id_state)return gr.update(value=history_data)# 定义全局 CSS 样式
css = """
.gradio-containerR{    /* Register的相关 */max-width: 50%;margin: 40px auto;padding: 40px;border: 1px solid #ccc;border-radius: 8px;box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.centered-containerR{text-align: center;
}
.input-rowR{display: flex;justify-content: space-between;margin-bottom: 16px;
}
.input-rowR > * {width: 48%;
}
.button-rowR {display: flex;justify-content: center;margin-top: 16px;
}.gradio-containerL { /*登录界面*/width: 840px; /* 固定宽度 */height: 550px; /* 固定高度 */margin: auto; /* 水平居中 */display: flex; /* 使用 Flexbox 实现内容居中 */align-items: center; /* 垂直居中 */justify-content: center; /* 水平居中 */border: 6px solid #e0e0e0; /* 外边框 */border-radius: 16px; /* 圆角 */box-shadow: 0px 4px 12px rgba(0, 0, 0, 0.1); /* 阴影效果 */background: linear-gradient(145deg, #ffffff, #f8f9fa); /* 渐变背景 */
}.verification-boxL {height: 60px; margin-bottom: 15px;}
.send-btnL {width: 100%; background: #4CAF50; color: white; border: none; padding: 12px 0;}
#custom-galleryL {background-color: #f0feee !important; border-radius: 8px;}/* 新增样式 */
.button-primary {background-color: #4CAF50 !important;color: white !important;border: none !important;padding: 10px 20px !important;font-size: 16px !important;cursor: pointer !important;
}.button-secondar {background-color: #f0f0f0 !important;color: black !important;border: none !important;padding: 10px 20px !important;font-size: 16px !important;cursor: pointer !important;
}.send-btn {width: 80%;height: 50%; /* 固定高度 */background-color: 	#F4A460; /*  */color: black; /* 白色文字 */font-size: 16px;border: none;border-radius: 5px;cursor: pointer;/* 居中对齐 */display: block; /* 块级元素:将按钮设置为块级元素,以便可以使用 margin 属性进行居中 */margin-left: 30px; /* 左外边距自动:水平方向左对齐 */margin-right: 10px; /* 右外边距自动:水平方向右对齐 */margin-top: 5px; /* 上外边距:设置按钮距离上方 10px 的间距(可选) */margin-bottom: 5px; /* 下外边距:设置按钮距离下方 10px 的间距(可选) */
}
.send-btn2 {    # width: 50px;# height: 50px; /* 较小的高度 */background-color: #8B003; /* 木色 */color: white;font-size: 18px;border: none;border-radius: 5px;cursor: pointer;/* 居中对齐 */display: block; /* 块级元素:将按钮设置为块级元素,以便可以使用 margin 属性进行居中 */margin-left: 80px; /* 左外边距自动:水平方向左对齐 */margin-right: 80px; /* 右外边距自动:水平方向右对齐 */margin-top: 5px; /* 上外边距:设置按钮距离上方 10px 的间距(可选) */margin-bottom: 5px; /* 下外边距:设置按钮距离下方 10px 的间距(可选) */}.send-btn3 {width: 50px; /* 自动宽度:按钮宽度根据内容自动调整 */height: 50px; /* 中等高度:设置按钮的固定高度为 35px */background-color:  #4CAF50; /* 蓝色背景:设置按钮的背景颜色为蓝色 (#2196F3) */color: white; /* 白色文字:设置按钮的文字颜色为白色 */font-size: 15px; /* 字体大小:设置按钮文字的字体大小为 15px */border: none; /* 无边框:移除按钮的默认边框 */border-radius: 20px; /* 圆角:设置按钮的圆角半径为 5px,使其看起来更柔和 */cursor: pointer; /* 鼠标悬停时显示手型光标:提示用户该按钮是可点击的 *//* 居中对齐 */display: block; /* 块级元素:将按钮设置为块级元素,以便可以使用 margin 属性进行居中 */margin-left: auto; /* 左外边距自动:将按钮推到右边 */margin-right: 0; /* 右外边距为 0:确保按钮紧贴容器右边 */}
.send-btn4 {width: 50px; /* 自动宽度:按钮宽度根据内容自动调整 */height: 50px; /* 中等高度:设置按钮的固定高度为 35px */background-color: #808080; /* 蓝色背景:设置按钮的背景颜色为蓝色 (#2196F3) */color: white; /* 白色文字:设置按钮的文字颜色为白色 */font-size: 15px; /* 字体大小:设置按钮文字的字体大小为 15px */border: none; /* 无边框:移除按钮的默认边框 */border-radius: 5px; /* 圆角:设置按钮的圆角半径为 5px,使其看起来更柔和 */cursor: pointer; /* 鼠标悬停时显示手型光标:提示用户该按钮是可点击的 *//* 居中对齐 */display: block; /* 块级元素:将按钮设置为块级元素,以便可以使用 margin 属性进行居中 */margin-left: 0; /* 左外边距自动:水平方向左对齐 */margin-right: 0; /* 右外边距自动:水平方向右对齐 */margin-top: 0; /* 上外边距:设置按钮距离上方 10px 的间距(可选) */margin-bottom: 0; /* 下外边距:设置按钮距离下方 10px 的间距(可选) */}.highlight-border {border: 2px solid #007BFF; /* 蓝色边框 */padding: 10px;             /* 内边距 */margin: 5px;               /* 外边距 */border-radius: 5px;        /* 圆角 */}"""# 创建主应用
with gr.Blocks(title="知识库问答系统", css=css) as demo:# 创建一个标题gr.Markdown("# 知识库问答系统")Login_state = 0# 登录界面with gr.Row(visible=True) as login_row:login_content, register_button, login_code_button, login_pwd_button ,should_redirect,login_result,username = login_interface()# 定义全局变量用于存储用户信息user_id_state = usernameprint(f"user_id_state: {global_vars.user_id_state}")# 注册界面with gr.Row(visible=False) as register_row:register_content, send_code_btn, register_btn,back_to_login_btn = register_interface()# 主界面with gr.Row(visible=False) as main_row:main_content,history_btn,history_button,back_tologin_btn= main_interface(user_id_state)# 历史记录界面with gr.Row(visible=False) as history_row:history_content,back_to_main_btn,change_btn,history_output,search_box,time_period_dropdown  = history_interface(user_id_state)from History import update_historysearch_box.change(lambda search_query, user_id: update_history(user_id, search_query),inputs=[search_box, user_id_state],outputs=[history_output])# 绑定按钮事件register_button.click(navigate_to_register,inputs=[],outputs=[login_row, register_row, main_row, history_row])back_to_login_btn.click(navigate_to_login,inputs=[],outputs=[login_row, register_row, main_row, history_row])back_tologin_btn.click(navigate_to_login,inputs=[],outputs=[login_row, register_row, main_row, history_row])# 密码登录跳转绑定login_pwd_button.click(navigate_to_main1,inputs=[login_result, should_redirect],outputs=[login_row, register_row, main_row, history_row]  # 假设 main_row 是主界面,login_row 是登录界面)# 验证码跳转绑定login_code_button.click(navigate_to_main2,inputs=[],outputs=[login_row, register_row, main_row, history_row])history_btn.click(navigate_to_history,inputs=[],outputs=[login_row, register_row, main_row, history_row, history_output]).then(fn=updateA_history,inputs=[user_id_state],outputs=[history_output])# 跳转历史记录绑定history_button.click(navigate_to_history,inputs=[],outputs=[login_row, register_row, main_row, history_row, history_output])back_to_main_btn.click(navigate_to_main_from_history,inputs=[],outputs=[login_row, register_row, main_row, history_row])# 监听时间范围选择器和搜索框的变化,动态更新历史记录def on_change(user_id, time_period, search_query):return update_history(user_id, time_period, search_query)time_period_dropdown.change(on_change,inputs=[user_id_state, time_period_dropdown, search_box],outputs=[history_output])search_box.change(on_change,inputs=[user_id_state, time_period_dropdown, search_box],outputs=[history_output])# change_btn.click(#     change_function,#     inputs=[user_id_state],#     outputs=[login_row, register_row, main_row, history_row]# )# 启动应用
demo.launch(server_name="0.0.0.0")

五、效果展示

这是前端实现完与后端进行交互之后的结果,相应的注册信息,聊天记录都是存在数据库中。

  1. 首先进行注册: 这里手机号功能后端暂未实现,只用输入用户名和密码。点击注册,会与后端进行交互存储用户信息,返回一个结果,前端根据返回结果进行相应的提示(注册成功!)
    在这里插入图片描述

  2. 登录过程,验证码、手机登录后端暂未实现,暂时支持密码登录(输入注册的用户名和密码),系统根据信息会给一个返回值,根据结果显示状态(登陆成功!):
    在这里插入图片描述

  3. 历史记录,这块是为了记录我们历史对话过程,刚注册的账号没有对话记录:

在这里插入图片描述

  1. 一轮对话:当输入问题并且有回复就说明我们与后端的交互是没有问题的,后端处理请求是基于数据库回答,在数据库中没有的情况下基于千问大模型接口来进行回答。
    第一轮对话首个问题: 贷款材料需要什么
    在这里插入图片描述
    多轮对话:在第一轮对话之后,提问回答过程中的相关内容,看它是否有分析检索的能力(这部分内容是数据库中没有的)
    在这里插入图片描述
  2. 验证基于数据库与大模型的回答

以下问题是数据库中的问题,看是否可以根据数据库中的内容直接回答。
这是第二次会话: 你好,银行贷款的五级分类

在这里插入图片描述

同样的问题,这是在千问中请求的结果,对比来看,回答的形式不同。

在这里插入图片描述

再查看数据库中的内容,这部分是完全直接输出给用户请求了。说明首先还是基于数据库进行回复的。

在这里插入图片描述

下图为再次咨询回答中某一条相关信息的具体内容的时候,他回复的在数据库中并没有,是根据学习数据库中的内容以及借助千问大模型给出的回复。

在这里插入图片描述

再重新进行一轮对话,我们问问数据库中没有的,第三轮对话内容:我有个数学难题不会解决,1+2等于,是可以正常输出的,此时就是调用千问接口进行回复的。

在这里插入图片描述
6. 查看历史会话记录

根据我们前面三次会话的第一问作为超链接显示某个会话,如图所示。

在这里插入图片描述
前端基本实现了,与刚开始设计的界面多少有差距,但是整体交互逻辑没问题。部分内容没有更新到位,希望这个笔记能更好的促进我们使用gradio,也期待宝子们的实践成果。
后端的内容请学习以下文章内容:
ollama+qwen2.5+nomic本地部署及通过API调用模型示例
使用FastAPI为知识库问答系统前端提供后端功能接口

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/73617.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

案例分享|树莓派媒体播放器,重构商场广告的“黄金三秒”

研究显示&#xff0c;与传统户外广告相比&#xff0c;数字户外广告在消费者心中的记忆率提高了17%&#xff0c;而动态户外广告更是能提升16%的销售业绩&#xff0c;整体广告效率提升了17%。这一显著优势&#xff0c;使得越来越多资源和技术流入数字广告行业。 户外裸眼3D广告 无…

23种设计模式-装饰器(Decorator)设计模式

装饰器设计模式 &#x1f6a9;什么是装饰器设计模式&#xff1f;&#x1f6a9;装饰器设计模式的特点&#x1f6a9;装饰器设计模式的结构&#x1f6a9;装饰器设计模式的优缺点&#x1f6a9;装饰器设计模式的Java实现&#x1f6a9;代码总结&#x1f6a9;总结 &#x1f6a9;什么是…

ubuntu22.04安装搜狗输入法保姆教程~

一、添加中文语言支持 1.首先打开设置,找到Language and Region 2.点击Manage Installed Languages 3.点击 Install/Remove Languages... 4.选中Chinese (simplified),点击Apply

强化学习和智能决策:Q-Learning和Deep Q-Learning算法

强化学习(Reinforcement Learning, RL)是机器学习的一个重要分支,它通过智能体(Agent)与环境交互来学习最优决策策略,旨在最大化智能体的长期累积奖励。Q-Learning和Deep Q-Learning是强化学习中的两种关键算法,它们在智能决策领域发挥着重要作用。 一、强化学习基础 …

ubuntu22.04 安装Jitsi meet 开源会议系统,代替腾讯会议

0.安装 官方安装教程Self-Hosting Guide - Debian/Ubuntu server | Jitsi Meet 一定要用域名访问&#xff0c; 一定要用域名访问&#xff0c; 一定要用域名访问&#xff0c; 一定要用域名访问&#xff0c; 域名一定要有ssl证书&#xff0c;域名一定要有ssl证书&#xff0c;域名…

专家管理系统(源码+文档+讲解+演示)

引言 在知识经济时代&#xff0c;专家管理系统成为了企业优化知识资源、提升决策效率的重要工具。本文将介绍一款创新的专家管理系统&#xff0c;该系统通过智能化工具&#xff0c;助力企业实现专家资源的高效管理和利用。 平台概述 专家管理系统采用前后端分离的架构设计&a…

关于cmd中出现无法识别某某指令的问题

今天来解决以下这个比较常见的问题&#xff0c;安装各种软件都可能会发生&#xff0c;一般是安装时没勾选注册环境变量&#xff0c;导致cmd无法识别该指令。例如mysql&#xff0c;git等&#xff0c;一般初学者可能不太清楚。 解决这类问题最主要的是了解环境变量的概念&#x…

【C++初阶】---类和对象(上)

1.类的定义 1.1类的定义格式 • class为定义类的关键字&#xff0c;Data为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后⾯分号不能省略。类体中内容称为类的成员&#xff1a;类中的变量称为类的属性或成员变量;类中的函数称为类的⽅法或者成员函数。 •…

Rust安装并配置配置vscode编译器

一. 下载rustup-init.exe rust下载网址&#xff1a;Getting started - Rust Programming Language 根据系统&#xff0c;选择适合的exe文件 我选择的的是右边64bit的 打开下载的文件 输入1&#xff0c;回车 二. Visual C 安装 自动下载安装vs 等待安装完毕 三. Rust 安装…

ECharts各类炫酷图表/3D柱形图

一、前言 最近鸡米花实现了各类的炫酷的图表&#xff0c;有3D柱形图、双边柱形图以及异形柱形图&#xff0c;好了&#xff0c;直接上图&#xff1a; 二、效果图 一个个来吧&#xff0c;下面就是代码啦&#xff0c;注意&#xff0c;一下图表展示的宽高均为800px*300px 三、异形横…

HCIP——园区网、VLAN

园区网 园区网搭建核心思路&#xff1a;冗余&#xff08;备份&#xff09;--- 保证其健壮性 1、设备冗余 2、线路冗余 3、网关冗余 4、ups&#xff08;不间断电源&#xff09;冗余—— 能不断电&#xff08;物理层&#xff09; 三层交换机和路由器的选择&#xff1a; 三层交换…

虚拟机(二):Android 篇

虚拟机&#xff08;一&#xff09;&#xff1a;Java 篇 虚拟机&#xff08;二&#xff09;&#xff1a;Android 篇 Dalvik和JVM区别 Dalvik 基于寄存器&#xff0c;而 JVM 基于栈。 基于栈的架构具有更好的可移植性&#xff0c;因为其实现不依赖于物理寄存器基于栈的架构通常指…

Vue Kubernetes项目 局部布局 下拉菜单

下拉菜单 [el-dropdown] 下拉菜单也比较简单&#xff0c;就是类似于按钮下面来一个下拉菜单。 示例Demo如下&#xff1a; <template><el-dropdown><span class"el-dropdown-link">下拉菜单<i class"el-icon-arrow-down el-icon--right&q…

Android之卡片式滑动

文章目录 前言一、效果图二、实现步骤1.主界面xml2.自定义的viewpage3.卡片接口类4.阴影和缩放变化类5.卡片adapter6.卡片adapter的xml7.style8.CardItem9.activity实现10.指示器drawable 总结 前言 对于这个需求&#xff0c;之前的项目也有做过&#xff0c;但是过于赶项目就没…

(UI自动化测试web端)第二篇:元素定位的方法_css定位之css选择器

看代码里的【find_element_by_css_selector( )】( )里的表达式怎么写&#xff1f; 文章介绍了第三种写法css选择器&#xff0c;你要根据网页中的实际情况来判断自己到底要用哪一种方法来进行元素定位。每种方法都要多练习&#xff0c;全都熟了之后你在工作当中使用起来元素定位…

使用vscode搭建pywebview集成vue项目示例

文章目录 前言环境准备项目源码下载一、项目说明1 目录结构2 前端项目3 后端项目获取python安装包(选择对应版本及系统) 三、调试与生成可执行文件1 本地调试2 打包应用 四、核心代码说明1、package.json2、vite.config.ts设置3、main.py后端入口文件说明 参考文档 前言 本节我…

C stm32f10x LED亮

#include<stm32f10x.h>int main(){#if 0 //APIOA 时钟初始化unsigned int * p(unsigned int*)0x40021018;*p | 0x1<<2;//A0 推挽输出p(unsigned int*)0x40010800;*p *p & ~0xf | 0x1;//A0低电平p(unsigned int*)0x4001080c;*p & ~0x1;#endifRCC->APB2E…

redux ,react-redux,redux-toolkit 简单总结

Redux、React-Redux 和 Redux Toolkit 是协同工作的三个库&#xff0c;各自承担不同角色&#xff0c;相互协同。 Redux&#xff1a;基础底座 底层状态管理库&#xff0c;负责状态存储、Action 派发和 Reducer 执行 ​React-Redux&#xff1a;连接 React 组件与 Redux Store 通…

智能制造:物联网和自动化之间的关系

工业自动化 工业自动化是机器设备或生产过程在不需要人工直接干预的情况下按预期的目标实现测量、操纵等信息处理和过程控制的统称。 在传统的工业生产过程中&#xff0c;很多环节需要人工操作&#xff0c;比如设备调试、生产监控、质量检测等。然而&#xff0c;随着工业自动化…

集成学习(下):Stacking集成方法

一、Stacking的元学习革命 1.1 概念 Stacking&#xff08;堆叠法&#xff09; 是一种集成学习技术&#xff0c;通过组合多个基学习器&#xff08;base learner&#xff09;的预测结果&#xff0c;并利用一个元模型&#xff08;meta-model&#xff09;进行二次训练&#xff0c…