diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 397c49fe..7181f918 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -11,9 +11,12 @@ body: - 其他(或暂未使用) - Nakuru(go-cqhttp) - aiocqhttp(使用 OneBot 协议接入的) - - qq-botpy(QQ官方API) + - qq-botpy(QQ官方API WebSocket) + - qqofficial(QQ官方API Webhook) - lark(飞书) - wecom(企业微信) + - gewechat(个人微信) + - discord validations: required: true - type: input diff --git a/README.md b/README.md index fc78032c..2921bf23 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@
-RockChinQ%2FQChatGPT | Trendshift +RockChinQ%2FLangBot | Trendshift 项目主页功能介绍 | diff --git a/pkg/core/notes/n003_print_version.py b/pkg/core/notes/n003_print_version.py new file mode 100644 index 00000000..6eed21d6 --- /dev/null +++ b/pkg/core/notes/n003_print_version.py @@ -0,0 +1,21 @@ +from __future__ import annotations + +import typing +import os +import sys +import logging + +from .. import note, app + + +@note.note_class("PrintVersion", 3) +class PrintVersion(note.LaunchNote): + """打印版本信息 + """ + + async def need_show(self) -> bool: + return True + + async def yield_note(self) -> typing.AsyncGenerator[typing.Tuple[str, int], None]: + + yield f"当前版本:{self.ap.ver_mgr.get_current_version()}", logging.INFO diff --git a/pkg/core/stages/show_notes.py b/pkg/core/stages/show_notes.py index 91cdbf01..63d8f580 100644 --- a/pkg/core/stages/show_notes.py +++ b/pkg/core/stages/show_notes.py @@ -1,7 +1,7 @@ from __future__ import annotations from .. import stage, app, note -from ..notes import n001_classic_msgs, n002_selection_mode_on_windows +from ..notes import n001_classic_msgs, n002_selection_mode_on_windows, n003_print_version @stage.stage_class("ShowNotesStage") diff --git a/pkg/pipeline/wrapper/wrapper.py b/pkg/pipeline/wrapper/wrapper.py index 1ffb3147..a06e4a80 100644 --- a/pkg/pipeline/wrapper/wrapper.py +++ b/pkg/pipeline/wrapper/wrapper.py @@ -102,7 +102,7 @@ class ResponseWrapper(stage.PipelineStage): new_query=query ) - if result.tool_calls is not None: # 有函数调用 + if result.tool_calls is not None and len(result.tool_calls) > 0: # 有函数调用 function_names = [tc.function.name for tc in result.tool_calls] diff --git a/pkg/platform/sources/qqofficial.py b/pkg/platform/sources/qqofficial.py index 924e7ba0..7993062a 100644 --- a/pkg/platform/sources/qqofficial.py +++ b/pkg/platform/sources/qqofficial.py @@ -47,6 +47,7 @@ class QQOfficialMessageConverter(adapter.MessageConverter): yiri_msg_list.append( platform_message.Image(base64=base64_url) ) + yiri_msg_list.append(platform_message.Plain(text=message)) chain = platform_message.MessageChain(yiri_msg_list) return chain diff --git a/pkg/provider/modelmgr/requesters/chatcmpl.py b/pkg/provider/modelmgr/requesters/chatcmpl.py index 9e3014af..0b1c4cf2 100644 --- a/pkg/provider/modelmgr/requesters/chatcmpl.py +++ b/pkg/provider/modelmgr/requesters/chatcmpl.py @@ -8,6 +8,7 @@ from typing import AsyncGenerator import openai import openai.types.chat.chat_completion as chat_completion +import openai.types.chat.chat_completion_message_tool_call as chat_completion_message_tool_call import httpx import aiohttp import async_lru @@ -40,6 +41,7 @@ class OpenAIChatCompletions(requester.LLMAPIRequester): timeout=self.requester_cfg['timeout'], http_client=httpx.AsyncClient( trust_env=True, + timeout=self.requester_cfg['timeout'] ) ) @@ -47,7 +49,67 @@ class OpenAIChatCompletions(requester.LLMAPIRequester): self, args: dict, ) -> chat_completion.ChatCompletion: - return await self.client.chat.completions.create(**args) + args["stream"] = True + + chunk = None + + pending_content = "" + + tool_calls = [] + + resp_gen: openai.AsyncStream = await self.client.chat.completions.create(**args) + + async for chunk in resp_gen: + # print(chunk) + if not chunk: + continue + + if chunk.choices[0].delta.content is not None: + pending_content += chunk.choices[0].delta.content + + if chunk.choices[0].delta.tool_calls is not None: + for tool_call in chunk.choices[0].delta.tool_calls: + for tc in tool_calls: + if tc.index == tool_call.index: + tc.function.arguments += tool_call.function.arguments + break + else: + tool_calls.append(tool_call) + + real_tool_calls = [] + + for tc in tool_calls: + function = chat_completion_message_tool_call.Function( + name=tc.function.name, + arguments=tc.function.arguments + ) + real_tool_calls.append(chat_completion_message_tool_call.ChatCompletionMessageToolCall( + id=tc.id, + function=function, + type="function" + )) + + return chat_completion.ChatCompletion( + id=chunk.id, + object="chat.completion", + created=chunk.created, + choices=[ + chat_completion.Choice( + index=0, + message=chat_completion.ChatCompletionMessage( + role="assistant", + content=pending_content, + tool_calls=real_tool_calls if len(real_tool_calls) > 0 else None + ), + finish_reason=chunk.choices[0].finish_reason if hasattr(chunk.choices[0], 'finish_reason') and chunk.choices[0].finish_reason is not None else 'stop', + logprobs=chunk.choices[0].logprobs, + ) + ], + model=chunk.model, + service_tier=chunk.service_tier if hasattr(chunk, 'service_tier') else None, + system_fingerprint=chunk.system_fingerprint if hasattr(chunk, 'system_fingerprint') else None, + usage=chunk.usage if hasattr(chunk, 'usage') else None + ) if chunk else None async def _make_msg( self, diff --git a/pkg/provider/modelmgr/requesters/deepseekchatcmpl.py b/pkg/provider/modelmgr/requesters/deepseekchatcmpl.py index bf414745..7b8c9ca8 100644 --- a/pkg/provider/modelmgr/requesters/deepseekchatcmpl.py +++ b/pkg/provider/modelmgr/requesters/deepseekchatcmpl.py @@ -46,6 +46,9 @@ class DeepseekChatCompletions(chatcmpl.OpenAIChatCompletions): # 发送请求 resp = await self._req(args) + if resp is None: + raise errors.RequesterError('接口返回为空,请确定模型提供商服务是否正常') + # 处理请求结果 message = await self._make_msg(resp) diff --git a/pkg/utils/constants.py b/pkg/utils/constants.py index 0dce973c..61ed497b 100644 --- a/pkg/utils/constants.py +++ b/pkg/utils/constants.py @@ -1,4 +1,4 @@ -semantic_version = "v3.4.6" +semantic_version = "v3.4.6.2" debug_mode = False diff --git a/web/package-lock.json b/web/package-lock.json index d692c64b..331b2815 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -4410,14 +4410,14 @@ } }, "node_modules/jsonpath-plus": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.1.0.tgz", - "integrity": "sha512-gHfV1IYqH8uJHYVTs8BJX1XKy2/rR93+f8QQi0xhx95aCiXn1ettYAd5T+7FU6wfqyDoX/wy0pm/fL3jOKJ9Lg==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.2.0.tgz", + "integrity": "sha512-T9V+8iNYKFL2n2rF+w02LBOT2JjDnTjioaNFrxRy0Bv1y/hNsqR/EBK7Ojy2ythRHwmz2cRIls+9JitQGZC/sw==", "license": "MIT", "dependencies": { - "@jsep-plugin/assignment": "^1.2.1", - "@jsep-plugin/regex": "^1.0.3", - "jsep": "^1.3.9" + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" }, "bin": { "jsonpath": "bin/jsonpath-cli.js",