From 5c584ee60df8a8a7f92b20ed892d335661eb22dc Mon Sep 17 00:00:00 2001 From: Junyan Qin Date: Sun, 16 Mar 2025 22:43:25 +0800 Subject: [PATCH] feat: requesters api --- .../controller/groups/provider/__init__.py | 0 .../groups/{ => provider}/models.py | 18 ++++++----- .../controller/groups/provider/requesters.py | 26 ++++++++++++++++ pkg/api/http/controller/main.py | 4 ++- pkg/discover/engine.py | 31 +++++++++++++++++++ pkg/provider/modelmgr/modelmgr.py | 28 ++++++++++++----- 6 files changed, 91 insertions(+), 16 deletions(-) create mode 100644 pkg/api/http/controller/groups/provider/__init__.py rename pkg/api/http/controller/groups/{ => provider}/models.py (70%) create mode 100644 pkg/api/http/controller/groups/provider/requesters.py diff --git a/pkg/api/http/controller/groups/provider/__init__.py b/pkg/api/http/controller/groups/provider/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pkg/api/http/controller/groups/models.py b/pkg/api/http/controller/groups/provider/models.py similarity index 70% rename from pkg/api/http/controller/groups/models.py rename to pkg/api/http/controller/groups/provider/models.py index d88df866..ab91ab6a 100644 --- a/pkg/api/http/controller/groups/models.py +++ b/pkg/api/http/controller/groups/provider/models.py @@ -1,8 +1,8 @@ import quart import uuid -from .. import group -from .....entity.persistence import model +from ... import group +from ......entity.persistence import model @group.group_class('models/llm', '/api/v1/provider/models/llm') @@ -22,7 +22,7 @@ class LLMModelsRouterGroup(group.RouterGroup): return self.success() - @self.route('/', methods=['GET', 'PUT', 'DELETE']) + @self.route('/', methods=['GET', 'DELETE']) async def _(model_uuid: str) -> str: if quart.request.method == 'GET': model = await self.ap.model_service.get_llm_model(model_uuid) @@ -30,13 +30,15 @@ class LLMModelsRouterGroup(group.RouterGroup): if model is None: return self.http_status(404, -1, 'model not found') - return self.success(data=model) - elif quart.request.method == 'PUT': - json_data = await quart.request.json + return self.success(data={ + 'model': model + }) + # elif quart.request.method == 'PUT': + # json_data = await quart.request.json - await self.ap.model_service.update_llm_model(model_uuid, json_data) + # await self.ap.model_service.update_llm_model(model_uuid, json_data) - return self.success() + # return self.success() elif quart.request.method == 'DELETE': await self.ap.model_service.delete_llm_model(model_uuid) diff --git a/pkg/api/http/controller/groups/provider/requesters.py b/pkg/api/http/controller/groups/provider/requesters.py new file mode 100644 index 00000000..7dd3cfea --- /dev/null +++ b/pkg/api/http/controller/groups/provider/requesters.py @@ -0,0 +1,26 @@ +import quart + +from ... import group + + +@group.group_class('provider/requesters', '/api/v1/provider/requesters') +class RequestersRouterGroup(group.RouterGroup): + + async def initialize(self) -> None: + @self.route('', methods=['GET']) + async def _() -> quart.Response: + return self.success(data={ + 'requesters': self.ap.model_mgr.get_available_requesters_info() + }) + + @self.route('/', methods=['GET']) + async def _(requester_name: str) -> quart.Response: + + requester_info = self.ap.model_mgr.get_available_requester_info_by_name(requester_name) + + if requester_info is None: + return self.http_status(404, -1, 'requester not found') + + return self.success(data={ + 'requester': requester_info + }) diff --git a/pkg/api/http/controller/main.py b/pkg/api/http/controller/main.py index e644e7e4..9aced3cf 100644 --- a/pkg/api/http/controller/main.py +++ b/pkg/api/http/controller/main.py @@ -7,7 +7,9 @@ import quart import quart_cors from ....core import app, entities as core_entities -from .groups import logs, system, settings, plugins, stats, user, models + +from .groups import logs, system, settings, plugins, stats, user +from .groups.provider import models, requesters from . import group diff --git a/pkg/discover/engine.py b/pkg/discover/engine.py index 297e6515..3960661c 100644 --- a/pkg/discover/engine.py +++ b/pkg/discover/engine.py @@ -23,6 +23,16 @@ class I18nString(pydantic.BaseModel): ja_JP: typing.Optional[str] = None """日文""" + def to_dict(self) -> dict: + """转换为字典""" + dic = {} + if self.en_US is not None: + dic['en_US'] = self.en_US + if self.zh_CN is not None: + dic['zh_CN'] = self.zh_CN + if self.ja_JP is not None: + dic['ja_JP'] = self.ja_JP + return dic class Metadata(pydantic.BaseModel): """元数据""" @@ -39,6 +49,17 @@ class Metadata(pydantic.BaseModel): icon: typing.Optional[str] = None """图标""" + def __init__(self, **kwargs): + super().__init__(**kwargs) + + if self.description is None: + self.description = I18nString( + en_US='' + ) + + if self.icon is None: + self.icon = '' + class PythonExecution(pydantic.BaseModel): """Python执行""" @@ -123,6 +144,16 @@ class Component(pydantic.BaseModel): module_path = module_path.replace('/', '.').replace('\\', '.') module = importlib.import_module(module_path) return getattr(module, self.execution.python.attr) + + def to_plain_dict(self) -> dict: + """转换为平铺字典""" + return { + 'name': self.metadata.name, + 'label': self.metadata.label.to_dict(), + 'description': self.metadata.description.to_dict(), + 'icon': self.metadata.icon, + 'spec': self.spec + } class ComponentDiscoveryEngine: diff --git a/pkg/provider/modelmgr/modelmgr.py b/pkg/provider/modelmgr/modelmgr.py index 2951d9ab..1884da4b 100644 --- a/pkg/provider/modelmgr/modelmgr.py +++ b/pkg/provider/modelmgr/modelmgr.py @@ -33,19 +33,19 @@ class RuntimeLLMModel: class ModelManager: """模型管理器""" - ap: app.Application + model_list: list[entities.LLMModelInfo] # deprecated - requester_components: list[engine.Component] + requesters: dict[str, requester.LLMAPIRequester] # deprecated - model_list: list[entities.LLMModelInfo] - - requesters: dict[str, requester.LLMAPIRequester] - - token_mgrs: dict[str, token.TokenManager] + token_mgrs: dict[str, token.TokenManager] # deprecated # ====== 4.0 ====== + ap: app.Application + llm_models: list[RuntimeLLMModel] + + requester_components: list[engine.Component] def __init__(self, ap: app.Application): self.ap = ap @@ -140,3 +140,17 @@ class ModelManager: except Exception as e: self.ap.logger.error(f"初始化模型 {model['name']} 失败: {type(e)} {e} ,请检查配置文件") + + def get_available_requesters_info(self) -> list[dict]: + """获取所有可用的请求器""" + return [ + component.to_plain_dict() + for component in self.requester_components + ] + + def get_available_requester_info_by_name(self, name: str) -> dict | None: + """通过名称获取请求器信息""" + for component in self.requester_components: + if component.metadata.name == name: + return component.to_plain_dict() + return None