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)