feat:统一API格式为Gemini
This commit is contained in:
@@ -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:])
|
candidates = data.get("candidates", [])
|
||||||
delta = data.get("choices", [{}])[0].get("delta", {})
|
if candidates:
|
||||||
content = delta.get("content", "")
|
parts = candidates[0].get("content", {}).get("parts", [])
|
||||||
if content:
|
for part in parts:
|
||||||
description += content
|
if "text" in part:
|
||||||
except:
|
description += part["text"]
|
||||||
pass
|
except:
|
||||||
|
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 的工具调用响应
|
||||||
|
|||||||
Reference in New Issue
Block a user