初始提交:识流 AI 助手项目
微信自动回复机器人,基于截图+OCR识别消息,支持关键词规则和 AI(OpenAI/DeepSeek/Dify)自动回复。 技术栈:PySide6 + Flask + Vue3 + RapidOCR + SQLite 注:OCR大模型文件(.onnx / .pdiparams)不纳入版本控制,需单独下载。 🤖 Generated with [Qoder][https://qoder.com]
This commit is contained in:
95
app/presentation/shell.py
Normal file
95
app/presentation/shell.py
Normal file
@@ -0,0 +1,95 @@
|
||||
import time
|
||||
|
||||
from PySide6.QtCore import QTimer, Qt, QUrl
|
||||
from PySide6.QtGui import QGuiApplication
|
||||
from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel, QProgressBar
|
||||
|
||||
|
||||
class LoadingWindowController:
|
||||
def __init__(self):
|
||||
self.loading_window = None
|
||||
self.loading_min_ms = 700
|
||||
self.loading_started_ms = 0.0
|
||||
|
||||
def show(self):
|
||||
self.loading_started_ms = time.time() * 1000
|
||||
if self.loading_window is not None:
|
||||
self.loading_window.show()
|
||||
self.loading_window.raise_()
|
||||
self.loading_window.activateWindow()
|
||||
return self.loading_window
|
||||
win = QWidget()
|
||||
win.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
|
||||
win.setAttribute(Qt.WA_DeleteOnClose, True)
|
||||
win.resize(560, 220)
|
||||
screen = QGuiApplication.primaryScreen()
|
||||
if screen is not None:
|
||||
geo = screen.availableGeometry()
|
||||
win.move(geo.center().x() - win.width() // 2, geo.center().y() - win.height() // 2)
|
||||
win.setStyleSheet("background:qlineargradient(x1:0,y1:0,x2:0,y2:1, stop:0 #f8fbff, stop:1 #eef4fb);border:1px solid #dbe7f5;border-radius:16px;")
|
||||
lay = QVBoxLayout(win)
|
||||
lay.setContentsMargins(30, 28, 30, 28)
|
||||
lay.setSpacing(10)
|
||||
|
||||
title = QLabel("识流 AI 助手")
|
||||
title.setStyleSheet("font-size:18px;font-weight:700;color:#0f172a;")
|
||||
label = QLabel("正在启动服务与管理台…")
|
||||
label.setStyleSheet("font-size:14px;color:#334155;")
|
||||
hint = QLabel("首次启动会稍慢一点,请稍候")
|
||||
hint.setStyleSheet("font-size:12px;color:#64748b;")
|
||||
|
||||
bar = QProgressBar()
|
||||
bar.setRange(0, 0)
|
||||
bar.setTextVisible(False)
|
||||
bar.setFixedHeight(8)
|
||||
bar.setStyleSheet("QProgressBar{background:#e5edf8;border:0;border-radius:4px;}QProgressBar::chunk{background:qlineargradient(x1:0,y1:0,x2:1,y2:0, stop:0 #22c1c3, stop:1 #3b82f6);border-radius:4px;}")
|
||||
|
||||
lay.addWidget(title)
|
||||
lay.addWidget(label)
|
||||
lay.addSpacing(4)
|
||||
lay.addWidget(bar)
|
||||
lay.addWidget(hint)
|
||||
lay.addStretch(1)
|
||||
|
||||
self.loading_window = win
|
||||
self.loading_window.show()
|
||||
self.loading_window.raise_()
|
||||
self.loading_window.activateWindow()
|
||||
return self.loading_window
|
||||
|
||||
def close(self):
|
||||
if self.loading_window is not None:
|
||||
self.loading_window.close()
|
||||
self.loading_window = None
|
||||
|
||||
def finish_with(self, callback):
|
||||
elapsed = int(time.time() * 1000 - self.loading_started_ms) if self.loading_started_ms else self.loading_min_ms
|
||||
remain = max(0, self.loading_min_ms - elapsed)
|
||||
QTimer.singleShot(remain + 120, callback)
|
||||
|
||||
|
||||
class WebViewShellController:
|
||||
def __init__(self, web_view):
|
||||
self.web_view = web_view
|
||||
self.main_page_ready = False
|
||||
self.expecting_admin_load = False
|
||||
|
||||
def load(self, entry_url):
|
||||
if self.web_view is None:
|
||||
return
|
||||
self.main_page_ready = False
|
||||
self.expecting_admin_load = True
|
||||
self.web_view.setStyleSheet("background:#eef2f7;")
|
||||
self.web_view.load(QUrl(entry_url))
|
||||
|
||||
def mark_loaded(self, ok):
|
||||
if not self.expecting_admin_load or not ok:
|
||||
return False
|
||||
self.main_page_ready = True
|
||||
return True
|
||||
|
||||
def can_finish(self):
|
||||
return self.main_page_ready
|
||||
|
||||
def finish(self):
|
||||
self.expecting_admin_load = False
|
||||
Reference in New Issue
Block a user