From bc4289efc80c0b03ac908bfb15b56b4f51f330da Mon Sep 17 00:00:00 2001 From: yumoqing Date: Wed, 22 Jul 2026 18:30:01 +0800 Subject: [PATCH] feat: dynamic KB cards from DSPY with real stats --- .../knowledge_bases_list/get_kb_cards.dspy | 47 +++++++++++ wwwroot/knowledge_bases_list/index.ui | 77 +------------------ 2 files changed, 51 insertions(+), 73 deletions(-) create mode 100644 wwwroot/knowledge_bases_list/get_kb_cards.dspy diff --git a/wwwroot/knowledge_bases_list/get_kb_cards.dspy b/wwwroot/knowledge_bases_list/get_kb_cards.dspy new file mode 100644 index 0000000..6d2fbeb --- /dev/null +++ b/wwwroot/knowledge_bases_list/get_kb_cards.dspy @@ -0,0 +1,47 @@ +env = request._run_ns +userorgid = await env.get_userorgid() + +async with get_sor_context(env, 'rag') as sor: + recs = await sor.R("knowledge_bases", {"org_id": userorgid}) + +cards = [] +for r in recs: + kb_id = r.id + doc_recs = await sor.R("documents", {"kb_id": kb_id}) + doc_count = len(doc_recs) + total_size = r.total_size or 0 + if total_size > 1073741824: + size_str = f"{total_size/1073741824:.1f}GB" + elif total_size > 1048576: + size_str = f"{total_size/1048576:.0f}MB" + else: + size_str = f"{total_size/1024:.0f}KB" + + engine = r.embedding_engine or "CLIP" + + card = { + "widgettype": "VBox", + "options": { + "cwidth": 16, "cheight": 12, "bgcolor": "#f0f7ff", + "padding": "16px", "css": "card clickable", + "border": "1px solid #d0e4f7" + }, + "subwidgets": [ + {"widgettype": "Text", "options": {"text": "📚 " + str(r.name), "cfontsize": 16, "fontWeight": "bold"}}, + {"widgettype": "Text", "options": {"text": str(engine) + " · 1024维", "cfontsize": 12, "color": "#888"}}, + {"widgettype": "HBox", "options": {"spacing": "12px"}, "subwidgets": [ + {"widgettype": "Text", "options": {"text": "📄 " + str(doc_count) + "文档", "cfontsize": 12, "color": "#666"}}, + {"widgettype": "Text", "options": {"text": "💾 " + size_str, "cfontsize": 12, "color": "#666"}} + ]} + ], + "binds": [{"wid": "self", "event": "click", "actiontype": "urlwidget", + "target": "app.rag_main_content", "mode": "replace", + "options": {"url": entire_url('/knowledge_bases_list/detail.ui')}}] + } + cards.append(card) + +result = { + "widgettype": "HBox", + "options": {"width": "100%", "spacing": "12px", "wrap": True}, + "subwidgets": cards +} diff --git a/wwwroot/knowledge_bases_list/index.ui b/wwwroot/knowledge_bases_list/index.ui index 262df7b..0c448b4 100644 --- a/wwwroot/knowledge_bases_list/index.ui +++ b/wwwroot/knowledge_bases_list/index.ui @@ -25,84 +25,15 @@ }, { "widgettype": "Button", - "options": { - "label": "+ 新建知识库", - "bgcolor": "#4a90d9", - "color": "#fff" - } + "options": {"label": "+ 新建知识库", "bgcolor": "#4a90d9", "color": "#fff"} } ] }, { - "widgettype": "HBox", + "widgettype": "urlwidget", "options": { - "width": "100%", - "spacing": "12px", - "wrap": true - }, - "subwidgets": [ - { - "widgettype": "VBox", - "options": { - "cwidth": 16, - "cheight": 12, - "bgcolor": "#f0f7ff", - "padding": "16px", - "css": "card clickable", - "border": "1px solid #d0e4f7" - }, - "subwidgets": [ - {"widgettype": "Text", "options": {"text": "📚 产品文档", "cfontsize": 16, "fontWeight": "bold"}}, - {"widgettype": "Text", "options": {"text": "CLIP · 1024维", "cfontsize": 12, "color": "#888"}}, - {"widgettype": "HBox", "options": {"spacing": "12px"}, "subwidgets": [ - {"widgettype": "Text", "options": {"text": "📄 12文档", "cfontsize": 12, "color": "#666"}}, - {"widgettype": "Text", "options": {"text": "📁 3目录", "cfontsize": 12, "color": "#666"}}, - {"widgettype": "Text", "options": {"text": "💾 256MB", "cfontsize": 12, "color": "#666"}} - ]} - ], - "binds": [ - {"wid": "self", "event": "click", "actiontype": "urlwidget", "target": "app.rag_main_content", "mode": "replace", "options": {"url": "{{entire_url('/knowledge_bases_list/detail.ui')}}"}} - ] - }, - { - "widgettype": "VBox", - "options": { - "cwidth": 16, - "cheight": 12, - "bgcolor": "#f8f9fa", - "padding": "16px", - "css": "card clickable", - "border": "1px solid #e0e0e0" - }, - "subwidgets": [ - {"widgettype": "Text", "options": {"text": "🎵 音频资料库", "cfontsize": 16, "fontWeight": "bold"}}, - {"widgettype": "Text", "options": {"text": "Whisper · 音频向量化", "cfontsize": 12, "color": "#888"}}, - {"widgettype": "HBox", "options": {"spacing": "12px"}, "subwidgets": [ - {"widgettype": "Text", "options": {"text": "📄 45文档", "cfontsize": 12, "color": "#666"}}, - {"widgettype": "Text", "options": {"text": "📁 5目录", "cfontsize": 12, "color": "#666"}}, - {"widgettype": "Text", "options": {"text": "💾 1.2GB", "cfontsize": 12, "color": "#666"}} - ]} - ], - "binds": [ - {"wid": "self", "event": "click", "actiontype": "urlwidget", "target": "app.rag_main_content", "mode": "replace", "options": {"url": "{{entire_url('/knowledge_bases_list/detail.ui')}}"}} - ] - }, - { - "widgettype": "VBox", - "options": { - "cwidth": 16, - "cheight": 12, - "bgcolor": "#f8f9fa", - "padding": "16px", - "css": "card clickable", - "border": "1px solid #e0e0e0" - }, - "subwidgets": [ - {"widgettype": "Text", "options": {"text": "+ 新建知识库", "cfontsize": 16, "color": "#aaa", "halign": "center"}}, - {"widgettype": "Text", "options": {"text": "点击创建", "cfontsize": 12, "color": "#ccc", "halign": "center"}} - ] - } - ] + "url": "{{entire_url('/knowledge_bases_list/get_kb_cards.dspy')}}" + } } ] }