feat:统一API格式为Gemini

This commit is contained in:
2025-12-11 14:35:39 +08:00
parent 908b5c8c07
commit 09de5862dc

View File

@@ -488,7 +488,7 @@ class AIChat(PluginBase):
async def _generate_image_description(self, image_base64: str, prompt: str, config: dict) -> str: async def _generate_image_description(self, image_base64: str, prompt: str, config: dict) -> str:
""" """
使用 AI 生成图片描述 使用 Gemini API 生成图片描述
Args: Args:
image_base64: 图片的 base64 数据 image_base64: 图片的 base64 数据
@@ -498,26 +498,39 @@ class AIChat(PluginBase):
Returns: Returns:
图片描述文本,失败返回空字符串 图片描述文本,失败返回空字符串
""" """
import json
try: try:
api_config = self.config["api"] api_config = self.config["api"]
description_model = config.get("model", api_config["model"]) description_model = config.get("model", api_config["model"])
api_url = api_config.get("gemini_url", "https://api.functen.cn/v1beta/models")
# 构建消息 # 处理 base64 数据
messages = [ image_data = image_base64
{ mime_type = "image/jpeg"
"role": "user", if image_data.startswith("data:"):
"content": [ mime_type = image_data.split(";")[0].split(":")[1]
{"type": "text", "text": prompt}, image_data = image_data.split(",", 1)[1]
{"type": "image_url", "image_url": {"url": image_base64}}
] # 构建 Gemini 格式请求
} full_url = f"{api_url}/{description_model}:streamGenerateContent?alt=sse"
]
payload = { payload = {
"model": description_model, "contents": [
"messages": messages, {
"max_tokens": config.get("max_tokens", 1000), "parts": [
"stream": True {"text": prompt},
{
"inline_data": {
"mime_type": mime_type,
"data": image_data
}
}
]
}
],
"generationConfig": {
"maxOutputTokens": config.get("max_tokens", 1000)
}
} }
headers = { headers = {
@@ -525,12 +538,12 @@ class AIChat(PluginBase):
"Authorization": f"Bearer {api_config['api_key']}" "Authorization": f"Bearer {api_config['api_key']}"
} }
timeout = aiohttp.ClientTimeout(total=api_config["timeout"]) timeout = aiohttp.ClientTimeout(total=api_config.get("timeout", 120))
# 配置代理 # 配置代理
connector = None connector = None
proxy_config = self.config.get("proxy", {}) proxy_config = self.config.get("proxy", {})
if proxy_config.get("enabled", False): if proxy_config.get("enabled", False) and PROXY_SUPPORT:
proxy_type = proxy_config.get("type", "socks5").upper() proxy_type = proxy_config.get("type", "socks5").upper()
proxy_host = proxy_config.get("host", "127.0.0.1") proxy_host = proxy_config.get("host", "127.0.0.1")
proxy_port = proxy_config.get("port", 7890) proxy_port = proxy_config.get("port", 7890)
@@ -542,43 +555,37 @@ class AIChat(PluginBase):
else: else:
proxy_url = f"{proxy_type}://{proxy_host}:{proxy_port}" proxy_url = f"{proxy_type}://{proxy_host}:{proxy_port}"
if PROXY_SUPPORT:
try: try:
connector = ProxyConnector.from_url(proxy_url) connector = ProxyConnector.from_url(proxy_url)
except Exception as e: except Exception as e:
logger.warning(f"代理配置失败,将直连: {e}") logger.warning(f"代理配置失败,将直连: {e}")
connector = None
async with aiohttp.ClientSession(timeout=timeout, connector=connector) as session: async with aiohttp.ClientSession(timeout=timeout, connector=connector) as session:
async with session.post( async with session.post(full_url, json=payload, headers=headers) as resp:
api_config["url"],
json=payload,
headers=headers
) as resp:
if resp.status != 200: if resp.status != 200:
error_text = await resp.text() error_text = await resp.text()
logger.error(f"图片描述 API 返回错误: {resp.status}, {error_text[:200]}") logger.error(f"图片描述 API 返回错误: {resp.status}, {error_text[:200]}")
return "" return ""
# 流式接收响应 # 流式接收 Gemini 响应
import json
description = "" description = ""
async for line in resp.content: async for line in resp.content:
line = line.decode('utf-8').strip() line = line.decode('utf-8').strip()
if not line or line == "data: [DONE]": if not line or not line.startswith("data: "):
continue continue
if line.startswith("data: "):
try: try:
data = json.loads(line[6:]) data = json.loads(line[6:])
delta = data.get("choices", [{}])[0].get("delta", {}) candidates = data.get("candidates", [])
content = delta.get("content", "") if candidates:
if content: parts = candidates[0].get("content", {}).get("parts", [])
description += content for part in parts:
if "text" in part:
description += part["text"]
except: except:
pass pass
logger.debug(f"图片描述生成成功: {description}") logger.debug(f"图片描述生成成功: {description[:100]}...")
return description.strip() return description.strip()
except Exception as e: except Exception as e:
@@ -788,6 +795,7 @@ class AIChat(PluginBase):
Gemini 格式: {"functionCall": {"name": "...", "args": {...}}} Gemini 格式: {"functionCall": {"name": "...", "args": {...}}}
转换为内部格式: {"id": "...", "function": {"name": "...", "arguments": "..."}} 转换为内部格式: {"id": "...", "function": {"name": "...", "arguments": "..."}}
""" """
import json
tool_calls = [] tool_calls = []
for i, part in enumerate(response_parts): for i, part in enumerate(response_parts):
if "functionCall" in part: if "functionCall" in part:
@@ -812,6 +820,7 @@ class AIChat(PluginBase):
tool_calls: 工具调用列表 tool_calls: 工具调用列表
tool_results: 工具执行结果列表 tool_results: 工具执行结果列表
""" """
import json
new_contents = contents.copy() new_contents = contents.copy()
# 添加 model 的工具调用响应 # 添加 model 的工具调用响应