| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- #!/usr/bin/env python3
- """
- 混合检索HTTP服务
- 使用FastAPI框架实现,提供混合检索的HTTP POST接口
- """
- import sys
- import os
- import requests
- from io import BytesIO
- from typing import List, Dict, Any
- from fastapi import FastAPI, HTTPException, Body
- from pydantic import BaseModel
- from PIL import Image
- # 添加项目根目录到Python路径
- sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
- from utils.infinity_util import InfinityVectorDB
- from model.multimodal_embedding import Embedding
- from conf.config import ModelConfig, VectorDBConfig
- # 初始化FastAPI应用
- app = FastAPI(
- title="混合检索HTTP服务",
- description="提供混合检索的HTTP POST接口",
- version="1.0.0"
- )
- # 初始化向量数据库
- vector_db = InfinityVectorDB()
- # 初始化多模态嵌入模型
- embedding_model = Embedding(
- model_name=ModelConfig.get_multimodal_embedding_model_name(),
- api_key=ModelConfig.get_dashscope_api_key()
- )
- # 定义请求模型
- class HybridSearchRequest(BaseModel):
- """混合检索请求模型"""
- text_query: str
- image: str
- topn: int = 2
- # 定义响应模型
- class HybridSearchResponse(BaseModel):
- """混合检索响应模型"""
- success: bool
- message: str
- output: List[Dict[str, Any]] = []
- total: int = 0
- @app.post("/hybrid_search", response_model=HybridSearchResponse)
- def hybrid_search(request: HybridSearchRequest = Body(...)):
- """
- 混合检索API
- 使用文本查询和向量查询进行混合检索
-
- 请求参数:
- - text_query: 文本查询
- - image: 图片URL
- - topn: 返回结果数量,默认2
-
- 返回结果:
- - success: 是否成功
- - message: 结果消息
- - output: 检索结果列表
- - total: 总命中数
- """
- try:
- # 解析请求参数
- text_query = request.text_query
- image_url = request.image
- topn = request.topn
-
- print(f"开始混合检索,数据库: {VectorDBConfig.get_infinity_database}, 知识库id: {ModelConfig.get_dataset_id()}, 文本查询: {text_query}, 返回数量: {topn}")
-
- # 构建索引名称
- index_name = f"{VectorDBConfig.get_infinity_table_name()}"
- print(f"开始生成多模态嵌入,文本长度: {len(text_query)}")
-
- # 处理image_url为image: Image.Image
- if isinstance(image_url, str):
- # 下载图片
- response = requests.get(image_url)
- response.raise_for_status() # 检查HTTP状态码
-
- # 将响应内容转换为字节流
- image_bytes = BytesIO(response.content)
-
- # 创建Image对象
- image = Image.open(image_bytes)
-
- # 生成多模态嵌入向量
- embedding = embedding_model.get_multimodal_embedding(text_query, image)
-
- print(f"多模态嵌入生成完成,向量长度: {len(embedding)}")
-
- # 执行混合检索
- result = vector_db.hybrid_search(
- index_name=index_name,
- match_method="dense",
- vector_field="dense_vector_1024",
- query_vector=embedding,
- element_type="float",
- metric_type="cosine",
- topn=topn,
- text_query=text_query,
- text_field="content"
- )
-
- print(f"混合检索完成,总命中数: {result.get('total', 0)}")
-
- # 返回成功响应
- return HybridSearchResponse(
- success=True,
- message="混合检索成功",
- output=result.get("output", []),
- total=result.get("total", topn)
- )
- except Exception as e:
- print(f"混合检索失败: {str(e)}")
- raise HTTPException(status_code=500, detail=str(e))
- @app.get("/health")
- def health_check():
- """健康检查接口"""
- return {
- "status": "ok",
- "message": "混合检索HTTP服务正常运行"
- }
- if __name__ == "__main__":
- import uvicorn
- uvicorn.run(app, host="0.0.0.0", port=18001)
|