From 2706cfbb2f8e00bcbbf1ae252cece11442bb691b Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Wed, 5 Aug 2026 00:00:03 +0800 Subject: [PATCH 01/22] feat: add smartMatchAssets API for Q5 smart match simplify --- apps/web/src/api/assets/assets.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/web/src/api/assets/assets.ts b/apps/web/src/api/assets/assets.ts index 902aface1..7899c643f 100644 --- a/apps/web/src/api/assets/assets.ts +++ b/apps/web/src/api/assets/assets.ts @@ -49,6 +49,19 @@ export const getAssetsByKind = async ( return response.data.items || [] } +/** + * 智能匹配素材(后端 AI 选素材) + * 调用后端 smart-match 端点,由后端根据素材库内容智能选择素材 + */ +export const smartMatchAssets = async ( + libraryId: string, +): Promise<{ items: AssetItem[] }> => { + const response = await apiClient.post("/assets/smart-match", { + library_id: libraryId, + }) + return response.data +} + /** 创建素材(上传文件后调用,附带 metadata) */ export const createAsset = async (data: { library_id: string @@ -85,3 +98,4 @@ export const updateAssetReviewStatus = async ( export const deleteAsset = async (assetId: string): Promise => { await apiClient.delete(`/assets/${assetId}`) } + -- 2.54.0 From 1609bdc7f4b03501a91682f92eab8dbe733a33d4 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Wed, 5 Aug 2026 00:00:19 +0800 Subject: [PATCH 02/22] feat: export smartMatchAssets --- apps/web/src/api/assets/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/web/src/api/assets/index.ts b/apps/web/src/api/assets/index.ts index a69db9a6c..6704fbfcc 100644 --- a/apps/web/src/api/assets/index.ts +++ b/apps/web/src/api/assets/index.ts @@ -29,10 +29,11 @@ export { deleteAssetLibrary, } from "./libraries" -// 素材 CRUD +// 素材 CRUD + 智能匹配 export { getAssets, getAssetsByKind, + smartMatchAssets, createAsset, updateAsset, updateAssetReviewStatus, @@ -53,3 +54,4 @@ export { batchClassifyAssets, batchMarkAssets, } from "./batch" + -- 2.54.0 From 774e6361d493293fa9a25f97b85400a67b361746 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Wed, 5 Aug 2026 00:00:46 +0800 Subject: [PATCH 03/22] feat: simplify useSmartMatch - one-click AI selection --- .../hooks/step2-materials/useSmartMatch.ts | 133 ++++++------------ 1 file changed, 46 insertions(+), 87 deletions(-) diff --git a/apps/web/src/pages/generate/hooks/step2-materials/useSmartMatch.ts b/apps/web/src/pages/generate/hooks/step2-materials/useSmartMatch.ts index 98bb0840f..5c1220f4c 100755 --- a/apps/web/src/pages/generate/hooks/step2-materials/useSmartMatch.ts +++ b/apps/web/src/pages/generate/hooks/step2-materials/useSmartMatch.ts @@ -1,75 +1,75 @@ -import { useState, useCallback, useMemo } from "react" +import { useState, useCallback } from "react" import { message } from "antd" import type { AssetItem } from "@/api/assets" -import { SMART_MATCH_REASONS } from "../../constants" - -interface SmartMatchedResult { - asset: AssetItem - matchScore: number - matchReason: string -} +import { smartMatchAssets, getAssets } from "@/api/assets" interface UseSmartMatchOptions { + libraryId: string materials: { items: AssetItem[]; total: number } smartSelectedIds: string[] onSmartSelectedIdsChange: (ids: string[]) => void } /** - * 智能素材匹配 Hook - * 封装 AI 匹配、换一批、全选/清空等逻辑 + * 智能素材匹配 Hook(Q5 简化版) + * 用户不手动选素材时,一键调用后端 AI 选素材 + * 后端统一选素材逻辑后续完善,当前先走前端流程简化 */ export function useSmartMatch({ + libraryId, materials, smartSelectedIds, onSmartSelectedIdsChange, }: UseSmartMatchOptions) { - const [smartMatchInput, setSmartMatchInput] = useState("") const [smartMatching, setSmartMatching] = useState(false) - const [smartMatchedResults, setSmartMatchedResults] = useState([]) const [hasMatched, setHasMatched] = useState(false) - /* ── 智能素材匹配 ── */ + /* ── 一键智能匹配 ── */ const handleSmartMatch = useCallback(async () => { - if (!smartMatchInput.trim()) { - message.warning("请先输入视频内容描述") - return - } if (materials.items.length === 0) { message.warning("当前视频库暂无素材") return } setSmartMatching(true) - setHasMatched(true) - // 模拟 AI 匹配延迟 - await new Promise((resolve) => setTimeout(resolve, 1500)) + try { + // 调用后端智能匹配 API + const result = await smartMatchAssets(libraryId) + const matchedIds = result.items.map((a: AssetItem) => a.id) - // 从素材库中随机选取 5-8 个作为推荐结果 - const shuffled = [...materials.items].sort(() => Math.random() - 0.5) - const count = Math.min(shuffled.length, 5 + Math.floor(Math.random() * 4)) - const picked = shuffled.slice(0, count) + if (matchedIds.length > 0) { + onSmartSelectedIdsChange(matchedIds) + setHasMatched(true) + message.success(`AI 已为你选择 ${matchedIds.length} 个素材`) + } else { + // 后端返回空结果,回退到全选 + onSmartSelectedIdsChange(materials.items.map((a) => a.id)) + setHasMatched(true) + message.info("AI 暂未找到匹配素材,已全选当前库素材") + } + } catch { + // 后端 API 尚未就绪时,回退到全选当前库素材 + onSmartSelectedIdsChange(materials.items.map((a) => a.id)) + setHasMatched(true) + message.info("已为你全选当前库素材(智能匹配功能即将上线)") + } finally { + setSmartMatching(false) + } + }, [libraryId, materials.items, onSmartSelectedIdsChange]) - const results = picked.map((asset, idx) => ({ - asset, - matchScore: Math.round(85 + Math.random() * 14), // 85-99 分 - matchReason: - SMART_MATCH_REASONS[idx % SMART_MATCH_REASONS.length] + - (Math.random() > 0.5 ? ",画面质感优秀" : ""), - })) + const handleRefreshMatch = useCallback(async () => { + // 换一批 = 重新触发智能匹配 + await handleSmartMatch() + }, [handleSmartMatch]) - // 按匹配度从高到低排序 - results.sort((a, b) => b.matchScore - a.matchScore) + const handleSelectAllMatched = useCallback(() => { + onSmartSelectedIdsChange(materials.items.map((a) => a.id)) + }, [materials.items, onSmartSelectedIdsChange]) - setSmartMatchedResults(results) - // 默认选中匹配度 >= 90 的素材 - const defaultSelected = results.filter((r) => r.matchScore >= 90).map((r) => r.asset.id) - onSmartSelectedIdsChange( - defaultSelected.length > 0 ? defaultSelected : results.slice(0, 3).map((r) => r.asset.id), - ) - setSmartMatching(false) - }, [smartMatchInput, materials.items, onSmartSelectedIdsChange]) + const handleClearSmartSelect = useCallback(() => { + onSmartSelectedIdsChange([]) + }, [onSmartSelectedIdsChange]) const handleToggleSmartSelect = useCallback( (assetId: string) => { @@ -82,55 +82,13 @@ export function useSmartMatch({ [smartSelectedIds, onSmartSelectedIdsChange], ) - const handleRefreshMatch = useCallback(async () => { - if (materials.items.length <= 5) { - message.info("视频库素材较少,无法换一批") - return - } - setSmartMatching(true) - await new Promise((resolve) => setTimeout(resolve, 800)) - - const remaining = materials.items.filter( - (m) => !smartMatchedResults.some((r) => r.asset.id === m.id), - ) - const shuffled = [...remaining].sort(() => Math.random() - 0.5) - const count = Math.min(shuffled.length, 5 + Math.floor(Math.random() * 3)) - const picked = shuffled.slice(0, count) - - const results = picked.map((asset, idx) => ({ - asset, - matchScore: Math.round(80 + Math.random() * 19), - matchReason: - SMART_MATCH_REASONS[(idx + 2) % SMART_MATCH_REASONS.length] + - (Math.random() > 0.5 ? ",节奏明快" : ""), - })) - results.sort((a, b) => b.matchScore - a.matchScore) - - setSmartMatchedResults(results) - onSmartSelectedIdsChange([]) - setSmartMatching(false) - }, [materials.items, smartMatchedResults, onSmartSelectedIdsChange]) - - const handleSelectAllMatched = useCallback(() => { - onSmartSelectedIdsChange(smartMatchedResults.map((r) => r.asset.id)) - }, [smartMatchedResults, onSmartSelectedIdsChange]) - - const handleClearSmartSelect = useCallback(() => { - onSmartSelectedIdsChange([]) - }, [onSmartSelectedIdsChange]) - - /* ── 计算已选智能匹配素材的总时长 ── */ - const smartSelectedTotalDuration = useMemo(() => { - return smartMatchedResults - .filter((r) => smartSelectedIds.includes(r.asset.id)) - .reduce((sum, r) => sum + (r.asset.duration || 0), 0) - }, [smartMatchedResults, smartSelectedIds]) + /* ── 计算已选素材总时长 ── */ + const smartSelectedTotalDuration = materials.items + .filter((a) => smartSelectedIds.includes(a.id)) + .reduce((sum, a) => sum + (a.duration || 0), 0) return { - smartMatchInput, - setSmartMatchInput, smartMatching, - smartMatchedResults, hasMatched, smartSelectedIds, handleSmartMatch, @@ -141,3 +99,4 @@ export function useSmartMatch({ smartSelectedTotalDuration, } } + -- 2.54.0 From 937b72bf3a992dc9bcaf03f4b5dc90ef3d3db38f Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Wed, 5 Aug 2026 00:01:09 +0800 Subject: [PATCH 04/22] feat: update useStep2Materials for simplified smart match --- apps/web/src/pages/generate/hooks/useStep2Materials.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/web/src/pages/generate/hooks/useStep2Materials.ts b/apps/web/src/pages/generate/hooks/useStep2Materials.ts index 3a07d95ef..5efa1dd8d 100755 --- a/apps/web/src/pages/generate/hooks/useStep2Materials.ts +++ b/apps/web/src/pages/generate/hooks/useStep2Materials.ts @@ -28,6 +28,7 @@ export function useStep2Materials({ useMaterialLibrary() const smartMatch = useSmartMatch({ + libraryId: selectedLibraryId, materials, smartSelectedIds, onSmartSelectedIdsChange, @@ -58,11 +59,8 @@ export function useStep2Materials({ // 手动选择 selectedMaterials, handleToggleMaterial, - // 智能匹配 - smartMatchInput: smartMatch.smartMatchInput, - setSmartMatchInput: smartMatch.setSmartMatchInput, + // 智能匹配(简化版) smartMatching: smartMatch.smartMatching, - smartMatchedResults: smartMatch.smartMatchedResults, hasMatched: smartMatch.hasMatched, smartSelectedIds: smartMatch.smartSelectedIds, handleSmartMatch: smartMatch.handleSmartMatch, @@ -77,3 +75,4 @@ export function useStep2Materials({ } export default useStep2Materials + -- 2.54.0 From 962bd60022570bb710c74d6c4ed9db910b215393 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Wed, 5 Aug 2026 00:01:27 +0800 Subject: [PATCH 05/22] feat: simplify SmartMatchInput - one-click AI selection --- .../components/material/SmartMatchInput.tsx | 39 +++++++------------ 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/apps/web/src/pages/generate/components/material/SmartMatchInput.tsx b/apps/web/src/pages/generate/components/material/SmartMatchInput.tsx index 4cb6be046..cd8135d4d 100644 --- a/apps/web/src/pages/generate/components/material/SmartMatchInput.tsx +++ b/apps/web/src/pages/generate/components/material/SmartMatchInput.tsx @@ -1,13 +1,11 @@ /** - * 智能匹配输入区 - * textarea + 提示 + 按钮组 + * 智能匹配操作区(Q5 简化版) + * 一键触发 AI 选素材,无需输入描述 */ import React from "react" -import { LoadingOutlined } from "@ant-design/icons" +import { LoadingOutlined, ThunderboltOutlined } from "@ant-design/icons" interface SmartMatchInputProps { - inputValue: string - onInputChange: (value: string) => void matching: boolean onMatch: () => void hasMatched: boolean @@ -17,8 +15,6 @@ interface SmartMatchInputProps { } const SmartMatchInput: React.FC = ({ - inputValue, - onInputChange, matching, onMatch, hasMatched, @@ -28,22 +24,11 @@ const SmartMatchInput: React.FC = ({ }) => { return (
- -