1
0

2 کامیت‌ها 5bff45fa45 ... 75af9629b5

نویسنده SHA1 پیام تاریخ
  PUGE 75af9629b5 Merge branch 'main' of https://git.port.run/puge/pythonTest 1 ماه پیش
  PUGE 41552d1eeb 主播工具 1 ماه پیش
1فایلهای تغییر یافته به همراه363 افزوده شده و 60 حذف شده
  1. 363 60
      主播工具.py

+ 363 - 60
主播工具.py

@@ -1,11 +1,194 @@
 import sys
 import sys
 import json
 import json
+import threading
 from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QHBoxLayout, 
 from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QHBoxLayout, 
                              QVBoxLayout, QListWidget, QListWidgetItem, QCheckBox, 
                              QVBoxLayout, QListWidget, QListWidgetItem, QCheckBox, 
                              QPushButton, QLineEdit, QTextEdit, QGroupBox, 
                              QPushButton, QLineEdit, QTextEdit, QGroupBox, 
                              QSplitter, QLabel, QMessageBox, QComboBox, QShortcut)
                              QSplitter, QLabel, QMessageBox, QComboBox, QShortcut)
-from PyQt5.QtCore import Qt
+from PyQt5.QtCore import Qt, QTimer, pyqtSignal, QObject
 from PyQt5.QtGui import QKeySequence
 from PyQt5.QtGui import QKeySequence
+import websocket
+import time
+
+class WebSocketClient(QObject):
+    """WebSocket客户端,用于与服务器通信"""
+    user_list_updated = pyqtSignal(list)  # 用户列表更新信号
+    message_received = pyqtSignal(dict)   # 接收消息信号
+    connection_status = pyqtSignal(bool)  # 连接状态信号
+    
+    def __init__(self, type_str="抖音自动评论-153"):
+        super().__init__()
+        self.type_str = type_str
+        self.ws = None
+        self.ws_user_info = None
+        self.is_connected = False
+        self.running = True
+        self.is_admin = True
+        self.user_id = None
+        self.ws_thread = None
+        
+    def start(self):
+        """启动WebSocket连接"""
+        self.running = True
+        self.ws_thread = threading.Thread(target=self._connect_websocket, daemon=True)
+        self.ws_thread.start()
+        
+    def stop(self):
+        """停止WebSocket连接"""
+        self.running = False
+        if self.ws:
+            try:
+                self.ws.close()
+            except:
+                pass
+    
+    def _connect_websocket(self):
+        """WebSocket连接逻辑(在独立线程中运行)"""
+        time_connect = 0
+        
+        def reconnect():
+            nonlocal time_connect
+            while self.running:
+                try:
+                    time_connect += 1
+                    print(f"第{time_connect}次重连")
+                    
+                    # 创建WebSocket连接
+                    self.ws = websocket.WebSocketApp(
+                        'wss://ws.lamp.run',
+                        on_open=self._on_open,
+                        on_message=self._on_message,
+                        on_error=self._on_error,
+                        on_close=self._on_close
+                    )
+                    
+                    # 运行WebSocket
+                    self.ws.run_forever()
+                    
+                    # 如果连接断开且还在运行中,等待后重连
+                    if self.running:
+                        time.sleep(3)
+                        
+                except Exception as e:
+                    print(f"WebSocket错误: {e}")
+                    if self.running:
+                        time.sleep(3)
+        
+        # 启动连接
+        reconnect()
+    
+    def _on_open(self, ws):
+        """WebSocket打开回调"""
+        login_data = {
+            "route": "login",
+            "type": self.type_str,
+            "admin": self.is_admin,
+            "id": "PYQT_CLIENT"
+        }
+        ws.send(json.dumps(login_data))
+        self.is_connected = True
+        self.connection_status.emit(True)
+        print("WebSocket连接成功")
+        
+        # 延迟一下,等登录完成后再获取列表
+        def get_list():
+            time.sleep(0.5)
+            if self.ws and self.is_connected:
+                self.send("getList")
+        
+        threading.Thread(target=get_list, daemon=True).start()
+    
+    def _on_message(self, ws, message):
+        """接收消息回调"""
+        try:
+            data = json.loads(message)
+            
+            if data.get('type') == 'userInfo':
+                self.ws_user_info = data.get('value')
+                if self.ws_user_info:
+                    self.user_id = self.ws_user_info.get('userID')
+                print(f"用户信息: {data.get('value')}")
+                
+            elif data.get('type') == 'getList':
+                # 接收到用户列表
+                user_list = data.get('value', [])
+                # 提取用户ID列表
+                user_ids = []
+                for user in user_list:
+                    user_id = user.get('id')
+                    if user_id and user_id != 'PYQT_CLIENT':  # 排除自己
+                        user_ids.append(user_id)
+                
+                # 发送信号更新UI
+                self.user_list_updated.emit(user_ids)
+                print(f"收到用户列表: {user_ids}")
+                
+            else:
+                # 其他消息
+                self.message_received.emit(data)
+                
+        except json.JSONDecodeError as e:
+            print(f"JSON解析错误: {e}")
+        except Exception as e:
+            print(f"消息处理错误: {e}")
+    
+    def _on_error(self, ws, error):
+        """WebSocket错误回调"""
+        print(f"WebSocket错误: {error}")
+        self.is_connected = False
+        self.connection_status.emit(False)
+    
+    def _on_close(self, ws, close_status_code, close_msg):
+        """WebSocket关闭回调"""
+        print("WebSocket连接关闭")
+        self.is_connected = False
+        self.connection_status.emit(False)
+    
+    def send(self, route, value=None, send_to=None):
+        """发送消息
+        
+        Args:
+            route: 路由名称,如 "sendmessage"
+            value: 要发送的内容(话术)
+            send_to: 接收方的userID
+        """
+        if not self.ws or not self.is_connected:
+            print("WebSocket未连接")
+            return False
+        
+        try:
+            message = {
+                "route": route,
+                "type": self.type_str,
+            }
+            
+            # 添加userID(发送者的ID)
+            if self.user_id:
+                message["userID"] = self.user_id
+            
+            # 添加接收者ID
+            if send_to:
+                message["id"] = "抖音自动评论-153-" + send_to
+            
+            # 添加内容
+            if value is not None:
+                message["value"] = value
+            
+            # 发送消息
+            self.ws.send(json.dumps(message))
+            print(f"发送消息: {message}")
+            return True
+            
+        except Exception as e:
+            print(f"发送消息失败: {e}")
+            return False
+    
+    def get_user_list(self):
+        """主动获取用户列表"""
+        if self.is_connected:
+            return self.send("getList")
+        return False
+
 
 
 class MainWindow(QMainWindow):
 class MainWindow(QMainWindow):
     def __init__(self):
     def __init__(self):
@@ -17,6 +200,10 @@ class MainWindow(QMainWindow):
         self.user_scripts = {}
         self.user_scripts = {}
         # 当前选中的用户
         # 当前选中的用户
         self.current_user = None
         self.current_user = None
+        # WebSocket客户端
+        self.ws_client = None
+        # 用户列表缓存
+        self.user_cache = []
         
         
         # 中央部件
         # 中央部件
         central_widget = QWidget()
         central_widget = QWidget()
@@ -61,6 +248,19 @@ class MainWindow(QMainWindow):
         user_label.setStyleSheet("font-weight: bold; font-size: 14px;")
         user_label.setStyleSheet("font-weight: bold; font-size: 14px;")
         middle_layout.addWidget(user_label)
         middle_layout.addWidget(user_label)
         
         
+        # 连接状态和控制按钮
+        control_layout = QHBoxLayout()
+        self.status_label = QLabel("⚪ 未连接")
+        self.status_label.setStyleSheet("color: red;")
+        control_layout.addWidget(self.status_label)
+        control_layout.addStretch()
+        
+        self.refresh_btn = QPushButton("🔄 刷新列表")
+        self.refresh_btn.clicked.connect(self.refresh_user_list)
+        self.refresh_btn.setEnabled(False)
+        control_layout.addWidget(self.refresh_btn)
+        middle_layout.addLayout(control_layout)
+        
         select_btn_layout = QHBoxLayout()
         select_btn_layout = QHBoxLayout()
         self.select_all_btn = QPushButton("✅ 全选")
         self.select_all_btn = QPushButton("✅ 全选")
         self.deselect_all_btn = QPushButton("❌ 取消全选")
         self.deselect_all_btn = QPushButton("❌ 取消全选")
@@ -73,19 +273,11 @@ class MainWindow(QMainWindow):
         
         
         self.user_list_widget = QListWidget()
         self.user_list_widget = QListWidget()
         self.user_list_widget.setSelectionMode(QListWidget.NoSelection)
         self.user_list_widget.setSelectionMode(QListWidget.NoSelection)
-        # 添加示例用户
-        sample_users = ["用户A", "用户B", "用户C", "用户D", "用户E"]
-        for user in sample_users:
-            self.add_user_item(user)
-            # 初始化用户话术数据
-            self.user_scripts[user] = [f"话术1: 您好{user},请问有什么可以帮您?", 
-                                       f"话术2: {user},感谢您的反馈,我们会尽快处理。",
-                                       f"话术3: {user},请您稍等,我为您转接专员。"]
         middle_layout.addWidget(self.user_list_widget)
         middle_layout.addWidget(self.user_list_widget)
         
         
-        user_count_label = QLabel(f"当前在线人数: {self.user_list_widget.count()}")
-        user_count_label.setStyleSheet("color: gray;")
-        middle_layout.addWidget(user_count_label)
+        self.user_count_label = QLabel("当前在线人数: 0")
+        self.user_count_label.setStyleSheet("color: gray;")
+        middle_layout.addWidget(self.user_count_label)
         
         
         # ---------- 右侧:用户独立话术列表 ----------
         # ---------- 右侧:用户独立话术列表 ----------
         right_widget = QWidget()
         right_widget = QWidget()
@@ -96,7 +288,6 @@ class MainWindow(QMainWindow):
         user_select_layout = QHBoxLayout()
         user_select_layout = QHBoxLayout()
         user_select_layout.addWidget(QLabel("选择用户 (快捷键F1-F5):"))
         user_select_layout.addWidget(QLabel("选择用户 (快捷键F1-F5):"))
         self.user_combo = QComboBox()
         self.user_combo = QComboBox()
-        self.user_combo.addItems(sample_users)
         self.user_combo.currentTextChanged.connect(self.on_user_changed)
         self.user_combo.currentTextChanged.connect(self.on_user_changed)
         user_select_layout.addWidget(self.user_combo)
         user_select_layout.addWidget(self.user_combo)
         user_select_layout.addStretch()
         user_select_layout.addStretch()
@@ -160,11 +351,6 @@ class MainWindow(QMainWindow):
         main_splitter.addWidget(right_widget)
         main_splitter.addWidget(right_widget)
         main_splitter.setSizes([300, 450, 450])
         main_splitter.setSizes([300, 450, 450])
         
         
-        # 初始化显示第一个用户的话术
-        if sample_users:
-            self.current_user = sample_users[0]
-            self.load_user_scripts(self.current_user)
-        
         # ---------- 设置快捷键 F1-F5 ----------
         # ---------- 设置快捷键 F1-F5 ----------
         self.setup_shortcuts()
         self.setup_shortcuts()
         
         
@@ -193,34 +379,116 @@ class MainWindow(QMainWindow):
                 min-width: 150px;
                 min-width: 150px;
             }
             }
         """)
         """)
-    
-    # ---------- 快捷键设置 ----------
-    def setup_shortcuts(self):
-        """设置F1-F5快捷键切换用户"""
-        # F1 选择第一个用户,F2 第二个,以此类推
-        shortcuts = [
-            (Qt.Key_F1, 0),
-            (Qt.Key_F2, 1),
-            (Qt.Key_F3, 2),
-            (Qt.Key_F4, 3),
-            (Qt.Key_F5, 4),
-        ]
         
         
-        for key, index in shortcuts:
-            shortcut = QShortcut(QKeySequence(key), self)
-            # 使用lambda捕获index,并绑定到切换函数
-            shortcut.activated.connect(lambda idx=index: self.switch_to_user_by_index(idx))
+        # 连接WebSocket
+        self.connect_websocket()
     
     
-    def switch_to_user_by_index(self, index):
-        """根据索引切换到对应用户"""
-        if index < self.user_combo.count():
-            user = self.user_combo.itemText(index)
-            self.user_combo.setCurrentText(user)
-            self.log_text.append(f"[快捷键] 切换到用户: {user}")
+    # ---------- WebSocket连接管理 ----------
+    def connect_websocket(self):
+        """连接到WebSocket服务器"""
+        self.log_text.append("[系统] 正在连接WebSocket服务器...")
+        self.status_label.setText("🔄 正在连接...")
+        self.status_label.setStyleSheet("color: orange;")
+        
+        # 创建WebSocket客户端
+        self.ws_client = WebSocketClient("抖音自动评论-153")
+        
+        # 连接信号
+        self.ws_client.user_list_updated.connect(self.on_user_list_updated)
+        self.ws_client.message_received.connect(self.on_ws_message)
+        self.ws_client.connection_status.connect(self.on_connection_status)
+        
+        # 启动WebSocket
+        self.ws_client.start()
+        
+        # 定时器检查连接状态
+        self.status_timer = QTimer()
+        self.status_timer.timeout.connect(self.check_connection)
+        self.status_timer.start(5000)  # 每5秒检查一次
+    
+    def on_connection_status(self, connected):
+        """WebSocket连接状态变化"""
+        if connected:
+            self.status_label.setText("🟢 已连接")
+            self.status_label.setStyleSheet("color: green;")
+            self.refresh_btn.setEnabled(True)
+            self.log_text.append("[系统] WebSocket连接成功")
+            # 延迟获取用户列表
+            QTimer.singleShot(1000, self.refresh_user_list)
         else:
         else:
-            self.log_text.append(f"[快捷键] 用户索引 {index} 不存在")
+            self.status_label.setText("🔴 已断开")
+            self.status_label.setStyleSheet("color: red;")
+            self.refresh_btn.setEnabled(False)
+            self.log_text.append("[系统] WebSocket连接断开")
+    
+    def check_connection(self):
+        """检查WebSocket连接状态"""
+        if self.ws_client:
+            if not self.ws_client.is_connected:
+                # 尝试重新获取列表
+                self.ws_client.get_user_list()
+    
+    def refresh_user_list(self):
+        """刷新用户列表"""
+        if self.ws_client and self.ws_client.is_connected:
+            self.log_text.append("[系统] 刷新用户列表...")
+            self.ws_client.get_user_list()
+        else:
+            self.log_text.append("[系统] WebSocket未连接,无法刷新列表")
+    
+    def on_user_list_updated(self, user_list):
+        """用户列表更新"""
+        self.user_cache = user_list
+        self.update_user_list(user_list)
+        self.log_text.append(f"[系统] 更新用户列表,当前在线: {len(user_list)}人")
+    
+    def on_ws_message(self, message):
+        """WebSocket消息接收"""
+        # 处理其他类型的消息
+        msg_type = message.get('type')
+        if msg_type:
+            self.log_text.append(f"[WebSocket] 收到消息: {msg_type}")
     
     
     # ---------- 用户管理 ----------
     # ---------- 用户管理 ----------
+    def update_user_list(self, user_list):
+        """更新用户列表UI"""
+        # 保存当前选中的用户
+        selected_users = self.get_selected_users()
+        current_combo_text = self.user_combo.currentText()
+        
+        # 清空列表
+        self.user_list_widget.clear()
+        
+        # 添加用户
+        for user_id in user_list:
+            self.add_user_item(user_id)
+            # 如果用户不存在,初始化话术数据
+            if user_id not in self.user_scripts:
+                self.user_scripts[user_id] = [f"{user_id},666"]
+        
+        # 更新下拉框
+        self.user_combo.clear()
+        self.user_combo.addItems(user_list)
+        
+        # 恢复选中状态
+        if current_combo_text in user_list:
+            self.user_combo.setCurrentText(current_combo_text)
+        elif user_list:
+            self.user_combo.setCurrentIndex(0)
+        
+        # 恢复复选框选中状态
+        for user in selected_users:
+            if user in user_list:
+                for i in range(self.user_list_widget.count()):
+                    item = self.user_list_widget.item(i)
+                    widget = self.user_list_widget.itemWidget(item)
+                    if isinstance(widget, QCheckBox) and widget.text() == user:
+                        widget.setChecked(True)
+                        break
+        
+        # 更新人数
+        self.user_count_label.setText(f"当前在线人数: {len(user_list)}")
+    
     def add_user_item(self, username):
     def add_user_item(self, username):
         """添加一个带复选框的用户项"""
         """添加一个带复选框的用户项"""
         item = QListWidgetItem()
         item = QListWidgetItem()
@@ -278,6 +546,31 @@ class MainWindow(QMainWindow):
         elif current_users:
         elif current_users:
             self.user_combo.setCurrentIndex(0)
             self.user_combo.setCurrentIndex(0)
     
     
+    # ---------- 快捷键设置 ----------
+    def setup_shortcuts(self):
+        """设置F1-F5快捷键切换用户"""
+        shortcuts = [
+            (Qt.Key_F1, 0),
+            (Qt.Key_F2, 1),
+            (Qt.Key_F3, 2),
+            (Qt.Key_F4, 3),
+            (Qt.Key_F5, 4),
+        ]
+        
+        for key, index in shortcuts:
+            shortcut = QShortcut(QKeySequence(key), self)
+            shortcut.activated.connect(lambda idx=index: self.switch_to_user_by_index(idx))
+    
+    def switch_to_user_by_index(self, index):
+        """根据索引切换到对应用户"""
+        if index < self.user_combo.count():
+            user = self.user_combo.itemText(index)
+            if user:
+                self.user_combo.setCurrentText(user)
+                self.log_text.append(f"[快捷键] 切换到用户: {user}")
+        else:
+            self.log_text.append(f"[快捷键] 用户索引 {index} 不存在")
+    
     # ---------- 话术管理 (用户独立) ----------
     # ---------- 话术管理 (用户独立) ----------
     def load_user_scripts(self, username):
     def load_user_scripts(self, username):
         """加载指定用户的话术列表"""
         """加载指定用户的话术列表"""
@@ -293,7 +586,6 @@ class MainWindow(QMainWindow):
         if username and username != self.current_user:
         if username and username != self.current_user:
             # 如果当前用户有修改但未保存,先保存
             # 如果当前用户有修改但未保存,先保存
             if self.current_user and self.current_user in self.user_scripts:
             if self.current_user and self.current_user in self.user_scripts:
-                # 自动保存当前用户的话术
                 self.save_current_user_scripts()
                 self.save_current_user_scripts()
             
             
             self.load_user_scripts(username)
             self.load_user_scripts(username)
@@ -331,7 +623,6 @@ class MainWindow(QMainWindow):
         if text:
         if text:
             self.script_list_widget.addItem(text)
             self.script_list_widget.addItem(text)
             self.script_input.clear()
             self.script_input.clear()
-            # 自动保存
             self.save_current_user_scripts()
             self.save_current_user_scripts()
             self.log_text.append(f"[操作] 为用户 '{self.current_user}' 添加话术: {text}")
             self.log_text.append(f"[操作] 为用户 '{self.current_user}' 添加话术: {text}")
         else:
         else:
@@ -343,7 +634,6 @@ class MainWindow(QMainWindow):
         if current_row >= 0:
         if current_row >= 0:
             item_text = self.script_list_widget.item(current_row).text()
             item_text = self.script_list_widget.item(current_row).text()
             self.script_list_widget.takeItem(current_row)
             self.script_list_widget.takeItem(current_row)
-            # 自动保存
             self.save_current_user_scripts()
             self.save_current_user_scripts()
             self.log_text.append(f"[操作] 删除用户 '{self.current_user}' 的话术: {item_text}")
             self.log_text.append(f"[操作] 删除用户 '{self.current_user}' 的话术: {item_text}")
         else:
         else:
@@ -358,7 +648,6 @@ class MainWindow(QMainWindow):
                                                text=old_text)
                                                text=old_text)
             if ok and new_text.strip():
             if ok and new_text.strip():
                 self.script_list_widget.item(current_row).setText(new_text.strip())
                 self.script_list_widget.item(current_row).setText(new_text.strip())
-                # 自动保存
                 self.save_current_user_scripts()
                 self.save_current_user_scripts()
                 self.log_text.append(f"[操作] 修改用户 '{self.current_user}' 的话术: {old_text} -> {new_text.strip()}")
                 self.log_text.append(f"[操作] 修改用户 '{self.current_user}' 的话术: {old_text} -> {new_text.strip()}")
             elif ok and not new_text.strip():
             elif ok and not new_text.strip():
@@ -380,39 +669,53 @@ class MainWindow(QMainWindow):
             QMessageBox.warning(self, "提示", "请至少选择一个用户!")
             QMessageBox.warning(self, "提示", "请至少选择一个用户!")
             return
             return
         
         
-        # 获取每个用户选中的话术 (这里演示:取每个用户的第一条话术)
-        task_details = []
-        for user in selected_users:
-            if user in self.user_scripts and self.user_scripts[user]:
-                script = self.user_scripts[user][0]  # 取第一条
-                task_details.append(f"{user}: {script}")
-            else:
-                task_details.append(f"{user}: (无话术)")
+        # 获取当前选中的话术
+        current_row = self.script_list_widget.currentRow()
+        if current_row < 0:
+            QMessageBox.warning(self, "提示", "请先在话术列表中选中一条话术!")
+            return
+        
+        selected_script = self.script_list_widget.item(current_row).text()
         
         
         # 记录日志
         # 记录日志
+        self.log_text.append(f"[任务] 发送话术: {selected_script}")
         self.log_text.append(f"[任务] 发送给 {len(selected_users)} 个用户:")
         self.log_text.append(f"[任务] 发送给 {len(selected_users)} 个用户:")
-        for detail in task_details:
-            self.log_text.append(f"  - {detail}")
-        self.log_text.append("[任务] 发送完成 (功能待实现)")
         
         
-        # 显示详情
-        msg = "\n".join(task_details)
-        QMessageBox.information(self, "发送任务", 
-                                 f"已发送任务给 {len(selected_users)} 个用户:\n\n{msg}")
+        # 通过WebSocket发送任务
+        if self.ws_client and self.ws_client.is_connected:
+            success_count = 0
+            for user in selected_users:
+                # 发送给指定用户,路由为 "sendmessage"
+                if self.ws_client.send("sendmessage", selected_script, user):
+                    success_count += 1
+                    self.log_text.append(f"[任务] 已发送给用户: {user}")
+                else:
+                    self.log_text.append(f"[任务] 发送给用户 {user} 失败")
+            
+            self.log_text.append(f"[任务] 发送完成,成功发送给 {success_count}/{len(selected_users)} 个用户")
+        else:
+            self.log_text.append("[任务] WebSocket未连接,无法发送")
     
     
     # ---------- 窗口关闭时保存 ----------
     # ---------- 窗口关闭时保存 ----------
     def closeEvent(self, event):
     def closeEvent(self, event):
         """关闭窗口时自动保存所有用户话术"""
         """关闭窗口时自动保存所有用户话术"""
         if self.current_user:
         if self.current_user:
             self.save_current_user_scripts()
             self.save_current_user_scripts()
+        
         try:
         try:
             with open("user_scripts_backup.json", "w", encoding="utf-8") as f:
             with open("user_scripts_backup.json", "w", encoding="utf-8") as f:
                 json.dump(self.user_scripts, f, ensure_ascii=False, indent=2)
                 json.dump(self.user_scripts, f, ensure_ascii=False, indent=2)
             self.log_text.append("[系统] 程序退出,已自动保存所有话术配置")
             self.log_text.append("[系统] 程序退出,已自动保存所有话术配置")
         except:
         except:
             pass
             pass
+        
+        # 关闭WebSocket连接
+        if self.ws_client:
+            self.ws_client.stop()
+        
         event.accept()
         event.accept()
 
 
+
 if __name__ == "__main__":
 if __name__ == "__main__":
     app = QApplication(sys.argv)
     app = QApplication(sys.argv)
     window = MainWindow()
     window = MainWindow()