mixvideo-v2/docs/outfit-search-implementatio...

5.5 KiB

服装搭配搜索功能实现

概述

本文档描述了服装搭配搜索功能的实现,该功能直接调用 Google Vertex AI Search API 进行搜索,而不是通过 RAG Grounding。

核心功能

1. 直接 Vertex AI Search 调用

  • API 端点: https://discoveryengine.googleapis.com/v1beta/projects/{project_id}/locations/global/collections/default_collection/engines/{app_id}/servingConfigs/default_search:search
  • 认证: 通过 Google 访问令牌进行认证
  • 数据存储: 使用配置的 vertex_ai_app_iddata_store_id

2. 搜索配置

pub struct SearchRequest {
    pub query: String,                    // 搜索查询字符串
    pub config: SearchConfig,             // 搜索配置
    pub page_size: usize,                 // 页面大小
    pub page_offset: usize,               // 页面偏移量
}

pub struct SearchConfig {
    pub relevance_threshold: RelevanceThreshold,  // 相关性阈值
    pub environments: Vec<String>,                // 环境标签过滤
    pub categories: Vec<String>,                  // 类别过滤
    pub color_filters: HashMap<String, ColorFilter>,     // 颜色过滤器
    pub design_styles: HashMap<String, Vec<String>>,     // 设计风格过滤
    pub max_keywords: usize,                      // 最大关键词数量
}

3. 搜索流程

  1. 获取访问令牌: 通过 Modal.run API 获取 Google 访问令牌
  2. 构建搜索过滤器: 根据搜索配置构建 Vertex AI Search 过滤器
  3. 组合查询字符串: 将用户查询与关键词组合
  4. 发送 HTTP 请求: 直接调用 Vertex AI Search API
  5. 解析响应: 将 Vertex AI 响应转换为应用程序格式
  6. 应用过滤: 根据相关性阈值过滤结果

4. 响应格式转换

pub struct SearchResult {
    pub id: String,                       // 结果ID
    pub image_url: String,                // 图片URL
    pub style_description: String,        // 风格描述
    pub environment_tags: Vec<String>,    // 环境标签
    pub products: Vec<ProductInfo>,       // 产品信息列表
    pub relevance_score: f64,             // 相关性评分
}

pub struct ProductInfo {
    pub category: String,                 // 产品类别
    pub description: String,              // 产品描述
    pub color_pattern: ColorHSV,          // 主要颜色
    pub design_styles: Vec<String>,       // 设计风格
}

实现细节

1. 访问令牌获取

async fn get_google_access_token() -> Result<String, anyhow::Error> {
    let config = GeminiConfig::default();
    let client = reqwest::Client::new();
    
    let url = format!("{}/google/access-token", config.base_url);
    
    let response = client
        .get(&url)
        .header("Authorization", format!("Bearer {}", config.bearer_token))
        .send()
        .await?;
    
    // 解析访问令牌...
}

2. 搜索请求构建

let mut payload = serde_json::json!({
    "query": enhanced_query,
    "relevanceThreshold": request.config.relevance_threshold.to_value().to_string(),
    "relevanceScoreSpec": {
        "returnRelevanceScore": true
    },
    "pageSize": request.page_size,
    "offset": request.page_offset
});

// 添加过滤器(如果有)
if !search_filter.is_empty() {
    payload["filter"] = serde_json::Value::String(search_filter);
}

3. 响应解析

  • 从 Vertex AI Search 响应中提取 results 数组
  • 解析每个结果的 document.structData 字段
  • 提取图片URL、风格描述、环境标签等信息
  • 解析产品信息和颜色模式
  • 获取相关性评分并应用阈值过滤

配置参数

全局配置

impl Default for OutfitSearchGlobalConfig {
    fn default() -> Self {
        Self {
            google_project_id: "gen-lang-client-0413414134".to_string(),
            vertex_ai_app_id: "jeans-search_1751353769585".to_string(),
            storage_bucket_name: "fashion_image_block".to_string(),
            data_store_id: "jeans_pattern_data_store".to_string(),
            cloudflare_project_id: "67720b647ff2b55cf37ba3ef9e677083".to_string(),
            cloudflare_gateway_id: "bowong-dev".to_string(),
        }
    }
}

相关性阈值

  • LOWEST: 0.3 - 显示更多相关结果
  • LOW: 0.5 - 包含较多相关结果
  • MEDIUM: 0.7 - 平衡相关性和数量
  • HIGH: 0.9 - 只显示高度相关结果

错误处理

  • 访问令牌获取失败
  • HTTP 请求失败
  • JSON 解析错误
  • 数据格式不匹配
  • 网络超时

测试

实现了以下测试用例:

  1. test_search_request_creation - 测试搜索请求创建
  2. test_search_filter_builder - 测试搜索过滤器构建
  3. test_query_keywords_builder - 测试查询关键词构建

使用示例

import { OutfitSearchService } from '../services/outfitSearchService';

const searchRequest = {
  query: "牛仔裤搭配",
  config: {
    relevance_threshold: "HIGH",
    categories: ["上装", "下装"],
    environments: ["Outdoor"],
    color_filters: {},
    design_styles: {},
    max_keywords: 10
  },
  page_size: 9,
  page_offset: 0
};

const response = await OutfitSearchService.searchSimilarOutfits(searchRequest);
console.log(`找到 ${response.total_size} 个搜索结果`);

性能优化

  • 使用连接池减少HTTP连接开销
  • 实现访问令牌缓存机制
  • 支持分页查询避免大量数据传输
  • 客户端相关性过滤减少无效结果

未来改进

  1. 添加向量搜索支持
  2. 实现搜索结果缓存
  3. 支持更复杂的过滤条件
  4. 添加搜索分析和统计
  5. 实现搜索建议优化