From 7a0e526eff90c0b575461ac7a2bd809d9ef2f2e7 Mon Sep 17 00:00:00 2001 From: old-tom <892955278@msn.cn> Date: Sat, 19 Apr 2025 17:05:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- env.toml | 35 +++ llmagent/llm_agent.py | 83 ++++++ llmagent/llm_config.py | 56 ++++ llmtools/__init__.py | 7 + llmtools/tool_impl.py | 89 ++++++ log_conf.py | 44 +++ pyproject.toml | 3 + uv.lock | 52 ++++ vector_db.py | 632 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 1001 insertions(+) create mode 100644 env.toml create mode 100644 llmtools/__init__.py create mode 100644 llmtools/tool_impl.py create mode 100644 log_conf.py create mode 100644 vector_db.py diff --git a/env.toml b/env.toml new file mode 100644 index 0000000..5c82f06 --- /dev/null +++ b/env.toml @@ -0,0 +1,35 @@ +[base] +# 向量库相似度阈值 +similarity_threshold = 0.93 +# 模型供应商 +model_form = 'siliconflow' + +[siliconflow] +# 硅基流动 +# 密钥 +api_key = 'sk-rdoyeoxcyvqjynufqjmewmipwtvrhjjzerqlinpqxiodyafp' +# 模型名称 +model = 'Qwen/QwQ-32B' +# API地址 +base_url = 'https://api.siliconflow.cn/v1/' +# 最大token数 +max_tokens = 4096 +# 温度系数 +temperature = 0.6 +# 是否流式返回 +streaming = true + +[ark] +# 火山引擎 +# 密钥 +api_key = '4eefc827-187f-4756-9637-7e0153c93d81' +# 模型名称 +model = 'deepseek-r1-250120' +# API地址 +base_url = 'https://ark.cn-beijing.volces.com/api/v3/' +# 最大token数 +max_tokens = 4096 +# 温度系数 +temperature = 0.6 +# 是否流式返回 +streaming = true diff --git a/llmagent/llm_agent.py b/llmagent/llm_agent.py index 5bba804..c4250d7 100644 --- a/llmagent/llm_agent.py +++ b/llmagent/llm_agent.py @@ -5,4 +5,87 @@ # @File : llm_agent # @Project : reActLLMDemo # @Desc : 代理 +from typing import Annotated +from langgraph.checkpoint.memory import MemorySaver +from langchain_openai import ChatOpenAI +from llmagent.llm_config import LLMConfigLoader +from llmagent.llm_config import base_conf +from llmtools.tool_impl import tools, tool_node +from langchain_core.messages import AnyMessage +from typing_extensions import TypedDict +from langgraph.graph import StateGraph, START, END +from langgraph.graph.message import add_messages +from langgraph.prebuilt import tools_condition + +# 内存记忆 +memory = MemorySaver() + +# 初始化LLM模型 +llm_conf = LLMConfigLoader.load(item_name=base_conf.model_form) +llm = ChatOpenAI( + model=llm_conf.model, api_key=llm_conf.api_key, + base_url=llm_conf.base_url, max_tokens=llm_conf.max_tokens, + temperature=llm_conf.temperature, + streaming=llm_conf.streaming +) +# 绑定工具 +llm_with_tools = llm.bind_tools(tools) + + +class AgentState(TypedDict): + """ + 状态机 + add_messages 函数会自动合并message到一个list中,例如HumanMessage\AIMessage + """ + messages: Annotated[list[AnyMessage], add_messages] + + +graph_builder = StateGraph(AgentState) + + +def chat(state: AgentState): + """ + LLM单轮对话 + :param state: 状态机 + LLM需要从状态机获取message + :return: + """ + return {"messages": [llm_with_tools.invoke(state["messages"])]} + + +# LLM节点 +graph_builder.add_node("chat_llm", chat) +# 工具节点 +graph_builder.add_node("tools", tool_node) +graph_builder.add_edge(START, "chat_llm") +graph_builder.add_edge("chat_llm", END) +# 添加条件边,tools_condition 是官方实现的函数,用于判断是否应该调用tool或者直接结束 +graph_builder.add_conditional_edges("chat_llm", tools_condition) +graph_builder.add_edge("tools", "chat_llm") +# checkpointer 是检查点设置 +graph = graph_builder.compile(name='语音助手', checkpointer=memory) + + +def stream_graph_updates(user_input: str): + config = {"configurable": {"thread_id": "1"}} + for chunk, metadata in graph.stream({"messages": [{"role": "user", "content": user_input}]}, config, + stream_mode='messages'): + if chunk.content: + print(chunk.content, end='', flush=True) + print('\n') + + +while True: + try: + user_input = input("User: ") + if user_input.lower() in ["quit", "exit", "q"]: + print("Goodbye!") + break + + stream_graph_updates(user_input) + except: + user_input = "What do you know about LangGraph?" + print("User: " + user_input) + stream_graph_updates(user_input) + break diff --git a/llmagent/llm_config.py b/llmagent/llm_config.py index 69098d0..273953d 100644 --- a/llmagent/llm_config.py +++ b/llmagent/llm_config.py @@ -5,3 +5,59 @@ # @File : llm_config # @Project : reActLLMDemo # @Desc : llm配置文件解析 +import os + +from pydantic import BaseModel +import toml + +# 默认配置文件名 +DEFAULT_CONF_NAME = 'env.toml' +path = os.path.dirname(__file__) +path = os.path.dirname(path) +# 默认配置文件位置 +DEFAULT_CONF_PATH = os.path.join(path, DEFAULT_CONF_NAME) + + +class ConfigNotFoundError(Exception): + """ + 配置不存在异常 + """ + + def __init__(self, msg): + Exception.__init__(self, msg) + + +def load_env(): + if not os.path.isfile(DEFAULT_CONF_PATH): + raise ConfigNotFoundError(f'模型配置文件{DEFAULT_CONF_NAME}不存在') + return toml.load(DEFAULT_CONF_PATH) + + +conf = load_env() + + +class LLMConf(BaseModel): + api_key: str + model: str + base_url: str + max_tokens: int + temperature: float + streaming: bool = True + + +class LLMConfigLoader(object): + @staticmethod + def load(item_name) -> LLMConf: + """ + 校验并加载配置 + :return: + """ + return LLMConf(**conf[item_name]) + + +class BaseConf(BaseModel): + similarity_threshold: float + model_form: str + + +base_conf = BaseConf(**conf['base']) diff --git a/llmtools/__init__.py b/llmtools/__init__.py new file mode 100644 index 0000000..d55a32d --- /dev/null +++ b/llmtools/__init__.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# @Time : 2025/4/17 15:40 +# @Author : old-tom +# @File : __init__.py +# @Project : reActLLMDemo +# @Desc : diff --git a/llmtools/tool_impl.py b/llmtools/tool_impl.py new file mode 100644 index 0000000..5d2a072 --- /dev/null +++ b/llmtools/tool_impl.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# @Time : 2025/4/12 14:55 +# @Author : old-tom +# @File : tool_impl +# @Project : sttFunctionCallBackend +# @Desc : 工具定义 + +from typing import Annotated +from langchain_core.tools import tool +from vector_db import query_vector_db +from log_conf import log +from llmagent.llm_config import base_conf +from langgraph.prebuilt import ToolNode + + +@tool("play_video", description="播放、查看、打开实时视频") +def play_video(camera_name: Annotated[str, "相机名称,例如:南卡口1号相机"]) -> str: + camera_info = query_camera_from_db(camera_name) + log.info('【function】play_video 输入 [{}],向量库返回{}', camera_name, camera_info) + if camera_info: + if len(camera_info) > 1: + hit_camera_names = [x['carme_name'] for x in camera_info] + return f"找到以下相机,请选择一个:{hit_camera_names}" + else: + # TODO 调用业务系统 + return f"正在打开{camera_name},请等待操作完成" + else: + return "未找到该相机,请尝试其他名称" + + +@tool("split_screen", description="切换分屏") +def split_screen(split_n: Annotated[int, "要切换的分屏数量,整数并且大于0,例如:1分屏、2分屏"]) -> str: + return f"正在切换到{split_n}分屏,请等待操作完成" + + +@tool("play_video_record", description="播放、打开录像") +def play_video_record(camera_name: Annotated[str, "相机名称,例如:南卡口1号相机"], + start_time: Annotated[str, "录像开始时间,格式为yyyy-MM-dd hh:mm:ss,例 2025-03-16 01:00:00"], + end_time: Annotated[str, "录像结束时间,格式为yyyy-MM-dd hh:mm:ss,例 2025-03-16 02:09:31"]) -> str: + log.info('【function】play_video_record 输入 [{},{},{}]', camera_name, start_time, end_time) + return f"正在打开{camera_name}的录像,请等待操作完成" + + +@tool("switch_page", description="打开、跳转页面") +def switch_page(page_name: Annotated[str, "页面中文名称或者缩写,例:人员核查、系统日志、设备管理、首页"]) -> str: + log.info('【function】switch_page 输入 [{}]', page_name) + return f"正在打开{page_name},请等待操作完成" + + +@tool("zoom_in", description="放大电子地图") +def zoom_in(level_n: Annotated[int, "放大等级,整数并且大于0小于5,例如:放大1级、放大2级"]) -> str: + log.info('【function】zoom_in 输入 [{}]', level_n) + return f"正在放大电子地图至{level_n}级,请等待操作完成" + + +@tool("view_flight_details", description="查询指定机场指定航班及时间的出入境人员明细") +def view_flight_details( + airport_name: Annotated[str, "机场名称,简体中文,可以是缩写,例如:成都天府机场、天府机场、长水机场、上海浦东机场"], + flight_code: Annotated[ + str, "航班编号,由字母+数字组成的完整编号,若编号包含多余字符(如标点符号),需过滤后保留有效部分"], + flight_date: Annotated[str, "提取完整日期(年月日),自动补零至标准格式 yyyy-MM-dd, 例:2025-03-16"], + ie_type: Annotated[str, "出入境类型,仅识别'入境'或'出境'两种类型"]) -> str: + log.info('【function】view_flight_details 输入 [{},{},{},{}]', airport_name, flight_code, flight_date, ie_type) + return f"{airport_name}航班号{flight_code}{flight_date}{ie_type}数据,共100人乘机,起飞准时,晚点降落" + + +def query_camera_from_db(camera_name: str, top_n: int = 3) -> str: + """ + 相机名称查询向量库,根据相似度阈值取top_one或者top_n + :param camera_name: 相机名称 + :param top_n: 返回前N个 + :return: + """ + rt = query_vector_db(camera_name) + if rt: + log.info('【function】相机相似度检索查询[{}],返回 {}', camera_name, rt) + # 判断相似度最高的相机是否超过阈值 + top_one = rt['hits'][0] + # 相似度评分 + score = top_one['_score'] + if score > base_conf.similarity_threshold: + return rt['hits'][0:1] + else: + return rt['hits'][0:top_n] + + +tools = [play_video, split_screen, play_video_record, switch_page, zoom_in, view_flight_details] +tool_node = ToolNode(tools=tools) diff --git a/log_conf.py b/log_conf.py new file mode 100644 index 0000000..26abb9b --- /dev/null +++ b/log_conf.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# @Time : 2025/4/12 14:51 +# @Author : old-tom +# @File : log_conf +# @Project : sttFunctionCallBackend +# @Desc : + +import sys +import os +from loguru import logger + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) + +# 日志输出路径 +LOG_PATH = os.path.join(BASE_DIR, r'logout/logout.log') + + +class Logger(object): + def __init__(self): + self.logger = logger + self.logger.remove() + self.logger.add(sys.stdout, + format="{time:YYYY-MM-DD HH:mm:ss} | " # 颜色>时间 + "{process.name} | " # 进程名 + "{thread.name} | " # 进程名 + "{module}.{function}" # 模块名.方法名 + ":{line} | " # 行号 + "{level}: " # 等级 + "{message}", # 日志内容 + ) + # 输出到文件的格式,注释下面的add',则关闭日志写入 + self.logger.add(LOG_PATH, level='DEBUG', + format='{time:YYYY-MM-DD HH:mm:ss} - ' # 时间 + "{process.name} | " # 进程名 + "{thread.name} | " # 进程名 + '{module}.{function}:{line} - {level} -{message}', # 模块名.方法名:行号 + rotation="10 MB") + + def get_logger(self): + return self.logger + + +log = Logger().get_logger() diff --git a/pyproject.toml b/pyproject.toml index 7015ac0..4bdcf95 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,6 +8,9 @@ dependencies = [ "langchain-community>=0.3.21", "langchain-openai>=0.3.13", "langgraph>=0.3.30", + "loguru>=0.7.3", + "marqo>=3.12.0", + "toml>=0.10.2", ] [[tool.uv.index]] diff --git a/uv.lock b/uv.lock index bb23a4b..41e6db1 100644 --- a/uv.lock +++ b/uv.lock @@ -558,6 +558,34 @@ wheels = [ { url = "https://mirrors.aliyun.com/pypi/packages/64/c3/5db3d0977bb53e16eab834f2eea6e1c68d327e2f5c25b88f6506ef06e692/langsmith-0.3.31-py3-none-any.whl", hash = "sha256:ee780ae3eac69998c336817c0b9f5ccfecaaaa3e67d94b7ef726b58ab3e72a25" }, ] +[[package]] +name = "loguru" +version = "0.7.3" +source = { registry = "https://mirrors.aliyun.com/pypi/simple/" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "win32-setctime", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://mirrors.aliyun.com/pypi/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6" } +wheels = [ + { url = "https://mirrors.aliyun.com/pypi/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c" }, +] + +[[package]] +name = "marqo" +version = "3.12.0" +source = { registry = "https://mirrors.aliyun.com/pypi/simple/" } +dependencies = [ + { name = "packaging" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "urllib3" }, +] +sdist = { url = "https://mirrors.aliyun.com/pypi/packages/b2/36/3c5678593df50ff8795056cd46224b32febe414f5900af8a569b8aac4192/marqo-3.12.0.tar.gz", hash = "sha256:5c2e0a01fc3a7be5a7db8a4630f2f7d7164b09cf8d72480a5f6db68550f24afb" } +wheels = [ + { url = "https://mirrors.aliyun.com/pypi/packages/b1/6f/b478951b8e3b3ff32f2af36bbf9cd28b0cf232894f25ec93294f6ace3aa7/marqo-3.12.0-py3-none-any.whl", hash = "sha256:e30e33308465629ff5b245d1072cb5a94606891fceb84d8cd873995066bd4b17" }, +] + [[package]] name = "marshmallow" version = "3.26.1" @@ -944,6 +972,9 @@ dependencies = [ { name = "langchain-community" }, { name = "langchain-openai" }, { name = "langgraph" }, + { name = "loguru" }, + { name = "marqo" }, + { name = "toml" }, ] [package.metadata] @@ -951,6 +982,9 @@ requires-dist = [ { name = "langchain-community", specifier = ">=0.3.21" }, { name = "langchain-openai", specifier = ">=0.3.13" }, { name = "langgraph", specifier = ">=0.3.30" }, + { name = "loguru", specifier = ">=0.7.3" }, + { name = "marqo", specifier = ">=3.12.0" }, + { name = "toml", specifier = ">=0.10.2" }, ] [[package]] @@ -1089,6 +1123,15 @@ wheels = [ { url = "https://mirrors.aliyun.com/pypi/packages/de/a8/8f499c179ec900783ffe133e9aab10044481679bb9aad78436d239eee716/tiktoken-0.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:5ea0edb6f83dc56d794723286215918c1cde03712cbbafa0348b33448faf5b95" }, ] +[[package]] +name = "toml" +version = "0.10.2" +source = { registry = "https://mirrors.aliyun.com/pypi/simple/" } +sdist = { url = "https://mirrors.aliyun.com/pypi/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" } +wheels = [ + { url = "https://mirrors.aliyun.com/pypi/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b" }, +] + [[package]] name = "tqdm" version = "4.67.1" @@ -1144,6 +1187,15 @@ wheels = [ { url = "https://mirrors.aliyun.com/pypi/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813" }, ] +[[package]] +name = "win32-setctime" +version = "1.2.0" +source = { registry = "https://mirrors.aliyun.com/pypi/simple/" } +sdist = { url = "https://mirrors.aliyun.com/pypi/packages/b3/8f/705086c9d734d3b663af0e9bb3d4de6578d08f46b1b101c2442fd9aecaa2/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0" } +wheels = [ + { url = "https://mirrors.aliyun.com/pypi/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390" }, +] + [[package]] name = "xxhash" version = "3.5.0" diff --git a/vector_db.py b/vector_db.py new file mode 100644 index 0000000..f466db8 --- /dev/null +++ b/vector_db.py @@ -0,0 +1,632 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# @Time : 2025/3/16 20:09 +# @Author : old-tom +# @File : vector_agent +# @Project : llmFunctionCallDemo +# @Desc : 向量数据库,解决相似度查询,例如 相机名称 +import marqo + +# 索引名称 +INDEX_NAME = 'test_index' +# 初始化marqo +mq = marqo.Client(url='http://171.92.0.3:8882') + +# mq.delete_index(INDEX_NAME) + + +# settings = { +# "treatUrlsAndPointersAsImages": False, +# "model": "hf/bge-large-zh-v1.5", +# "normalizeEmbeddings": True, +# } + + +def create_and_set_index(): + """ + 全局只能调用一次 + :return: + """ + mq.create_index(INDEX_NAME, model='hf/e5-base-v2') + # 添加文档(测试用) + mq.index(INDEX_NAME).add_documents([ + { + "carme_name": "中方国门AI算法", + "ip": "192.168.10.80", + "location": "国门顶部" + }, + { + "carme_name": "中方国门AI算法0102", + "ip": "192.168.10.80", + "location": "国门顶部" + }, + { + "carme_name": "中方国门入境1", + "ip": "192.168.10.77", + "location": "国门通道" + }, + { + "carme_name": "中方国门入境2", + "ip": "192.168.10.79", + "location": "国门通道" + }, + { + "carme_name": "中方国门入境摄像头中", + "ip": "192.168.10.72", + "location": "登临检验" + }, + { + "carme_name": "中方国门入境摄像头右", + "ip": "192.168.10.74", + "location": "登临检验" + }, + { + "carme_name": "中方国门入境摄像头左", + "ip": "192.168.10.75", + "location": "登临检验" + }, + { + "carme_name": "中方国门出境1", + "ip": "192.168.10.76", + "location": "国门通道" + }, + { + "carme_name": "中方国门出境2", + "ip": "192.168.10.78", + "location": "国门通道" + }, + { + "carme_name": "中方国门出境摄像头右", + "ip": "192.168.10.71", + "location": "登临检验" + }, + { + "carme_name": "中方国门出境摄像头左", + "ip": "192.168.10.73", + "location": "登临检验" + }, + { + "carme_name": "中方国门-面向国门球机", + "ip": "192.168.10.215", + "location": "国门通道拐角" + }, + { + "carme_name": "中方国门高点1", + "ip": "192.168.10.70", + "location": "国门顶部" + }, + { + "carme_name": "北卡口AI摄像头全景", + "ip": "192.168.10.30", + "location": "北卡口对面" + }, + { + "carme_name": "北卡口AI摄像头细节", + "ip": "192.168.10.30", + "location": "北卡口对面" + }, + { + "carme_name": "北卡口入境摄像头入场4号通道", + "ip": "192.168.10.112", + "location": "入场通道" + }, + { + "carme_name": "北卡口入境摄像头入场5号通道", + "ip": "192.168.10.114", + "location": "入场通道" + }, + { + "carme_name": "北卡口入境摄像头入场6号通道", + "ip": "192.168.10.117", + "location": "入场通道" + }, + { + "carme_name": "北卡口入境摄像头出场1号通道", + "ip": "192.168.10.115", + "location": "出场通道" + }, + { + "carme_name": "北卡口入境摄像头出场2号通道", + "ip": "192.168.10.116", + "location": "出场通道" + }, + { + "carme_name": "北卡口入境摄像头出场3号通道", + "ip": "192.168.10.113", + "location": "出场通道" + }, + { + "carme_name": "北卡口出口道路监控", + "ip": "192.168.10.153", + "location": "路口" + }, + { + "carme_name": "能投大厦高点1", + "ip": "192.168.10.89", + "location": "能投楼顶" + }, + { + "carme_name": "南卡口AI算法2", + "ip": "192.168.10.210", + "location": "南卡口顶部" + }, + { + "carme_name": "南卡口AI算法20102", + "ip": "192.168.10.210", + "location": "南卡口顶部" + }, + { + "carme_name": "南卡口AI算法识别摄像机", + "ip": "192.168.10.91", + "location": "南卡口顶部" + }, + { + "carme_name": "南卡口AI算法识别摄像机0102", + "ip": "192.168.10.91", + "location": "南卡口顶部" + }, + { + "carme_name": "南卡口出境摄像头1号通道", + "ip": "192.168.10.100", + "location": "出境通道" + }, + { + "carme_name": "南卡口出境摄像头2号通道", + "ip": "192.168.10.103", + "location": "出境通道" + }, + { + "carme_name": "南卡口出境摄像头3号通道", + "ip": "192.168.10.104", + "location": "出境通道" + }, + { + "carme_name": "南卡口出境摄像头4号通道", + "ip": "192.168.10.102", + "location": "出境通道" + }, + { + "carme_name": "南卡口出境摄像头5号通道", + "ip": "192.168.10.99", + "location": "出境通道" + }, + { + "carme_name": "南卡口出境摄像头6号通道", + "ip": "192.168.10.101", + "location": "出境通道" + }, + { + "carme_name": "南卡口入境摄像头7号通道", + "ip": "192.168.10.98", + "location": "入境通道" + }, + { + "carme_name": "南卡口入境摄像头8号通道", + "ip": "192.168.10.93", + "location": "入境通道" + }, + { + "carme_name": "南卡口入境摄像头9号通道", + "ip": "192.168.10.97", + "location": "入境通道" + }, + { + "carme_name": "南卡口入境摄像头10号通道", + "ip": "192.168.10.96", + "location": "入境通道" + }, + { + "carme_name": "南卡口入境摄像头11号通道", + "ip": "192.168.10.94", + "location": "入境通道" + }, + { + "carme_name": "南卡口入境摄像头12号通道", + "ip": "192.168.10.95", + "location": "入境通道" + }, + { + "carme_name": "南卡口高点-1", + "ip": "192.168.10.90", + "location": "南卡口顶部" + }, + { + "carme_name": "南卡口高点-2", + "ip": "192.168.10.92", + "location": "南卡口顶部" + }, + { + "carme_name": "南卡口高点-3", + "ip": "192.168.3.12", + "location": "南卡口顶部" + }, + { + "carme_name": "1.3公里封闭道路入境出场1", + "ip": "192.168.10.82", + "location": "南卡口顶部" + }, + { + "carme_name": "1.3公里封闭道路入境出场2", + "ip": "192.168.10.88", + "location": "南卡口顶部" + }, + { + "carme_name": "1.3公里封闭道路入境出场20102", + "ip": "192.168.10.88", + "location": "南卡口顶部" + }, + { + "carme_name": "1.3公里封闭道路入境摄像头入场2", + "ip": "192.168.10.87", + "location": "南卡口顶部" + }, + { + "carme_name": "1.3公里封闭道路入境摄像头入场20102", + "ip": "192.168.10.87", + "location": "南卡口顶部" + }, + { + "carme_name": "1.3公里封闭道路入境入场1", + "ip": "192.168.10.81", + "location": "南卡口顶部" + }, + { + "carme_name": "H9861号口摄像头入场", + "ip": "192.168.10.107", + "location": "H986停车场出入口" + }, + { + "carme_name": "H9862号口摄像头出场", + "ip": "192.168.10.109", + "location": "H987停车场出入口" + }, + { + "carme_name": "H9862号口摄像头入场", + "ip": "192.168.10.190", + "location": "H988停车场出入口" + }, + { + "carme_name": "车辆定位AI摄像头", + "ip": "192.168.10.29", + "location": "H988停车场山上" + }, + { + "carme_name": "车辆定位AI摄像头0102", + "ip": "192.168.10.29", + "location": "H989停车场山上" + }, + { + "carme_name": "北山货场森林公园制高点", + "ip": "192.168.10.191", + "location": "H990停车场山上" + }, + { + "carme_name": "边民互市入境摄像头出场", + "ip": "192.168.10.119", + "location": "边民互市" + }, + { + "carme_name": "边民互市入境摄像头入场", + "ip": "192.168.10.118", + "location": "出入口" + }, + { + "carme_name": "车辆缓冲区1号门入口", + "ip": "192.168.10.193", + "location": "出入口" + }, + { + "carme_name": "车辆缓冲区2号门入口", + "ip": "192.168.10.195", + "location": "出入口" + }, + { + "carme_name": "车辆缓冲区2号门出口", + "ip": "192.168.10.194", + "location": "出入口" + }, + { + "carme_name": "车辆缓冲区1号门出口", + "ip": "192.168.10.192", + "location": "出入口" + }, + { + "carme_name": "大贸查验场进口入境摄像头入场东口", + "ip": "192.168.10.181", + "location": "出入口" + }, + { + "carme_name": "大贸查验场进口入境摄像头出场东口", + "ip": "192.168.10.180", + "location": "出入口" + }, + { + "carme_name": "大贸查验场(进口)入境摄像头入场(西口)", + "ip": "192.168.10.106", + "location": "出入口" + }, + { + "carme_name": "大贸查验场(进口)高点1", + "ip": "192.168.10.156", + "location": "高点" + }, + { + "carme_name": "大贸查验场出口出境摄像头出场2", + "ip": "192.168.10.110", + "location": "出入口" + }, + { + "carme_name": "大贸查验场出口出境摄像头入场左", + "ip": "192.168.10.184", + "location": "出入口" + }, + { + "carme_name": "大贸查验场出口出境摄像头出场1", + "ip": "192.168.10.111", + "location": "出入口" + }, + { + "carme_name": "北山高速收费站入境摄像头入场出方向", + "ip": "192.168.10.170", + "location": "道路" + }, + { + "carme_name": "北山高速收费站入境摄像头入场入方向", + "ip": "192.168.10.169", + "location": "道路" + }, + { + "carme_name": "坝洒高点", + "ip": "192.168.10.164", + "location": "" + }, + { + "carme_name": "停车场卡口(坝洒)入境摄像头入场", + "ip": "192.168.10.165", + "location": "出入口" + }, + { + "carme_name": "停车场卡口(坝洒)入境摄像头出场", + "ip": "192.168.10.166", + "location": "出入口" + }, + { + "carme_name": "东西干道卡口入境摄像头入场", + "ip": "192.168.10.136", + "location": "出入口" + }, + { + "carme_name": "东西干道卡口入境摄像头出场", + "ip": "192.168.10.135", + "location": "出入口" + }, + { + "carme_name": "主卡口(临时)货场大门-高点", + "ip": "192.168.10.146", + "location": "" + }, + { + "carme_name": "利丰酒店往边民互市高点", + "ip": "192.168.10.211", + "location": "利丰酒店楼顶" + }, + { + "carme_name": "利丰货场近御峰货场入境摄像头出场2", + "ip": "192.168.10.132", + "location": "出入口" + }, + { + "carme_name": "利丰酒店往边民互市高点2", + "ip": "192.168.10.212", + "location": "利丰酒店楼顶" + }, + { + "carme_name": "利丰货场近御峰货场入境摄像头入场2", + "ip": "192.168.10.139", + "location": "出入口" + }, + { + "carme_name": "利丰货场入境摄像头出场左", + "ip": "192.168.10.127", + "location": "出入口" + }, + { + "carme_name": "利丰货场入境摄像头入场左", + "ip": "192.168.10.128", + "location": "出入口" + }, + { + "carme_name": "利丰货场入境摄像头出场右", + "ip": "192.168.10.126", + "location": "出入口" + }, + { + "carme_name": "利丰货场-高点", + "ip": "192.168.10.125", + "location": "" + }, + { + "carme_name": "利丰货场近御峰货场入境摄像头出场1", + "ip": "192.168.10.131", + "location": "出入口" + }, + { + "carme_name": "利丰货场入境摄像头入场右", + "ip": "192.168.10.129", + "location": "出入口" + }, + { + "carme_name": "利丰货场近御峰货场入境摄像头入场1", + "ip": "192.168.10.130", + "location": "出入口" + }, + { + "carme_name": "南屏高速收费站入境摄像头出场", + "ip": "192.168.10.168", + "location": "道路" + }, + { + "carme_name": "南屏高速收费站入境摄像头入场", + "ip": "192.168.10.167", + "location": "道路" + }, + { + "carme_name": "停车场卡口老表入境摄像头入场", + "ip": "192.168.10.160", + "location": "出入口" + }, + { + "carme_name": "停车场卡口老表右入境摄像头入场", + "ip": "192.168.10.162", + "location": "出入口" + }, + { + "carme_name": "停车场卡口老表入境摄像头出场", + "ip": "192.168.10.161", + "location": "出入口" + }, + { + "carme_name": "停车场卡口老表右入境摄像头出场", + "ip": "192.168.10.163", + "location": "出入口" + }, + { + "carme_name": "槟榔寨站入境摄像头入场", + "ip": "192.168.10.173", + "location": "道路" + }, + { + "carme_name": "槟榔寨站入境摄像头出场", + "ip": "192.168.10.174", + "location": "道路" + }, + { + "carme_name": "外围冷链停车区入境摄像头出场", + "ip": "192.168.10.158", + "location": "出入口" + }, + { + "carme_name": "外围冷链停车区入境摄像头入场", + "ip": "192.168.10.157", + "location": "出入口" + }, + { + "carme_name": "清水河隧道出", + "ip": "192.168.10.175", + "location": "道路" + }, + { + "carme_name": "清水河隧道入", + "ip": "192.168.10.186", + "location": "道路" + }, + { + "carme_name": "商阜路闭环区道路监控-高点", + "ip": "192.168.10.154", + "location": "道路" + }, + { + "carme_name": "商阜路闭环区道路监控道路监控高点2", + "ip": "192.168.10.155", + "location": "道路" + }, + { + "carme_name": "商阜路闭环区道路监控道路监控-后", + "ip": "192.168.10.152", + "location": "道路" + }, + { + "carme_name": "越南城十字路口-东西干道入境摄像头出场", + "ip": "192.168.10.172", + "location": "道路" + }, + { + "carme_name": "越南城十字路口-东西干道入境摄像头入场", + "ip": "192.168.10.171", + "location": "道路" + }, + { + "carme_name": "停车场卡口能投入境摄像头出场", + "ip": "192.168.10.124", + "location": "出入口" + }, + { + "carme_name": "停车场卡口能投入境摄像头入场2", + "ip": "192.168.10.123", + "location": "出入口" + }, + { + "carme_name": "停车场卡口能投入境摄像头入场1", + "ip": "192.168.10.122", + "location": "出入口" + }, + { + "carme_name": "御峰货场冷链入境摄像头出场出口", + "ip": "192.168.10.145", + "location": "出入口" + }, + { + "carme_name": "御峰货场(冷链)-高点", + "ip": "192.168.10.137", + "location": "" + }, + { + "carme_name": "御峰货场冷链入境摄像头入场进口", + "ip": "192.168.10.133", + "location": "出入口" + }, + { + "carme_name": "御峰货场冷链入境摄像头入场出口", + "ip": "192.168.10.138", + "location": "出入口" + }, + { + "carme_name": "御峰货场冷链入境摄像头出场进口", + "ip": "192.168.10.141", + "location": "出入口" + }, + { + "carme_name": "御峰货场干货入境摄像头入场", + "ip": "192.168.10.140", + "location": "出入口" + }, + { + "carme_name": "御峰货场干货入境摄像头入场2", + "ip": "192.168.10.148", + "location": "出入口" + }, + { + "carme_name": "御峰货场干货入境摄像头出场", + "ip": "192.168.10.144", + "location": "出入口" + }, + { + "carme_name": "御峰货场(干货)-高点1", + "ip": "192.168.10.142", + "location": "" + }, + { + "carme_name": "御峰货场(干货)-高点2", + "ip": "192.168.10.143", + "location": "" + }, + { + "carme_name": "御峰货场干货入境摄像头出场2", + "ip": "192.168.10.147", + "location": "出入口" + }], + tensor_fields=["carme_name"] + ) + + +def query_vector_db(query): + return mq.index(INDEX_NAME).search(q=query) + + +if __name__ == '__main__': + # create_and_set_index() + rt = query_vector_db('利丰高点') + # TODO 根据 _score字段 取出相似度最高的结果 + if rt: + for ele in rt['hits']: + print(ele)