mirror of
https://github.com/Nezumi-2711/astrbot_plugin_qq_group_daily_analysis.git
synced 2026-09-22 20:01:04 +00:00
[feat] (provider) 添加对自定义 LLM 服务的支持(兼容 OpenAI 格式),需指定 apikey, base_url 与 model ,留空就使用 Astrbot 内置的 LLM 统一方法
This commit is contained in:
@@ -99,6 +99,24 @@
|
||||
"default": 2,
|
||||
"hint": "重试之间的基准等待时间(秒),实际等待时间为基值乘以尝试次数。"
|
||||
},
|
||||
"custom_api_key": {
|
||||
"type": "string",
|
||||
"description": "自定义 LLM 服务 API Key (选填)",
|
||||
"default": "",
|
||||
"hint": "若使用自建或第三方的 LLM 服务,可在此填写 API Key;留空则使用 Astrbot 统一内置提供商。"
|
||||
},
|
||||
"custom_api_base_url": {
|
||||
"type": "string",
|
||||
"description": "自定义 LLM 服务 Base URL (选填)",
|
||||
"default": "",
|
||||
"hint": "自定义 LLM 服务的基础请求地址,例如 https://api.example.com/v1/chat 。留空则使用 Astrbot 统一内置提供商。"
|
||||
},
|
||||
"custom_model_name": {
|
||||
"type": "string",
|
||||
"description": "自定义 LLM 模型名称 (选填)",
|
||||
"default": "",
|
||||
"hint": "自定义服务所使用的模型名称,例如 gpt-4 或自定义模型标识。留空则使用 Astrbot 统一内置提供商。"
|
||||
},
|
||||
"pdf_output_dir": {
|
||||
"type": "string",
|
||||
"description": "PDF输出目录",
|
||||
|
||||
@@ -20,17 +20,53 @@ class LLMAnalyzer:
|
||||
self.config_manager = config_manager
|
||||
|
||||
async def _call_provider_with_retry(self, provider, prompt: str, max_tokens: int, temperature: float):
|
||||
"""调用LLM提供者,带超时、重试与退避。"""
|
||||
|
||||
"""调用LLM提供者,带超时、重试与退避。支持自定义服务商。"""
|
||||
timeout = self.config_manager.get_llm_timeout()
|
||||
retries = self.config_manager.get_llm_retries()
|
||||
backoff = self.config_manager.get_llm_backoff()
|
||||
|
||||
# 获取自定义服务商参数
|
||||
custom_api_key = getattr(self.config_manager, 'get_custom_api_key', lambda: None)()
|
||||
custom_api_base = getattr(self.config_manager, 'get_custom_api_base_url', lambda: None)()
|
||||
custom_model = getattr(self.config_manager, 'get_custom_model_name', lambda: None)()
|
||||
|
||||
last_exc = None
|
||||
for attempt in range(1, retries + 1):
|
||||
try:
|
||||
coro = provider.text_chat(prompt=prompt, max_tokens=max_tokens, temperature=temperature)
|
||||
return await asyncio.wait_for(coro, timeout=timeout)
|
||||
if custom_api_key and custom_api_base and custom_model:
|
||||
logger.info(f"使用自定义LLM提供商: {custom_api_base} model={custom_model}")
|
||||
import aiohttp
|
||||
async with aiohttp.ClientSession() as session:
|
||||
headers = {
|
||||
"Authorization": f"Bearer {custom_api_key}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
payload = {
|
||||
"model": custom_model,
|
||||
"messages": [{"role": "user", "content": prompt}],
|
||||
"max_tokens": max_tokens,
|
||||
"temperature": temperature
|
||||
}
|
||||
async with session.post(custom_api_base, json=payload, headers=headers, timeout=timeout) as resp:
|
||||
if resp.status != 200:
|
||||
error_text = await resp.text()
|
||||
logger.error(f"自定义LLM服务商请求失败: HTTP {resp.status}, 内容: {error_text}")
|
||||
try:
|
||||
response_json = await resp.json()
|
||||
except Exception as json_err:
|
||||
error_text = await resp.text()
|
||||
logger.error(f"自定义LLM服务商响应JSON解析失败: {json_err}, 内容: {error_text}")
|
||||
# 兼容 OpenAI 格式
|
||||
content = response_json["choices"][0]["message"]["content"]
|
||||
# 构造一个兼容原有逻辑的对象
|
||||
class CustomResponse:
|
||||
completion_text = content
|
||||
raw_completion = response_json
|
||||
return CustomResponse()
|
||||
else:
|
||||
logger.info(f"使用默认LLM provider: {provider}")
|
||||
coro = provider.text_chat(prompt=prompt, max_tokens=max_tokens, temperature=temperature)
|
||||
return await asyncio.wait_for(coro, timeout=timeout)
|
||||
except asyncio.TimeoutError as e:
|
||||
last_exc = e
|
||||
logger.warning(f"LLM请求超时: 第{attempt}次, timeout={timeout}s")
|
||||
|
||||
@@ -83,6 +83,17 @@ class ConfigManager:
|
||||
"""获取LLM请求重试退避基值(秒),实际退避会乘以尝试次数"""
|
||||
return self.config.get("llm_backoff", 2)
|
||||
|
||||
def get_custom_api_key(self) -> str:
|
||||
"""获取自定义 LLM 服务的 API Key"""
|
||||
return self.config.get("custom_api_key", "")
|
||||
|
||||
def get_custom_api_base_url(self) -> str:
|
||||
"""获取自定义 LLM 服务的 Base URL"""
|
||||
return self.config.get("custom_api_base_url", "")
|
||||
|
||||
def get_custom_model_name(self) -> str:
|
||||
"""获取自定义 LLM 服务的模型名称"""
|
||||
return self.config.get("custom_model_name", "")
|
||||
def get_pdf_output_dir(self) -> str:
|
||||
"""获取PDF输出目录"""
|
||||
return self.config.get("pdf_output_dir", "data/plugins/astrbot-qq-group-daily-analysis/reports")
|
||||
|
||||
Reference in New Issue
Block a user