# Video Search & Vector Recall API 接口文档 > 项目: video-vector-server > 文档版本: 2026-05-09 > 适用 Controller: `VideoSearchController`、`VectorRecallTestController`、`MaterialController`、`FileController`、`HealthController`、`XxlJobController` --- ## 通用约定 ### 基础路径 | Controller | 前缀 | |---|---| | VideoSearchController | `/videoSearch` | | VectorRecallTestController | `/recallTest` | | MaterialController | `/material` | | FileController | `/file` | | HealthController | `/` | | XxlJobController | `/job` | ### 统一响应格式 `CommonResponse` 所有接口均返回以下 JSON 结构: ```json { "code": 0, "msg": "success", "data": } ``` | 字段 | 类型 | 说明 | |---|---|---| | `code` | `int` | 业务状态码。`0` 表示成功 | | `msg` | `String` | 状态消息。成功时为 `"success"` | | `data` | `T` (泛型) | 业务数据,具体结构见各接口定义。失败时可能为 `null` | ### 全局行为 - **CORS**: 由全局拦截器 `CrosDomainAllowInterceptor` 统一处理,前端无需额外配置。`FileController` 额外加了 `@CrossOrigin(origins = "*")` - **鉴权**: MVP 阶段不校验鉴权,所有接口均可直接调用 --- ## 一、VideoSearchController (`/videoSearch`) 视频解构与相似视频匹配。 ### 1.1 触发内容解构 ``` POST /videoSearch/deconstruct ``` **用途**: 对指定内容(长文/图文/视频)发起 AI 解构任务,提取选题、灵感点、关键点、目的点等结构化信息。 **Request Body** (`application/json`): | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `bizType` | `Integer` | 否 | 业务类型。`0` = 投流 | | `contentType` | `Integer` | 否 | 内容类型: `1` = 长文, `2` = 图文, `3` = 视频 | | `channelContentId` | `String` | 否 | 业务内容ID(帖子ID/视频ID) | | `title` | `String` | 否 | 标题 | | `bodyText` | `String` | 否 | 正文内容 | | `videoUrl` | `String` | 否 | 视频地址 | | `imageList` | `List` | 否 | 图片URL列表 | | `channelAccountId` | `String` | 否 | 作者ID | | `channelAccountName` | `String` | 否 | 作者名称 | **Request 示例**: ```json { "bizType": 0, "contentType": 3, "channelContentId": "abc123", "title": "产品种草视频", "bodyText": "这是一款非常好用的护肤品...", "videoUrl": "https://example.com/video.mp4", "imageList": ["https://example.com/img1.jpg"], "channelAccountId": "account_001", "channelAccountName": "美妆达人小A" } ``` **Response**: ```json { "code": 0, "msg": "success", "data": "" } ``` `data` 为 `String` 类型,返回解构任务的唯一标识 `taskId`,可用于后续调用 `getDeconstructResult` 查询结果。 --- ### 1.2 查询解构结果 ``` POST /videoSearch/getDeconstructResult ``` **用途**: 根据任务ID或业务内容ID查询解构任务的处理结果。 **Request Body** (`application/json`): | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `taskId` | `String` | 否 | 解构任务ID(由 `deconstruct` 接口返回) | | `bizType` | `Integer` | 否 | 业务类型: `0` = 选题, `1` = 创作, `2` = 制作 | | `contentType` | `Integer` | 否 | 内容类型: `1` = 长文, `2` = 图文, `3` = 视频 | | `channelContentId` | `String` | 否 | 业务内容ID(帖子ID/视频ID) | | `forceRefresh` | `Boolean` | 否 | 是否强制从远程API重新拉取,不走Redis缓存 | > **查询逻辑**: 至少提供 `taskId` 或 `channelContentId` 之一。若提供 `taskId` 则按任务ID查询;若提供 `channelContentId` 则按内容ID查询最新结果。 **Request 示例**: ```json { "taskId": "task_20260507_001", "bizType": 0, "contentType": 3, "channelContentId": "abc123", "forceRefresh": false } ``` **Response**: `data` 为 `JSONObject`,结构为解构引擎返回的原始结果JSON,包含但不限于: - 选题(topic) - 灵感点(inspiration points) - 关键点(key points) - 目的点(purpose points) - 各点的实质词汇及贡献度分数(0~1) --- ### 1.3 按内容ID获取解构结果 ``` GET /videoSearch/getDeconstructResultByChannelContentId ``` **用途**: 通过业务内容ID直接获取解构结果(简化版,仅需 channelContentId)。 **Query Parameters**: | 参数 | 类型 | 必填 | 说明 | |---|---|---|---| | `channelContentId` | `String` | 是 | 业务内容ID(帖子ID/视频ID) | **示例请求**: ``` GET /videoSearch/getDeconstructResultByChannelContentId?channelContentId=abc123 ``` **Response**: `data` 为 `JSONObject`,与接口 1.2 返回结构一致。 --- ### 1.4 查询解构结果(精简版) ``` POST /videoSearch/getDeconstructResultMini ``` **用途**: 查询解构结果的精简版,参数与 `getDeconstructResult` 一致,返回裁剪后的解构结果。 **Request Body** (`application/json`): | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `taskId` | `String` | 否 | 解构任务ID | | `bizType` | `Integer` | 否 | 业务类型: `0` = 选题, `1` = 创作, `2` = 制作 | | `contentType` | `Integer` | 否 | 内容类型: `1` = 长文, `2` = 图文, `3` = 视频 | | `channelContentId` | `String` | 否 | 业务内容ID(帖子ID/视频ID) | | `forceRefresh` | `Boolean` | 否 | 是否强制从远程API重新拉取 | **Request 示例**: ```json { "taskId": "task_20260507_001", "bizType": 0, "contentType": 3, "channelContentId": "abc123", "forceRefresh": false } ``` **Response**: `data` 为 `JSONObject`,返回精简后的解构结果JSON。 --- ### 1.5 相似视频匹配(Top-N 召回) ``` POST /videoSearch/matchTopNVideo ``` **用途**: 基于内容解构结果,在向量库中检索最相似的 Top-N 个视频。 **Request Body** (`application/json`): | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `channelContentId` | `String` | 否 | 参考内容的业务ID,用于自动获取该内容的解构向量 | | `configCode` | `String` | 否 | 向量配置编码,指定搜索维度。不传使用默认配置 | | `queryText` | `String` | 否 | 查询文本,将被向量化后检索 | | `queryVector` | `List` | 否 | 直接传入查询向量,优先级高于 `queryText` | | `topN` | `Integer` | 否 | 返回结果数量,默认 `10` | > **检索逻辑**: `queryVector` > `queryText` > `channelContentId`。即若传入 `queryVector` 直接用于检索;否则若有 `queryText` 则将其向量化;否则使用 `channelContentId` 的解构向量进行检索。 **Request 示例**: ```json { "channelContentId": "abc123", "configCode": "VIDEO_TOPIC", "topN": 10 } ``` 按文本查询: ```json { "configCode": "VIDEO_INSPIRATION", "queryText": "如何做美妆教程", "topN": 20 } ``` **Response**: `data` 为 `List`: ```json { "code": 0, "msg": "success", "data": [ { "configCode": "VIDEO_TOPIC", "videoId": 10001, "score": 0.9523, "text": "美妆护肤教程 春季妆容", "videoDetail": { "topic": "美妆护肤", "灵感点": "产品成分解读", "灵感点-实质": [ { "word": "成分", "score": 0.92 }, { "word": "安全", "score": 0.88 } ], "关键点": "使用时需注意过敏", "关键点-实质": [ { "word": "过敏", "score": 0.85 } ], "目的点": "种草转化", "目的点-实质": [ { "word": "购买", "score": 0.91 } ] } } ] } ``` **VideoMatchResult 字段说明**: | 字段 | 类型 | 说明 | |---|---|---| | `configCode` | `String` | 命中时使用的向量配置编码 | | `videoId` | `Long` | 匹配到的视频ID | | `score` | `Double` | 余弦相似度分值(0~1,越大越相似) | | `text` | `String` | 向量化原文 | | `videoDetail` | `Map` | 视频解构详情,来源 Redis `recall:vid_decode:{vid}`。包含 topic、灵感点、关键点、目的点及其"实质"分词信息 | --- ### 1.6 召回视频并按综合评分排序 ``` POST /videoSearch/recallWithScore ``` **用途**: 召回视频后按综合评分排序返回。综合分 = `alpha * sim_norm + (1-alpha) * rov_norm`,同时考虑相似度和效率分。 **Request Body** (`application/json`): | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `channelContentId` | `String` | 否 | 业务内容ID(帖子ID/视频ID) | | `configCode` | `String` | 否 | 向量配置编码 | | `queryText` | `String` | 否 | 查询文本,将被向量化后检索 | | `queryVector` | `List` | 否 | 直接传入查询向量,优先级高于 `queryText` | | `topN` | `Integer` | 否 | 返回 Top-N 结果数量,默认 `10` | | `alpha` | `Double` | 否 | 相关性权重,取值 0~1,默认 `0.6`。越大越看重相关性(sim) | | `rovP95` | `Double` | 否 | ROV 全局历史 P95,默认 `0.05` | | `rovP5` | `Double` | 否 | ROV 全局历史 P5,默认 `0.005` | | `simMin` | `Double` | 否 | 相似度下界(粗筛阈值),默认 `0.7` | **Request 示例**: ```json { "configCode": "VIDEO_TOPIC", "queryText": "美妆护肤教程", "topN": 20, "alpha": 0.6, "simMin": 0.7 } ``` **Response**: `data` 为 `RecallVideoScoreVO`: ```json { "code": 0, "msg": "success", "data": { "items": [ { "videoId": 10001, "configCode": "VIDEO_TOPIC", "sim": 0.9523, "simNorm": 0.87, "rov": 0.032, "rovNorm": 0.65, "score": 0.782, "text": "美妆护肤教程 春季妆容", "videoDetail": { } } ], "total": 1, "scoreParams": { "alpha": 0.6, "rovP95": 0.05, "rovP5": 0.005, "simMin": 0.7, "simMax": 0.98 } } } ``` **RecallVideoScoreVO 字段说明**: | 字段 | 类型 | 说明 | |---|---|---| | `items` | `List` | 按综合分降序排列的结果列表 | | `total` | `int` | 总条数 | | `scoreParams` | `ScoreParams` | 本次使用的评分参数 | **ScoredVideoItem 子结构**: | 字段 | 类型 | 说明 | |---|---|---| | `videoId` | `Long` | 匹配到的视频ID | | `configCode` | `String` | 命中的配置编码 | | `sim` | `Double` | 原始相似度分数 | | `simNorm` | `Double` | 归一化后的相似度 | | `rov` | `Double` | 效率分(来自视频维度表) | | `rovNorm` | `Double` | 归一化后的效率分 | | `score` | `Double` | 综合得分 = alpha * sim_norm + (1-alpha) * rov_norm | | `text` | `String` | 向量化原文 | | `videoDetail` | `Map` | 视频基础信息及解构子对象 | **ScoreParams 子结构**: | 字段 | 类型 | 说明 | |---|---|---| | `alpha` | `Double` | 相关性权重 | | `rovP95` | `Double` | ROV P95 | | `rovP5` | `Double` | ROV P5 | | `simMin` | `Double` | 相似度下界 | | `simMax` | `Double` | 相似度上界 | --- ### 1.7 查询渠道需求匹配结果 ``` POST /videoSearch/queryDemandMatchResult ``` **用途**: 查询渠道需求匹配结果,按日期、渠道、人群、维度查询匹配到的视频ID及分数。 **Request Body** (`application/json`): | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `dt` | `String` | 是 | 数据日期,格式 `yyyyMMdd` | | `channelName` | `String` | 是 | 渠道类名称 | | `crowdSegment` | `String` | 否 | 人群细分 | | `dimension` | `String` | 否 | 维度(如"传播的分发") | | `pointType` | `String` | 否 | 点类型(关键点/灵感点/目的点) | | `standardElement` | `String` | 否 | 标准化元素(搜索词) | **Request 示例**: ```json { "dt": "20260509", "channelName": "美妆类", "crowdSegment": "年轻女性", "dimension": "传播的分发", "pointType": "灵感点", "standardElement": "成分安全" } ``` **Response**: `data` 为 `List`: ```json { "code": 0, "msg": "success", "data": [ { "dt": "20260509", "channelName": "美妆类", "crowdSegment": "年轻女性", "dimension": "传播的分发", "pointType": "灵感点", "standardElement": "成分安全", "categoryName": "护肤品", "visitUv": 12345, "totalRov": 0.052, "matchedVideos": [ { "videoId": 10001, "configCode": "VIDEO_INSPIRATION", "score": 0.852, "sim": 0.92, "rov": 0.035, "text": "护肤品成分安全解析" } ] } ] } ``` **ChannelDemandMatchVO 字段说明**: | 字段 | 类型 | 说明 | |---|---|---| | `dt` | `String` | 数据日期 | | `channelName` | `String` | 渠道类名称 | | `crowdSegment` | `String` | 人群细分 | | `dimension` | `String` | 维度 | | `pointType` | `String` | 点类型 | | `standardElement` | `String` | 标准化元素(搜索词) | | `categoryName` | `String` | 分类名称 | | `visitUv` | `Long` | 访问 UV | | `totalRov` | `Double` | 总 ROV | | `matchedVideos` | `List` | 匹配到的视频列表 | **MatchedVideo 子结构**: | 字段 | 类型 | 说明 | |---|---|---| | `videoId` | `Long` | 匹配视频ID | | `configCode` | `String` | 匹配使用的向量配置编码 | | `score` | `Double` | 综合评分 | | `sim` | `Double` | 相似度分数 | | `rov` | `Double` | 匹配视频 ROV | | `text` | `String` | 匹配命中的向量原文 | --- ### 1.8 获取所有配置编码 ``` GET /videoSearch/getAllConfigCodes ``` **用途**: 查询系统支持的所有向量配置编码及对应描述,供前端下拉选择。 **请求参数**: 无。 **示例请求**: ``` GET /videoSearch/getAllConfigCodes ``` **Response**: `data` 为 `Map`,key 为 configCode,value 为中文描述: ```json { "code": 0, "msg": "success", "data": { "VIDEO_TOPIC": "选题维度", "VIDEO_INSPIRATION": "灵感点维度", "VIDEO_KEYPOINT": "关键点维度", "VIDEO_PURPOSE": "目的点维度" } } ``` --- ## 二、VectorRecallTestController (`/recallTest`) 向量召回前端测试页面专用接口。MVP 阶段不加鉴权。 ### 支持的 configCode | configCode | 说明 | |---|---| | `VIDEO_TOPIC` | 选题维度检索(默认) | | `VIDEO_INSPIRATION` | 灵感点维度检索 | > 不传 `configCode` 时默认使用 `VIDEO_TOPIC`。 --- ### 2.1 获取视频基础详情 (Tab1) ``` GET /recallTest/videoDetail ``` **用途**: 查询单个视频的基础信息,用于测试页面 Tab1 展示。 **Query Parameters**: | 参数 | 类型 | 必填 | 说明 | |---|---|---|---| | `videoId` | `Long` | 是 | 视频ID | **示例请求**: ``` GET /recallTest/videoDetail?videoId=10086 ``` **Response**: `data` 为 `VideoBasicVO`: ```json { "code": 0, "msg": "success", "data": { "videoId": 10086, "title": "2025春季妆容教程", "videoUrl": "https://example.com/video/10086.mp4", "cover": "https://example.com/cover/10086.jpg", "playCount": "--" } } ``` **VideoBasicVO 字段说明**: | 字段 | 类型 | 说明 | |---|---|---| | `videoId` | `Long` | 视频ID | | `title` | `String` | 视频标题 | | `videoUrl` | `String` | 视频播放地址 | | `cover` | `String` | 封面图URL | | `playCount` | `String` | 播放量。长视频API当前不返回播放量,值为 `"--"` | --- ### 2.2 文本召回 (Tab2) ``` POST /recallTest/matchByText ``` **用途**: 输入自由文本,在向量库中检索语义最相似的 Top-N 个视频/素材/长文。 **Request Body** (`application/json`): | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `queryText` | `String` | 是 | 查询文本,将向量化后在指定维度检索 | | `configCode` | `String` | 否 | 向量配置编码,不传默认 `VIDEO_TOPIC`。支持: `VIDEO_TOPIC` / `VIDEO_INSPIRATION` | | `topN` | `Integer` | 否 | 返回 Top-N 结果,默认 `10` | **Request 示例**: ```json { "queryText": "美妆护肤教程", "configCode": "VIDEO_TOPIC", "topN": 20 } ``` **Response**: `data` 为 `RecallResultVO`: ```json { "code": 0, "msg": "success", "data": { "items": [ { "id": 10001, "modality": "VIDEO", "configCode": "VIDEO_TOPIC", "score": 0.9523, "title": "春季护肤全攻略", "cover": "https://example.com/cover/10001.jpg", "videoUrl": "https://example.com/video/10001.mp4", "imageList": null, "bodyText": null, "playCount": "--", "exposure": "--", "ctr": "--", "readCount": "--", "rov": "--", "text": "美妆护肤教程 春季妆容", "videoDetail": { "topic": "护肤教程", "灵感点": "产品成分解析", "灵感点-实质": [ { "word": "成分", "score": 0.92 } ], "关键点": "敏感肌适用", "关键点-实质": [ { "word": "敏感肌", "score": 0.89 } ], "目的点": "提升转化", "目的点-实质": [ { "word": "购买", "score": 0.87 } ] } }, { "id": 20005, "modality": "MATERIAL", "configCode": "VIDEO_TOPIC", "score": 0.8912, "title": "护肤品种草图文", "cover": "https://example.com/cover/20005.jpg", "videoUrl": null, "imageList": ["https://example.com/material/20005_1.jpg", "https://example.com/material/20005_2.jpg"], "bodyText": null, "playCount": "--", "exposure": "--", "ctr": "--", "readCount": "--", "rov": "--", "text": "护肤品种草推荐", "videoDetail": { } } ], "videoCount": 1, "materialCount": 1, "articleCount": 0, "total": 2 } } ``` **RecallResultVO 字段说明**: | 字段 | 类型 | 说明 | |---|---|---| | `items` | `List` | 召回结果列表(已 enrich,含模态信息) | | `videoCount` | `int` | 命中视频数量 | | `materialCount` | `int` | 命中素材(图文)数量 | | `articleCount` | `int` | 命中长文数量 | | `total` | `int` | 总召回条数 | **VideoMatchEnrichedVO 单条结果字段说明**: | 字段 | 类型 | 说明 | |---|---|---| | `id` | `Long` | 业务ID。视频时 = `wx_video.id`,素材时 = `channelContentId` 数值化 | | `modality` | `Modality` 枚举 | 模态类型: `VIDEO` / `MATERIAL` / `ARTICLE` | | `configCode` | `String` | 命中的向量配置编码 | | `score` | `Double` | 余弦相似度分值(0~1) | | `title` | `String` | 标题 | | `cover` | `String` | 封面/缩略图URL | | `videoUrl` | `String` | 视频播放地址(仅 `modality=VIDEO` 时有值,其余为 `null`) | | `imageList` | `List` | 图片列表(仅 `modality=MATERIAL` 时有值,其余为 `null`) | | `bodyText` | `String` | 正文(仅 `modality=ARTICLE` 时有值,其余为 `null`) | | `playCount` | `String` | 播放量,默认 `"--"` | | `exposure` | `String` | 曝光量,默认 `"--"` | | `ctr` | `String` | CTR,默认 `"--"` | | `readCount` | `String` | 阅读数,默认 `"--"` | | `rov` | `String` | ROV,默认 `"--"` | | `text` | `String` | 向量化原文 | | `videoDetail` | `Map` | 视频解构详情 KV(来源 Redis `recall:vid_decode:{vid}`),含 topic、灵感点、关键点、目的点及其"实质-分词" | **Modality 枚举映射**: | 枚举值 | 对应 content_type | 说明 | |---|---|---| | `VIDEO` | `3` | 视频 | | `MATERIAL` | `2` | 图文素材 | | `ARTICLE` | `1` | 长文 | > `content_type` 缺省或未知时默认按 `VIDEO` 处理。 --- ### 2.3 获取视频解构层级 (Tab1 解构树) ``` GET /recallTest/deconstructPoints ``` **用途**: 获取视频的解构层级数据(选题 + 高价值点),用于前端解构树组件递归渲染。数据来源: Singapore RDS → Python 解析筛选 → 国内 Redis。 **Query Parameters**: | 参数 | 类型 | 必填 | 说明 | |---|---|---|---| | `videoId` | `Long` | 是 | 视频ID/素材ID | **示例请求**: ``` GET /recallTest/deconstructPoints?videoId=10086 ``` **Response**: `data` 为 `DeconstructPointsVO`: ```json { "code": 0, "msg": "success", "data": { "vid": 10086, "title": "2025春季妆容教程", "videoUrl": "https://example.com/video/10086.mp4", "htmlUrl": "https://example.com/viz/10086.html", "topic": "美妆教程-春季妆容", "highValuePoints": [ { "id": "inspiration_1", "type": "灵感点", "name": "春季流行色系运用", "essences": [ { "word": "春季", "score": 0.95 }, { "word": "色系", "score": 0.91 }, { "word": "流行", "score": 0.86 } ] }, { "id": "kp_abc123", "type": "关键点", "name": "底妆持久度关键步骤", "essences": [ { "word": "持久", "score": 0.93 }, { "word": "底妆", "score": 0.88 } ] }, { "id": "purpose_1", "type": "目的点", "name": "提升完播率与互动", "essences": [ { "word": "完播", "score": 0.82 }, { "word": "互动", "score": 0.80 } ] } ] } } ``` **DeconstructPointsVO 字段说明**: | 字段 | 类型 | 说明 | |---|---|---| | `vid` | `Long` | 视频ID | | `title` | `String` | 视频标题 | | `videoUrl` | `String` | 视频播放地址 | | `htmlUrl` | `String` | 带权重的可视化页面URL | | `topic` | `String` | 最终选题(格式: `最终选题.选题`) | | `highValuePoints` | `List` | 实质≥0.8 的高价值解构点列表 | **HighValuePoint 子结构**: | 字段 | 类型 | 说明 | |---|---|---| | `id` | `String` | 业务侧ID,格式如 `inspiration_1` / `purpose_1` / `kp_xxxxxx` | | `type` | `String` | 点类型: `灵感点` / `目的点` / `关键点` | | `name` | `String` | 该点的描述名称 | | `essences` | `List` | 拆解出的"实质"分词列表(score ≥ 0.8) | **EssenceWord 子结构**: | 字段 | 类型 | 说明 | |---|---|---| | `word` | `String` | 实质词 | | `score` | `Double` | 词级贡献度(0~1,越大越重要) | --- ### 2.4 按视频ID召回相似内容 (Tab1 解构节点点击触发) ``` POST /recallTest/matchByVideoId ``` **用途**: 以指定视频/素材为参考,召回与之在指定维度(选题/灵感点)上最相似的内容。典型场景: 用户在解构树上看到某个节点,点击后查询与该节点对应的高价值点相似的内容。 **Request Body** (`application/json`): | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `videoId` | `Long` | 是 | 视频ID 或 `channelContentId` 数值化后的值 | | `configCode` | `String` | 否 | 向量配置编码,不传默认 `VIDEO_TOPIC`。支持: `VIDEO_TOPIC` / `VIDEO_INSPIRATION` | | `topN` | `Integer` | 否 | 返回 Top-N 结果,默认 `10` | **Request 示例**: ```json { "videoId": 10086, "configCode": "VIDEO_INSPIRATION", "topN": 15 } ``` **Response**: `data` 为 `RecallResultVO`,结构与 2.2 接口完全一致。 --- ### 2.5 获取视频AI理解结果 (Tab1) ``` GET /recallTest/aiUnderstanding ``` **用途**: 获取视频的 AI 理解结果(选题、主题、关键词、口播文案等)。数据来源: ODPS `loghubods.result_log` → DataWorks 同步 Job → 本地表 `video_ai_understanding`。 > **重要**: MVP 阶段本地表可能为空,此时 `data` 的 field 全部为 `null`,前端需展示"AI理解数据未就绪,等待同步Job"。**严禁后端伪造任何字段返回值。** **Query Parameters**: | 参数 | 类型 | 必填 | 说明 | |---|---|---|---| | `videoId` | `Long` | 是 | 视频ID | **示例请求**: ``` GET /recallTest/aiUnderstanding?videoId=10086 ``` **Response (数据就绪时)**: `data` 为 `AIUnderstandingVO`: ```json { "code": 0, "msg": "success", "data": { "videoId": 10086, "contentTopic": "美妆护肤", "videoTheme": "春季妆容教程", "videoKeywords": "春季,妆容,护肤,教程", "videoNarration": "大家好,今天我们来分享一款春季日常妆容...", "dt": "2026050712" } } ``` **Response (数据未就绪时)**: ```json { "code": 0, "msg": "success", "data": null } ``` > 前端在收到 `data == null` 时应展示"AI理解数据未就绪"占位状态,不可报错。 **AIUnderstandingVO 字段说明**: | 字段 | 类型 | 说明 | |---|---|---| | `videoId` | `Long` | 视频ID | | `contentTopic` | `String` | 内容选题(AI识别) | | `videoTheme` | `String` | 视频主题 | | `videoKeywords` | `String` | 视频关键词(逗号分隔) | | `videoNarration` | `String` | 视频口播文案(ASR识别文本) | | `dt` | `String` | 数据所属分区,格式 `yyyyMMddHH`(如 `2026050712` 表示 2026-05-07 12时) | --- ## 三、MaterialController (`/material`) 素材向量化搜索接口。支持素材入库(解构 + 异步向量化)和相似素材搜索。 ### 3.1 素材入库 ``` POST /material/submit ``` **用途**: 提交素材进行解构和异步向量化入库。 **Request Body** (`application/json`): | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `channelContentId` | `String` | 否 | 素材业务ID | | `contentType` | `Integer` | 否 | 内容类型: `1` = 长文, `2` = 图文, `3` = 视频 | | `title` | `String` | 否 | 素材标题 | | `bodyText` | `String` | 否 | 素材正文/描述 | | `videoUrl` | `String` | 否 | 视频地址(可选) | | `imageList` | `List` | 否 | 图片列表(可选) | | `channelAccountId` | `String` | 否 | 作者ID(可选) | | `channelAccountName` | `String` | 否 | 作者名称(可选) | **Request 示例**: ```json { "channelContentId": "mat_001", "contentType": 2, "title": "护肤品图文种草素材", "bodyText": "这款精华液含有烟酰胺成分...", "imageList": ["https://example.com/img1.jpg", "https://example.com/img2.jpg"], "channelAccountId": "author_001", "channelAccountName": "护肤小达人" } ``` **Response**: `data` 为 `String`,返回任务唯一标识: ```json { "code": 0, "msg": "success", "data": "" } ``` --- ### 3.2 素材相似搜索 ``` POST /material/matchTopN ``` **用途**: 在素材向量库中检索语义最相似的 Top-N 个素材。 **Request Body** (`application/json`): | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `queryText` | `String` | 否 | 查询文本,将被向量化后检索 | | `queryVector` | `List` | 否 | 直接传入查询向量,优先级高于 `queryText` | | `channelContentId` | `String` | 否 | 业务内容ID,用于复用历史向量(可选) | | `configCode` | `String` | 否 | 配置编码。传 `ALL` 可搜索所有启用的配置维度 | | `topN` | `Integer` | 否 | 返回 Top-N 结果,默认 `10` | **Request 示例**: ```json { "queryText": "烟酰胺精华液功效", "configCode": "ALL", "topN": 10 } ``` **Response**: `data` 为 `List`: ```json { "code": 0, "msg": "success", "data": [ { "configCode": "VIDEO_TOPIC", "contentId": 20001, "channelContentId": "mat_005", "score": 0.9213, "title": "烟酰胺美白精华种草", "sourceText": "烟酰胺是一种高效美白成分..." } ] } ``` **MaterialMatchResult 字段说明**: | 字段 | 类型 | 说明 | |---|---|---| | `configCode` | `String` | 命中的配置编码 | | `contentId` | `Long` | deconstruct_content.id | | `channelContentId` | `String` | 素材业务ID | | `score` | `Double` | 余弦相似度分值(0~1) | | `title` | `String` | 素材标题 | | `sourceText` | `String` | 命中的向量原文 | --- ## 四、FileController (`/file`) OSS 文件上传与签名接口。所有端点均配置 `@CrossOrigin(origins = "*")`。 ### 4.1 文件上传 ``` POST /file/upload ``` **用途**: 上传文件到阿里云 OSS。 **Request**: `multipart/form-data` | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `file` | `MultipartFile` | 是 | 上传的文件 | | `fileUri` | `String` | 否 | 文件存储路径。不传则自动生成 `video-vector/{timestamp}_{random}.{ext}` | | `fileType` | `EnumFileType` | 是 | 文件类型枚举 | **Response**: `data` 为 `FileInfo`: ```json { "code": 0, "msg": "success", "data": { "fileName": "example.jpg", "fileUrl": "https://bucket.oss-cn-hangzhou.aliyuncs.com/video-vector/123456_abc.jpg", "fileSize": 102400.0 } } ``` **FileInfo 字段说明**: | 字段 | 类型 | 说明 | |---|---|---| | `fileName` | `String` | 文件名 | | `fileUrl` | `String` | 文件访问URL | | `fileSize` | `Double` | 文件大小(字节) | --- ### 4.2 获取OSS上传签名 ``` POST /file/signature ``` **用途**: 获取阿里云 OSS 上传策略签名,供前端直传 OSS 使用。 **Request Body** (`application/json`): | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `fileType` | `Integer` | 是 | 文件类型: `1` = 图片, `2` = 视频, `3` = 音频, `4` = 文件, `5` = GIF, `6` = 字幕 | > 该参数继承自 `VideoApiBaseParam`,包含大量通用参数(laginUid, token, versionCode 等),此处仅列出必填的 `fileType`。 **Request 示例**: ```json { "fileType": 1 } ``` **Response**: `data` 为 `SignatureVO`: ```json { "code": 0, "msg": "success", "data": { "accessId": "LTAI5xxx", "policy": "eyJleHBpcmF0aW9uIjo...", "signature": "abc123...", "fileName": "video-vector/abc.jpg", "host": "https://bucket.oss-cn-hangzhou.aliyuncs.com", "expire": "2026-05-09T12:00:00Z" } } ``` **SignatureVO 字段说明**: | 字段 | 类型 | 说明 | |---|---|---| | `accessId` | `String` | OSS AccessKeyId | | `policy` | `String` | Base64 编码的上传策略 | | `signature` | `String` | 策略签名 | | `fileName` | `String` | 随机生成的文件名 | | `host` | `String` | OSS Bucket 域名 | | `expire` | `String` | 签名过期时间 | --- ### 4.3 获取STS临时令牌 ``` POST /file/getTempStsToken ``` **用途**: 获取阿里云 STS 临时访问令牌,有效期为 15 分钟。用于前端安全直传 OSS,降低安全风险。 **Request Body** (`application/json`): | 字段 | 类型 | 必填 | 说明 | |---|---|---|---| | `fileType` | `Integer` | 是 | 文件类型: `1` = 图片, `2` = 视频, `3` = 音频, `4` = 文件, `5` = GIF, `6` = 字幕 | | `uploadId` | `String` | 否 | 上传ID | > 该参数继承自 `VideoApiBaseParam`,包含大量通用参数,此处仅列出业务参数。 **Request 示例**: ```json { "fileType": 2, "uploadId": "upload_001" } ``` **Response**: `data` 为 `StsTokenVO`: ```json { "code": 0, "msg": "success", "data": { "Expiration": "2026-05-09T10:15:00Z", "AccessKeyId": "STS.xxx", "AccessKeySecret": "yyy", "SecurityToken": "zzz", "RequestId": "req-001", "FileName": "video-vector/123456_abc.mp4", "Host": "https://bucket.oss-cn-hangzhou.aliyuncs.com", "Hosts": ["https://bucket.oss-cn-hangzhou.aliyuncs.com"], "Bucket": "bucket-name", "Region": "oss-cn-hangzhou", "Cname": false, "serverTimestamp": 1746782100000 } } ``` **StsTokenVO 字段说明**: | 字段 | 类型 | 说明 | |---|---|---| | `Expiration` | `String` | 令牌过期时间 | | `AccessKeyId` | `String` | STS AccessKeyId | | `AccessKeySecret` | `String` | STS AccessKeySecret | | `SecurityToken` | `String` | STS 安全令牌 | | `RequestId` | `String` | 请求ID | | `FileName` | `String` | 随机生成的文件名 | | `Host` | `String` | OSS Bucket 域名 | | `Hosts` | `String[]` | OSS Bucket 域名列表 | | `Bucket` | `String` | OSS Bucket 名称 | | `Region` | `String` | OSS 区域 | | `Cname` | `Boolean` | 是否使用 CNAME | | `serverTimestamp` | `Long` | 服务器时间戳(毫秒) | --- ## 五、HealthController (`/`) ### 5.1 健康检查 ``` GET /healthcheck ``` **用途**: 服务探活端点,用于负载均衡/容器编排的健康检查。 **请求参数**: 无。 **示例请求**: ``` GET /healthcheck ``` **Response**: 返回纯文本 `ok` (非 `CommonResponse` 包装): ``` ok ``` --- ## 六、XxlJobController (`/job`) 定时任务触发器,供 XXL-Job 调度中心回调。所有接口无请求参数,返回 `CommonResponse`。 ### 6.1 视频向量化任务 ``` GET /job/vectorVideoJob ``` **用途**: 触发视频向量化任务。 ### 6.2 AIGC视频向量化任务 ``` GET /job/aigcVideoVectorJob ``` **用途**: 触发 AIGC 视频向量化任务。 ### 6.3 结果日志视频向量化任务 ``` GET /job/resultLogVideoVectorJob ``` **用途**: 触发结果日志视频向量化任务。 ### 6.4 全量视频向量化任务 ``` GET /job/allVideoVectorJob ``` **用途**: 触发全量视频向量化任务。 ### 6.5 重试解构任务 ``` GET /job/retryDeconstructJob ``` **用途**: 重试失败的解构任务。 ### 6.6 检查素材解构任务 ``` GET /job/checkMaterialDeconstructJob ``` **用途**: 触发素材解构状态检查。 ### 6.7 素材向量化任务 ``` GET /job/vectorMaterialJob ``` **用途**: 触发素材向量化任务。 ### 6.8 同步视频详情任务 ``` GET /job/syncVideoDetailJob ``` **用途**: 触发视频详情同步任务(从外部数据源同步至本地)。 ### 6.9 视频标题向量化任务 ``` GET /job/videoTitleVectorJob ``` **用途**: 触发视频标题向量化任务。 ### 6.10 同步AI理解数据任务 ``` GET /job/syncAiUnderstandingJob ``` **用途**: 触发 AI 理解数据同步任务(从 ODPS → DataWorks → 本地表)。 ### 6.11 渠道需求匹配任务 ``` GET /job/channelDemandMatchJob ``` **用途**: 触发渠道需求匹配计算任务。 --- ## 七、数据流与架构说明 ### 解构数据管线的来源链路 ``` Singapore RDS (aigc_topic_decode_task_result) → Python 解析脚本(筛选实质 ≥ 0.8 的高价值点) → 国内 Redis (key: recall:vid_decode:{vid}) → Java 后端 (DeconstructPointsVO / VideoMatchResult) → 前端渲染 ``` ### 向量召回流程 ``` 输入(queryText / videoId / channelContentId) → 获取或计算查询向量 → Milvus/ES 向量检索 (按 configCode 指定维度) → 返回 Top-N 候选 vid → enrich: 从 Redis recall:vid_decode:{vid} 读取解构详情 → 组装 RecallResultVO / VideoMatchResult 返回 ``` ### AI理解数据链路 ``` ODPS (loghubods.result_log) → DataWorks 同步 Job → 本地 MySQL (video_ai_understanding 表) → Java 后端查询 → 前端渲染 ``` --- ## 八、接口总览表 | 接口 | Method | 路径 | 说明 | |---|---|---|---| | 触发内容解构 | `POST` | `/videoSearch/deconstruct` | 发起AI解构任务,返回 taskId | | 查询解构结果 | `POST` | `/videoSearch/getDeconstructResult` | 按 taskId/channelContentId 查结果 | | 按内容ID查解构 | `GET` | `/videoSearch/getDeconstructResultByChannelContentId` | 简化查询,仅需 channelContentId | | 查询解构结果(精简版) | `POST` | `/videoSearch/getDeconstructResultMini` | 返回精简后的解构结果 | | 相似视频匹配 | `POST` | `/videoSearch/matchTopNVideo` | Top-N 向量召回相似视频 | | 召回并综合评分 | `POST` | `/videoSearch/recallWithScore` | 召回后按 sim + rov 综合分排序 | | 查询渠道需求匹配 | `POST` | `/videoSearch/queryDemandMatchResult` | 按日期/渠道/维度查询匹配视频 | | 获取所有配置码 | `GET` | `/videoSearch/getAllConfigCodes` | 查询支持的向量配置维度 | | 视频基础详情 | `GET` | `/recallTest/videoDetail` | 查单视频基础信息(Tab1) | | 文本召回 | `POST` | `/recallTest/matchByText` | 自由文本语义检索(Tab2) | | 解构层级 | `GET` | `/recallTest/deconstructPoints` | 视频解构树数据(Tab1) | | 按视频ID召回 | `POST` | `/recallTest/matchByVideoId` | 相似视频召回(Tab1节点触发) | | AI理解结果 | `GET` | `/recallTest/aiUnderstanding` | 视频AI理解数据(Tab1) | | 素材入库 | `POST` | `/material/submit` | 提交素材进行解构+向量化 | | 素材相似搜索 | `POST` | `/material/matchTopN` | 检索相似素材 | | 文件上传 | `POST` | `/file/upload` | 上传文件至阿里云OSS | | 获取OSS签名 | `POST` | `/file/signature` | 获取OSS上传策略签名 | | 获取STS令牌 | `POST` | `/file/getTempStsToken` | 获取STS临时访问令牌(15min) | | 健康检查 | `GET` | `/healthcheck` | 服务探活,返回 "ok" | | 视频向量化Job | `GET` | `/job/vectorVideoJob` | 触发视频向量化任务 | | AIGC视频向量化Job | `GET` | `/job/aigcVideoVectorJob` | 触发AIGC视频向量化 | | 结果日志向量化Job | `GET` | `/job/resultLogVideoVectorJob` | 触发结果日志向量化 | | 全量向量化Job | `GET` | `/job/allVideoVectorJob` | 触发全量视频向量化 | | 重试解构Job | `GET` | `/job/retryDeconstructJob` | 重试失败解构任务 | | 素材解构检查Job | `GET` | `/job/checkMaterialDeconstructJob` | 检查素材解构状态 | | 素材向量化Job | `GET` | `/job/vectorMaterialJob` | 触发素材向量化 | | 同步视频详情Job | `GET` | `/job/syncVideoDetailJob` | 同步视频详情数据 | | 标题向量化Job | `GET` | `/job/videoTitleVectorJob` | 触发标题向量化 | | 同步AI理解Job | `GET` | `/job/syncAiUnderstandingJob` | 同步AI理解数据 | | 渠道需求匹配Job | `GET` | `/job/channelDemandMatchJob` | 触发渠道需求匹配计算 | --- ## 九、错误状态码 | code | 含义 | 典型场景 | |---|---|---| | `0` | 成功 | — | | 非 `0` | 业务异常 | 参数校验失败、向量库不可用、查询超时等,具体 `msg` 字段会描述原因 |