feat: 自定义请求超时时长
This commit is contained in:
@@ -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}")
|
||||||
|
|||||||
@@ -64,12 +64,22 @@
|
|||||||
value="{{ default_api_model }}">
|
value="{{ default_api_model }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
<label for="apiKey" class="block text-sm font-medium text-gray-700 mb-1">API Key</label>
|
<div>
|
||||||
<input type="password" id="apiKey"
|
<label for="apiKey" class="block text-sm font-medium text-gray-700 mb-1">API Key</label>
|
||||||
class="w-full p-2 border rounded bg-white focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
<input type="password" id="apiKey"
|
||||||
placeholder="输入您的API Key">
|
class="w-full p-2 border rounded bg-white focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||||
<p class="mt-1 text-sm text-gray-500">如不填写,将使用系统默认配置</p>
|
placeholder="输入您的API Key">
|
||||||
|
<p class="mt-1 text-sm text-gray-500">如不填写,将使用系统默认配置</p>
|
||||||
|
</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>
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
)
|
)
|
||||||
|
|
||||||
# 检查响应
|
# 检查响应
|
||||||
|
|||||||
Reference in New Issue
Block a user