mirror of
https://github.com/Zippland/Snap-Solver.git
synced 2026-01-19 01:21:13 +08:00
修复gemini接口,添加豆包接口
This commit is contained in:
6
app.py
6
app.py
@@ -101,6 +101,8 @@ def create_model_instance(model_id, settings, is_reasoning=False):
|
||||
api_key_id = "AlibabaApiKey"
|
||||
elif "gemini" in model_id.lower() or "google" in model_id.lower():
|
||||
api_key_id = "GoogleApiKey"
|
||||
elif "doubao" in model_id.lower():
|
||||
api_key_id = "DoubaoApiKey"
|
||||
|
||||
# 首先尝试从本地配置获取API密钥
|
||||
api_key = get_api_key(api_key_id)
|
||||
@@ -156,6 +158,10 @@ def create_model_instance(model_id, settings, is_reasoning=False):
|
||||
custom_base_url = api_base_urls.get('google')
|
||||
if custom_base_url:
|
||||
base_url = custom_base_url
|
||||
elif "doubao" in model_id.lower():
|
||||
custom_base_url = api_base_urls.get('doubao')
|
||||
if custom_base_url:
|
||||
base_url = custom_base_url
|
||||
|
||||
# 创建模型实例
|
||||
model_instance = ModelFactory.create_model(
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
"OpenaiApiBaseUrl": "",
|
||||
"DeepseekApiBaseUrl": "",
|
||||
"AlibabaApiBaseUrl": "",
|
||||
"GoogleApiBaseUrl": ""
|
||||
"GoogleApiBaseUrl": "",
|
||||
"DoubaoApiBaseUrl": ""
|
||||
}
|
||||
@@ -24,6 +24,11 @@
|
||||
"name": "Google",
|
||||
"api_key_id": "GoogleApiKey",
|
||||
"class_name": "GoogleModel"
|
||||
},
|
||||
"doubao": {
|
||||
"name": "Doubao",
|
||||
"api_key_id": "DoubaoApiKey",
|
||||
"class_name": "DoubaoModel"
|
||||
}
|
||||
},
|
||||
"models": {
|
||||
@@ -91,13 +96,13 @@
|
||||
"version": "latest",
|
||||
"description": "阿里通义千问VL-MAX模型,视觉理解能力最强,支持图像理解和复杂任务"
|
||||
},
|
||||
"gemini-2.5-pro-preview-03-25": {
|
||||
"gemini-2.5-pro": {
|
||||
"name": "Gemini 2.5 Pro",
|
||||
"provider": "google",
|
||||
"supportsMultimodal": true,
|
||||
"isReasoning": true,
|
||||
"version": "preview-03-25",
|
||||
"description": "Google最强大的Gemini 2.5 Pro模型,支持图像理解"
|
||||
"version": "latest",
|
||||
"description": "Google最强大的Gemini 2.5 Pro模型,支持图像理解(需要付费API密钥)"
|
||||
},
|
||||
"gemini-2.0-flash": {
|
||||
"name": "Gemini 2.0 Flash",
|
||||
@@ -105,7 +110,15 @@
|
||||
"supportsMultimodal": true,
|
||||
"isReasoning": false,
|
||||
"version": "latest",
|
||||
"description": "Google更快速的Gemini 2.0 Flash模型,支持图像理解,响应更迅速"
|
||||
"description": "Google更快速的Gemini 2.0 Flash模型,支持图像理解,有免费配额"
|
||||
},
|
||||
"doubao-seed-1-6-250615": {
|
||||
"name": "Doubao-Seed-1.6",
|
||||
"provider": "doubao",
|
||||
"supportsMultimodal": true,
|
||||
"isReasoning": false,
|
||||
"version": "latest",
|
||||
"description": "支持auto/thinking/non-thinking三种思考模式、支持多模态、256K长上下文"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,8 @@
|
||||
"anthropic": "",
|
||||
"deepseek": "",
|
||||
"google": "",
|
||||
"openai": ""
|
||||
"openai": "",
|
||||
"doubao": ""
|
||||
},
|
||||
"enabled": true
|
||||
}
|
||||
@@ -4,6 +4,7 @@ from .openai import OpenAIModel
|
||||
from .deepseek import DeepSeekModel
|
||||
from .alibaba import AlibabaModel
|
||||
from .google import GoogleModel
|
||||
from .doubao import DoubaoModel
|
||||
from .factory import ModelFactory
|
||||
|
||||
__all__ = [
|
||||
@@ -13,5 +14,6 @@ __all__ = [
|
||||
'DeepSeekModel',
|
||||
'AlibabaModel',
|
||||
'GoogleModel',
|
||||
'DoubaoModel',
|
||||
'ModelFactory'
|
||||
]
|
||||
|
||||
@@ -4,12 +4,13 @@ from openai import OpenAI
|
||||
from .base import BaseModel
|
||||
|
||||
class AlibabaModel(BaseModel):
|
||||
def __init__(self, api_key: str, temperature: float = 0.7, system_prompt: str = None, language: str = None, model_name: str = None):
|
||||
def __init__(self, api_key: str, temperature: float = 0.7, system_prompt: str = None, language: str = None, model_name: str = None, api_base_url: str = None):
|
||||
# 如果没有提供模型名称,才使用默认值
|
||||
self.model_name = model_name if model_name else "QVQ-Max-2025-03-25"
|
||||
print(f"初始化阿里巴巴模型: {self.model_name}")
|
||||
# 在super().__init__之前设置model_name,这样get_default_system_prompt能使用它
|
||||
super().__init__(api_key, temperature, system_prompt, language)
|
||||
self.api_base_url = api_base_url # 存储API基础URL
|
||||
|
||||
def get_default_system_prompt(self) -> str:
|
||||
"""根据模型名称返回不同的默认系统提示词"""
|
||||
|
||||
@@ -6,9 +6,10 @@ from openai import OpenAI
|
||||
from .base import BaseModel
|
||||
|
||||
class DeepSeekModel(BaseModel):
|
||||
def __init__(self, api_key: str, temperature: float = 0.7, system_prompt: str = None, language: str = None, model_name: str = "deepseek-reasoner"):
|
||||
def __init__(self, api_key: str, temperature: float = 0.7, system_prompt: str = None, language: str = None, model_name: str = "deepseek-reasoner", api_base_url: str = None):
|
||||
super().__init__(api_key, temperature, system_prompt, language)
|
||||
self.model_name = model_name
|
||||
self.api_base_url = api_base_url # 存储API基础URL
|
||||
|
||||
def get_default_system_prompt(self) -> str:
|
||||
return """You are an expert at analyzing questions and providing detailed solutions. When presented with an image of a question:
|
||||
|
||||
312
models/doubao.py
Normal file
312
models/doubao.py
Normal file
@@ -0,0 +1,312 @@
|
||||
import json
|
||||
import os
|
||||
import base64
|
||||
from typing import Generator, Dict, Any, Optional
|
||||
import requests
|
||||
from .base import BaseModel
|
||||
|
||||
class DoubaoModel(BaseModel):
|
||||
"""
|
||||
豆包API模型实现类
|
||||
支持字节跳动的豆包AI模型,可处理文本和图像输入
|
||||
"""
|
||||
|
||||
def __init__(self, api_key: str, temperature: float = 0.7, system_prompt: str = None, language: str = None, model_name: str = None, api_base_url: str = None):
|
||||
"""
|
||||
初始化豆包模型
|
||||
|
||||
Args:
|
||||
api_key: 豆包API密钥
|
||||
temperature: 生成温度
|
||||
system_prompt: 系统提示词
|
||||
language: 首选语言
|
||||
model_name: 指定具体模型名称,如不指定则使用默认值
|
||||
api_base_url: API基础URL,用于设置自定义API端点
|
||||
"""
|
||||
super().__init__(api_key, temperature, system_prompt, language)
|
||||
self.model_name = model_name or self.get_model_identifier()
|
||||
self.base_url = api_base_url or "https://ark.cn-beijing.volces.com/api/v3"
|
||||
self.max_tokens = 4096 # 默认最大输出token数
|
||||
|
||||
def get_default_system_prompt(self) -> str:
|
||||
return """你是一个专业的问题分析专家。当看到问题图片时:
|
||||
1. 仔细阅读并理解问题
|
||||
2. 分解问题的关键组成部分
|
||||
3. 提供清晰的分步解决方案
|
||||
4. 如果相关,解释涉及的概念或理论
|
||||
5. 如果有多种方法,优先解释最有效的方法"""
|
||||
|
||||
def get_model_identifier(self) -> str:
|
||||
"""返回默认的模型标识符"""
|
||||
return "doubao-seed-1-6-250615" # Doubao-Seed-1.6
|
||||
|
||||
def get_actual_model_name(self) -> str:
|
||||
"""根据配置的模型名称返回实际的API调用标识符"""
|
||||
# 豆包API的实际模型名称映射
|
||||
model_mapping = {
|
||||
"doubao-seed-1-6-250615": "doubao-seed-1-6-250615"
|
||||
}
|
||||
|
||||
return model_mapping.get(self.model_name, "doubao-seed-1-6-250615")
|
||||
|
||||
def analyze_text(self, text: str, proxies: dict = None) -> Generator[dict, None, None]:
|
||||
"""流式生成文本响应"""
|
||||
try:
|
||||
yield {"status": "started"}
|
||||
|
||||
# 设置环境变量代理(如果提供)
|
||||
original_proxies = None
|
||||
if proxies:
|
||||
original_proxies = {
|
||||
'http_proxy': os.environ.get('http_proxy'),
|
||||
'https_proxy': os.environ.get('https_proxy')
|
||||
}
|
||||
if 'http' in proxies:
|
||||
os.environ['http_proxy'] = proxies['http']
|
||||
if 'https' in proxies:
|
||||
os.environ['https_proxy'] = proxies['https']
|
||||
|
||||
try:
|
||||
# 构建请求头
|
||||
headers = {
|
||||
"Authorization": f"Bearer {self.api_key}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
# 构建消息 - 根据官方API文档,暂时不使用系统提示词
|
||||
messages = []
|
||||
|
||||
# 添加用户查询
|
||||
user_content = text
|
||||
if self.language and self.language != 'auto':
|
||||
user_content = f"请使用{self.language}回答以下问题: {text}"
|
||||
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": user_content
|
||||
})
|
||||
|
||||
# 构建请求数据
|
||||
data = {
|
||||
"model": self.get_actual_model_name(),
|
||||
"messages": messages,
|
||||
"temperature": self.temperature,
|
||||
"max_tokens": self.max_tokens,
|
||||
"stream": True
|
||||
}
|
||||
|
||||
# 发送流式请求
|
||||
response = requests.post(
|
||||
f"{self.base_url}/chat/completions",
|
||||
headers=headers,
|
||||
json=data,
|
||||
stream=True,
|
||||
proxies=proxies if proxies else None,
|
||||
timeout=60
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
error_text = response.text
|
||||
raise Exception(f"HTTP {response.status_code}: {error_text}")
|
||||
|
||||
response.raise_for_status()
|
||||
|
||||
# 初始化响应缓冲区
|
||||
response_buffer = ""
|
||||
|
||||
# 处理流式响应
|
||||
for line in response.iter_lines():
|
||||
if not line:
|
||||
continue
|
||||
|
||||
line = line.decode('utf-8')
|
||||
if not line.startswith('data: '):
|
||||
continue
|
||||
|
||||
line = line[6:] # 移除 'data: ' 前缀
|
||||
|
||||
if line == '[DONE]':
|
||||
break
|
||||
|
||||
try:
|
||||
chunk_data = json.loads(line)
|
||||
choices = chunk_data.get('choices', [])
|
||||
|
||||
if choices and len(choices) > 0:
|
||||
delta = choices[0].get('delta', {})
|
||||
content = delta.get('content', '')
|
||||
|
||||
if content:
|
||||
response_buffer += content
|
||||
|
||||
# 发送响应进度
|
||||
yield {
|
||||
"status": "streaming",
|
||||
"content": response_buffer
|
||||
}
|
||||
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
# 确保发送完整的最终内容
|
||||
yield {
|
||||
"status": "completed",
|
||||
"content": response_buffer
|
||||
}
|
||||
|
||||
finally:
|
||||
# 恢复原始代理设置
|
||||
if original_proxies:
|
||||
for key, value in original_proxies.items():
|
||||
if value is None:
|
||||
if key in os.environ:
|
||||
del os.environ[key]
|
||||
else:
|
||||
os.environ[key] = value
|
||||
|
||||
except Exception as e:
|
||||
yield {
|
||||
"status": "error",
|
||||
"error": f"豆包API错误: {str(e)}"
|
||||
}
|
||||
|
||||
def analyze_image(self, image_data: str, proxies: dict = None) -> Generator[dict, None, None]:
|
||||
"""分析图像并流式生成响应"""
|
||||
try:
|
||||
yield {"status": "started"}
|
||||
|
||||
# 设置环境变量代理(如果提供)
|
||||
original_proxies = None
|
||||
if proxies:
|
||||
original_proxies = {
|
||||
'http_proxy': os.environ.get('http_proxy'),
|
||||
'https_proxy': os.environ.get('https_proxy')
|
||||
}
|
||||
if 'http' in proxies:
|
||||
os.environ['http_proxy'] = proxies['http']
|
||||
if 'https' in proxies:
|
||||
os.environ['https_proxy'] = proxies['https']
|
||||
|
||||
try:
|
||||
# 构建请求头
|
||||
headers = {
|
||||
"Authorization": f"Bearer {self.api_key}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
# 处理图像数据
|
||||
if image_data.startswith('data:image'):
|
||||
# 如果是data URI,提取base64部分
|
||||
image_data = image_data.split(',', 1)[1]
|
||||
|
||||
# 构建用户消息 - 使用豆包API官方示例格式
|
||||
# 首先检查图像数据的格式,确保是有效的图像
|
||||
image_format = "jpeg" # 默认使用jpeg
|
||||
if image_data.startswith('/9j/'): # JPEG magic number in base64
|
||||
image_format = "jpeg"
|
||||
elif image_data.startswith('iVBORw0KGgo'): # PNG magic number in base64
|
||||
image_format = "png"
|
||||
|
||||
user_content = [
|
||||
{
|
||||
"type": "text",
|
||||
"text": f"请使用{self.language}分析这张图片并提供详细解答。" if self.language and self.language != 'auto' else "请分析这张图片并提供详细解答?"
|
||||
},
|
||||
{
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
"url": f"data:image/{image_format};base64,{image_data}"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
messages = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": user_content
|
||||
}
|
||||
]
|
||||
|
||||
# 构建请求数据
|
||||
data = {
|
||||
"model": self.get_actual_model_name(),
|
||||
"messages": messages,
|
||||
"temperature": self.temperature,
|
||||
"max_tokens": self.max_tokens,
|
||||
"stream": True
|
||||
}
|
||||
|
||||
# 发送流式请求
|
||||
response = requests.post(
|
||||
f"{self.base_url}/chat/completions",
|
||||
headers=headers,
|
||||
json=data,
|
||||
stream=True,
|
||||
proxies=proxies if proxies else None,
|
||||
timeout=60
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
error_text = response.text
|
||||
raise Exception(f"HTTP {response.status_code}: {error_text}")
|
||||
|
||||
response.raise_for_status()
|
||||
|
||||
# 初始化响应缓冲区
|
||||
response_buffer = ""
|
||||
|
||||
# 处理流式响应
|
||||
for line in response.iter_lines():
|
||||
if not line:
|
||||
continue
|
||||
|
||||
line = line.decode('utf-8')
|
||||
if not line.startswith('data: '):
|
||||
continue
|
||||
|
||||
line = line[6:] # 移除 'data: ' 前缀
|
||||
|
||||
if line == '[DONE]':
|
||||
break
|
||||
|
||||
try:
|
||||
chunk_data = json.loads(line)
|
||||
choices = chunk_data.get('choices', [])
|
||||
|
||||
if choices and len(choices) > 0:
|
||||
delta = choices[0].get('delta', {})
|
||||
content = delta.get('content', '')
|
||||
|
||||
if content:
|
||||
response_buffer += content
|
||||
|
||||
# 发送响应进度
|
||||
yield {
|
||||
"status": "streaming",
|
||||
"content": response_buffer
|
||||
}
|
||||
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
# 确保发送完整的最终内容
|
||||
yield {
|
||||
"status": "completed",
|
||||
"content": response_buffer
|
||||
}
|
||||
|
||||
finally:
|
||||
# 恢复原始代理设置
|
||||
if original_proxies:
|
||||
for key, value in original_proxies.items():
|
||||
if value is None:
|
||||
if key in os.environ:
|
||||
del os.environ[key]
|
||||
else:
|
||||
os.environ[key] = value
|
||||
|
||||
except Exception as e:
|
||||
yield {
|
||||
"status": "error",
|
||||
"error": f"豆包图像分析错误: {str(e)}"
|
||||
}
|
||||
@@ -114,6 +114,25 @@ class ModelFactory:
|
||||
)
|
||||
# 对于阿里巴巴模型,也需要传递正确的模型名称
|
||||
elif 'qwen' in model_name.lower() or 'qvq' in model_name.lower() or 'alibaba' in model_name.lower():
|
||||
return model_class(
|
||||
api_key=api_key,
|
||||
temperature=temperature,
|
||||
system_prompt=system_prompt,
|
||||
language=language,
|
||||
model_name=model_name
|
||||
)
|
||||
# 对于Google模型,也需要传递正确的模型名称
|
||||
elif 'gemini' in model_name.lower() or 'google' in model_name.lower():
|
||||
return model_class(
|
||||
api_key=api_key,
|
||||
temperature=temperature,
|
||||
system_prompt=system_prompt,
|
||||
language=language,
|
||||
model_name=model_name,
|
||||
api_base_url=api_base_url
|
||||
)
|
||||
# 对于豆包模型,也需要传递正确的模型名称
|
||||
elif 'doubao' in model_name.lower():
|
||||
return model_class(
|
||||
api_key=api_key,
|
||||
temperature=temperature,
|
||||
|
||||
@@ -46,7 +46,7 @@ class GoogleModel(BaseModel):
|
||||
|
||||
def get_model_identifier(self) -> str:
|
||||
"""返回默认的模型标识符"""
|
||||
return "gemini-2.5-pro-preview-03-25"
|
||||
return "gemini-2.0-flash" # 使用有免费配额的模型作为默认值
|
||||
|
||||
def analyze_text(self, text: str, proxies: dict = None) -> Generator[dict, None, None]:
|
||||
"""流式生成文本响应"""
|
||||
|
||||
@@ -381,6 +381,7 @@ class SettingsManager {
|
||||
'DeepseekApiKey': '',
|
||||
'AlibabaApiKey': '',
|
||||
'GoogleApiKey': '',
|
||||
'DoubaoApiKey': '',
|
||||
'MathpixAppId': '',
|
||||
'MathpixAppKey': ''
|
||||
};
|
||||
@@ -391,7 +392,8 @@ class SettingsManager {
|
||||
'OpenaiApiBaseUrl': '',
|
||||
'DeepseekApiBaseUrl': '',
|
||||
'AlibabaApiBaseUrl': '',
|
||||
'GoogleApiBaseUrl': ''
|
||||
'GoogleApiBaseUrl': '',
|
||||
'DoubaoApiBaseUrl': ''
|
||||
};
|
||||
|
||||
// 加载模型配置
|
||||
@@ -759,6 +761,8 @@ class SettingsManager {
|
||||
apiKeyToHighlight = document.querySelector('.api-key-status:nth-child(4)'); // Alibaba
|
||||
} else if (modelType && (modelType.toLowerCase().includes('gemini') || modelType.toLowerCase().includes('google'))) {
|
||||
apiKeyToHighlight = document.querySelector('.api-key-status:nth-child(5)'); // Google
|
||||
} else if (modelType && modelType.toLowerCase().includes('doubao')) {
|
||||
apiKeyToHighlight = document.querySelector('.api-key-status:nth-child(6)'); // 豆包
|
||||
}
|
||||
|
||||
if (apiKeyToHighlight) {
|
||||
@@ -869,6 +873,9 @@ class SettingsManager {
|
||||
if (this.apiBaseUrlValues['GoogleApiBaseUrl']) {
|
||||
apiBaseUrls.google = this.apiBaseUrlValues['GoogleApiBaseUrl'];
|
||||
}
|
||||
if (this.apiBaseUrlValues['DoubaoApiBaseUrl']) {
|
||||
apiBaseUrls.doubao = this.apiBaseUrlValues['DoubaoApiBaseUrl'];
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -2260,6 +2267,7 @@ class SettingsManager {
|
||||
'DeepseekApiKey': '',
|
||||
'AlibabaApiKey': '',
|
||||
'GoogleApiKey': '',
|
||||
'DoubaoApiKey': '',
|
||||
'MathpixAppId': '',
|
||||
'MathpixAppKey': ''
|
||||
};
|
||||
@@ -2359,7 +2367,8 @@ class SettingsManager {
|
||||
'OpenaiApiBaseUrl': proxyApiConfig.apis?.openai || '',
|
||||
'DeepseekApiBaseUrl': proxyApiConfig.apis?.deepseek || '',
|
||||
'AlibabaApiBaseUrl': proxyApiConfig.apis?.alibaba || '',
|
||||
'GoogleApiBaseUrl': proxyApiConfig.apis?.google || ''
|
||||
'GoogleApiBaseUrl': proxyApiConfig.apis?.google || '',
|
||||
'DoubaoApiBaseUrl': proxyApiConfig.apis?.doubao || ''
|
||||
};
|
||||
this.updateApiBaseUrlStatus(apiBaseUrls);
|
||||
console.log('API基础URL状态已刷新');
|
||||
@@ -2449,6 +2458,9 @@ class SettingsManager {
|
||||
case 'GoogleApiBaseUrl':
|
||||
config.apis.google = value;
|
||||
break;
|
||||
case 'DoubaoApiBaseUrl':
|
||||
config.apis.doubao = value;
|
||||
break;
|
||||
}
|
||||
|
||||
// 确保启用中转API
|
||||
|
||||
@@ -425,6 +425,28 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="api-key-status">
|
||||
<span class="key-name">Doubao API:</span>
|
||||
<div class="key-status-wrapper">
|
||||
<!-- 显示状态 -->
|
||||
<div class="key-display">
|
||||
<span id="DoubaoApiKeyStatus" class="key-status" data-key="DoubaoApiKey">未设置</span>
|
||||
<button class="btn-icon edit-api-key" data-key-type="DoubaoApiKey" title="编辑此密钥">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
</div>
|
||||
<!-- 编辑状态 -->
|
||||
<div class="key-edit hidden">
|
||||
<input type="password" class="key-input" data-key-type="DoubaoApiKey" placeholder="输入Doubao API key">
|
||||
<button class="btn-icon toggle-visibility">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
<button class="btn-icon save-api-key" data-key-type="DoubaoApiKey" title="保存密钥">
|
||||
<i class="fas fa-save"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="api-key-status">
|
||||
<span class="key-name">Mathpix App ID:</span>
|
||||
<div class="key-status-wrapper">
|
||||
@@ -577,6 +599,25 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="api-key-status">
|
||||
<span class="key-name">Doubao API URL:</span>
|
||||
<div class="key-status-wrapper">
|
||||
<!-- 显示状态 -->
|
||||
<div class="key-display">
|
||||
<span id="DoubaoApiBaseUrlStatus" class="key-status" data-key="DoubaoApiBaseUrl">未设置</span>
|
||||
<button class="btn-icon edit-api-base-url" data-key-type="DoubaoApiBaseUrl" title="编辑此URL">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
</div>
|
||||
<!-- 编辑状态 -->
|
||||
<div class="key-edit hidden">
|
||||
<input type="text" class="key-input" data-key-type="DoubaoApiBaseUrl" placeholder="https://ark.cn-beijing.volces.com/api/v3">
|
||||
<button class="btn-icon save-api-base-url" data-key-type="DoubaoApiBaseUrl" title="保存URL">
|
||||
<i class="fas fa-save"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user