jiayongqiang пре 3 недеља
родитељ
комит
f1f2fdb4b7

BIN
agent/agent-0.1.0-py3-none-any.whl


+ 0 - 24
agent/build.md

@@ -1,24 +0,0 @@
-# 1. 锁定并安装(确保 pdm.lock 最新)
-pdm install --prod
-
-# 2. 导出 requirements.txt
-pdm export -o requirements.txt --prod
-
-# 3. 下载所有 wheel
-rm -rf release
-mkdir -p release
-pip download -r requirements.txt -d release/ --prefer-binary
-
-# 4. 导出pdm wheel
-pip download pdm -d ./release
-
-# 5. 打包
-rm release.tar.gz
-tar -czvf release.tar.gz release/
-
-# 6. 在目标机上安装pdm
-pip install --no-index --find-links ./release pdm
-
-# 7. 修改 PDM 配置,设置 find-links
-pdm config pypi.url file://$(pwd)/release
-pdm install

+ 9 - 3
agent/config.ini

@@ -4,20 +4,26 @@ port = 4321
 user = root
 user = root
 password = admin
 password = admin
 database = ai_tagging
 database = ai_tagging
+schema=ai_tagging
 
 
 [llm]
 [llm]
-model = Qwen3-4B-Instruct
+model = qwen3-32b
 temperature = 0.2
 temperature = 0.2
-base_url = http://10.192.72.12:8003/v1
+base_url = http://172.16.40.16:20001/compatible-mode/v1
 api_key = 
 api_key = 
 
 
 [embedding]
 [embedding]
 model = Qwen3-Embedding-8B
 model = Qwen3-Embedding-8B
 base_url = http://10.192.72.11:18081/v1/embeddings
 base_url = http://10.192.72.11:18081/v1/embeddings
+api_key =
 
 
 [es]
 [es]
 url = http://10.192.72.13:9200
 url = http://10.192.72.13:9200
 vecotr_dims = 4096
 vecotr_dims = 4096
 
 
 [app]
 [app]
-top_k = 2
+top_k = 2
+port=9876
+
+[logging]
+log_path= logs/aitagging-app.log

+ 16 - 0
agent/export.md

@@ -0,0 +1,16 @@
+# 1. 锁定并安装(确保 pdm.lock 最新)
+pdm install --prod
+
+# 2. 导出 requirements.txt
+pdm export -o requirements.txt --prod
+
+# 3. 下载所有 wheel
+rm -rf dependices
+mkdir -p dependices
+pip download -r requirements.txt -d dependices/ --prefer-binary
+
+# 5. 打包
+rm dependices.tar.gz
+tar -czvf dependices.tar.gz dependices/
+
+

+ 12 - 0
agent/install.md

@@ -0,0 +1,12 @@
+# 1. 离线机器执行,安装依赖包
+pip3 install  --no-index   --find-links=file:///home/agent/dependices   ./dependices/*.whl
+
+# 2. 安装程序包,/home/agent/目录下放agent-xxx.whl
+pip3 install --no-index   --find-links=file:///home/agent/dist   agent
+
+# 3. 设置配置文件
+vim ~/.bashrc
+export TAGGING_AGENT_CONFIG=/home/app/fjnx/agent/config.ini
+
+# 4. 启动
+nohup tagging-agent-server & 

BIN
agent/logs/aitagging-app.2026-03-10_10-12-47_456980.log.zip


BIN
agent/logs/aitagging-app.2026-03-11_17-19-07_238711.log.zip


+ 28 - 26
agent/pdm.lock

@@ -5,7 +5,7 @@
 groups = ["default"]
 groups = ["default"]
 strategy = ["inherit_metadata"]
 strategy = ["inherit_metadata"]
 lock_version = "4.5.0"
 lock_version = "4.5.0"
-content_hash = "sha256:6a1a545a1c99640c343310f0f13ce6066b537cd47b5ed4701c17c2b07a3be751"
+content_hash = "sha256:18528969456576163740af5ea9d8d07f14204187b864c4a5918cb728c31716b5"
 
 
 [[metadata.targets]]
 [[metadata.targets]]
 requires_python = "==3.10.*"
 requires_python = "==3.10.*"
@@ -182,6 +182,18 @@ files = [
 ]
 ]
 
 
 [[package]]
 [[package]]
+name = "et-xmlfile"
+version = "2.0.0"
+requires_python = ">=3.8"
+summary = "An implementation of lxml.xmlfile for the standard library"
+groups = ["default"]
+marker = "python_version == \"3.10\""
+files = [
+    {file = "et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa"},
+    {file = "et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54"},
+]
+
+[[package]]
 name = "exceptiongroup"
 name = "exceptiongroup"
 version = "1.3.1"
 version = "1.3.1"
 requires_python = ">=3.7"
 requires_python = ">=3.7"
@@ -487,31 +499,6 @@ files = [
 ]
 ]
 
 
 [[package]]
 [[package]]
-name = "numpy"
-version = "2.2.6"
-requires_python = ">=3.10"
-summary = "Fundamental package for array computing in Python"
-groups = ["default"]
-marker = "python_version == \"3.10\""
-files = [
-    {file = "numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb"},
-    {file = "numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90"},
-    {file = "numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163"},
-    {file = "numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf"},
-    {file = "numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83"},
-    {file = "numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915"},
-    {file = "numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680"},
-    {file = "numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289"},
-    {file = "numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d"},
-    {file = "numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3"},
-    {file = "numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d"},
-    {file = "numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db"},
-    {file = "numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543"},
-    {file = "numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00"},
-    {file = "numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd"},
-]
-
-[[package]]
 name = "openai"
 name = "openai"
 version = "2.17.0"
 version = "2.17.0"
 requires_python = ">=3.9"
 requires_python = ">=3.9"
@@ -534,6 +521,21 @@ files = [
 ]
 ]
 
 
 [[package]]
 [[package]]
+name = "openpyxl"
+version = "3.1.5"
+requires_python = ">=3.8"
+summary = "A Python library to read/write Excel 2010 xlsx/xlsm files"
+groups = ["default"]
+marker = "python_version == \"3.10\""
+dependencies = [
+    "et-xmlfile",
+]
+files = [
+    {file = "openpyxl-3.1.5-py2.py3-none-any.whl", hash = "sha256:5282c12b107bffeef825f4617dc029afaf41d0ea60823bbb665ef3079dc79de2"},
+    {file = "openpyxl-3.1.5.tar.gz", hash = "sha256:cf0e3cf56142039133628b5acffe8ef0c12bc902d2aadd3e0fe5878dc08d1050"},
+]
+
+[[package]]
 name = "orjson"
 name = "orjson"
 version = "3.11.7"
 version = "3.11.7"
 requires_python = ">=3.10"
 requires_python = ">=3.10"

+ 6 - 3
agent/pyproject.toml

@@ -1,6 +1,6 @@
 [project]
 [project]
 name = "agent"
 name = "agent"
-version = "0.1.0"
+version = "0.1.1"
 description = "Default template for PDM package"
 description = "Default template for PDM package"
 authors = [
 authors = [
     {name = "jiayongqiang", email = "15936285643@163.com"},
     {name = "jiayongqiang", email = "15936285643@163.com"},
@@ -12,10 +12,10 @@ dependencies = [
     "langchain>=1.2.9",
     "langchain>=1.2.9",
     "langchain-openai>=1.1.7",
     "langchain-openai>=1.1.7",
     "elasticsearch==8.9.0",
     "elasticsearch==8.9.0",
-    "numpy>=2.2.6",
     "asyncer>=0.0.17",
     "asyncer>=0.0.17",
     "psycopg2-binary>=2.9.11",
     "psycopg2-binary>=2.9.11",
     "loguru>=0.7.3",
     "loguru>=0.7.3",
+    "openpyxl>=3.1.5",
 ]
 ]
 requires-python = ">=3.10"
 requires-python = ">=3.10"
 readme = "README.md"
 readme = "README.md"
@@ -25,8 +25,11 @@ license = {text = "MIT"}
 build.package-dir = "src"
 build.package-dir = "src"
 distribution = true
 distribution = true
 
 
+[project.scripts]
+tagging-agent-server = "agent.main:main"   # 格式:模块:函数
+
 [tool.pdm.scripts]
 [tool.pdm.scripts]
-start = "uvicorn agent.main:app --host 0.0.0.0 --port 9876"
+start = "python -m agent.main"
 start-bg = { shell = "nohup pdm run start > uvicorn.log 2>&1 & echo 'Started in background'; echo \"Logs in uvicorn.log\"" }
 start-bg = { shell = "nohup pdm run start > uvicorn.log 2>&1 & echo 'Started in background'; echo \"Logs in uvicorn.log\"" }
 
 
 [build-system]
 [build-system]

+ 6 - 0
agent/readme.md

@@ -14,6 +14,12 @@
 - Content-Type: application/json
 - Content-Type: application/json
 - Body:{"tag_ids": ["2","3"]}
 - Body:{"tag_ids": ["2","3"]}
 
 
+## 1.3 按体系同步标签
+- URL:/api/aitag/admin/v1/synchronize_category
+- METHOD: post
+- Content-Type: application/json
+- BODY:{"category_id": xx}
+
 ### 1.3 生成正则表达式接口
 ### 1.3 生成正则表达式接口
 - URL: /api/aitag/admin/v1/generate_reg
 - URL: /api/aitag/admin/v1/generate_reg
 - METHOD:POST
 - METHOD:POST

+ 3 - 3
agent/src/agent/agent.py

@@ -1,10 +1,10 @@
 from langchain.chat_models import init_chat_model
 from langchain.chat_models import init_chat_model
-import configparser
 from langchain.agents import create_agent
 from langchain.agents import create_agent
 from pydantic import BaseModel,Field
 from pydantic import BaseModel,Field
 
 
-config = configparser.ConfigParser()
-config.read('config.ini')
+from agent.core.config import get_config_path
+config = get_config_path()
+TOP_K = config['app']['top_k']
 
 
 base_url = config['llm']['base_url']
 base_url = config['llm']['base_url']
 api_key_env_var = config['llm']['api_key']
 api_key_env_var = config['llm']['api_key']

+ 53 - 7
agent/src/agent/api_inner.py

@@ -3,18 +3,17 @@ from langchain.chat_models import init_chat_model
 from pydantic import BaseModel, Field
 from pydantic import BaseModel, Field
 from agent.core import es, dao
 from agent.core import es, dao
 from agent.core.vector import get_embeddings
 from agent.core.vector import get_embeddings
-import configparser
 from fastapi import BackgroundTasks
 from fastapi import BackgroundTasks
 import agent.agent as agent
 import agent.agent as agent
 from fastapi import BackgroundTasks
 from fastapi import BackgroundTasks
 from agent.logger import logger
 from agent.logger import logger
-
+from agent.core.config import get_config_path
+from typing import Optional
+config = get_config_path()
+TOP_K = config['app']['top_k']
 
 
 router = APIRouter(prefix="/v1", tags=["平台内部接口"])
 router = APIRouter(prefix="/v1", tags=["平台内部接口"])
 
 
-config = configparser.ConfigParser()
-config.read('config.ini')
-
 base_url = config['llm']['base_url']
 base_url = config['llm']['base_url']
 api_key_env_var = config['llm']['api_key']
 api_key_env_var = config['llm']['api_key']
 temperature = config['llm']['temperature']
 temperature = config['llm']['temperature']
@@ -30,7 +29,8 @@ llm = init_chat_model(
 )
 )
 
 
 class SynchronizeTagRequest(BaseModel):
 class SynchronizeTagRequest(BaseModel):
-    tag_ids: list[str] = Field(..., description="需要同步的标签编码列表")
+    tag_ids: Optional[list[str]] = Field(None, description="需要同步的标签编码列表")
+    category_id: Optional[str] = Field(None, description="标签分类ID")
 
 
 def load_tag_2_es(tag_ids: list[str]):
 def load_tag_2_es(tag_ids: list[str]):
     if not tag_ids:
     if not tag_ids:
@@ -50,7 +50,7 @@ def load_tag_2_es(tag_ids: list[str]):
                     ttc.category_code,
                     ttc.category_code,
                     tti.tag_prompt,
                     tti.tag_prompt,
                     tti.category_id
                     tti.category_id
-                    from ai_tagging.aitag_tag_info tti left join ai_tagging.aitag_tag_category  ttc 
+                    from aitag_tag_info tti left join aitag_tag_category  ttc 
                     on tti.category_id = ttc.id 
                     on tti.category_id = ttc.id 
                     where ttc.is_delete=0 and tti.is_delete=0 and ttc.state =  0 and tti.state = 0 and tti.tag_level = ttc.visibility_level
                     where ttc.is_delete=0 and tti.is_delete=0 and ttc.state =  0 and tti.state = 0 and tti.tag_level = ttc.visibility_level
                     and tti.id in ({placeholders})"""    
                     and tti.id in ({placeholders})"""    
@@ -69,6 +69,41 @@ def load_tag_2_es(tag_ids: list[str]):
     } for label in labels])
     } for label in labels])
     return labels
     return labels
 
 
+def load_category_2_es(category_id: str):
+    if not category_id:
+        return None
+    sql = f"""select 
+                    tti.id,
+                    tti.tag_nm,
+                    tti.tag_code,
+                    tti.tag_remark,
+                    tti.reg,
+                    tti.tag_level,
+                    tti.tag_path,
+                    ttc.category_nm,
+                    ttc.category_code,
+                    tti.tag_prompt,
+                    tti.category_id
+                    from aitag_tag_info tti left join aitag_tag_category  ttc 
+                    on tti.category_id = ttc.id 
+                    where ttc.is_delete=0 and tti.is_delete=0 and ttc.state =  0 and tti.state = 0 and tti.tag_level = ttc.visibility_level
+                    and tti.category_id = %s"""    
+    labels = dao.query(sql, (category_id,))
+    res = es.bulk_upsert([{
+        "id": label[0],
+        "tag_code": label[2],
+        "tag_name": label[1],
+        "tag_path": label[6],
+        "tag_level": label[5],
+        "tag_remark": label[3],
+        "tag_reg": label[4],
+        "tag_prompt": label[9],
+        "category_id":label[10],
+        "tag_vector": get_embeddings([(label[6] or '')+(label[4] or '')])[0] 
+    } for label in labels])
+    return labels
+
+
 @router.post("/synchronize_tag")
 @router.post("/synchronize_tag")
 def synchronize_tag(request: SynchronizeTagRequest):
 def synchronize_tag(request: SynchronizeTagRequest):
     logger.info(f"Received request to synchronize tags: {request.tag_ids}")
     logger.info(f"Received request to synchronize tags: {request.tag_ids}")
@@ -78,6 +113,7 @@ def synchronize_tag(request: SynchronizeTagRequest):
         "message": "synchronize_tag successful"
         "message": "synchronize_tag successful"
     }
     }
 
 
+
 @router.post("/delete_tag")
 @router.post("/delete_tag")
 def delete_tag(request: SynchronizeTagRequest):
 def delete_tag(request: SynchronizeTagRequest):
     logger.info(f"Received request to delete tags: {request.tag_ids}")
     logger.info(f"Received request to delete tags: {request.tag_ids}")
@@ -88,6 +124,16 @@ def delete_tag(request: SynchronizeTagRequest):
         "message": "delete_tag successful"
         "message": "delete_tag successful"
     }   
     }   
 
 
+@router.post("/synchronize_category")
+def synchronize_category(request: SynchronizeTagRequest):
+    logger.info(f"Received request to synchronize category: {request.category_id}")
+    es.delete_category_documents(request.category_id)
+    load_category_2_es(request.category_id)
+    return {
+        "code": 200,
+        "message": "synchronize_category successful"
+    }
+
 class GenerateRegRequest(BaseModel):
 class GenerateRegRequest(BaseModel):
     tag_name: str = Field(..., description="标签名称")
     tag_name: str = Field(..., description="标签名称")
     tag_remark: str = Field(..., description="标签定义")
     tag_remark: str = Field(..., description="标签定义")

+ 12 - 11
agent/src/agent/api_outter.py

@@ -1,4 +1,3 @@
-import configparser
 import re
 import re
 from fastapi import APIRouter , UploadFile 
 from fastapi import APIRouter , UploadFile 
 from pydantic import BaseModel,Field
 from pydantic import BaseModel,Field
@@ -15,12 +14,12 @@ from fastapi import BackgroundTasks
 from typing import Optional
 from typing import Optional
 import json
 import json
 from agent.logger import logger
 from agent.logger import logger
+from agent.core.config import get_config_path
+config = get_config_path()
+TOP_K = config['app']['top_k']
 
 
 router = APIRouter(prefix="/v1", tags=["AI Tagging"])
 router = APIRouter(prefix="/v1", tags=["AI Tagging"])
 
 
-config = configparser.ConfigParser()
-config.read('config.ini')
-TOP_K = config['app']['top_k']
 
 
 
 
 class TaggingRequest(BaseModel):
 class TaggingRequest(BaseModel):
@@ -35,7 +34,7 @@ async def execute_reg(log_id:str,tag_category_id:str,phrase: str)-> list:
     sql = f"""select 
     sql = f"""select 
                     tti.id,
                     tti.id,
                     tti.reg
                     tti.reg
-                    from ai_tagging.aitag_tag_info tti left join ai_tagging.aitag_tag_category  ttc 
+                    from aitag_tag_info tti left join aitag_tag_category  ttc 
                     on tti.category_id = ttc.id 
                     on tti.category_id = ttc.id 
                     where ttc.is_delete=0 and tti.is_delete=0 and ttc.state =  0 and tti.state = 0 and tti.tag_level = ttc.visibility_level
                     where ttc.is_delete=0 and tti.is_delete=0 and ttc.state =  0 and tti.state = 0 and tti.tag_level = ttc.visibility_level
                     """    
                     """    
@@ -49,7 +48,9 @@ async def execute_reg(log_id:str,tag_category_id:str,phrase: str)-> list:
             reg = label[1]
             reg = label[1]
             if reg is not None:
             if reg is not None:
                 pattern = re.compile(reg, re.VERBOSE)
                 pattern = re.compile(reg, re.VERBOSE)
+                logger.info(f"Executing regex for label_id {label[0]}: {reg}")
                 if pattern.match(phrase):
                 if pattern.match(phrase):
+                    logger.info(f"Executing regex for label_id {label[0]}: {reg} true")
                     result.append(label[0])
                     result.append(label[0])
             else:
             else:
                 result.append(label[0])
                 result.append(label[0])
@@ -57,7 +58,7 @@ async def execute_reg(log_id:str,tag_category_id:str,phrase: str)-> list:
         logger.error(f"Regex execution failed: {e}")
         logger.error(f"Regex execution failed: {e}")
     logger.info(f"Regex filtering candidates: {result}")
     logger.info(f"Regex filtering candidates: {result}")
     dao.execute(
     dao.execute(
-            """UPDATE ai_tagging.aitag_tag_log SET reg_result = %s WHERE id = %s""",
+            """UPDATE aitag_tag_log SET reg_result = %s WHERE id = %s""",
             (str(result), log_id)
             (str(result), log_id)
         )
         )
     logger.info(f"Updated reg_result for log_id {id}")
     logger.info(f"Updated reg_result for log_id {id}")
@@ -74,20 +75,20 @@ def init_tag_log(request: TaggingRequest):
     id = uuid.uuid4().hex
     id = uuid.uuid4().hex
     # 保证business_attr的唯一性,如果已经存在相同business_attr且状态为0(处理中)的记录,则将is_delete设为1(已删除),然后插入新记录
     # 保证business_attr的唯一性,如果已经存在相同business_attr且状态为0(处理中)的记录,则将is_delete设为1(已删除),然后插入新记录
     dao.execute(
     dao.execute(
-        """UPDATE ai_tagging.aitag_tag_log SET is_delete = 1 WHERE business_attr = %s""",
+        """UPDATE aitag_tag_log SET is_delete = 1 WHERE business_attr = %s""",
         (request.business_attr,)
         (request.business_attr,)
     )
     )
     # 业务编号如果以test开头,则tag_scope = 1,否则都是0
     # 业务编号如果以test开头,则tag_scope = 1,否则都是0
     tag_scope = 1 if request.business_attr.startswith("test") else 0
     tag_scope = 1 if request.business_attr.startswith("test") else 0
     dao.execute(
     dao.execute(
-        """INSERT INTO ai_tagging.aitag_tag_log (id,app_id, insert_time, business_attr, phrase, state, tag_scope) VALUES (%s, %s, %s, %s, %s, %s, %s)""",
+        """INSERT INTO aitag_tag_log (id,app_id, insert_time, business_attr, phrase, state, tag_scope) VALUES (%s, %s, %s, %s, %s, %s, %s)""",
         (id,request.app_id, datetime.now(), request.business_attr, request.phrase, 0, tag_scope)
         (id,request.app_id, datetime.now(), request.business_attr, request.phrase, 0, tag_scope)
     )
     )
     return id
     return id
 
 
 def update_tag_log(id:str, result:str):
 def update_tag_log(id:str, result:str):
     dao.execute(
     dao.execute(
-            """UPDATE ai_tagging.aitag_tag_log SET state = %s, result = %s WHERE id = %s""",
+            """UPDATE aitag_tag_log SET state = %s, result = %s WHERE id = %s""",
             (1, result, id)
             (1, result, id)
         )
         )
 
 
@@ -138,7 +139,7 @@ async def ai_tagging(request: TaggingRequest,background_tasks: BackgroundTasks):
 def query(business_attr: str):
 def query(business_attr: str):
     logger.info(f"Querying tag log for business_attr: {business_attr}")
     logger.info(f"Querying tag log for business_attr: {business_attr}")
     # 查询指定business_attr对应的标签信息
     # 查询指定business_attr对应的标签信息
-    sql = """SELECT * FROM ai_tagging.aitag_tag_log WHERE business_attr = %s and is_delete = 0"""
+    sql = """SELECT * FROM aitag_tag_log WHERE business_attr = %s and is_delete = 0"""
     result = dao.query_dict(sql, (business_attr,))
     result = dao.query_dict(sql, (business_attr,))
     logger.info(f"Query result: {result}")
     logger.info(f"Query result: {result}")
     return {"code": 200, "message": "AI Query Endpoint", "data": result[0] if result else None}
     return {"code": 200, "message": "AI Query Endpoint", "data": result[0] if result else None}
@@ -158,7 +159,7 @@ def ai_feedback(feedback_request: FeedbackRequest):
     logger.info(f"Received feedback request: {feedback_request}")
     logger.info(f"Received feedback request: {feedback_request}")
     # 这里将用户的反馈信息保存到数据库中aitag_tag_log,供后续分析和模型优化使用
     # 这里将用户的反馈信息保存到数据库中aitag_tag_log,供后续分析和模型优化使用
     dao.execute(
     dao.execute(
-        """update ai_tagging.aitag_tag_log set feedback = %s, feedback_result = %s, feedback_time = %s, feedback_user_id = %s, feedback_user_nm = %s, contract_no = %s, feedback_user_org = %s, feedback_user_endpoint = %s, state = %s where business_attr = %s""",   
+        """update aitag_tag_log set feedback = %s, feedback_result = %s, feedback_time = %s, feedback_user_id = %s, feedback_user_nm = %s, contract_no = %s, feedback_user_org = %s, feedback_user_endpoint = %s, state = %s where business_attr = %s""",   
         (feedback_request.feedback, feedback_request.feedback_result, datetime.now(), feedback_request.user_id, feedback_request.user_nm, feedback_request.contract_no, feedback_request.user_org, feedback_request.user_endpoint, 2, feedback_request.business_attr)
         (feedback_request.feedback, feedback_request.feedback_result, datetime.now(), feedback_request.user_id, feedback_request.user_nm, feedback_request.contract_no, feedback_request.user_org, feedback_request.user_endpoint, 2, feedback_request.business_attr)
     )
     )
     return {"code": 200, "message": "Feedback received successfully"}
     return {"code": 200, "message": "Feedback received successfully"}

+ 15 - 0
agent/src/agent/core/config.py

@@ -0,0 +1,15 @@
+import os
+import configparser
+
+from uvicorn import config
+
+def get_config_path():
+    config = configparser.ConfigParser()
+    # 1. 优先读取环境变量指定的配置路径
+    config_path = os.getenv("TAGGING_AGENT_CONFIG")  
+    if config_path and os.path.exists(config_path):
+        config.read(config_path)
+    else:
+        config.read("config.ini")
+        
+    return config

+ 7 - 4
agent/src/agent/core/dao.py

@@ -1,16 +1,18 @@
 import psycopg2
 import psycopg2
 from psycopg2 import pool
 from psycopg2 import pool
-import configparser
+
 from contextlib import contextmanager
 from contextlib import contextmanager
 
 
-config = configparser.ConfigParser()
-config.read('config.ini')
+from agent.core.config import get_config_path
+config = get_config_path()
+TOP_K = config['app']['top_k']
 
 
 host = config['database']['host']
 host = config['database']['host']
 port = int(config['database']['port'])
 port = int(config['database']['port'])
 user = config['database']['user']
 user = config['database']['user']
 password = config['database']['password']
 password = config['database']['password']
 database = config['database']['database']
 database = config['database']['database']
+schema = config['database']['schema']
 
 
 pool = psycopg2.pool.SimpleConnectionPool(
 pool = psycopg2.pool.SimpleConnectionPool(
     20, 50,
     20, 50,
@@ -18,7 +20,8 @@ pool = psycopg2.pool.SimpleConnectionPool(
     port=port,
     port=port,
     database=database,
     database=database,
     user=user,
     user=user,
-    password=password
+    password=password,
+    options=f'-c search_path={schema}'
 )
 )
 
 
 @contextmanager
 @contextmanager

+ 16 - 5
agent/src/agent/core/es.py

@@ -1,11 +1,9 @@
 from elasticsearch import Elasticsearch,helpers
 from elasticsearch import Elasticsearch,helpers
-import configparser
 import logging
 import logging
 
 
-from numpy.ma import count
-
-config = configparser.ConfigParser()
-config.read('config.ini')
+from agent.core.config import get_config_path
+config = get_config_path()
+TOP_K = config['app']['top_k']
 
 
 url = config['es']['url']
 url = config['es']['url']
 DIMS = int(config['es']['vecotr_dims'])
 DIMS = int(config['es']['vecotr_dims'])
@@ -50,6 +48,16 @@ def delete_document(doc_id):
         index=INDEX_NAME,
         index=INDEX_NAME,
         id=doc_id
         id=doc_id
     )
     )
+
+def delete_category_documents(category_id):
+    query = {
+        "query": {
+            "term": {
+                "category_id": category_id
+            }
+        }
+    }
+    es.options(request_timeout=60).delete_by_query(index=INDEX_NAME, body=query)
     
     
 def search_documents(query):
 def search_documents(query):
     response = es.search(
     response = es.search(
@@ -105,5 +113,8 @@ def hybrid_search( target_doc_ids, query_vector, top_k=2):
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":
     results = search_all()
     results = search_all()
+    for r in results:
+        # 排除 tag_vector 字段的输出
+        print({k: v for k, v in r["_source"].items() if k != "tag_vector"})
     print(f"Search results: {len(results)}")
     print(f"Search results: {len(results)}")
     
     

+ 5 - 4
agent/src/agent/core/vector.py

@@ -1,17 +1,18 @@
 import requests
 import requests
 import json
 import json
-import configparser
 
 
-config = configparser.ConfigParser()
-config.read('config.ini')
+from agent.core.config import get_config_path
+config = get_config_path()
+TOP_K = config['app']['top_k']
 
 
 model = config['embedding']['model']
 model = config['embedding']['model']
 base_url = config['embedding']['base_url']
 base_url = config['embedding']['base_url']
+api_key = config['embedding']['api_key']
 
 
 def get_embeddings(texts):
 def get_embeddings(texts):
     url = base_url
     url = base_url
     headers = {
     headers = {
-        "Authorization": "1",
+        "Authorization": api_key,
         "Content-Type": "application/json"
         "Content-Type": "application/json"
     }
     }
     data = {
     data = {

+ 4 - 1
agent/src/agent/logger.py

@@ -1,5 +1,8 @@
 from loguru import logger
 from loguru import logger
 import sys
 import sys
+from agent.core.config import get_config_path
+config = get_config_path()
+log_path = config['logging']['log_path']
 
 
 logger.remove()
 logger.remove()
 
 
@@ -11,7 +14,7 @@ logger.add(
 
 
 
 
 logger.add(
 logger.add(
-    "logs/ai-tagging.log",
+    log_path,
     rotation="00:00",        # 每天午夜轮转
     rotation="00:00",        # 每天午夜轮转
     retention="30 days",      # 保留 7 天
     retention="30 days",      # 保留 7 天
     compression="zip",       # 轮转后压缩(可选)
     compression="zip",       # 轮转后压缩(可选)

+ 14 - 1
agent/src/agent/main.py

@@ -2,16 +2,29 @@ from fastapi import FastAPI,APIRouter
 from agent.api_outter import router as outter_router
 from agent.api_outter import router as outter_router
 from agent.api_inner import router as inner_router  
 from agent.api_inner import router as inner_router  
 from agent.logger import logger
 from agent.logger import logger
-
+import uvicorn
+print('hello')
 logger.info("ai-tagging starting!")
 logger.info("ai-tagging starting!")
 
 
 api_router = APIRouter()
 api_router = APIRouter()
 api_router.include_router(inner_router,prefix="/admin")
 api_router.include_router(inner_router,prefix="/admin")
 api_router.include_router(outter_router,prefix="")
 api_router.include_router(outter_router,prefix="")
 
 
+from agent.core.config import get_config_path
+config = get_config_path()
+# 如果没有配置port,默认使用9876
+port = int(config['app'].get('port', 9876))
+
 app = FastAPI(
 app = FastAPI(
     title="AI-TAGGING",
     title="AI-TAGGING",
     description="智能打标系统", 
     description="智能打标系统", 
     version="0.1.0"
     version="0.1.0"
 )
 )
 app.include_router(api_router, prefix="/api/aitag")
 app.include_router(api_router, prefix="/api/aitag")
+print('API routes initialized')
+def main():
+    print("Starting AI Tagging Service...")
+    uvicorn.run(app, host="0.0.0.0", port=port)
+
+if __name__ == "__main__":
+    main()

+ 15 - 0
agent/tests/test_embedding.py

@@ -0,0 +1,15 @@
+import requests
+import json
+url = "http://10.192.72.11:18081/v1/embeddings"
+headers = {
+    "Authorization": "1",
+    "Content-Type": "application/json"
+}
+data = {
+    "input": ["Hello, world!"],
+    "model": "Qwen3-Embedding-8B"
+}
+response = requests.post(url, headers=headers, data=json.dumps(data))
+# embeddings = response.json()['data']
+# print([e['embedding'] for e in embeddings])
+print(response.text)

+ 1 - 1
agent/tests/test_generate_reg.py

@@ -8,5 +8,5 @@ res = requests.post("http://10.192.72.13:9876/api/aitag/admin/v1/generate_reg",
 #     "tag_name": "智能电网",
 #     "tag_name": "智能电网",
 #     "tag_remark": "指以智能电网技术为核心,建设或改造电力系统,提升电力系统智能化水平和运行效率的项目。"
 #     "tag_remark": "指以智能电网技术为核心,建设或改造电力系统,提升电力系统智能化水平和运行效率的项目。"
 # })
 # })
-print(res.json())
+print(res.text)
 
 

+ 8 - 4
agent/tests/test_inner_api.py

@@ -90,9 +90,13 @@ res = requests.post("http://localhost:9876/api/aitag/admin/v1/synchronize_tag",
 })
 })
 print(res.text)
 print(res.text)
 
 
-# res = requests.post("http://localhost:9876/api/aitag/admin/v1/delete_tag", json={
-#     "tag_ids": ["20260200083"]
-# })
+res = requests.post("http://localhost:9876/api/aitag/admin/v1/delete_tag", json={
+    "tag_ids": ["20260200083"]
+})
+print(res.text)
 
 
-# print(res.text)
+res = requests.post("http://10.192.72.13:9876/api/aitag/admin/v1/synchronize_category", json={
+    "category_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
+})
+print(res.text)
 
 

+ 2 - 2
agent/tests/test_reg.py

@@ -1,14 +1,14 @@
 import re
 import re
 
 
 regstr = """
 regstr = """
-^(?!.*(服装|纺织|食品|农业|医疗)).*(海洋.{0,6}(防护|防腐|防污|防附着|防渗透)|防护.{0,6}海洋|防腐.{0,6}(材料|涂料)|防污.{0,6}(材料|涂层)|船舶.{0,3}(防腐|防污)|海工.{0,3}(材料|防护))
+^(?!.*(淡水|池塘|内河|江河|湖泊|水库|观赏鱼|锦鲤|龙鱼|花鸟)).*?(?:海.{0,100}(养殖|鲍|参|虾|蟹|贝|蚝|蛎|蛤|扇贝|鲍鱼|海参|对虾|虾|贻贝|牡蛎|蛏|螺|紫菜|海带)|(养殖|鲍|参|虾|蟹|贝|蚝|蛎|蛤|扇贝|鲍鱼|海参|对虾|蟹|虾|贻贝|牡蛎|蛏|螺|紫菜|海带).{0,100}海)
 """
 """
 
 
 test_cases = [
 test_cases = [
     "防腐材料",       
     "防腐材料",       
     "海洋防污涂层",     
     "海洋防污涂层",     
     "船舶防腐",        
     "船舶防腐",        
-    "职业:个体;投向:船体防腐;用途:海洋防污涂层", 
+    "职业:水产养殖人员 投向:海水养殖 用途:养殖鲍鱼", 
     "材料",           
     "材料",           
     "医疗防护服",      
     "医疗防护服",      
 ]
 ]

+ 7 - 0
agent/tests/test_sync_category.py

@@ -0,0 +1,7 @@
+import requests
+
+res = requests.post("http://10.192.72.13:9876/api/aitag/admin/v1/synchronize_category", json={
+    "category_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
+})
+print(res.text)
+

+ 3 - 1
agent/tests/test_tagging.py

@@ -8,7 +8,9 @@ res = requests.post("http://10.192.72.13:9876/api/aitag/v1/tagging", json={
     # "timestamp": 1234567890,
     # "timestamp": 1234567890,
     # "sign": "test_sign",
     # "sign": "test_sign",
     "business_attr": "test_attr",
     "business_attr": "test_attr",
-    "phrase": "职业:水产养殖人员 投向:海水养殖 用途:渔排养殖"
+    "phrase": "职业:水产养殖人员 投向:海水养殖 用途:养殖鲍鱼"
 })
 })
+
+
 logging.info(res.text)
 logging.info(res.text)
 
 

+ 0 - 5
agent/tests/test_tagging_batch.py

@@ -1,8 +1,5 @@
 import requests
 import requests
-import logging
 import uuid
 import uuid
-logging.basicConfig(level=logging.INFO, force=True,format='%(asctime)s - %(levelname)s - %(message)s')
-logging.info("app starting!")
 
 
 #批量读取test_data.txt中的测试用例,并调用接口进行测试
 #批量读取test_data.txt中的测试用例,并调用接口进行测试
 with open("tests/test_data.txt", "r", encoding="utf-8") as f:
 with open("tests/test_data.txt", "r", encoding="utf-8") as f:
@@ -15,11 +12,9 @@ with open("tests/test_data.txt", "r", encoding="utf-8") as f:
         if len(phrase) == 3:
         if len(phrase) == 3:
             phrase = "职业:"+phrase[0]+" "+"投向:"+phrase[1]+" "+"用途:"+phrase[2]
             phrase = "职业:"+phrase[0]+" "+"投向:"+phrase[1]+" "+"用途:"+phrase[2]
 
 
-        logging.info("测试用例: "+phrase)
         res = requests.post("http://10.192.72.13:9876/api/aitag/v1/tagging", json={
         res = requests.post("http://10.192.72.13:9876/api/aitag/v1/tagging", json={
             "business_attr": uuid.uuid4().hex,
             "business_attr": uuid.uuid4().hex,
             "phrase": phrase
             "phrase": phrase
         })
         })
-        logging.info(res.text)