From eff60ef04c821bd7ad29ba259f7b455233df8baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=AF=9B=E8=B7=83=E8=BE=89?= Date: Thu, 25 Jun 2026 11:20:56 +0800 Subject: [PATCH 01/10] =?UTF-8?q?feat:=20add=20results=20copy=E3=80=81add?= =?UTF-8?q?=20ability(Embed=E3=80=81Rerank)=E3=80=81ico?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/app/favicon.ico | Bin 67646 -> 15976 bytes .../components/pages/launch-model/index.tsx | 4 +- .../launch-dialog/launch-dialog.tsx | 1 + .../capability-config.tsx | 39 ++++++++++ .../pages/running-model-detail/index.tsx | 29 +++++-- .../panels/capability-task-panel.tsx | 61 ++++++++++++++- .../panels/form-panels.tsx | 71 +++++++++++++++++- .../panels/result-panels.tsx | 30 +------- frontend/src/i18n/locales/en.ts | 2 + frontend/src/i18n/locales/ja.ts | 2 + frontend/src/i18n/locales/ko.ts | 2 + frontend/src/i18n/locales/zh.ts | 2 + frontend/src/lib/utils.ts | 2 +- frontend/src/types/services.ts | 57 +++++++++++++- 14 files changed, 259 insertions(+), 43 deletions(-) diff --git a/frontend/src/app/favicon.ico b/frontend/src/app/favicon.ico index dcdac621286ea4d7486ed5b25230340eef580394..f7e916c14510271dc79f3fbb5028e667fd7ec99c 100644 GIT binary patch literal 15976 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 literal 67646 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 c`O4hj_iID)jn { value={ability} onChange={(value) => setAbility(value ?? '')} options={abilityOptions} - placeholder="Ability" + placeholder={t('launchModel.modelAbility')} allowClear className="w-40" /> @@ -451,7 +451,7 @@ const LaunchModel = ({ routeType, initialCustomType }: LaunchModelProps) => { value={status} onChange={(value) => setStatus(value ?? '')} options={statusOptions} - placeholder="Status" + placeholder={t('launchModel.status')} allowClear className="w-40" /> diff --git a/frontend/src/components/pages/launch-model/launch-dialog/launch-dialog.tsx b/frontend/src/components/pages/launch-model/launch-dialog/launch-dialog.tsx index 6e02846c88..8009f555fe 100644 --- a/frontend/src/components/pages/launch-model/launch-dialog/launch-dialog.tsx +++ b/frontend/src/components/pages/launch-model/launch-dialog/launch-dialog.tsx @@ -1229,6 +1229,7 @@ export default function LaunchDialog({ request .post('/v1/models', newValues, { noTimeout: true }) .then(() => { + // Prevents a false deployment success notification when /v1/models returns model_uid after download cancellation, triggering the success logic below. if (isCanceledLaunchRef.current) { return; } diff --git a/frontend/src/components/pages/running-model-detail/capability-config.tsx b/frontend/src/components/pages/running-model-detail/capability-config.tsx index c93ac2cae4..b6db7c8c27 100644 --- a/frontend/src/components/pages/running-model-detail/capability-config.tsx +++ b/frontend/src/components/pages/running-model-detail/capability-config.tsx @@ -1,9 +1,11 @@ import { AudioLines, + Binary, FileText, FileSearch, ImagePlus, ImageUp, + ListFilter, Mic, Paintbrush, ScanText, @@ -21,6 +23,8 @@ import { ImageToVideoPanel, InpaintingPanel, OcrPanel, + EmbedPanel, + RerankPanel, SpeechPanel, TextPromptPanel, TextToImagePanel, @@ -180,6 +184,41 @@ export const CAPABILITY_CONFIGS: Partial> : {}), }), }, + [ModelAbility.Embed]: { + ability: ModelAbility.Embed, + label: 'Embedding', + icon: Binary, + requestApi: '/v1/embeddings', + initialValues: { + input: '', + }, + formPanel: EmbedPanel, + resultPanel: ResultPanels.Universal, + transformValues: ({ modelUid, values }) => ({ + model: modelUid, + input: stringValue(values.input), + }), + }, + [ModelAbility.Rerank]: { + ability: ModelAbility.Rerank, + label: 'Rerank', + icon: ListFilter, + requestApi: '/v1/rerank', + initialValues: { + query: '', + documents: ['', ''], + }, + formPanel: RerankPanel, + resultPanel: ResultPanels.Universal, + transformValues: ({ modelUid, values }) => ({ + model: modelUid, + query: stringValue(values.query), + documents: Array.isArray(values.documents) + ? values.documents.map((item) => stringValue(item).trim()).filter(Boolean) + : [], + }), + }, + [ModelAbility.Ocr]: { ability: ModelAbility.Ocr, label: 'OCR', diff --git a/frontend/src/components/pages/running-model-detail/index.tsx b/frontend/src/components/pages/running-model-detail/index.tsx index fb058a7de8..c20385c5ac 100644 --- a/frontend/src/components/pages/running-model-detail/index.tsx +++ b/frontend/src/components/pages/running-model-detail/index.tsx @@ -7,7 +7,7 @@ import { useRouter } from 'next/navigation'; import { Button } from '@/components/ui/button'; import { CollapsiblePanel } from '@/components/ui/collapsible'; import PageContainer from '@/components/ui/page-container'; -import { ModelAbility } from '@/constants'; +import { ModelAbility, ModelType } from '@/constants'; import request from '@/lib/request'; import type { RunningModelDetail as RunningModelDetailType } from '@/types/services'; @@ -21,6 +21,11 @@ interface RunningModelDetailProps { modelUid: string; } +const MODEL_TYPE_ABILITY_MAP: Record = { + [ModelType.Rerank]: [ModelAbility.Rerank], + [ModelType.Embedding]: [ModelAbility.Embed], +}; + function DetailItem({ label, value }: { label: string; value?: string | number | null }) { return (

@@ -61,7 +66,7 @@ function ModelDetails({ model, modelUid }: { model: RunningModelDetailType; mode ); } const EmptyForAbility = () => ( -
+

No supported interactive capability

@@ -83,9 +88,18 @@ const RunningModelDetail: FC = ({ modelUid }) => { request .get(`/v1/models/${modelUid}`) .then((res) => { - const firstAbility = (res?.model_ability || []).filter((item) => !item.includes('_'))?.[0]; + const newModel = { + ...res, + // fix model_ability was not returned when model_type was Rerank or Embedding. + model_ability: Array.isArray(res?.model_ability) + ? res.model_ability + : MODEL_TYPE_ABILITY_MAP[res.model_type] + ? MODEL_TYPE_ABILITY_MAP[res.model_type] + : [], + }; + const firstAbility = newModel.model_ability.filter((item) => !item.includes('_'))?.[0]; setSelectAbility(firstAbility); - setModel(res); + setModel(newModel); }) .finally(() => setLoading(false)); }, [modelUid]); @@ -103,7 +117,7 @@ const RunningModelDetail: FC = ({ modelUid }) => { label: t(`launchModel.${item}`), }; }); - }, [model]); + }, [model, t]); const handleAbility = (value?: ModelAbility) => { if (!value) return; @@ -111,15 +125,16 @@ const RunningModelDetail: FC = ({ modelUid }) => { capabilityTaskPanelRef.current?.reset?.(); }; const renderCapability = () => { - if (!model || !selectAbility) return null; + if (!model) return null; if (isChat) { return ; } - if (!CAPABILITY_CONFIGS[selectAbility]) { + if (!selectAbility || !CAPABILITY_CONFIGS[selectAbility]) { return ; } + return ( (); + const showCopyResult = useMemo(() => { + return ( + config.ability === ModelAbility.Generate || + model.model_type === ModelType.Rerank || + model.model_type === ModelType.Embedding + ); + }, [config.ability, model.model_type]); + const copyResultValue = useMemo(() => { + if (result === undefined) { + return ''; + } + if (config.ability === ModelAbility.Generate) { + const text = (result as CompletionResponse)?.choices?.[0]?.text; + return typeof text === 'string' ? text : ''; + } + if (model.model_type === ModelType.Rerank) { + const results = (result as RerankResponse)?.results; + try { + return JSON.stringify(results, null, 2); + } catch { + return String(results); + } + } + + if (model.model_type === ModelType.Embedding) { + const data = (result as EmbeddingsResponse)?.data; + try { + return JSON.stringify(data, null, 2); + } catch { + return String(data); + } + } + + return ''; + }, [result, config.ability, model.model_type]); + const trackProgress = async ( requestId: string, runToken: number, @@ -89,7 +131,7 @@ const CapabilityTaskPanel = forwardRef { @@ -171,6 +213,17 @@ const CapabilityTaskPanel = forwardRef

Results

+ {showCopyResult && copyResultValue && !loading && ( + + )}
({ label: value, value }) ); @@ -144,6 +146,73 @@ export function TextPromptPanel() { ); } +export function EmbedPanel() { + return ( + +