diff --git a/pkg/api/http/controller/groups/plugins.py b/pkg/api/http/controller/groups/plugins.py index 670f13ed..28a3c44c 100644 --- a/pkg/api/http/controller/groups/plugins.py +++ b/pkg/api/http/controller/groups/plugins.py @@ -75,6 +75,20 @@ class PluginsRouterGroup(group.RouterGroup): return self.success(data={}) + @self.route( + '///icon', + methods=['GET'], + auth_type=group.AuthType.NONE, + ) + async def _(author: str, plugin_name: str) -> quart.Response: + icon_data = await self.ap.plugin_connector.get_plugin_icon(author, plugin_name) + icon_base64 = icon_data['plugin_icon_base64'] + mime_type = icon_data['mime_type'] + + icon_data = base64.b64decode(icon_base64) + + return quart.Response(icon_data, mimetype=mime_type) + @self.route('/install/github', methods=['POST'], auth_type=group.AuthType.USER_TOKEN) async def _() -> str: data = await quart.request.json diff --git a/pkg/plugin/connector.py b/pkg/plugin/connector.py index 6afc0661..da7de024 100644 --- a/pkg/plugin/connector.py +++ b/pkg/plugin/connector.py @@ -7,6 +7,8 @@ import typing import os import sys +from async_lru import alru_cache + from ..core import app from . import handler from ..utils import platform @@ -153,6 +155,10 @@ class PluginRuntimeConnector: async def set_plugin_config(self, plugin_author: str, plugin_name: str, config: dict[str, Any]) -> dict[str, Any]: return await self.handler.set_plugin_config(plugin_author, plugin_name, config) + @alru_cache(ttl=5 * 60) # 5 minutes + async def get_plugin_icon(self, plugin_author: str, plugin_name: str) -> dict[str, Any]: + return await self.handler.get_plugin_icon(plugin_author, plugin_name) + async def emit_event( self, event: events.BaseEventModel, diff --git a/pkg/plugin/handler.py b/pkg/plugin/handler.py index a677b9be..36d11d09 100644 --- a/pkg/plugin/handler.py +++ b/pkg/plugin/handler.py @@ -534,6 +534,17 @@ class RuntimeConnectionHandler(handler.Handler): return result['tools'] + async def get_plugin_icon(self, plugin_author: str, plugin_name: str) -> dict[str, Any]: + """Get plugin icon""" + result = await self.call_action( + LangBotToRuntimeAction.GET_PLUGIN_ICON, + { + 'plugin_author': plugin_author, + 'plugin_name': plugin_name, + }, + ) + return result + async def call_tool(self, tool_name: str, parameters: dict[str, Any]) -> dict[str, Any]: """Call tool""" result = await self.call_action( diff --git a/web/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx b/web/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx index a67237b5..a3e7596d 100644 --- a/web/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx +++ b/web/src/app/home/plugins/plugin-installed/plugin-card/PluginCardComponent.tsx @@ -14,6 +14,7 @@ import { ArrowUp, } from 'lucide-react'; import { getCloudServiceClientSync } from '@/app/infra/http'; +import { httpClient } from '@/app/infra/http/HttpClient'; import { PluginComponent } from '@/app/infra/entities/plugin'; import { Button } from '@/components/ui/button'; import { @@ -87,14 +88,19 @@ export default function PluginCardComponent({ onClick={onCardClick} >
- - + */} + plugin icon
diff --git a/web/src/app/infra/http/BackendClient.ts b/web/src/app/infra/http/BackendClient.ts index ef270258..10f28da2 100644 --- a/web/src/app/infra/http/BackendClient.ts +++ b/web/src/app/infra/http/BackendClient.ts @@ -438,6 +438,17 @@ export class BackendClient extends BaseHttpClient { return this.put(`/api/v1/plugins/${author}/${name}/config`, config); } + public getPluginIconURL(author: string, name: string): string { + if (this.instance.defaults.baseURL === '/') { + const url = window.location.href; + const baseURL = url.split('/').slice(0, 3).join('/'); + return `${baseURL}/api/v1/plugins/${author}/${name}/icon`; + } + return ( + this.instance.defaults.baseURL + `/api/v1/plugins/${author}/${name}/icon` + ); + } + public installPluginFromGithub( source: string, ): Promise {