Files
ai-shiliu/app/presentation/shell.py
figmar 81115dc23d 初始提交:识流 AI 助手项目
微信自动回复机器人,基于截图+OCR识别消息,支持关键词规则和 AI(OpenAI/DeepSeek/Dify)自动回复。
技术栈:PySide6 + Flask + Vue3 + RapidOCR + SQLite

注:OCR大模型文件(.onnx / .pdiparams)不纳入版本控制,需单独下载。

🤖 Generated with [Qoder][https://qoder.com]
2026-05-30 15:09:40 +08:00

96 lines
3.4 KiB
Python

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