fix(voices): 配音素材上传卡「处理中…」修复
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m1s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m5s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m30s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m45s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m51s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m54s
AI Code Review / AI Code Review (pull_request) Failing after 5m57s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Failing after 411h53m4s
CI/CD Pipeline / PR Build API Image (pull_request) Failing after 411h53m21s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 411h53m58s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 411h58m45s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 411h58m45s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 411h58m47s
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Failing after 411h58m49s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Failing after 411h58m49s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 411h58m51s
CI/CD Pipeline / Check push changed paths (pull_request) Failing after 411h58m53s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 411h58m51s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 412h32m52s
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Failing after 412h32m56s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 412h32m58s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (pull_request) Successful in 1s
CI/CD Pipeline / Check if frontend-only change (pull_request) Successful in 4m1s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 4m5s
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 4m30s
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 4m45s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Successful in 4m51s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 5m54s
AI Code Review / AI Code Review (pull_request) Failing after 5m57s
CI/CD Pipeline / Validate - Code Quality (pull_request) Has been cancelled
CI/CD Pipeline / Integration Tests (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Lint (pull_request) Has been cancelled
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production API Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Web Image (pull_request) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been cancelled
CI/CD Pipeline / Deploy Production (pull_request) Has been cancelled
CI/CD Pipeline / Production Browser E2E (pull_request) Has been cancelled
CI/CD Pipeline / Canary Release to Production (pull_request) Has been cancelled
CI/CD Pipeline / CI Gate (pull_request) Has been cancelled
CI/CD Pipeline / PR Build Worker Image (pull_request) Failing after 411h53m4s
CI/CD Pipeline / PR Build API Image (pull_request) Failing after 411h53m21s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 411h53m58s
CI/CD Pipeline / ACR Image Cleanup (pull_request) Failing after 411h58m45s
CI/CD Pipeline / Staging E2E Tests (pull_request) Failing after 411h58m45s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 411h58m47s
CI/CD Pipeline / Retag skipped Staging Web Image (pull_request) Failing after 411h58m49s
CI/CD Pipeline / Retag skipped Staging API Image (pull_request) Failing after 411h58m49s
CI/CD Pipeline / Build Staging Worker Image (pull_request) Failing after 411h58m51s
CI/CD Pipeline / Check push changed paths (pull_request) Failing after 411h58m53s
CI/CD Pipeline / Build Staging Web Image (pull_request) Failing after 411h58m51s
CI/CD Pipeline / Staging API Integration Tests (pull_request) Failing after 412h32m52s
CI/CD Pipeline / Retag skipped Staging Worker Image (pull_request) Failing after 412h32m56s
CI/CD Pipeline / Build Staging API Image (pull_request) Failing after 412h32m58s
- 轮询成功状态从 'ready' 改为 'completed'('ready' 是 voice-clones 状态,误用)
- 去重命中分支:complete 接口返回 duplicated=true 或 ingest_job_id 为空时,
不轮询直接按上传成功处理(刷新列表、关闭弹窗)
- 轮询优化:complete 后立即查第一次(后端通常 <1s 处理完),未完成再每 5s 轮询
- 两个上传 hook 同步修改:
- pages/voices/hooks/useVoiceUpload.ts(旧配音库页)
- pages/voice-materials/hooks/useVoiceMaterials/actions/useVoiceUpload.ts
(新配音库页;去重命中时跳过轮询和打标签)
- api/assets/types.ts 的 DirectUploadCompleteResult 补充 duplicated/asset_id 字段
This commit is contained in:
@@ -140,4 +140,8 @@ export interface DirectUploadCompleteResult {
|
||||
storage_key: string
|
||||
ingest_job_id: string
|
||||
url: string
|
||||
/** 同库已存在相同 file_hash 的素材时为 true,ingest_job_id 为空 */
|
||||
duplicated?: boolean
|
||||
/** duplicated 为 true 时返回已存在素材的 id */
|
||||
asset_id?: string
|
||||
}
|
||||
|
||||
+12
-5
@@ -48,20 +48,27 @@ export function useVoiceUpload({ voiceLibrary, createLibMutation }: UseVoiceUplo
|
||||
}
|
||||
|
||||
// 2. 上传文件(带进度,后端自动创建 ingest job)
|
||||
const { ingest_job_id } = await uploadAssetDirect({
|
||||
const complete = await uploadAssetDirect({
|
||||
file: data.file,
|
||||
library_id: lib.id,
|
||||
onProgress: (p) => setUploadProgress(p),
|
||||
})
|
||||
|
||||
// 3. 轮询 ingest job 状态
|
||||
// 去重命中(同库已存在相同 file_hash 素材):
|
||||
// 后端返回 duplicated=true 且 ingest_job_id 为空;跳过轮询和打标签,直接走 onSuccess
|
||||
if (complete.duplicated === true || !complete.ingest_job_id) {
|
||||
return
|
||||
}
|
||||
const { ingest_job_id } = complete
|
||||
|
||||
// 3. 轮询 ingest job 状态(complete 后先立即查一次,未完成再每 5s 轮询)
|
||||
let job: Awaited<ReturnType<typeof getIngestJob>> | null = null
|
||||
let retries = 0
|
||||
const maxRetries = 60 // 最多等待 5 分钟
|
||||
while (retries < maxRetries) {
|
||||
job = await getIngestJob(ingest_job_id)
|
||||
while (job.status !== "completed" && job.status !== "failed" && retries < maxRetries) {
|
||||
await new Promise((r) => setTimeout(r, 5000))
|
||||
job = await getIngestJob(ingest_job_id)
|
||||
if (job.status === "completed" || job.status === "failed") break
|
||||
retries++
|
||||
}
|
||||
|
||||
@@ -72,7 +79,7 @@ export function useVoiceUpload({ voiceLibrary, createLibMutation }: UseVoiceUplo
|
||||
throw new Error("音频处理超时,请稍后在素材库查看")
|
||||
}
|
||||
|
||||
// 4. 打标签(标签走独立 API)
|
||||
// 4. 打标签(标签走独立 API;去重命中时已提前 return,这里只对新创建的素材执行)
|
||||
if (data.tagIds.length > 0 && job.result_asset_id) {
|
||||
await tagAsset(job.result_asset_id, data.tagIds)
|
||||
}
|
||||
|
||||
@@ -32,24 +32,35 @@ export function useVoiceUpload({ showToast }: UseVoiceUploadProps) {
|
||||
if (!lib) throw new Error("配音库不存在,请先在配音库页面创建")
|
||||
|
||||
/* 直传文件(后端会自动创建 ingest job) */
|
||||
const { ingest_job_id } = await uploadAssetDirect({
|
||||
const complete = await uploadAssetDirect({
|
||||
file: data.file,
|
||||
library_id: lib.id,
|
||||
onProgress: (p) => setUploadProgress(p),
|
||||
})
|
||||
|
||||
/* 轮询 ingest job 状态,等待 Worker 处理完成 */
|
||||
let jobStatus = ""
|
||||
/* 去重命中(同库已存在相同 file_hash 素材):
|
||||
* 后端返回 duplicated=true 且 ingest_job_id 为空,
|
||||
* 不轮询、直接按上传成功处理(onSuccess 分支 toast + 刷新列表)
|
||||
*/
|
||||
if (complete.duplicated === true || !complete.ingest_job_id) {
|
||||
return
|
||||
}
|
||||
const { ingest_job_id } = complete
|
||||
|
||||
/* 轮询 ingest job 状态,等待 Worker 处理完成;
|
||||
* complete 后先立即查一次(后端通常不到 1s 处理完),未完成再每 5s 轮询。
|
||||
* 成功状态为 IngestJobStatus.completed;"ready" 是 voice-clones 的状态,此处误用需避免。
|
||||
*/
|
||||
let job = await getIngestJob(ingest_job_id)
|
||||
let retries = 0
|
||||
const maxRetries = 60 // 最多等待 5 分钟(60 * 5秒)
|
||||
while (jobStatus !== "ready" && jobStatus !== "failed" && retries < maxRetries) {
|
||||
while (job.status !== "completed" && job.status !== "failed" && retries < maxRetries) {
|
||||
await new Promise((r) => setTimeout(r, 5000))
|
||||
const job = await getIngestJob(ingest_job_id)
|
||||
jobStatus = job.status
|
||||
job = await getIngestJob(ingest_job_id)
|
||||
retries++
|
||||
}
|
||||
|
||||
if (jobStatus === "failed") {
|
||||
if (job.status === "failed") {
|
||||
throw new Error("音频处理失败,请重试")
|
||||
}
|
||||
if (retries >= maxRetries) {
|
||||
|
||||
Reference in New Issue
Block a user