diff --git a/json/llmusage.json b/json/llmusage.json index 8e409d0..3aabe13 100644 --- a/json/llmusage.json +++ b/json/llmusage.json @@ -31,7 +31,7 @@ "height": "70%" }, "options": { - "url": "{{entire_url('../llmusage_usages_display.ui')}}?id=${id}$" + "url": "{{entire_url('../llmusage_usages_display.dspy')}}?id=${id}$" } }, { @@ -45,7 +45,7 @@ "height": "70%" }, "options": { - "url": "{{entire_url('../llmusage_ioinfo_display.ui')}}?id=${id}$" + "url": "{{entire_url('../llmusage_ioinfo_display.dspy')}}?id=${id}$" } } ], diff --git a/llmage/utils.py b/llmage/utils.py index 2df9400..e2f6d3d 100644 --- a/llmage/utils.py +++ b/llmage/utils.py @@ -149,6 +149,32 @@ async def write_llmio(luid, io_dic): webpath = await fs.save(name, s, userid='llmio') return webpath +async def get_llmusage_by_id(usage_id): + """从数据库获取 llmusage 记录""" + env = ServerEnv() + async with get_sor_context(env, 'llmage') as sor: + sql = "select id, llmid, ioinfo, usages from llmusage where id = ${id}$" + recs = await sor.sqlExe(sql, {'id': usage_id}) + if recs and len(recs) > 0: + return dict(recs[0]) + return None + + +async def read_ioinfo_content(ioinfo_webpath): + """从 FileStorage 读取交互信息文件内容""" + if not ioinfo_webpath: + return None + try: + fs = FileStorage() + real_path = fs.realPath(ioinfo_webpath) + async with aiofiles.open(real_path, 'rb') as f: + bin_data = await f.read() + return json.loads(bin_data.decode('utf-8')) + except Exception as e: + debug(f'read_ioinfo_content error: {e}') + return None + + async def llm_query_orders(userorgid, page, pagerows=80): env = ServerEnv() async with get_sor_context(env, 'llmage') as sor: diff --git a/models/llmusage.json b/models/llmusage.json index 0e88fee..799931b 100644 --- a/models/llmusage.json +++ b/models/llmusage.json @@ -151,6 +151,13 @@ "userorgid", "use_time" ] + }, + { + "name": "idx_llmusage_usetime", + "idxtype": "index", + "idxfields": [ + "use_time" + ] } ], "codes": [ @@ -193,4 +200,4 @@ "cond": "parentid='accounting_status'" } ] -} +} \ No newline at end of file diff --git a/scripts/load_path.py b/scripts/load_path.py index d8aa50e..c078ff4 100644 --- a/scripts/load_path.py +++ b/scripts/load_path.py @@ -155,8 +155,8 @@ PATHS_LOGINED = [ f"/{MOD}/llmusage/delete_llmusage.dspy", f"/{MOD}/llmusage/get_llmusage.dspy", f"/{MOD}/llmusage/update_llmusage.dspy", - f"/{MOD}/llmusage_usages_display.ui", - f"/{MOD}/llmusage_ioinfo_display.ui", + f"/{MOD}/llmusage_usages_display.dspy", + f"/{MOD}/llmusage_ioinfo_display.dspy", # CRUD 子目录 — llmusage_accounting_failed/ f"/{MOD}/llmusage_accounting_failed/index.ui", diff --git a/wwwroot/llmusage_ioinfo_display.dspy b/wwwroot/llmusage_ioinfo_display.dspy new file mode 100644 index 0000000..59436c1 --- /dev/null +++ b/wwwroot/llmusage_ioinfo_display.dspy @@ -0,0 +1,48 @@ +import json +from llmage.utils import get_llmusage_by_id, read_ioinfo_content + +usage_id = params_kw.get('id') +if not usage_id: + return {"widgettype": "Message", "options": {"message": "缺少 id 参数", "type": "error"}} + +record = await get_llmusage_by_id(usage_id) +if not record: + return {"widgettype": "Message", "options": {"message": "未找到记录", "type": "error"}} + +llmid = record.get('llmid', '') +ioinfo_webpath = record.get('ioinfo', '') + +ioinfo_content = await read_ioinfo_content(ioinfo_webpath) if ioinfo_webpath else None +ioinfo_text = json.dumps(ioinfo_content, ensure_ascii=False, indent=2) if ioinfo_content else "无交互内容" + +return { + "widgettype": "VScrollPanel", + "options": { + "width": "100%", + "height": "100%" + }, + "subwidgets": [ + { + "widgettype": "VBox", + "options": { + "width": "100%", + "padding": "16px", + "spacing": 12 + }, + "subwidgets": [ + { + "widgettype": "Title4", + "options": { + "text": f"Model: {llmid}" + } + }, + { + "widgettype": "Text", + "options": { + "text": ioinfo_text + } + } + ] + } + ] +} diff --git a/wwwroot/llmusage_ioinfo_display.ui b/wwwroot/llmusage_ioinfo_display.ui deleted file mode 100644 index 25ec9b3..0000000 --- a/wwwroot/llmusage_ioinfo_display.ui +++ /dev/null @@ -1,35 +0,0 @@ -{% set sor = db.sqlorContext() %} -{% set row = sor.execute_sql('select llmid, ioinfo from llmusage where id = ${id}$').first() %} -{% set ioinfo = row.ioinfo if row and row.ioinfo else '' %} -{% set model_id = row.llmid if row else '' %} -{ - "widgettype": "VScrollPanel", - "options": { - "width": "100%", - "height": "100%" - }, - "subwidgets": [ - { - "widgettype": "VBox", - "options": { - "width": "100%", - "padding": "16px", - "spacing": 12 - }, - "subwidgets": [ - { - "widgettype": "Title4", - "options": { - "text": "Model: {{ model_id }}" - } - }, - { - "widgettype": "Text", - "options": { - "text": {{ ioinfo | tojson }} - } - } - ] - } - ] -} diff --git a/wwwroot/llmusage_usages_display.dspy b/wwwroot/llmusage_usages_display.dspy new file mode 100644 index 0000000..aaafb04 --- /dev/null +++ b/wwwroot/llmusage_usages_display.dspy @@ -0,0 +1,52 @@ +import json +from llmage.utils import get_llmusage_by_id + +usage_id = params_kw.get('id') +if not usage_id: + return {"widgettype": "Message", "options": {"message": "缺少 id 参数", "type": "error"}} + +record = await get_llmusage_by_id(usage_id) +if not record: + return {"widgettype": "Message", "options": {"message": "未找到记录", "type": "error"}} + +llmid = record.get('llmid', '') +usages_raw = record.get('usages', '') + +try: + usages_obj = json.loads(usages_raw) if isinstance(usages_raw, str) else usages_raw +except (json.JSONDecodeError, TypeError): + usages_obj = usages_raw + +usages_text = json.dumps(usages_obj, ensure_ascii=False, indent=2) if usages_obj else "无使用信息" + +return { + "widgettype": "VScrollPanel", + "options": { + "width": "100%", + "height": "100%" + }, + "subwidgets": [ + { + "widgettype": "VBox", + "options": { + "width": "100%", + "padding": "16px", + "spacing": 12 + }, + "subwidgets": [ + { + "widgettype": "Title4", + "options": { + "text": f"Model: {llmid}" + } + }, + { + "widgettype": "Text", + "options": { + "text": usages_text + } + } + ] + } + ] +} diff --git a/wwwroot/llmusage_usages_display.ui b/wwwroot/llmusage_usages_display.ui deleted file mode 100644 index ee7a112..0000000 --- a/wwwroot/llmusage_usages_display.ui +++ /dev/null @@ -1,35 +0,0 @@ -{% set sor = db.sqlorContext() %} -{% set row = sor.execute_sql('select llmid, usages from llmusage where id = ${id}$').first() %} -{% set usages = row.usages if row and row.usages else '' %} -{% set model_id = row.llmid if row else '' %} -{ - "widgettype": "VScrollPanel", - "options": { - "width": "100%", - "height": "100%" - }, - "subwidgets": [ - { - "widgettype": "VBox", - "options": { - "width": "100%", - "padding": "16px", - "spacing": 12 - }, - "subwidgets": [ - { - "widgettype": "Title4", - "options": { - "text": "Model: {{ model_id }}" - } - }, - { - "widgettype": "Text", - "options": { - "text": {{ usages | tojson }} - } - } - ] - } - ] -}