增加几个文件

This commit is contained in:
2025-11-20 20:13:05 +08:00
parent 5279700e1c
commit 99d9eea757
3 changed files with 437 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
"""
FAISS向量匹配器
基于向量相似度从候选集中检索最匹配的菜品名
"""
import json
import os
from typing import List, Tuple
import faiss
import numpy as np
class DishNameMatcher:
"""
菜品名向量匹配器
加载预构建的FAISS索引,执行相似度检索
"""
def __init__(self, index_dir: str):
"""
参数:
index_dir: 索引目录,应包含:
- dish_names.json: 菜品名列表
- dish_embeddings.npy: 归一化后的向量
- faiss_index.bin: FAISS索引文件
"""
self.index_dir = index_dir
# 加载菜品名列表
names_path = os.path.join(index_dir, "dish_names.json")
with open(names_path, "r", encoding="utf-8") as f:
self.dish_names: List[str] = json.load(f)
# 加载向量(可选,用于调试)
embeddings_path = os.path.join(index_dir, "dish_embeddings.npy")
self.embeddings = np.load(embeddings_path)
# 加载FAISS索引
index_path = os.path.join(index_dir, "faiss_index.bin")
self.index = faiss.read_index(index_path)
print(
f"[DishNameMatcher] Loaded index_dir={index_dir} "
f"num_dishes={len(self.dish_names)} "
f"embeddings_shape={self.embeddings.shape} "
f"index_ntotal={self.index.ntotal}"
)
def match(
self,
query_embedding: np.ndarray,
top_k: int = 3
) -> List[Tuple[str, float]]:
"""
检索最相似的菜品名
参数:
query_embedding: 查询向量 (1D或2D数组)
top_k: 返回的候选数量
返回:
[(dish_name, similarity_score), ...] 按相似度降序排列
"""
# 确保是2D数组 (1, embedding_dim)
if query_embedding.ndim == 1:
query_embedding = query_embedding.reshape(1, -1)
# 归一化(因为索引是IndexFlatIP,需要归一化才能表示余弦相似度)
norm = np.linalg.norm(query_embedding, axis=1, keepdims=True)
if norm[0, 0] > 0:
query_embedding = query_embedding / norm
# 执行检索
scores, indices = self.index.search(
query_embedding.astype(np.float32),
min(top_k, len(self.dish_names))
)
# 构建结果
results = []
for score, idx in zip(scores[0], indices[0]):
if idx == -1: # FAISS在结果不足时会返回-1
break
dish_name = self.dish_names[idx]
results.append((dish_name, float(score)))
print(
f"[DishNameMatcher] Query shape={query_embedding.shape} "
f"top_k={top_k} results={len(results)}"
)
for rank, (name, score) in enumerate(results, 1):
print(f" [{rank}] {name} (score={score:.4f})")
return results
def match_text(
self,
text: str,
embedder,
top_k: int = 3
) -> List[Tuple[str, float]]:
"""
便捷方法:直接从文本检索(自动调用embedder)
参数:
text: 查询文本(菜品名)
embedder: OllamaEmbedder实例
top_k: 返回的候选数量
"""
query_emb = embedder.encode_single(text)
return self.match(query_emb, top_k)