@@ -52,8 +52,9 @@ class ModelModule {
5252 this . systemFetchPending = false ;
5353 this . systemPollingHandle = null ;
5454 this . systemPollingInterval = null ;
55- this . systemPollingDelayMs = 30000 ;
55+ this . systemPollingDelayMs = 5000 ;
5656 this . systemDownloadRequests = new Set ( ) ;
57+ this . systemUninstallRequests = new Set ( ) ;
5758 this . registryListeners = new Set ( ) ;
5859
5960 this . dependencies = {
@@ -123,8 +124,8 @@ class ModelModule {
123124 } ,
124125 {
125126 key : 'clip_vit_b_32' ,
126- name : 'CLIP ViT-B' ,
127- description : '支持图文向量化的 CLIP 模型,用于图片检索与比对 。' ,
127+ name : 'CLIP ViT-B 32 ' ,
128+ description : '英文优化的标准 CLIP 模型,适用于通用图文检索 。' ,
128129 tags : [ '图像嵌入' , '多模态' ] ,
129130 status : 'not_downloaded' ,
130131 progress : 0 ,
@@ -135,6 +136,20 @@ class ModelModule {
135136 endpoint : null ,
136137 updatedAt : now
137138 } ,
139+ {
140+ key : 'clip_vit_b_32_multilingual' ,
141+ name : 'CLIP ViT-B Multilingual' ,
142+ description : '支持中文等多语言查询的 CLIP 模型,提升图文检索效果。' ,
143+ tags : [ '图像嵌入' , '多模态' , '多语言' ] ,
144+ status : 'not_downloaded' ,
145+ progress : 0 ,
146+ downloadedBytes : 0 ,
147+ totalBytes : null ,
148+ message : '点击卡片开始下载模型。' ,
149+ error : null ,
150+ endpoint : null ,
151+ updatedAt : now
152+ } ,
138153 {
139154 key : 'pdf_extract_kit' ,
140155 name : 'PDF Extract Kit 套件' ,
@@ -384,6 +399,7 @@ class ModelModule {
384399 return ;
385400 }
386401 if ( model . status === 'downloaded' ) {
402+ this . confirmUninstallSystemModel ( model ) ;
387403 return ;
388404 }
389405 if ( this . systemDownloadRequests . has ( model . key ) || model . status === 'downloading' ) {
@@ -435,6 +451,72 @@ class ModelModule {
435451 }
436452 }
437453
454+ async triggerSystemModelUninstall ( key ) {
455+ if ( ! key || this . systemUninstallRequests . has ( key ) ) {
456+ return ;
457+ }
458+ this . systemUninstallRequests . add ( key ) ;
459+ this . updateSystemModelPartial ( key , {
460+ status : 'pending' ,
461+ message : '正在卸载...' ,
462+ error : null
463+ } ) ;
464+ this . renderAllModels ( ) ;
465+ this . updateSystemPollingState ( { forceFast : true } ) ;
466+
467+ try {
468+ const response = await fetch ( `${ this . baseApiUrl } /api/models/${ encodeURIComponent ( key ) } /uninstall` , {
469+ method : 'POST' ,
470+ headers : { 'Accept' : 'application/json' }
471+ } ) ;
472+ if ( ! response . ok ) {
473+ throw new Error ( `HTTP ${ response . status } ` ) ;
474+ }
475+ const data = await response . json ( ) ;
476+ this . mergeSystemModelStatus ( data ) ;
477+ if ( data && data . status === 'not_downloaded' ) {
478+ this . updateSystemModelPartial ( key , { message : '模型已卸载' } ) ;
479+ }
480+ this . renderAllModels ( ) ;
481+ this . updateSystemPollingState ( ) ;
482+ } catch ( error ) {
483+ console . error ( '卸载模型失败:' , error ) ;
484+ this . updateSystemModelPartial ( key , {
485+ status : 'failed' ,
486+ message : '卸载失败,请稍后重试。' ,
487+ error : error ?. message || '卸载失败'
488+ } ) ;
489+ this . renderAllModels ( ) ;
490+ this . updateSystemPollingState ( ) ;
491+ } finally {
492+ this . systemUninstallRequests . delete ( key ) ;
493+ this . updateSystemPollingState ( ) ;
494+ }
495+ }
496+
497+ confirmUninstallSystemModel ( model ) {
498+ const doUninstall = ( ) => {
499+ this . triggerSystemModelUninstall ( model . key ) ;
500+ } ;
501+
502+ if ( typeof window . showModal === 'function' ) {
503+ window . showModal ( {
504+ type : 'warning' ,
505+ title : '卸载系统模型' ,
506+ message : `确定要卸载 ${ model . name } 吗?这将删除本地模型数据。` ,
507+ confirmText : '卸载' ,
508+ cancelText : '取消' ,
509+ showCancel : true ,
510+ onConfirm : doUninstall
511+ } ) ;
512+ return ;
513+ }
514+
515+ if ( window . confirm ( `确定要卸载 ${ model . name } 吗?这将删除本地模型数据。` ) ) {
516+ doUninstall ( ) ;
517+ }
518+ }
519+
438520 buildSystemModelCard ( model ) {
439521 const card = document . createElement ( 'article' ) ;
440522 card . className = 'model-card system-model-card' ;
@@ -458,7 +540,8 @@ class ModelModule {
458540 const header = document . createElement ( 'div' ) ;
459541 header . className = 'system-model-card__header' ;
460542 header . appendChild ( title ) ;
461- header . appendChild ( providerLabel ) ;
543+ // 将开发商标签从标题区域移除,移动到标签列表末尾
544+ // header.appendChild(providerLabel);
462545 header . appendChild ( statusBadge ) ;
463546
464547 const description = document . createElement ( 'p' ) ;
@@ -475,19 +558,32 @@ class ModelModule {
475558 tagsWrapper . appendChild ( tagEl ) ;
476559 } ) ;
477560 }
561+ // 将开发商标签追加到描述标签之后
562+ tagsWrapper . appendChild ( providerLabel ) ;
478563
479564 card . appendChild ( header ) ;
565+
566+ const messageText = this . buildSystemModelMessage ( model ) ;
567+ let inlineMessageAttached = false ;
568+ const shouldAttachToTags =
569+ messageText && model . key === 'clip_vit_b_32_multilingual' && tagsWrapper . children . length > 0 ;
570+ if ( shouldAttachToTags ) {
571+ const inlineMessage = this . createSystemModelInlineMessage ( messageText ) ;
572+ inlineMessage . classList . add ( 'system-model-card__inline-message--after-tags' ) ;
573+ tagsWrapper . appendChild ( inlineMessage ) ;
574+ inlineMessageAttached = true ;
575+ }
576+
480577 card . appendChild ( description ) ;
481- if ( tagsWrapper . children . length > 0 ) {
482- card . appendChild ( tagsWrapper ) ;
578+
579+ if ( messageText && ! inlineMessageAttached ) {
580+ const inlineMessage = this . createSystemModelInlineMessage ( messageText ) ;
581+ inlineMessage . classList . add ( 'system-model-card__inline-message--after-description' ) ;
582+ description . appendChild ( inlineMessage ) ;
483583 }
484584
485- const messageText = this . buildSystemModelMessage ( model ) ;
486- if ( messageText ) {
487- const message = document . createElement ( 'div' ) ;
488- message . className = 'system-model-card__message' ;
489- message . textContent = messageText ;
490- card . appendChild ( message ) ;
585+ if ( tagsWrapper . children . length > 0 ) {
586+ card . appendChild ( tagsWrapper ) ;
491587 }
492588
493589 card . addEventListener ( 'click' , ( event ) => {
@@ -499,6 +595,13 @@ class ModelModule {
499595 return card ;
500596 }
501597
598+ createSystemModelInlineMessage ( text ) {
599+ const inlineMessage = document . createElement ( 'span' ) ;
600+ inlineMessage . className = 'system-model-card__inline-message' ;
601+ inlineMessage . textContent = text ;
602+ return inlineMessage ;
603+ }
604+
502605 describeSystemModelStatus ( model ) {
503606 if ( ! model ) {
504607 return '未知状态' ;
@@ -510,10 +613,13 @@ class ModelModule {
510613 const percent = Math . max ( 0 , Math . min ( 100 , Math . round ( ( model . progress || 0 ) * 100 ) ) ) ;
511614 return `下载中 ${ percent } %` ;
512615 }
616+ if ( model . status === 'pending' ) {
617+ return '卸载中' ;
618+ }
513619 if ( model . status === 'failed' ) {
514620 return '下载失败' ;
515621 }
516- return '点击下载 ' ;
622+ return '未下载 ' ;
517623 }
518624
519625 buildSystemModelMessage ( model ) {
@@ -555,6 +661,7 @@ class ModelModule {
555661 case 'bge_reranker_v2_m3' :
556662 return 'AAAI' ;
557663 case 'clip_vit_b_32' :
664+ case 'clip_vit_b_32_multilingual' :
558665 return 'SentenceTransformer' ;
559666 case 'pdf_extract_kit' :
560667 return 'opendatalab' ;
0 commit comments