feat: 自定义请求超时时长

This commit is contained in:
Cassianvale
2025-03-04 16:23:21 +08:00
parent ebe4312954
commit 7a57b1366e
4 changed files with 43 additions and 19 deletions

View File

@@ -12,7 +12,7 @@ from logger import get_logger
logger = get_logger() logger = get_logger()
class StockAnalyzer: class StockAnalyzer:
def __init__(self, initial_cash=1000000, custom_api_url=None, custom_api_key=None, custom_api_model=None): def __init__(self, initial_cash=1000000, custom_api_url=None, custom_api_key=None, custom_api_model=None, custom_api_timeout=None):
# 加载环境变量 # 加载环境变量
load_dotenv() load_dotenv()
@@ -21,8 +21,9 @@ class StockAnalyzer:
self.API_URL = custom_api_url or os.getenv('API_URL') self.API_URL = custom_api_url or os.getenv('API_URL')
self.API_KEY = custom_api_key or os.getenv('API_KEY') self.API_KEY = custom_api_key or os.getenv('API_KEY')
self.API_MODEL = custom_api_model or os.getenv('API_MODEL', 'gpt-3.5-turbo') self.API_MODEL = custom_api_model or os.getenv('API_MODEL', 'gpt-3.5-turbo')
self.API_TIMEOUT = int(custom_api_timeout or os.getenv('API_TIMEOUT', 60))
logger.debug(f"初始化StockAnalyzer: API_URL={self.API_URL}, API_MODEL={self.API_MODEL}, API_KEY={'已提供' if self.API_KEY else '未提供'}") logger.debug(f"初始化StockAnalyzer: API_URL={self.API_URL}, API_MODEL={self.API_MODEL}, API_KEY={'已提供' if self.API_KEY else '未提供'}, API_TIMEOUT={self.API_TIMEOUT}")
# 配置参数 # 配置参数
self.params = { self.params = {
@@ -294,7 +295,7 @@ class StockAnalyzer:
api_url, api_url,
headers=headers, headers=headers,
json=payload, json=payload,
timeout=60, # 增加超时时间 timeout=self.API_TIMEOUT, # 增加超时时间
stream=True stream=True
) )
@@ -328,7 +329,7 @@ class StockAnalyzer:
api_url, api_url,
headers=headers, headers=headers,
json=payload, json=payload,
timeout=60 timeout=self.API_TIMEOUT
) )
logger.debug(f"API非流式响应状态码: {response.status_code}") logger.debug(f"API非流式响应状态码: {response.status_code}")

View File

@@ -64,6 +64,7 @@
value="{{ default_api_model }}"> value="{{ default_api_model }}">
</div> </div>
</div> </div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div> <div>
<label for="apiKey" class="block text-sm font-medium text-gray-700 mb-1">API Key</label> <label for="apiKey" class="block text-sm font-medium text-gray-700 mb-1">API Key</label>
<input type="password" id="apiKey" <input type="password" id="apiKey"
@@ -71,6 +72,15 @@
placeholder="输入您的API Key"> placeholder="输入您的API Key">
<p class="mt-1 text-sm text-gray-500">如不填写,将使用系统默认配置</p> <p class="mt-1 text-sm text-gray-500">如不填写,将使用系统默认配置</p>
</div> </div>
<div>
<label for="apiTimeout" class="block text-sm font-medium text-gray-700 mb-1">API 超时时间 (秒)</label>
<input type="number" id="apiTimeout"
class="w-full p-2 border rounded bg-white focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="例如: 60"
value="{{ default_api_timeout }}" min="1" max="300">
<p class="mt-1 text-sm text-gray-500">请求超时时间默认60秒</p>
</div>
</div>
<div class="flex justify-between"> <div class="flex justify-between">
<div class="flex items-center"> <div class="flex items-center">
<input type="checkbox" id="saveApiConfig" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> <input type="checkbox" id="saveApiConfig" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded">
@@ -349,6 +359,7 @@
const apiUrl = document.getElementById('apiUrl').value.trim(); const apiUrl = document.getElementById('apiUrl').value.trim();
const apiKey = document.getElementById('apiKey').value.trim(); const apiKey = document.getElementById('apiKey').value.trim();
const apiModel = document.getElementById('apiModel').value.trim(); const apiModel = document.getElementById('apiModel').value.trim();
const apiTimeout = document.getElementById('apiTimeout').value.trim();
if (!stockInput) { if (!stockInput) {
alert('请输入代码'); alert('请输入代码');
@@ -385,7 +396,8 @@
market_type: marketType, market_type: marketType,
api_url: apiUrl, api_url: apiUrl,
api_key: apiKey, api_key: apiKey,
api_model: apiModel api_model: apiModel,
api_timeout: apiTimeout
}) })
}); });
@@ -718,6 +730,7 @@
const apiUrl = document.getElementById('apiUrl'); const apiUrl = document.getElementById('apiUrl');
const apiKey = document.getElementById('apiKey'); const apiKey = document.getElementById('apiKey');
const apiModel = document.getElementById('apiModel'); const apiModel = document.getElementById('apiModel');
const apiTimeout = document.getElementById('apiTimeout');
const saveApiConfig = document.getElementById('saveApiConfig'); const saveApiConfig = document.getElementById('saveApiConfig');
const resetApiConfig = document.getElementById('resetApiConfig'); const resetApiConfig = document.getElementById('resetApiConfig');
const testApiConfig = document.getElementById('testApiConfig'); const testApiConfig = document.getElementById('testApiConfig');
@@ -743,6 +756,7 @@
apiUrl.value = '{{ default_api_url }}'; apiUrl.value = '{{ default_api_url }}';
apiKey.value = ''; apiKey.value = '';
apiModel.value = '{{ default_api_model }}'; apiModel.value = '{{ default_api_model }}';
apiTimeout.value = '{{ default_api_timeout }}';
saveApiConfig.checked = false; saveApiConfig.checked = false;
// 清除localStorage中的配置 // 清除localStorage中的配置
@@ -756,6 +770,7 @@
const url = apiUrl.value.trim(); const url = apiUrl.value.trim();
const key = apiKey.value.trim(); const key = apiKey.value.trim();
const model = apiModel.value.trim(); const model = apiModel.value.trim();
const timeout = apiTimeout.value.trim();
if (!url) { if (!url) {
alert('请输入API URL'); alert('请输入API URL');
@@ -779,7 +794,8 @@
body: JSON.stringify({ body: JSON.stringify({
api_url: url, api_url: url,
api_key: key, api_key: key,
api_model: model api_model: model,
api_timeout: timeout
}) })
}); });
@@ -804,7 +820,7 @@
}); });
// 监听输入变化,自动保存配置 // 监听输入变化,自动保存配置
[apiUrl, apiKey, apiModel].forEach(input => { [apiUrl, apiKey, apiModel, apiTimeout].forEach(input => {
input.addEventListener('change', function() { input.addEventListener('change', function() {
if (saveApiConfig.checked) { if (saveApiConfig.checked) {
saveApiConfigToLocalStorage(); saveApiConfigToLocalStorage();
@@ -828,6 +844,7 @@
url: document.getElementById('apiUrl').value.trim(), url: document.getElementById('apiUrl').value.trim(),
model: document.getElementById('apiModel').value.trim(), model: document.getElementById('apiModel').value.trim(),
key: document.getElementById('apiKey').value.trim(), key: document.getElementById('apiKey').value.trim(),
timeout: document.getElementById('apiTimeout').value.trim(),
saveEnabled: true saveEnabled: true
}; };
@@ -845,6 +862,7 @@
if (config.url) document.getElementById('apiUrl').value = config.url; if (config.url) document.getElementById('apiUrl').value = config.url;
if (config.model) document.getElementById('apiModel').value = config.model; if (config.model) document.getElementById('apiModel').value = config.model;
if (config.key) document.getElementById('apiKey').value = config.key; if (config.key) document.getElementById('apiKey').value = config.key;
if (config.timeout) document.getElementById('apiTimeout').value = config.timeout;
document.getElementById('saveApiConfig').checked = config.saveEnabled || false; document.getElementById('saveApiConfig').checked = config.saveEnabled || false;
} catch (error) { } catch (error) {

View File

@@ -85,7 +85,7 @@ def test_api_stream():
api_url, api_url,
headers=headers, headers=headers,
json=payload, json=payload,
timeout=60, timeout=int(os.getenv('API_TIMEOUT', 60)),
stream=True stream=True
) )

View File

@@ -20,11 +20,13 @@ def index():
# 获取默认API配置信息 # 获取默认API配置信息
default_api_url = os.getenv('API_URL', '') default_api_url = os.getenv('API_URL', '')
default_api_model = os.getenv('API_MODEL', 'gpt-3.5-turbo') default_api_model = os.getenv('API_MODEL', 'gpt-3.5-turbo')
default_api_timeout = os.getenv('API_TIMEOUT', '60')
# 不传递API_KEY到前端出于安全考虑 # 不传递API_KEY到前端出于安全考虑
return render_template('index.html', return render_template('index.html',
announcement=announcement, announcement=announcement,
default_api_url=default_api_url, default_api_url=default_api_url,
default_api_model=default_api_model) default_api_model=default_api_model,
default_api_timeout=default_api_timeout)
@app.route('/analyze', methods=['POST']) @app.route('/analyze', methods=['POST'])
def analyze(): def analyze():
@@ -40,14 +42,16 @@ def analyze():
custom_api_url = data.get('api_url') custom_api_url = data.get('api_url')
custom_api_key = data.get('api_key') custom_api_key = data.get('api_key')
custom_api_model = data.get('api_model') custom_api_model = data.get('api_model')
custom_api_timeout = data.get('api_timeout')
logger.debug(f"自定义API配置: URL={custom_api_url}, 模型={custom_api_model}, API Key={'已提供' if custom_api_key else '未提供'}") logger.debug(f"自定义API配置: URL={custom_api_url}, 模型={custom_api_model}, API Key={'已提供' if custom_api_key else '未提供'}, Timeout={custom_api_timeout}")
# 创建新的分析器实例,使用自定义配置 # 创建新的分析器实例,使用自定义配置
custom_analyzer = StockAnalyzer( custom_analyzer = StockAnalyzer(
custom_api_url=custom_api_url, custom_api_url=custom_api_url,
custom_api_key=custom_api_key, custom_api_key=custom_api_key,
custom_api_model=custom_api_model custom_api_model=custom_api_model,
custom_api_timeout=custom_api_timeout
) )
if not stock_codes: if not stock_codes:
@@ -121,8 +125,9 @@ def test_api_connection():
api_url = data.get('api_url') api_url = data.get('api_url')
api_key = data.get('api_key') api_key = data.get('api_key')
api_model = data.get('api_model') api_model = data.get('api_model')
api_timeout = data.get('api_timeout', 10) # 默认测试连接超时为10秒
logger.debug(f"测试API连接: URL={api_url}, 模型={api_model}, API Key={'已提供' if api_key else '未提供'}") logger.debug(f"测试API连接: URL={api_url}, 模型={api_model}, API Key={'已提供' if api_key else '未提供'}, Timeout={api_timeout}")
if not api_url: if not api_url:
logger.warning("未提供API URL") logger.warning("未提供API URL")
@@ -158,7 +163,7 @@ def test_api_connection():
], ],
"max_tokens": 20 "max_tokens": 20
}, },
timeout=10 timeout=int(api_timeout)
) )
# 检查响应 # 检查响应