支持阿里云百炼的通用模型和自定义大模型应用

This commit is contained in:
Civic_Crab
2025-02-09 06:32:49 +08:00
parent 4d8ebc8c38
commit 52eb37d13d
5 changed files with 215 additions and 1 deletions

View File

@@ -6,7 +6,7 @@ from . import entities, requester
from ...core import app
from . import token
from .requesters import chatcmpl, anthropicmsgs, moonshotchatcmpl, deepseekchatcmpl, ollamachat, giteeaichatcmpl, xaichatcmpl, zhipuaichatcmpl, lmstudiochatcmpl, siliconflowchatcmpl
from .requesters import chatcmpl, anthropicmsgs, moonshotchatcmpl, deepseekchatcmpl, ollamachat, giteeaichatcmpl, xaichatcmpl, zhipuaichatcmpl, lmstudiochatcmpl, siliconflowchatcmpl, dashscopecmpl, qwenchatcmpl
FETCH_MODEL_LIST_URL = "https://api.qchatgpt.rockchin.top/api/v2/fetch/model_list"

View File

@@ -0,0 +1,167 @@
from __future__ import annotations
import re
import asyncio
import typing
import dashscope
from .. import entities, errors, requester
from ....core import entities as core_entities, app
from ... import entities as llm_entities
from ...tools import entities as tools_entities
#阿里云百炼平台的自定义应用支持资料引用,此函数可以将引用标签替换为参考资料
def replace_references(text, references_dict):
# 修正正则表达式,匹配 <ref>[index_id]</ref> 形式的字符串
pattern = re.compile(r'<ref>\[(.*?)\]</ref>')
def replacement(match):
ref_key = match.group(1) # 获取引用编号
if ref_key in references_dict:
return f"(参考资料来自:{references_dict[ref_key]}"
else:
return match.group(0) # 如果没有对应的参考资料,保留原样
# 使用 re.sub() 进行替换
return pattern.sub(replacement, text)
@requester.requester_class("dashscope-chat-applications")
class DashscopeChatApplication(requester.LLMAPIRequester):
"""Dashscope ChatApplications API 请求器"""
requester_cfg: dict
def __init__(self, ap: app.Application):
self.requester_cfg = ap.provider_cfg.data['requester']['dashscope-chat-applications']
self.ap = ap
async def initialize(self):
dashscope.api_key = self.ap.provider_cfg.data['keys']['dashscope'][0]
async def _req(self, args: dict):
#print("args:", args)
#局部变量
chunk = None
pending_content = ""
output = {
"role": "assistant",
"content": "",
"tool_calls": [],
"tool_call_id": None # Dashscope暂时不支持工具调用
} #由于Dashscope的content的键值是text所以需要定义一个新格式的字典适配llm_entities.Message
references_dict = {} # 用于存储引用编号和对应的参考资料
#调用API
response = dashscope.Application.call(
api_key=dashscope.api_key,
app_id=args["model"],
prompt=args["messages"],
stream=True, # 设置流式输出
tools=args.get("tools", None),
incremental_output = True,
)
#处理API返回的流式输出
for chunk in response:
#print(chunk)
if not chunk:
continue
#获取流式传输的output
stream_output = chunk.get("output", {})
if stream_output.get("text") is not None:
pending_content += stream_output.get("text")
#获取模型传出的参考资料列表
references_dict_list = stream_output.get("doc_references", [])
#从模型传出的参考资料信息中提取用于替换的字典
if references_dict_list is not None:
for doc in references_dict_list:
if doc.get("index_id") is not None:
references_dict[doc.get("index_id")] = doc.get("doc_name")
#将参考资料替换到文本中
pending_content = replace_references(pending_content, references_dict)
#将流式传输的内容整合到output中
output["content"] = pending_content
return output if chunk else None
async def _make_msg(
self,
chat_completion: dict,
) -> llm_entities.Message:
chatcmpl_message = chat_completion
# 确保 role 字段存在且不为 None
if 'role' not in chatcmpl_message or chatcmpl_message['role'] is None:
chatcmpl_message['role'] = 'assistant'
message = llm_entities.Message(**chatcmpl_message)
#print("message:", message)
return message
async def _closure(
self,
query: core_entities.Query,
req_messages: list[dict],
use_model: entities.LLMModelInfo,
use_funcs: list[tools_entities.LLMFunction] = None,
) -> llm_entities.Message:
args = self.requester_cfg['args'].copy()
args["model"] = use_model.name if use_model.model_name is None else use_model.model_name
# 设置此次请求中的messages
messages = req_messages.copy()
# 检查vision
for msg in messages:
if 'content' in msg and isinstance(msg["content"], list):
for me in msg["content"]:
if me["type"] == "image_base64":
me["image_url"] = {
"url": me["image_base64"]
}
me["type"] = "image_url"
del me["image_base64"]
args["messages"] = messages
# 发送请求
resp = await self._req(args)
# 处理请求结果
message = await self._make_msg(resp)
return message
async def call(
self,
query: core_entities.Query,
model: entities.LLMModelInfo,
messages: typing.List[llm_entities.Message],
funcs: typing.List[tools_entities.LLMFunction] = None,
) -> llm_entities.Message:
req_messages = [] # req_messages 仅用于类内,外部同步由 query.messages 进行
for m in messages:
msg_dict = m.dict(exclude_none=True)
content = msg_dict.get("content")
if isinstance(content, list):
# 检查 content 列表中是否每个部分都是文本
if all(isinstance(part, dict) and part.get("type") == "text" for part in content):
# 将所有文本部分合并为一个字符串
msg_dict["content"] = "\n".join(part["text"] for part in content)
req_messages.append(msg_dict)
try:
return await self._closure(query=query, req_messages=req_messages, use_model=model, use_funcs=funcs)
except asyncio.TimeoutError:
raise errors.RequesterError('请求超时')

View File

@@ -0,0 +1,21 @@
from __future__ import annotations
import openai
from . import chatcmpl
from .. import requester
from ....core import app
@requester.requester_class("siliconflow-chat-completions")
class QwenChatCompletions(chatcmpl.OpenAIChatCompletions):
"""Qwen ChatCompletion API 请求器"""
client: openai.AsyncClient
requester_cfg: dict
def __init__(self, ap: app.Application):
self.ap = ap
self.requester_cfg = self.ap.provider_cfg.data['requester']['qwen-chat-completions']

View File

@@ -211,6 +211,16 @@
"requester": "zhipuai-chat-completions",
"token_mgr": "zhipuai",
"vision_supported": true
},
{
"name": "your-dashscope-app-id",
"requester": "dashscope-chat-applications",
"token_mgr": "dashscope",
},
{
"name": "qwen-plus",
"requester": "qwen-chat-completions",
"token_mgr": "qwen",
}
]
}

View File

@@ -25,6 +25,12 @@
],
"siliconflow": [
"xxxxxxx"
],
"dashscope": [
"sk-1234567890"
],
"qwen": [
"sk-1234567890",
]
},
"requester": {
@@ -40,6 +46,16 @@
},
"timeout": 120
},
"dashscope-chat-applications": {
"args": {},
"base-url": "https://dashscope.aliyuncs.com/api/v1",
"timeout": 120
},
"qwen-chat-completions": {
"base-url": "https://dashscope.aliyuncs.com/compatible-mode/v1",
"args": {},
"timeout": 120
},
"moonshot-chat-completions": {
"base-url": "https://api.moonshot.cn/v1",
"args": {},