mirror of
https://github.com/Zippland/Snap-Solver.git
synced 2026-01-20 07:00:57 +08:00
优化WebSocket连接和图像处理的稳定性
This commit is contained in:
26
app.py
26
app.py
@@ -10,7 +10,7 @@ from PIL import Image, ImageDraw
|
||||
import pyperclip
|
||||
from models import ModelFactory
|
||||
app = Flask(__name__)
|
||||
socketio = SocketIO(app, cors_allowed_origins="*")
|
||||
socketio = SocketIO(app, cors_allowed_origins="*", ping_timeout=30, ping_interval=5, max_http_buffer_size=50 * 1024 * 1024)
|
||||
|
||||
# Commented out due to model file issues
|
||||
# from pix2text import Pix2Text
|
||||
@@ -188,6 +188,11 @@ def handle_text_extraction(data):
|
||||
image_data = data['image']
|
||||
if not isinstance(image_data, str):
|
||||
raise ValueError("Invalid image data format")
|
||||
|
||||
# 检查图像大小,避免处理过大的图像导致断开连接
|
||||
image_size_bytes = len(image_data) * 3 / 4 # 估算base64的实际大小
|
||||
if image_size_bytes > 10 * 1024 * 1024: # 10MB
|
||||
raise ValueError("Image too large, please crop to a smaller area")
|
||||
|
||||
settings = data.get('settings', {})
|
||||
if not isinstance(settings, dict):
|
||||
@@ -197,6 +202,13 @@ def handle_text_extraction(data):
|
||||
if not mathpix_key:
|
||||
raise ValueError("Mathpix API key is required")
|
||||
|
||||
# 先回复客户端,确认已收到请求,防止超时断开
|
||||
# 注意:这里不能使用return,否则后续代码不会执行
|
||||
socketio.emit('request_acknowledged', {
|
||||
'status': 'received',
|
||||
'message': 'Image received, text extraction in progress'
|
||||
}, room=request.sid)
|
||||
|
||||
try:
|
||||
app_id, app_key = mathpix_key.split(':')
|
||||
if not app_id.strip() or not app_key.strip():
|
||||
@@ -298,6 +310,11 @@ def handle_analyze_image(data):
|
||||
if not image_data:
|
||||
raise ValueError("No image data provided")
|
||||
|
||||
# 检查图像大小,避免处理过大的图像导致断开连接
|
||||
image_size_bytes = len(image_data) * 3 / 4 # 估算base64的实际大小
|
||||
if image_size_bytes > 10 * 1024 * 1024: # 10MB
|
||||
raise ValueError("Image too large, please crop to a smaller area or use text extraction")
|
||||
|
||||
settings = data.get('settings', {})
|
||||
|
||||
# 不需要分割了,因为前端已经做了分割
|
||||
@@ -327,6 +344,13 @@ def handle_analyze_image(data):
|
||||
}
|
||||
|
||||
try:
|
||||
# 先回复客户端,确认已收到请求,防止超时断开
|
||||
# 注意:这里不能使用return,否则后续代码不会执行
|
||||
socketio.emit('request_acknowledged', {
|
||||
'status': 'received',
|
||||
'message': 'Image received, analysis in progress'
|
||||
}, room=request.sid)
|
||||
|
||||
# Create model instance using factory
|
||||
model = ModelFactory.create_model(
|
||||
model_name=model_name,
|
||||
|
||||
@@ -61,6 +61,7 @@ class SnapSolver {
|
||||
this.croppedImage = null;
|
||||
this.history = JSON.parse(localStorage.getItem('snapHistory') || '[]');
|
||||
this.currentFormat = 'text';
|
||||
this.emitTimeout = null;
|
||||
this.extractedFormats = {
|
||||
text: '',
|
||||
latex: ''
|
||||
@@ -134,7 +135,14 @@ class SnapSolver {
|
||||
|
||||
initializeConnection() {
|
||||
try {
|
||||
this.socket = io(window.location.origin);
|
||||
this.socket = io(window.location.origin, {
|
||||
reconnection: true,
|
||||
reconnectionAttempts: 5,
|
||||
reconnectionDelay: 1000,
|
||||
reconnectionDelayMax: 5000,
|
||||
timeout: 20000,
|
||||
autoConnect: true
|
||||
});
|
||||
|
||||
this.socket.on('connect', () => {
|
||||
console.log('Connected to server');
|
||||
@@ -144,8 +152,29 @@ class SnapSolver {
|
||||
this.socket.on('disconnect', () => {
|
||||
console.log('Disconnected from server');
|
||||
this.updateConnectionStatus(false);
|
||||
this.socket = null;
|
||||
setTimeout(() => this.initializeConnection(), 5000);
|
||||
});
|
||||
|
||||
this.socket.on('connect_error', (error) => {
|
||||
console.error('Connection error:', error);
|
||||
this.updateConnectionStatus(false);
|
||||
});
|
||||
|
||||
this.socket.on('reconnect', (attemptNumber) => {
|
||||
console.log(`Reconnected after ${attemptNumber} attempts`);
|
||||
this.updateConnectionStatus(true);
|
||||
});
|
||||
|
||||
this.socket.on('reconnect_attempt', (attemptNumber) => {
|
||||
console.log(`Reconnection attempt: ${attemptNumber}`);
|
||||
});
|
||||
|
||||
this.socket.on('reconnect_error', (error) => {
|
||||
console.error('Reconnection error:', error);
|
||||
});
|
||||
|
||||
this.socket.on('reconnect_failed', () => {
|
||||
console.error('Failed to reconnect');
|
||||
window.showToast('连接服务器失败,请刷新页面重试', 'error');
|
||||
});
|
||||
|
||||
this.setupSocketEventHandlers();
|
||||
@@ -177,6 +206,17 @@ class SnapSolver {
|
||||
}
|
||||
});
|
||||
|
||||
// 请求确认响应处理器
|
||||
this.socket.on('request_acknowledged', (data) => {
|
||||
console.log('服务器确认收到请求:', data);
|
||||
window.showToast(data.message || '请求已接收,正在处理...', 'info');
|
||||
// 清除可能存在的超时计时器
|
||||
if (this.emitTimeout) {
|
||||
clearTimeout(this.emitTimeout);
|
||||
this.emitTimeout = null;
|
||||
}
|
||||
});
|
||||
|
||||
// Text extraction response handler
|
||||
this.socket.on('text_extracted', (data) => {
|
||||
if (data.error) {
|
||||
@@ -319,13 +359,6 @@ class SnapSolver {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.socket.on('connect_error', (error) => {
|
||||
console.error('Connection error:', error);
|
||||
this.updateConnectionStatus(false);
|
||||
this.socket = null;
|
||||
setTimeout(() => this.initializeConnection(), 5000);
|
||||
});
|
||||
}
|
||||
|
||||
// 新方法:安全设置DOM内容的方法(替代updateElementContent)
|
||||
@@ -751,11 +784,23 @@ class SnapSolver {
|
||||
}
|
||||
|
||||
try {
|
||||
// 设置超时时间(10秒)以避免长时间无响应
|
||||
this.emitTimeout = setTimeout(() => {
|
||||
window.showToast('文本提取超时,请重试或手动输入文本', 'error');
|
||||
this.extractTextBtn.disabled = false;
|
||||
this.extractTextBtn.innerHTML = '<i class="fas fa-font"></i><span>Extract Text</span>';
|
||||
this.extractedText.disabled = false;
|
||||
}, 10000);
|
||||
|
||||
this.socket.emit('extract_text', {
|
||||
image: this.croppedImage.split(',')[1],
|
||||
settings: {
|
||||
mathpixApiKey: `${mathpixAppId}:${mathpixAppKey}`
|
||||
}
|
||||
}, (ackResponse) => {
|
||||
// 如果服务器确认收到请求,清除超时
|
||||
clearTimeout(this.emitTimeout);
|
||||
console.log('服务器确认收到文本提取请求', ackResponse);
|
||||
});
|
||||
} catch (error) {
|
||||
window.showToast('Failed to extract text: ' + error.message, 'error');
|
||||
@@ -821,13 +866,36 @@ class SnapSolver {
|
||||
this.sendToClaudeBtn.disabled = true;
|
||||
|
||||
try {
|
||||
// 添加图片大小检查和压缩
|
||||
const base64Data = this.croppedImage.split(',')[1];
|
||||
// 计算图片大小(以字节为单位)
|
||||
const imageSize = Math.ceil((base64Data.length * 3) / 4);
|
||||
console.log(`图片大小: ${imageSize / 1024} KB`);
|
||||
|
||||
// 如果图片大小超过8MB(WebSocket默认限制),则显示错误
|
||||
if (imageSize > 8 * 1024 * 1024) {
|
||||
window.showToast('图片太大,请裁剪更小的区域或使用文本提取功能', 'error');
|
||||
this.sendToClaudeBtn.disabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置超时时间(10秒)以避免长时间无响应
|
||||
this.emitTimeout = setTimeout(() => {
|
||||
window.showToast('发送图片超时,请重试或使用文本提取功能', 'error');
|
||||
this.sendToClaudeBtn.disabled = false;
|
||||
}, 10000);
|
||||
|
||||
this.socket.emit('analyze_image', {
|
||||
image: this.croppedImage.split(',')[1],
|
||||
image: base64Data,
|
||||
settings: {
|
||||
...settings,
|
||||
api_keys: apiKeys,
|
||||
model: settings.model || 'claude-3-7-sonnet-20250219',
|
||||
}
|
||||
}, (ackResponse) => {
|
||||
// 如果服务器确认收到请求,清除超时
|
||||
clearTimeout(this.emitTimeout);
|
||||
console.log('服务器确认收到图片分析请求', ackResponse);
|
||||
});
|
||||
} catch (error) {
|
||||
this.responseContent.textContent = 'Error: Failed to send image for analysis - ' + error.message;
|
||||
|
||||
Reference in New Issue
Block a user