diff --git a/app.py b/app.py index ce43eee..c38da0c 100644 --- a/app.py +++ b/app.py @@ -679,157 +679,6 @@ def update_api_keys(): except Exception as e: return jsonify({"success": False, "message": f"更新API密钥错误: {str(e)}"}), 500 -# 验证API密钥 -@app.route('/api/keys/validate', methods=['POST']) -def validate_api_key(): - """验证API密钥有效性""" - try: - validate_data = request.json - if not isinstance(validate_data, dict) or 'key_type' not in validate_data or 'key_value' not in validate_data: - return jsonify({"success": False, "message": "无效的请求格式"}), 400 - - key_type = validate_data['key_type'] - key_value = validate_data['key_value'] - - if not key_value or key_value.strip() == "": - return jsonify({"success": False, "message": f"未提供{key_type}密钥"}), 400 - - # 基于密钥类型进行验证 - result = {"success": False, "message": "不支持的密钥类型"} - - if key_type == "AnthropicApiKey": - result = validate_anthropic_key(key_value) - elif key_type == "OpenaiApiKey": - result = validate_openai_key(key_value) - elif key_type == "DeepseekApiKey": - result = validate_deepseek_key(key_value) - elif key_type == "AlibabaApiKey": - result = validate_alibaba_key(key_value) - elif key_type == "MathpixAppId" or key_type == "MathpixAppKey": - # Mathpix需要两个密钥一起验证 - mathpix_app_id = key_value if key_type == "MathpixAppId" else get_api_key("MathpixAppId") - mathpix_app_key = key_value if key_type == "MathpixAppKey" else get_api_key("MathpixAppKey") - if mathpix_app_id and mathpix_app_key: - result = validate_mathpix_key(f"{mathpix_app_id}:{mathpix_app_key}") - else: - result = {"success": False, "message": "需要同时设置Mathpix App ID和App Key"} - - return jsonify(result) - - except Exception as e: - return jsonify({"success": False, "message": f"验证API密钥时出错: {str(e)}"}), 500 - -def validate_anthropic_key(api_key): - """验证Anthropic API密钥""" - try: - import anthropic - client = anthropic.Anthropic(api_key=api_key) - # 发送一个简单请求来验证密钥 - response = client.messages.create( - model="claude-3-haiku-20240307", - max_tokens=10, - messages=[{"role": "user", "content": "Hello"}] - ) - return {"success": True, "message": "Anthropic API密钥有效"} - except Exception as e: - error_message = str(e) - if "401" in error_message or "unauthorized" in error_message.lower(): - return {"success": False, "message": "Anthropic API密钥无效或已过期"} - return {"success": False, "message": f"验证Anthropic API密钥时出错: {error_message}"} - -def validate_openai_key(api_key): - """验证OpenAI API密钥""" - try: - import openai - client = openai.OpenAI(api_key=api_key) - # 发送一个简单请求来验证密钥 - response = client.chat.completions.create( - model="gpt-3.5-turbo", - messages=[{"role": "user", "content": "Hello"}], - max_tokens=10 - ) - return {"success": True, "message": "OpenAI API密钥有效"} - except Exception as e: - error_message = str(e) - if "401" in error_message or "invalid" in error_message.lower(): - return {"success": False, "message": "OpenAI API密钥无效或已过期"} - return {"success": False, "message": f"验证OpenAI API密钥时出错: {error_message}"} - -def validate_deepseek_key(api_key): - """验证DeepSeek API密钥""" - try: - import requests - headers = { - "Content-Type": "application/json", - "Authorization": f"Bearer {api_key}" - } - data = { - "model": "deepseek-chat", - "messages": [{"role": "user", "content": "Hello"}], - "max_tokens": 10 - } - response = requests.post( - "https://api.deepseek.com/v1/chat/completions", - headers=headers, - json=data, - timeout=10 - ) - if response.status_code == 200: - return {"success": True, "message": "DeepSeek API密钥有效"} - else: - error_message = response.json().get("error", {}).get("message", "未知错误") - return {"success": False, "message": f"DeepSeek API密钥无效: {error_message}"} - except Exception as e: - return {"success": False, "message": f"验证DeepSeek API密钥时出错: {str(e)}"} - -def validate_alibaba_key(api_key): - """验证阿里巴巴DashScope API密钥""" - try: - import dashscope - dashscope.api_key = api_key - response = dashscope.Generation.call( - model='qwen-vl-plus', - messages=[{'role': 'user', 'content': 'Hello'}], - result_format='message', - max_tokens=10 - ) - if response.status_code == 200: - return {"success": True, "message": "阿里巴巴API密钥有效"} - else: - error_message = response.message - return {"success": False, "message": f"阿里巴巴API密钥无效: {error_message}"} - except Exception as e: - error_message = str(e) - if "unauthorized" in error_message.lower() or "invalid" in error_message.lower(): - return {"success": False, "message": "阿里巴巴API密钥无效或已过期"} - return {"success": False, "message": f"验证阿里巴巴API密钥时出错: {error_message}"} - -def validate_mathpix_key(api_key): - """验证Mathpix API密钥""" - try: - import requests - # 分解API密钥 - app_id, app_key = api_key.split(":") - - headers = { - "app_id": app_id, - "app_key": app_key, - "Content-Type": "application/json" - } - # 构造一个简单的请求(只检查API密钥,不实际发送图像) - response = requests.get( - "https://api.mathpix.com/v3/app-setting", - headers=headers, - timeout=10 - ) - if response.status_code == 200: - return {"success": True, "message": "Mathpix API密钥有效"} - else: - error_message = response.json().get("error", "未知错误") - return {"success": False, "message": f"Mathpix API密钥无效: {error_message}"} - except Exception as e: - return {"success": False, "message": f"验证Mathpix API密钥时出错: {str(e)}"} - # 加载API密钥配置 def load_api_keys(): """从配置文件加载API密钥""" diff --git a/models/base.py b/models/base.py index f5db031..0d80e69 100644 --- a/models/base.py +++ b/models/base.py @@ -45,7 +45,3 @@ class BaseModel(ABC): def get_model_identifier(self) -> str: """Return the model identifier used in API calls""" pass - - def validate_api_key(self) -> bool: - """Validate if the API key is in the correct format""" - return bool(self.api_key and self.api_key.strip()) diff --git a/models/mathpix.py b/models/mathpix.py index ba7863b..795f2f8 100644 --- a/models/mathpix.py +++ b/models/mathpix.py @@ -211,16 +211,6 @@ class MathpixModel(BaseModel): """ return "mathpix" - def validate_api_key(self) -> bool: - """ - Validate if the API key is in the correct format (app_id:app_key). - """ - try: - app_id, app_key = self.api_key.split(':') - return bool(app_id.strip() and app_key.strip()) - except ValueError: - return False - def _format_response(self, result: Dict[str, Any]) -> str: """ Format the Mathpix API response into a readable string. diff --git a/pic.jpg b/pic.jpg deleted file mode 100644 index 306d952..0000000 Binary files a/pic.jpg and /dev/null differ diff --git a/static/js/main.js b/static/js/main.js index bc2c15c..59ae4b7 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -136,51 +136,62 @@ class SnapSolver { } updateStatusLight(status) { - 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) { + if (!progressLine || !statusText || !analysisIndicator) { + console.error('状态指示器元素未找到:', { + progressLine: !!progressLine, + statusText: !!statusText, + analysisIndicator: !!analysisIndicator + }); return; } + // 确保指示器可见 analysisIndicator.style.display = 'flex'; - statusLight.classList.remove('completed', 'error', 'working'); + + // 先移除所有可能的状态类 + analysisIndicator.classList.remove('processing', 'completed', 'error'); + progressLine.classList.remove('processing', 'completed', 'error'); switch (status) { case 'started': case 'thinking': case 'reasoning': case 'streaming': - statusLight.classList.add('working'); - progressLine.style.animation = 'progress-animation 2s linear infinite'; + // 添加处理中状态类 + analysisIndicator.classList.add('processing'); + progressLine.classList.add('processing'); statusText.textContent = '生成中'; break; case 'completed': - statusLight.classList.add('completed'); - progressLine.style.animation = 'none'; - progressLine.style.width = '100%'; + // 添加完成状态类 + analysisIndicator.classList.add('completed'); + progressLine.classList.add('completed'); statusText.textContent = '完成'; break; case 'error': - statusLight.classList.add('error'); - progressLine.style.animation = 'none'; - progressLine.style.width = '100%'; + // 添加错误状态类 + analysisIndicator.classList.add('error'); + progressLine.classList.add('error'); statusText.textContent = '出错'; break; case 'stopped': - statusLight.classList.add('error'); - progressLine.style.animation = 'none'; - progressLine.style.width = '100%'; + // 添加错误状态类(用于停止状态) + analysisIndicator.classList.add('error'); + progressLine.classList.add('error'); statusText.textContent = '已停止'; break; default: - analysisIndicator.style.display = 'none'; + // 对于未知状态,显示准备中 + statusText.textContent = '准备中'; break; } } diff --git a/static/js/settings.js b/static/js/settings.js index c3e7721..0199022 100644 --- a/static/js/settings.js +++ b/static/js/settings.js @@ -230,45 +230,6 @@ class SettingsManager { }); }); - // Initialize API key validate buttons - document.querySelectorAll('.validate-api-key').forEach(button => { - button.addEventListener('click', (e) => { - const keyType = e.currentTarget.getAttribute('data-key-type'); - const input = e.currentTarget.closest('.input-group').querySelector('input'); - const keyValue = input.value; - - if (keyValue.trim() === '') { - window.uiManager?.showToast('请先输入API密钥', 'warning'); - return; - } - - // 显示验证中状态 - const icon = e.currentTarget.querySelector('i'); - const originalClass = icon.className; - icon.className = 'fas fa-spinner fa-spin'; - e.currentTarget.disabled = true; - - this.validateApiKey(keyType, keyValue) - .then(result => { - if (result.success) { - window.uiManager?.showToast(result.message, 'success'); - // 更新状态显示 - this.saveSettings(); - } else { - window.uiManager?.showToast(result.message, 'error'); - } - }) - .catch(error => { - window.uiManager?.showToast(`验证失败: ${error.message}`, 'error'); - }) - .finally(() => { - // 恢复按钮状态 - icon.className = originalClass; - e.currentTarget.disabled = false; - }); - }); - }); - // 存储API密钥的对象 this.apiKeyValues = { 'AnthropicApiKey': '', @@ -1005,36 +966,6 @@ class SettingsManager { } } - /** - * 验证API密钥 - * @param {string} keyType 密钥类型 - * @param {string} keyValue 密钥值 - * @returns {Promise} 验证结果 - */ - async validateApiKey(keyType, keyValue) { - try { - const response = await fetch('/api/keys/validate', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ - key_type: keyType, - key_value: keyValue - }) - }); - - if (!response.ok) { - throw new Error(`服务器响应错误: ${response.status}`); - } - - return await response.json(); - } catch (error) { - console.error('验证API密钥时出错:', error); - throw error; - } - } - /** * 创建一个Toast提示消息 * @param {string} message 提示消息内容 diff --git a/static/style.css b/static/style.css index 0e9265e..9fa8c22 100644 --- a/static/style.css +++ b/static/style.css @@ -745,12 +745,13 @@ body { } .progress-line { - height: 2px; - width: 60px; + height: 4px; + width: 40px; background-color: var(--border-color); - border-radius: 1px; + border-radius: 2px; overflow: hidden; position: relative; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05) inset; } .progress-line::before { @@ -759,45 +760,48 @@ body { top: 0; left: 0; height: 100%; - width: 0%; + width: 100%; background-color: var(--primary); - border-radius: 1px; - transition: width 0.3s ease; + border-radius: 2px; + transform: translateX(-100%); + transition: transform 0.3s ease; } .progress-line.processing::before { - animation: progress-animation 2s ease-in-out infinite; + animation: pulse-animation 1.5s ease-in-out infinite; } .progress-line.completed::before { - width: 100%; - background-color: var(--success); + transform: translateX(0); + background-color: #4CAF50; + transition: transform 0.3s cubic-bezier(0.19, 1, 0.22, 1), background-color 0.3s ease; } .progress-line.error::before { - width: 100%; - background-color: var(--danger); + transform: translateX(0); + background-color: #F44336; + transition: transform 0.3s cubic-bezier(0.19, 1, 0.22, 1), background-color 0.3s ease; } -@keyframes progress-animation { +@keyframes pulse-animation { 0% { - width: 0%; - left: 0; + transform: translateX(-100%); } 50% { - width: 50%; - left: 25%; + transform: translateX(0); } 100% { - width: 0%; - left: 100%; + transform: translateX(100%); } } .status-text { - font-weight: 500; + font-weight: 600; white-space: nowrap; transition: color 0.3s ease; + font-size: 0.7rem; + letter-spacing: 0.3px; + text-transform: uppercase; } .analysis-indicator.processing .status-text { @@ -805,11 +809,11 @@ body { } .analysis-indicator.completed .status-text { - color: var(--success); + color: #4CAF50; } .analysis-indicator.error .status-text { - color: var(--danger); + color: #F44336; } /* Thinking Section */ @@ -2454,23 +2458,28 @@ button:disabled { /* 在适当位置添加停止生成按钮样式 */ .btn-stop-generation { display: none; - background-color: var(--error-color); - color: white; - border: none; - border-radius: 4px; - width: 32px; - height: 32px; + background-color: rgba(244, 67, 54, 0.1); + color: #F44336; + border: 1px solid rgba(244, 67, 54, 0.2); + border-radius: 50%; + width: 24px; + height: 24px; padding: 0; - margin-left: 10px; + margin-left: 8px; cursor: pointer; - transition: all 0.2s ease; + transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); align-items: center; justify-content: center; + font-size: 10px; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + position: relative; + overflow: hidden; } .btn-stop-generation:hover { - background-color: var(--error-hover-color); - transform: scale(1.05); + background-color: rgba(244, 67, 54, 0.15); + transform: scale(1.1); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .btn-stop-generation:active { @@ -2478,13 +2487,19 @@ button:disabled { } .btn-stop-generation i { - font-size: 14px; + font-size: 10px; } .btn-stop-generation.visible { display: flex; } +[data-theme="dark"] .btn-stop-generation { + background-color: rgba(248, 81, 73, 0.15); + color: #f85149; + border-color: rgba(248, 81, 73, 0.3); +} + /* API密钥状态高亮 */ .api-key-status.highlight { background-color: var(--hover-bg); @@ -2565,15 +2580,6 @@ textarea:focus { background-color: rgba(var(--primary-rgb), 0.1); } -.input-group .validate-api-key { - color: var(--text-success); -} - -.input-group .validate-api-key:hover { - color: var(--text-success); - background-color: rgba(40, 167, 69, 0.1); -} - .checkbox-label { display: flex; align-items: center; diff --git a/templates/index.html b/templates/index.html index 2834f4c..c8ca34f 100644 --- a/templates/index.html +++ b/templates/index.html @@ -344,16 +344,6 @@ - - -