mirror of
https://github.com/Zippland/Snap-Solver.git
synced 2026-01-20 07:00:57 +08:00
v1.1.1
This commit is contained in:
65
app.py
65
app.py
@@ -4,7 +4,8 @@ import pyautogui
|
||||
import base64
|
||||
from io import BytesIO
|
||||
import socket
|
||||
from threading import Thread
|
||||
from threading import Thread, Event
|
||||
import threading
|
||||
from PIL import Image
|
||||
import pyperclip
|
||||
from models import ModelFactory
|
||||
@@ -31,6 +32,9 @@ socketio = SocketIO(
|
||||
# 添加配置文件路径
|
||||
CONFIG_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config')
|
||||
|
||||
# 跟踪用户生成任务的字典
|
||||
generation_tasks = {}
|
||||
|
||||
# 初始化模型工厂
|
||||
ModelFactory.initialize()
|
||||
|
||||
@@ -310,6 +314,27 @@ def handle_text_extraction(data):
|
||||
'error': error_msg
|
||||
}, room=request.sid)
|
||||
|
||||
@socketio.on('stop_generation')
|
||||
def handle_stop_generation():
|
||||
"""处理停止生成请求"""
|
||||
sid = request.sid
|
||||
print(f"接收到停止生成请求: {sid}")
|
||||
|
||||
if sid in generation_tasks:
|
||||
# 设置停止标志
|
||||
stop_event = generation_tasks[sid]
|
||||
stop_event.set()
|
||||
|
||||
# 发送已停止状态
|
||||
socketio.emit('claude_response', {
|
||||
'status': 'stopped',
|
||||
'content': '生成已停止'
|
||||
}, room=sid)
|
||||
|
||||
print(f"已停止用户 {sid} 的生成任务")
|
||||
else:
|
||||
print(f"未找到用户 {sid} 的生成任务")
|
||||
|
||||
@socketio.on('analyze_text')
|
||||
def handle_analyze_text(data):
|
||||
try:
|
||||
@@ -350,8 +375,23 @@ def handle_analyze_text(data):
|
||||
'https': f"http://{settings.get('proxyHost')}:{settings.get('proxyPort')}"
|
||||
}
|
||||
|
||||
for response in model_instance.analyze_text(text, proxies=proxies):
|
||||
socketio.emit('claude_response', response)
|
||||
# 创建用于停止生成的事件
|
||||
sid = request.sid
|
||||
stop_event = Event()
|
||||
generation_tasks[sid] = stop_event
|
||||
|
||||
try:
|
||||
for response in model_instance.analyze_text(text, proxies=proxies):
|
||||
# 检查是否收到停止信号
|
||||
if stop_event.is_set():
|
||||
print(f"分析文本生成被用户 {sid} 停止")
|
||||
break
|
||||
|
||||
socketio.emit('claude_response', response, room=sid)
|
||||
finally:
|
||||
# 清理任务
|
||||
if sid in generation_tasks:
|
||||
del generation_tasks[sid]
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error in analyze_text: {str(e)}")
|
||||
@@ -398,8 +438,23 @@ def handle_analyze_image(data):
|
||||
'https': f"http://{settings.get('proxyHost')}:{settings.get('proxyPort')}"
|
||||
}
|
||||
|
||||
for response in model_instance.analyze_image(image_data, proxies=proxies):
|
||||
socketio.emit('claude_response', response)
|
||||
# 创建用于停止生成的事件
|
||||
sid = request.sid
|
||||
stop_event = Event()
|
||||
generation_tasks[sid] = stop_event
|
||||
|
||||
try:
|
||||
for response in model_instance.analyze_image(image_data, proxies=proxies):
|
||||
# 检查是否收到停止信号
|
||||
if stop_event.is_set():
|
||||
print(f"分析图像生成被用户 {sid} 停止")
|
||||
break
|
||||
|
||||
socketio.emit('claude_response', response, room=sid)
|
||||
finally:
|
||||
# 清理任务
|
||||
if sid in generation_tasks:
|
||||
del generation_tasks[sid]
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error in analyze_image: {str(e)}")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"build_date": "2025-04-02",
|
||||
"github_repo": "Zippland/Snap-Solver"
|
||||
}
|
||||
@@ -46,32 +46,40 @@ class SnapSolver {
|
||||
}
|
||||
|
||||
initializeElements() {
|
||||
// Main elements
|
||||
this.screenshotImg = document.getElementById('screenshotImg');
|
||||
this.imagePreview = document.getElementById('imagePreview');
|
||||
this.emptyState = document.getElementById('emptyState');
|
||||
// 移除对裁剪按钮的引用
|
||||
// 查找主要UI元素
|
||||
this.connectionStatus = document.getElementById('connectionStatus');
|
||||
this.captureBtn = document.getElementById('captureBtn');
|
||||
this.emptyState = document.getElementById('emptyState');
|
||||
this.imagePreview = document.getElementById('imagePreview');
|
||||
this.screenshotImg = document.getElementById('screenshotImg');
|
||||
this.sendToClaudeBtn = document.getElementById('sendToClaude');
|
||||
this.extractTextBtn = document.getElementById('extractText');
|
||||
this.extractedText = document.getElementById('extractedText');
|
||||
this.sendExtractedTextBtn = document.getElementById('sendExtractedText');
|
||||
this.cropContainer = document.getElementById('cropContainer');
|
||||
this.manualTextInput = document.getElementById('manualTextInput');
|
||||
this.claudePanel = document.getElementById('claudePanel');
|
||||
this.responseContent = document.getElementById('responseContent');
|
||||
this.closeClaudePanel = document.getElementById('closeClaudePanel');
|
||||
this.thinkingSection = document.getElementById('thinkingSection');
|
||||
this.thinkingContent = document.getElementById('thinkingContent');
|
||||
this.thinkingToggle = document.getElementById('thinkingToggle');
|
||||
this.connectionStatus = document.getElementById('connectionStatus');
|
||||
this.statusLight = document.querySelector('.status-light');
|
||||
this.progressLine = document.querySelector('.progress-line');
|
||||
this.statusText = document.querySelector('.status-text');
|
||||
this.analysisIndicator = document.querySelector('.analysis-indicator');
|
||||
|
||||
// Crop elements
|
||||
this.thinkingContent = document.getElementById('thinkingContent');
|
||||
this.responseContent = document.getElementById('responseContent');
|
||||
this.cropContainer = document.getElementById('cropContainer');
|
||||
this.cropCancel = document.getElementById('cropCancel');
|
||||
this.cropConfirm = document.getElementById('cropConfirm');
|
||||
this.stopGenerationBtn = document.getElementById('stopGenerationBtn');
|
||||
|
||||
// 处理按钮事件
|
||||
if (this.closeClaudePanel) {
|
||||
this.closeClaudePanel.addEventListener('click', () => {
|
||||
this.claudePanel.classList.add('hidden');
|
||||
});
|
||||
}
|
||||
|
||||
// 处理停止生成按钮点击事件
|
||||
if (this.stopGenerationBtn) {
|
||||
this.stopGenerationBtn.addEventListener('click', () => {
|
||||
this.stopGeneration();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
initializeState() {
|
||||
@@ -128,51 +136,52 @@ class SnapSolver {
|
||||
}
|
||||
|
||||
updateStatusLight(status) {
|
||||
// 更新状态指示器
|
||||
if (this.analysisIndicator) {
|
||||
this.analysisIndicator.className = 'analysis-indicator';
|
||||
this.progressLine.className = 'progress-line';
|
||||
|
||||
switch (status) {
|
||||
case 'started':
|
||||
case 'streaming':
|
||||
this.analysisIndicator.classList.add('processing');
|
||||
this.progressLine.classList.add('processing');
|
||||
this.statusText.textContent = '处理中...';
|
||||
break;
|
||||
case 'completed':
|
||||
this.analysisIndicator.classList.add('completed');
|
||||
this.progressLine.classList.add('completed');
|
||||
this.statusText.textContent = '已完成';
|
||||
break;
|
||||
case 'error':
|
||||
this.analysisIndicator.classList.add('error');
|
||||
this.progressLine.classList.add('error');
|
||||
this.statusText.textContent = '错误';
|
||||
break;
|
||||
default:
|
||||
// 重置为默认状态
|
||||
this.statusText.textContent = '准备中';
|
||||
break;
|
||||
}
|
||||
} else if (this.statusLight) {
|
||||
// 兼容旧版状态灯
|
||||
this.statusLight.className = 'status-light';
|
||||
switch (status) {
|
||||
case 'started':
|
||||
case 'streaming':
|
||||
this.statusLight.classList.add('processing');
|
||||
break;
|
||||
case 'completed':
|
||||
this.statusLight.classList.add('completed');
|
||||
break;
|
||||
case 'error':
|
||||
this.statusLight.classList.add('error');
|
||||
break;
|
||||
default:
|
||||
// Reset to default state
|
||||
break;
|
||||
}
|
||||
const statusLight = document.querySelector('.status-light');
|
||||
const progressLine = document.querySelector('.progress-line');
|
||||
const statusText = document.querySelector('.status-text');
|
||||
const analysisIndicator = document.querySelector('.analysis-indicator');
|
||||
|
||||
if (!statusLight || !progressLine || !statusText || !analysisIndicator) {
|
||||
return;
|
||||
}
|
||||
|
||||
analysisIndicator.style.display = 'flex';
|
||||
statusLight.classList.remove('completed', 'error', 'working');
|
||||
|
||||
switch (status) {
|
||||
case 'started':
|
||||
case 'thinking':
|
||||
case 'reasoning':
|
||||
case 'streaming':
|
||||
statusLight.classList.add('working');
|
||||
progressLine.style.animation = 'progress-animation 2s linear infinite';
|
||||
statusText.textContent = '生成中';
|
||||
break;
|
||||
|
||||
case 'completed':
|
||||
statusLight.classList.add('completed');
|
||||
progressLine.style.animation = 'none';
|
||||
progressLine.style.width = '100%';
|
||||
statusText.textContent = '完成';
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
statusLight.classList.add('error');
|
||||
progressLine.style.animation = 'none';
|
||||
progressLine.style.width = '100%';
|
||||
statusText.textContent = '出错';
|
||||
break;
|
||||
|
||||
case 'stopped':
|
||||
statusLight.classList.add('error');
|
||||
progressLine.style.animation = 'none';
|
||||
progressLine.style.width = '100%';
|
||||
statusText.textContent = '已停止';
|
||||
break;
|
||||
|
||||
default:
|
||||
analysisIndicator.style.display = 'none';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,6 +381,9 @@ class SnapSolver {
|
||||
this.responseContent.innerHTML = '<div class="loading-message">分析进行中,请稍候...</div>';
|
||||
this.responseContent.style.display = 'block';
|
||||
}
|
||||
|
||||
// 显示停止生成按钮
|
||||
this.showStopGenerationButton();
|
||||
break;
|
||||
|
||||
case 'thinking':
|
||||
@@ -406,6 +418,9 @@ class SnapSolver {
|
||||
'fas fa-chevron-up' : 'fas fa-chevron-down';
|
||||
}
|
||||
}
|
||||
|
||||
// 确保停止按钮可见
|
||||
this.showStopGenerationButton();
|
||||
break;
|
||||
|
||||
case 'reasoning':
|
||||
@@ -440,6 +455,9 @@ class SnapSolver {
|
||||
'fas fa-chevron-up' : 'fas fa-chevron-down';
|
||||
}
|
||||
}
|
||||
|
||||
// 确保停止按钮可见
|
||||
this.showStopGenerationButton();
|
||||
break;
|
||||
|
||||
case 'thinking_complete':
|
||||
@@ -529,6 +547,9 @@ class SnapSolver {
|
||||
// 平滑滚动到最新内容
|
||||
this.scrollToBottom();
|
||||
}
|
||||
|
||||
// 确保停止按钮可见
|
||||
this.showStopGenerationButton();
|
||||
break;
|
||||
|
||||
case 'completed':
|
||||
@@ -587,6 +608,27 @@ class SnapSolver {
|
||||
// 滚动到结果内容底部
|
||||
this.scrollToBottom();
|
||||
}
|
||||
|
||||
// 隐藏停止生成按钮
|
||||
this.hideStopGenerationButton();
|
||||
break;
|
||||
|
||||
case 'stopped':
|
||||
// 处理停止生成的响应
|
||||
console.log('Generation stopped');
|
||||
|
||||
// 重新启用按钮
|
||||
if (this.sendToClaudeBtn) this.sendToClaudeBtn.disabled = false;
|
||||
if (this.sendExtractedTextBtn) this.sendExtractedTextBtn.disabled = false;
|
||||
|
||||
// 恢复界面
|
||||
this.updateStatusLight('stopped');
|
||||
|
||||
// 隐藏停止生成按钮
|
||||
this.hideStopGenerationButton();
|
||||
|
||||
// 显示提示信息
|
||||
window.uiManager.showToast('已停止生成', 'info');
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
@@ -604,6 +646,9 @@ class SnapSolver {
|
||||
if (this.sendExtractedTextBtn) this.sendExtractedTextBtn.disabled = false;
|
||||
|
||||
window.uiManager.showToast('Analysis failed: ' + errorMessage, 'error');
|
||||
|
||||
// 隐藏停止生成按钮
|
||||
this.hideStopGenerationButton();
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -620,6 +665,9 @@ class SnapSolver {
|
||||
if (this.sendExtractedTextBtn) this.sendExtractedTextBtn.disabled = false;
|
||||
|
||||
window.uiManager.showToast('Unknown error occurred', 'error');
|
||||
|
||||
// 隐藏停止生成按钮
|
||||
this.hideStopGenerationButton();
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -1570,6 +1618,39 @@ class SnapSolver {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 添加停止生成方法
|
||||
stopGeneration() {
|
||||
console.log('停止生成请求');
|
||||
|
||||
// 向服务器发送停止生成信号
|
||||
if (this.socket && this.socket.connected) {
|
||||
this.socket.emit('stop_generation');
|
||||
|
||||
// 显示提示
|
||||
window.uiManager.showToast('正在停止生成...', 'info');
|
||||
|
||||
// 隐藏停止按钮
|
||||
this.hideStopGenerationButton();
|
||||
} else {
|
||||
console.error('无法停止生成: Socket未连接');
|
||||
window.uiManager.showToast('无法停止生成: 连接已断开', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 显示停止生成按钮
|
||||
showStopGenerationButton() {
|
||||
if (this.stopGenerationBtn) {
|
||||
this.stopGenerationBtn.classList.add('visible');
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏停止生成按钮
|
||||
hideStopGenerationButton() {
|
||||
if (this.stopGenerationBtn) {
|
||||
this.stopGenerationBtn.classList.remove('visible');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the application when the DOM is loaded
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
--text-secondary: #666666;
|
||||
--border-color: #e0e0e0;
|
||||
--shadow-color: rgba(0, 0, 0, 0.1);
|
||||
--error-color: #f44336;
|
||||
--error-color: #e53935;
|
||||
--success-color: #4CAF50;
|
||||
--primary: #2196f3;
|
||||
--primary-rgb: 33, 150, 243;
|
||||
@@ -32,6 +32,7 @@
|
||||
--accent: #4a6cf7;
|
||||
--placeholder: #a0a0a0;
|
||||
--disabled: #e6e6e6;
|
||||
--error-hover-color: #c62828;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
@@ -680,8 +681,8 @@ body {
|
||||
|
||||
.header-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.header-title h2 {
|
||||
@@ -2173,3 +2174,37 @@ button:disabled {
|
||||
padding-top: 0.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* 在适当位置添加停止生成按钮样式 */
|
||||
.btn-stop-generation {
|
||||
display: none;
|
||||
background-color: var(--error-color);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
padding: 0;
|
||||
margin-left: 10px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.btn-stop-generation:hover {
|
||||
background-color: var(--error-hover-color);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.btn-stop-generation:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.btn-stop-generation i {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.btn-stop-generation.visible {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@@ -100,6 +100,9 @@
|
||||
<div class="progress-line"></div>
|
||||
<div class="status-text">准备中</div>
|
||||
</div>
|
||||
<button id="stopGenerationBtn" class="btn-stop-generation" title="停止生成">
|
||||
<i class="fas fa-stop"></i>
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn-icon" id="closeClaudePanel" title="关闭分析结果">
|
||||
<i class="fas fa-times"></i>
|
||||
|
||||
Reference in New Issue
Block a user