吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2476|回复: 11
收起左侧

[Python 原创] 支持多模型的AI聊天助手py程序

[复制链接]
aifeisheng 发表于 2024-5-1 22:15
本帖最后由 aifeisheng 于 2024-5-1 22:23 编辑

AI聊天助手程序使用手册1. 程序概述本程序是一个基于Python的AI聊天助手,使用PyQt5库构建图形用户界面(GUI),集成了AI聊天对话和语音合成功能,允许用户通过文本或语音与AI进行交互。目前属于半成品,但大多数功能已经实现,属于重复造轮子里的铁轮子,仅用于学习研究。




2. 系统要求
  • Python 3.x
  • PyQt5
  • speech_recognition
  • pyttsx3
  • markdown
3. 安装指南在运行程序之前,请确保您的系统满足上述系统要求。如果缺少任何库,您可以通过以下命令安装: bash pip install PyQt5 speech_recognition pyttsx3 markdown

4. 程序功能
  • 文本聊天:用户可以通过输入框发送文本消息与AI进行对话。
  • 语音输入:用户可以开启语音输入功能,通过说话来输入文本。【当前版本未实现】
  • 情感分析:(当前版本未启用)未来版本中将提供情感分析功能。【可在模型文件通过命令实现】
  • 语音输出:用户可以开启语音输出功能,AI将以语音形式回复用户。
  • 模型选择:用户可以选择不同的AI模型进行对话。
  • 添加模型:用户可以添加自定义的AI模型文件。
  • 主题切换:用户可以在浅色和深色主题之间切换。
  • 消息历史:程序会保存聊天记录,并允许用户清空或导出历史记录。
5. 运行程序双击程序文件或在命令行中运行以下命令启动程序: bash python chat_window.py
6. 使用说明
  • 启动程序后,您将看到一个聊天窗口,可以输入文本消息并发送。
  • 要使用语音输入,请点击“语音输入”旁边的复选框,然后对着麦克风说话。
  • 要启用语音输出,请点击“语音输出”旁边的复选框,AI的回复将以语音形式播放。
  • 您可以通过下拉菜单选择不同的AI模型进行对话。
  • 点击“添加模型”按钮可以打开一个对话框,输入并保存自定义的AI模型代码。
  • 点击“帮助说明”按钮可以查看如何添加自定义AI模型的说明。
7. 退出程序您可以通过点击窗口右上角的关闭按钮或按下Alt + F4快捷键退出程序。
8. 注意事项
  • 确保在使用语音功能时麦克风可以正常工作。
  • 程序的语音识别功能依赖于网络连接,如果遇到连接问题,请检查您的网络设置。
  • 程序中的“情感分析”功能在当前版本中未启用,将在未来的更新中提供。
9. 技术支持如果您在使用程序时遇到任何问题,可以通过以下方式获取帮助: - 查看程序的帮助说明。 - 访问AI飞升社区获取更多信息和支持。
注意:本手册基于提供的程序代码编写,可能不包含所有未来的更新和功能。如果程序有新的版本发布,手册内容可能会有所变动。

  代码公开主程序文件 chat_window.py 部分(无需更改):
[Python] 纯文本查看 复制代码
import sys
import json
import os
import re  # 导入正则表达式模块
from PyQt5.QtWidgets import QApplication, QMainWindow, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout, QWidget, QLabel, QComboBox, QCheckBox, QTextBrowser, QMessageBox, QFileDialog, QDialog, QTextEdit
from PyQt5.QtGui import QFont, QIcon, QTextCursor
from PyQt5.QtCore import Qt, QDateTime
from threading import Thread
import importlib.util
import speech_recognition as sr
import pyttsx3
import markdown

class AddModelDialog(QDialog):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('添加模型')
        self.setGeometry(200, 200, 600, 400)

        main_layout = QVBoxLayout()

        code_label = QLabel('请输入模型代码:')
        self.code_editor = QTextEdit()
        self.code_editor.setPlaceholderText('在这里输入Python代码...')
        main_layout.addWidget(code_label)
        main_layout.addWidget(self.code_editor)

        button_layout = QHBoxLayout()
        self.save_button = QPushButton('保存')
        self.save_button.clicked.connect(self.save_model)
        button_layout.addWidget(self.save_button)

        self.cancel_button = QPushButton('取消')
        self.cancel_button.clicked.connect(self.close)
        button_layout.addWidget(self.cancel_button)

        main_layout.addLayout(button_layout)

        self.setLayout(main_layout)

    def save_model(self):
        model_code = self.code_editor.toPlainText()
        if model_code.strip():
            # 获取主模块文件的路径
            main_module_path = sys.modules['__main__'].__file__
            main_module_dir = os.path.dirname(main_module_path)
            file_path, _ = QFileDialog.getSaveFileName(self, "保存模型", main_module_dir, "Python文件 (*.py);;All Files (*)")
            if file_path:
                with open(file_path, 'w') as file:
                    file.write(model_code)
                QMessageBox.information(self, "提示", "模型已成功保存!")
                self.close()
        else:
            QMessageBox.warning(self, "警告", "请输入模型代码!")


class ChatWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('AI聊天助手')
        self.setGeometry(100, 100, 800, 600)
        self.setWindowIcon(QIcon('icon.png'))
        self.setStyleSheet('''
            QMainWindow {
                background-color: #F5F5F5;
            }
            QTextEdit, QTextBrowser {
                background-color: #FFFFFF;
                border: 1px solid #CCCCCC;
                border-radius: 5px;
                padding: 5px;
            }
            QLineEdit {
                border: 1px solid #CCCCCC;
                border-radius: 5px;
                padding: 5px;
            }
            QPushButton {
                background-color: #007BFF;
                color: #FFFFFF;
                border: none;
                border-radius: 5px;
                padding: 5px 10px;
            }
            QPushButton:hover {
                background-color: #0056B3;
            }
            QComboBox, QCheckBox {
                font-family: Arial;
                font-size: 14px;
            }
        ''')

        # 创建窗口主部件和布局
        central_widget = QWidget()
        main_layout = QVBoxLayout()

        # 标题栏
        header_layout = QHBoxLayout()
        header_label = QLabel('你的个人AI助手')
        header_label.setFont(QFont('Arial', 16))
        header_layout.addWidget(header_label)

        # 功能区
        function_layout = QHBoxLayout()
        self.theme_combo = QComboBox()
        self.theme_combo.addItems(['浅色', '深色'])
        self.theme_combo.currentTextChanged.connect(self.change_theme)
        function_layout.addWidget(QLabel('主题:'))
        function_layout.addWidget(self.theme_combo)
        function_layout.addSpacing(20)

        self.voice_check = QCheckBox('语音输入')
        function_layout.addWidget(self.voice_check)
        function_layout.addSpacing(20)

        self.emotion_check = QCheckBox('情感分析')
        self.emotion_check.setEnabled(False)  # Disable emotion analysis checkbox
        function_layout.addWidget(self.emotion_check)
        function_layout.addSpacing(20)

        self.tts_check = QCheckBox('语音输出')
        function_layout.addWidget(self.tts_check)
        function_layout.addStretch()

        # 模型选择区
        self.model_combo = QComboBox()
        self.update_model_list()  # 更新模型选择项
        function_layout.addWidget(QLabel('模型选择:'))
        function_layout.addWidget(self.model_combo)
        function_layout.addSpacing(20)

        # 添加模型按钮
        self.add_model_button = QPushButton('添加模型', clicked=self.add_model)
        function_layout.addWidget(self.add_model_button)

        # 添加帮助说明按钮
        self.help_button = QPushButton('帮助说明', clicked=self.show_help)
        function_layout.addWidget(self.help_button)

        # 消息历史区
        self.history_area = QTextBrowser()
        self.history_area.setReadOnly(True)

        # 输入区
        input_layout = QHBoxLayout()
        self.input_box = QLineEdit()
        self.input_box.returnPressed.connect(self.send_message)
        input_layout.addWidget(self.input_box)
        self.send_button = QPushButton('发送', clicked=self.send_message)
        input_layout.addWidget(self.send_button)

        # 清空记录按钮
        self.clear_button = QPushButton('清空记录', clicked=self.clear_history)
        input_layout.addWidget(self.clear_button)

        # 导出记录按钮
        self.export_button = QPushButton('导出记录', clicked=self.export_history)
        input_layout.addWidget(self.export_button)

        # 添加部件到主布局
        main_layout.addLayout(header_layout)
        main_layout.addLayout(function_layout)
        main_layout.addWidget(self.history_area)
        main_layout.addLayout(input_layout)

        central_widget.setLayout(main_layout)
        self.setCentralWidget(central_widget)

        # 加载聊天记录
        self.load_history()

        # 初始化语音识别器
        self.recognizer = sr.Recognizer()

        # 初始化语音合成器
        self.engine = pyttsx3.init()

        # 绑定语音输入按钮点击事件
        self.voice_check.stateChanged.connect(self.toggle_voice_input)

        # 绑定语音输出按钮点击事件
        self.tts_check.stateChanged.connect(self.toggle_tts_output)

        # 模型列表
        self.models = ['模型A', '模型B']

    def add_model(self):
        dialog = AddModelDialog()
        dialog.exec_()
        # 添加模型后更新模型选择项
        self.update_model_list()

    def update_model_list(self):
        # 清空模型选择项
        self.model_combo.clear()
        # 扫描模型文件并将其名称添加到模型选择项中
        model_files = [file for file in os.listdir() if re.match(r"model_[a-zA-Z0-9]+\.py", file)]
        for model_file in model_files:
            model_name = os.path.splitext(model_file)[0]
            self.model_combo.addItem(model_name)

    def toggle_voice_input(self, state):
        if state == Qt.Checked:
            # 开始录音
            self.listen_thread = Thread(target=self.listen_to_audio)
            self.listen_thread.start()
        else:
            # 停止录音
            self.voice_check.setCheckState(Qt.Unchecked)
            self.listen_thread.join()

    def toggle_tts_output(self, state):
        if state == Qt.Checked:
            # 启用语音输出
            self.tts_enabled = True
        else:
            # 禁用语音输出
            self.tts_enabled = False

    def listen_to_audio(self):
        with sr.Microphone() as source:
            self.input_box.setPlaceholderText("请开始说话...")
            try:
                # 使用PocketSphinx引擎识别语音
                audio = self.recognizer.listen(source)
                text = self.recognizer.recognize_sphinx(audio, language='zh-CN')
                self.input_box.setText(text)
            except sr.UnknownValueError:
                self.input_box.setPlaceholderText("无法识别,请重试...")
            except sr.RequestError:
                self.input_box.setPlaceholderText("无法连接到语音识别服务,请检查网络...")

    def send_message(self):
        user_input = self.input_box.text().strip()
        if user_input:
            # 获取当前时间戳
            timestamp = QDateTime.currentDateTime().toString('hh:mm')
            self.append_markdown_to_history(f'**[你] {timestamp}**\n{user_input}')
            self.input_box.clear()

            # 滚动到底部
            self.history_area.moveCursor(QTextCursor.End)
            self.history_area.ensureCursorVisible()  # 确保光标可见

            # 在新线程中生成回复
            Thread(target=self.generate_reply, args=(user_input, timestamp)).start()

    def generate_reply(self, user_input, timestamp):
        selected_model = self.model_combo.currentText()
        model_path = f"{selected_model}.py"
        spec = importlib.util.spec_from_file_location(selected_model, model_path)
        model_module = importlib.util.module_from_spec(spec)
        spec.loader.exec_module(model_module)
        ai_reply = model_module.generate_response(user_input)

        # 在历史记录区域中添加 AI 回复
        self.append_markdown_to_history(f'**<span style="opacity:0.7">[AI助手] {timestamp}</span>**\n\n{ai_reply}')  # 添加一个换行符
        self.save_history(user_input, ai_reply, timestamp)

        # 滚动到底部
        self.history_area.moveCursor(QTextCursor.End)
        self.history_area.ensureCursorVisible()  # 确保光标可见

        # 如果启用语音输出,将 AI 回复转换为语音
        if hasattr(self, 'tts_enabled') and self.tts_enabled:
            self.speak(ai_reply)

    def speak(self, text):
        self.engine.say(text)
        self.engine.runAndWait()

    def change_theme(self, theme):
        if theme == '浅色':
            self.setStyleSheet('''
                QMainWindow {
                    background-color: #F5F5F5;
                }
                QTextEdit, QTextBrowser {
                    background-color: #FFFFFF;
                    color: #333333;
                    border: 1px solid #CCCCCC;
                }
                QLineEdit {
                    background-color: #FFFFFF;
                    color: #333333;
                    border: 1px solid #CCCCCC;
                }
                QPushButton {
                    background-color: #007BFF;
                    color: #FFFFFF;
                }
                QPushButton:hover {
                    background-color: #0056B3;
                }
            ''')
        elif theme == '深色':
            self.setStyleSheet('''
                QMainWindow {
                    background-color: #333333;
                }
                QTextEdit, QTextBrowser {
                    background-color: #444444;
                    color: #FFFFFF;
                    border: 1px solid #555555;
                }
                QLineEdit {
                    background-color: #444444;
                    color: #FFFFFF;
                    border: 1px solid #555555;
                }
                QPushButton {
                    background-color: #007BFF;
                    color: #FFFFFF;
                }
                QPushButton:hover {
                    background-color: #0056B3;
                }
                QComboBox, QCheckBox {
                    color: #FFFFFF;
                }
            ''')

    def save_history(self, user_input, ai_reply, timestamp):
        data = {
            'user_input': user_input,
            'ai_reply': ai_reply,
            'timestamp': timestamp
        }
        with open('chat_history.json', 'a') as file:
            json.dump(data, file)
            file.write('\n')

    def load_history(self):
        try:
            with open('chat_history.json', 'r') as file:
                for line in file:
                    data = json.loads(line)
                    user_input = data['user_input']
                    ai_reply = data['ai_reply']
                    timestamp = data['timestamp']
                    self.append_markdown_to_history(f'**[你] {timestamp}**\n{user_input}')
                    self.append_markdown_to_history(f'**<span style="opacity:0.7">[AI助手] {timestamp}</span>**\n\n{ai_reply}')
        except FileNotFoundError:
            pass

    def append_markdown_to_history(self, markdown_text):
        html_text = markdown.markdown(markdown_text)
        self.history_area.append(html_text)

    def clear_history(self):
        # 清空聊天记录并重置界面
        self.history_area.clear()
        # 删除保存的历史记录文件
        try:
            os.remove('chat_history.json')
        except FileNotFoundError:
            pass

        # 弹出提示框
        QMessageBox.information(self, "提示", "聊天记录已清空!")

    def export_history(self):
        # 打开文件对话框以选择保存位置
        options = QFileDialog.Options()
        file_path, _ = QFileDialog.getSaveFileName(self, "保存聊天记录", "", "文本文件 (*.txt);;All Files (*)", options=options)
        if file_path:
            try:
                with open(file_path, 'w') as file:
                    # 遍历历史记录区域中的文本并写入文件
                    text = self.history_area.toPlainText()
                    file.write(text)
                QMessageBox.information(self, "提示", "聊天记录已成功导出!")
            except Exception as e:
                QMessageBox.warning(self, "警告", f"导出聊天记录时出现错误:{str(e)}")

    def show_help(self):
        # 显示帮助说明对话框
        help_text = "这个程序是由aifeisheng开发的开源项目,代码已经在社区上公开。你可以自由添加所有AI模型,模型文件名称格式:model_[a-zA-Z0-9]+\.py ,例model_a.py、model_2.py。"
        QMessageBox.information(self, "帮助说明", help_text)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_window = ChatWindow()
    main_window.show()
    sys.exit(app.exec_())




AI模型文件部分:你可以添加多个模型,程序会自动扫描在程序同目录的模型文件。
模型文件名称格式:model_[a-zA-Z0-9]+\.py ,例:model_a.py、model_2.py模型内容格式:模型格式输出的参数是 message,就能成功调用 月之暗面Moonshot AI模型名称:model_a.py.
[Python] 纯文本查看 复制代码
# model_a.py

from openai import OpenAI

def generate_response(message):
    client = OpenAI(
        api_key="你自己的KEY",
        base_url="https://api.moonshot.cn/v1",
    )
    completion = client.chat.completions.create(
        model="moonshot-v1-8k",
        messages=[
            {"role": "system", "content": "针对角色回复。"},
            {"role": "user", "content": message}
        ],
        temperature=0.3,
    )
    reply_message = completion.choices[0].message.content.strip()
    return reply_message

deepseek AI
[Python] 纯文本查看 复制代码
# model_b.py

from openai import OpenAI

def generate_response(message):
    client = OpenAI(
        api_key="你自己的KEY",
        base_url="https://api.deepseek.com/v1",
    )
    completion = client.chat.completions.create(
        model="deepseek-chat",
        messages=[
            {"role": "system", "content": "针对角色回复。"},
            {"role": "user", "content": message}
        ],
        temperature=0.3,
    )
    reply_message = completion.choices[0].message.content.strip()
    return reply_message


免费评分

参与人数 3威望 +1 吾爱币 +22 热心值 +3 收起 理由
zsb17173 + 1 + 1 用心讨论,共获提升!
苏紫方璇 + 1 + 20 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
ahaneo + 1 + 1 谢谢@Thanks!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

micen 发表于 2024-6-1 10:57
优秀,我根据你的代码改了一下,送我女朋友了, 哈哈哈哈  ,就是回答的信息一多就容易出现闪退的现象
生命的插曲 发表于 2024-5-2 07:03
lyt040722 发表于 2024-5-2 07:12
Eaglecad 发表于 2024-5-2 07:49
厉害&#128077;,感谢分享
HHJ200318 发表于 2024-5-2 09:24
厉害厉害
lyj901024 发表于 2024-5-2 09:33
厉害感谢分享
电脑小白。 发表于 2024-5-4 11:52
有没有大佬编译一下成品,谢谢,不太懂Python
xiaofu666 发表于 2024-5-6 08:48
膜拜大佬
longhua23 发表于 2024-5-15 17:14
感觉牛批
zgmn001 发表于 2024-5-17 21:46
有成品吗?大佬
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-12-13 03:56

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表