Files
xiaoxia-saas/apps/web/src/api/assets/assets.ts
T
xiaoxia ab23ca7e5a
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Frontend Unit Tests (push) Failing after 1s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 4s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 3m8s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 4m11s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 4m27s
CI/CD Pipeline / Check push changed paths (push) Successful in 5m48s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 7m22s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 8m11s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 1m31s
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 1m28s
AI Code Review / AI Code Review (pull_request) Failing after 8m31s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 9m2s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 1m47s
CI/CD Pipeline / CI Gate (pull_request) Successful in 2m27s
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Successful in 1m26s
CI/CD Pipeline / Retag skipped Staging API Image (push) Successful in 1m28s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m15s
CI/CD Pipeline / Integration Tests (push) Successful in 5m36s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m40s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m14s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 4m51s
CI/CD Pipeline / Unit Tests (push) Successful in 18m2s
CI/CD Pipeline / Production Browser E2E (push) Failing after 384h46m16s
CI/CD Pipeline / Deploy Production (push) Failing after 384h46m17s
CI/CD Pipeline / CI Gate (push) Failing after 384h46m18s
CI/CD Pipeline / Build Production Web Image (push) Failing after 384h46m18s
CI/CD Pipeline / Build Production API Image (push) Failing after 384h46m18s
CI/CD Pipeline / Retag skipped Staging Web Image (push) Failing after 384h54m4s
CI/CD Pipeline / Production Browser E2E (pull_request) Failing after 384h55m37s
CI/CD Pipeline / Deploy Production (pull_request) Failing after 384h55m39s
CI/CD Pipeline / Build Production Worker Image (pull_request) Failing after 384h55m41s
CI/CD Pipeline / Build Production API Image (pull_request) Failing after 384h55m41s
CI/CD Pipeline / Build Staging Worker Image (push) Failing after 384h55m53s
CI/CD Pipeline / PR Build Web Image (pull_request) Failing after 384h57m17s
CI/CD Pipeline / Build Staging API Image (push) Failing after 384h55m55s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 384h57m19s
CI/CD Pipeline / Frontend Lint (pull_request) Failing after 384h57m21s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 384h57m23s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 385h4m8s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 385h4m10s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 385h4m12s
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Failing after 385h4m12s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Failing after 385h4m14s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Failing after 385h4m14s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Failing after 385h4m16s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Failing after 385h4m16s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 385h4m18s
CI/CD Pipeline / Validate - Code Quality (pull_request) Failing after 385h4m16s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 385h4m18s
CI/CD Pipeline / Frontend Lint (push) Failing after 385h4m22s
CI/CD Pipeline / Check push changed paths (pull_request) Failing after 385h4m20s
CI/CD Pipeline / PR Build Web Image (push) Failing after 385h4m22s
CI/CD Pipeline / PR Build API Image (push) Failing after 385h4m22s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 385h4m24s
CI/CD Pipeline / Canary Release to Production (push) Failing after 385h20m28s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 385h20m29s
CI/CD Pipeline / Canary Release to Production (pull_request) Failing after 385h29m49s
CI/CD Pipeline / Build Production Web Image (pull_request) Failing after 385h29m52s
CI/CD Pipeline / Integration Tests (pull_request) Failing after 385h31m32s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 385h38m21s
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Failing after 385h38m25s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 385h38m29s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 385h38m33s
fix(assets): 智能选素材传 limit 参数,避免「有几个选几个」 (#1570)
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-08-31 14:21:00 +08:00

115 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 素材 CRUD API
*/
import apiClient from "../client"
import type { AssetItem, AssetMetadata } from "./types"
/** 获取素材库下的所有素材 */
export const getAssets = async (
libraryId: string,
options?: {
status?: string
page?: number
page_size?: number
},
): Promise<{ items: AssetItem[]; total: number }> => {
const params: Record<string, string | number> = { library_id: libraryId }
if (options?.status) params.status = options.status
if (options?.page) params.page = options.page
if (options?.page_size) params.page_size = options.page_size
const response = await apiClient.get("/assets", { params })
const data = response.data || {}
const items: AssetItem[] = data.items || []
const total: number = typeof data.total === "number" ? data.total : items.length
return { items, total }
}
/** 按类型获取素材(如 voice/video/image),支持可选筛选 */
export const getAssetsByKind = async (
kind: string,
filters?: {
keyword?: string
gender?: string
style?: string
tag_ids?: string[]
limit?: number
page?: number
page_size?: number
},
): Promise<AssetItem[]> => {
const params: Record<string, string | number> = { kind }
if (filters?.keyword) params.keyword = filters.keyword
if (filters?.gender) params.gender = filters.gender
if (filters?.style) params.style = filters.style
if (filters?.tag_ids?.length) params.tag_ids = filters.tag_ids.join(",")
if (filters?.limit) params.limit = filters.limit
if (filters?.page) params.page = filters.page
if (filters?.page_size) params.page_size = filters.page_size
const response = await apiClient.get("/assets", { params })
return response.data.items || []
}
/**
* 智能匹配素材(后端 AI 选素材)
* 调用后端 smart-match 端点,由后端根据素材库内容智能选择素材
*
* 后端返回 items 元素兼容两种结构(过渡期):
* - 扁平结构:AssetItem 本身(id 在顶层)
* - 包装结构:{ asset: AssetItem, score, breakdown }(id 需从 .asset 取)
* 这里统一归一化为 AssetItem[],调用方无需关心包装层。
*/
export interface SmartMatchResult {
items: AssetItem[]
}
interface SmartMatchWrappedItem {
asset?: AssetItem
id?: string
score?: number
breakdown?: unknown
}
export const smartMatchAssets = async (
libraryId: string,
limit?: number,
): Promise<SmartMatchResult> => {
const payload: Record<string, unknown> = { library_id: libraryId }
if (limit && limit > 0) payload.limit = limit
const response = await apiClient.post("/assets/smart-match", payload)
const rawItems: SmartMatchWrappedItem[] = response.data?.items ?? []
const items = rawItems
.map((it) =>
// 包装结构 { asset: {...} } 优先解包;否则视其本身为扁平 AssetItem
it?.asset && typeof it.asset === "object" && "id" in it.asset
? it.asset
: (it as unknown as AssetItem),
)
.filter((it): it is AssetItem => !!it && typeof it.id === "string" && it.id.length > 0)
return { items }
}
/** 更新素材(名称、metadata 等) */
export const updateAsset = async (
assetId: string,
data: { name?: string; metadata?: AssetMetadata },
): Promise<AssetItem> => {
const response = await apiClient.put(`/assets/${assetId}`, data)
return response.data
}
/** 更新素材审核状态 */
export const updateAssetReviewStatus = async (
assetId: string,
reviewStatus: "pending_review" | "approved" | "rejected",
): Promise<AssetItem> => {
const response = await apiClient.patch(`/assets/${assetId}/review`, {
review_status: reviewStatus,
})
return response.data
}
/** 删除素材 */
export const deleteAsset = async (assetId: string): Promise<void> => {
await apiClient.delete(`/assets/${assetId}`)
}