@@ -3,37 +3,37 @@ import path from 'path';
3
3
import { DpTaskState } from '@/backend/db/tables/dpTask' ;
4
4
import SrtUtil , { SrtLine } from '@/common/utils/SrtUtil' ;
5
5
import hash from 'object-hash' ;
6
- import { isErrorCancel } from '@/common/constants/error-constants' ;
7
6
import { inject , injectable } from 'inversify' ;
8
7
import DpTaskService from '../DpTaskService' ;
9
8
import TYPES from '@/backend/ioc/types' ;
10
9
import FfmpegService from '@/backend/services/FfmpegService' ;
11
10
import WhisperService from '@/backend/services/WhisperService' ;
12
11
import { TypeGuards } from '@/backend/utils/TypeGuards' ;
13
- import OpenAiWhisperRequest , { WhisperResponse } from '@/backend/objs/OpenAiWhisperRequest' ;
12
+ import OpenAiWhisperRequest from '@/backend/objs/OpenAiWhisperRequest' ;
14
13
import LocationService , { LocationType } from '@/backend/services/LocationService' ;
15
14
import dpLog from '@/backend/ioc/logger' ;
16
15
import { OpenAiService } from '@/backend/services/OpenAiService' ;
17
16
import { WaitLock } from '@/common/utils/Lock' ;
18
- import { SplitChunk , WhisperContext , WhisperContextSchema } from '@/common/types/video-info' ;
17
+ import { SplitChunk , WhisperContext , WhisperContextSchema , WhisperResponse } from '@/common/types/video-info' ;
19
18
import { ConfigTender } from '@/backend/objs/config-tender' ;
20
19
import FileUtil from '@/backend/utils/FileUtil' ;
21
- import { WhisperResponseFormatError } from '@/backend/errors/errors' ;
20
+ import { CancelByUserError , WhisperResponseFormatError } from '@/backend/errors/errors' ;
22
21
23
22
/**
24
23
* 将 Whisper 的 API 响应转换成 SRT 文件格式
25
24
*/
26
- function toSrt ( whisperResponses : WhisperResponse [ ] ) : string {
25
+ function toSrt ( chunks : SplitChunk [ ] ) : string {
27
26
// 按 offset 排序确保顺序正确
28
- whisperResponses . sort ( ( a , b ) => a . offset - b . offset ) ;
27
+ chunks . sort ( ( a , b ) => a . offset - b . offset ) ;
29
28
let counter = 1 ;
30
29
const lines : SrtLine [ ] = [ ] ;
31
- for ( const wr of whisperResponses ) {
32
- for ( const segment of wr . segments ) {
30
+ for ( const c of chunks ) {
31
+ const segments = c . response ?. segments ?? [ ] ;
32
+ for ( const segment of segments ) {
33
33
lines . push ( {
34
34
index : counter ,
35
- start : segment . start + wr . offset ,
36
- end : segment . end + wr . offset ,
35
+ start : segment . start + c . offset ,
36
+ end : segment . end + c . offset ,
37
37
contentEn : segment . text ,
38
38
contentZh : ''
39
39
} ) ;
@@ -106,6 +106,8 @@ class WhisperServiceImpl implements WhisperService {
106
106
const unfinishedChunks = context . chunks . filter ( chunk => ! chunk . response ) ;
107
107
if ( unfinishedChunks . length === 0 ) {
108
108
this . dpTaskService . finish ( taskId , { progress : '转录完成' } ) ;
109
+ context . state = 'done' ;
110
+ configTender . save ( context ) ;
109
111
return ;
110
112
}
111
113
@@ -118,14 +120,20 @@ class WhisperServiceImpl implements WhisperService {
118
120
119
121
try {
120
122
// 对所有分片并发执行转录
121
- await Promise . all ( context . chunks . map ( async ( chunk ) => {
123
+ const results = await Promise . allSettled ( context . chunks . map ( async ( chunk ) => {
122
124
// 如果该 chunk 已经有结果,则跳过
123
125
if ( chunk . response ) return ;
124
126
await this . whisperThreeTimes ( taskId , chunk ) ;
125
127
completedCount = context . chunks . filter ( chunk => chunk . response ) . length ;
126
128
const progress = Math . floor ( ( completedCount / context . chunks . length ) * 100 ) ;
127
129
this . dpTaskService . update ( { id : taskId , progress : `正在转录 ${ progress } %` } ) ;
128
130
} ) ) ;
131
+ // 检查是否有错误
132
+ for ( const result of results ) {
133
+ if ( result . status === 'rejected' ) {
134
+ throw result . reason ;
135
+ }
136
+ }
129
137
} finally {
130
138
// 保存当前状态
131
139
configTender . save ( context ) ;
@@ -134,17 +142,16 @@ class WhisperServiceImpl implements WhisperService {
134
142
// 整理结果,生成 SRT 文件
135
143
const srtName = filePath . replace ( path . extname ( filePath ) , '.srt' ) ;
136
144
dpLog . info ( `[WhisperService] Task ID: ${ taskId } - 生成 SRT 文件: ${ srtName } ` ) ;
137
- const whisperResponses = context . chunks . map ( chunk => chunk . response as WhisperResponse ) ;
138
- fs . writeFileSync ( srtName , toSrt ( whisperResponses ) ) ;
145
+ fs . writeFileSync ( srtName , toSrt ( context . chunks ) ) ;
139
146
140
147
// 完成任务,并保存状态
141
- context . state = 'processed ' ;
148
+ context . state = 'done ' ;
142
149
configTender . save ( context ) ;
143
150
this . dpTaskService . finish ( taskId , { progress : '转录完成' } ) ;
144
151
} catch ( error ) {
145
152
dpLog . error ( error ) ;
146
153
if ( ! ( error instanceof Error ) ) throw error ;
147
- const cancel = isErrorCancel ( error ) ;
154
+ const cancel = error instanceof CancelByUserError
148
155
this . dpTaskService . update ( {
149
156
id : taskId ,
150
157
status : cancel ? DpTaskState . CANCELLED : DpTaskState . FAILED ,
@@ -188,7 +195,7 @@ class WhisperServiceImpl implements WhisperService {
188
195
}
189
196
this . dpTaskService . registerTask ( taskId , req ) ;
190
197
const response = await req . invoke ( ) ;
191
- return { ...response , offset : chunk . offset } ;
198
+ return { ...response } ;
192
199
}
193
200
194
201
/**
0 commit comments