From 3132a837a69ec50399dc63cd9a6ded7352bd69b5 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Mon, 6 Jul 2026 14:23:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20add=20llm=5Fid=5Fto=5Fproduct=5Fid=20?= =?UTF-8?q?=E2=80=94=20LLM=20model=20ID=20to=20product=20ID=20mapping?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Converts llmage.llm.id → product.id via resource_ref_id + product_type filter. --- product_management/__init__.py | 10 ++++++++++ product_management/core.py | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/product_management/__init__.py b/product_management/__init__.py index 80fda7c..ef42251 100644 --- a/product_management/__init__.py +++ b/product_management/__init__.py @@ -100,6 +100,15 @@ async def calculate_product_cost(product_id=None, product_code=None, usage_data= return await manager.calculate_product_cost(product_id, product_code, usage_data, user_org_id) +async def llm_id_to_product_id(llm_id): + """Convert LLM model ID (llmage.llm.id) to product ID (product.id). + + Uses the product.resource_ref_id → llm.id mapping established during import. + """ + manager = get_manager() + return await manager.llm_id_to_product_id(llm_id) + + def load_product_management(): """Register all functions with ServerEnv so they can be called from .ui/.dspy files.""" env = ServerEnv() @@ -118,4 +127,5 @@ def load_product_management(): env.execute_product = execute_product env.execute_product_stream = execute_product_stream env.calculate_product_cost = calculate_product_cost + env.llm_id_to_product_id = llm_id_to_product_id return True diff --git a/product_management/core.py b/product_management/core.py index acae3e3..8610ca4 100644 --- a/product_management/core.py +++ b/product_management/core.py @@ -1327,3 +1327,18 @@ class ProductManager: user_org_id = self._get_current_org_id() return await fn(ref_id, usage_data or {}, user_org_id) + + async def llm_id_to_product_id(self, llm_id): + """Convert LLM model ID (llmage.llm.id) to product ID (product.id). + + Uses resource_ref_id mapping: product.resource_ref_id = llm.id + and product.product_type = 'llm_model'. + """ + dbname = self._get_dbname() + async with DBPools().sqlorContext(dbname) as sor: + sql = """SELECT id FROM product +WHERE resource_ref_id = ${llm_id}$ AND product_type = 'llm_model' LIMIT 1""" + recs = await sor.sqlExe(sql, {'llm_id': llm_id}) + if recs: + return recs[0].id + return None