超时时间
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 1m7s
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 1m7s
This commit is contained in:
parent
04072dc94b
commit
e3c4b0f697
@ -13,6 +13,7 @@ import {
|
||||
resolveMiniMaxTtsConfig,
|
||||
} from './src/server/minimaxTts';
|
||||
import { generateSubtitlePipeline } from './src/server/subtitleGeneration';
|
||||
import { resolveLlmProviderConfig } from './src/server/llmProvider';
|
||||
import { parseSubtitleRequest } from './src/server/subtitleRequest';
|
||||
import {
|
||||
buildAssSubtitleContent,
|
||||
@ -262,6 +263,9 @@ async function startServer() {
|
||||
});
|
||||
|
||||
const { provider, targetLanguage, ttsLanguage, fileId } = parseSubtitleRequest(req.body);
|
||||
const providerConfig = resolveLlmProviderConfig(provider, process.env);
|
||||
const pollTimeoutMs =
|
||||
providerConfig.provider === 'doubao' ? providerConfig.timeoutMs : undefined;
|
||||
if (!videoPath && !fileId) {
|
||||
logEvent({
|
||||
level: 'warn',
|
||||
@ -286,6 +290,7 @@ async function startServer() {
|
||||
provider,
|
||||
targetLanguage,
|
||||
ttsLanguage,
|
||||
pollTimeoutMs,
|
||||
fileId,
|
||||
filePath: videoPath,
|
||||
});
|
||||
|
||||
@ -56,4 +56,18 @@ describe('subtitleJobs', () => {
|
||||
|
||||
expect(toSubtitleJobResponse(job)).not.toHaveProperty('filePath');
|
||||
});
|
||||
|
||||
it('includes poll timeout metadata in api responses when provided', () => {
|
||||
const store = createSubtitleJobStore();
|
||||
const job = createSubtitleJob(store, {
|
||||
requestId: 'req-1',
|
||||
provider: 'doubao',
|
||||
targetLanguage: 'English',
|
||||
pollTimeoutMs: 900000,
|
||||
});
|
||||
|
||||
expect(toSubtitleJobResponse(job)).toMatchObject({
|
||||
pollTimeoutMs: 900000,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -22,6 +22,7 @@ export interface SubtitleJob {
|
||||
provider?: string | null;
|
||||
targetLanguage: string;
|
||||
ttsLanguage?: string;
|
||||
pollTimeoutMs?: number;
|
||||
fileId?: string;
|
||||
filePath?: string;
|
||||
error?: string;
|
||||
@ -73,6 +74,7 @@ export const createSubtitleJob = (
|
||||
provider,
|
||||
targetLanguage,
|
||||
ttsLanguage,
|
||||
pollTimeoutMs,
|
||||
fileId,
|
||||
filePath,
|
||||
}: {
|
||||
@ -80,6 +82,7 @@ export const createSubtitleJob = (
|
||||
provider?: string | null;
|
||||
targetLanguage: string;
|
||||
ttsLanguage?: string;
|
||||
pollTimeoutMs?: number;
|
||||
fileId?: string;
|
||||
filePath?: string;
|
||||
},
|
||||
@ -91,6 +94,7 @@ export const createSubtitleJob = (
|
||||
provider,
|
||||
targetLanguage,
|
||||
ttsLanguage,
|
||||
pollTimeoutMs,
|
||||
fileId,
|
||||
filePath,
|
||||
status: 'queued',
|
||||
@ -159,6 +163,7 @@ export const toSubtitleGenerationProgress = (job: SubtitleJob): SubtitleGenerati
|
||||
stage: job.stage,
|
||||
progress: job.progress,
|
||||
message: job.message,
|
||||
...(job.pollTimeoutMs ? { pollTimeoutMs: job.pollTimeoutMs } : {}),
|
||||
});
|
||||
|
||||
export const toSubtitleJobResponse = (job: SubtitleJob) => ({
|
||||
|
||||
@ -497,4 +497,87 @@ describe('generateSubtitlePipeline', () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('uses the server-provided poll timeout for doubao jobs', async () => {
|
||||
vi.useFakeTimers();
|
||||
const fetchMock = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
id: 'file-123',
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
.mockResolvedValueOnce(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
id: 'file-123',
|
||||
status: 'active',
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
.mockResolvedValueOnce(
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
jobId: 'job-1',
|
||||
requestId: 'req-1',
|
||||
status: 'queued',
|
||||
stage: 'queued',
|
||||
progress: 5,
|
||||
pollTimeoutMs: 1000,
|
||||
}),
|
||||
{
|
||||
status: 202,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
.mockImplementation(async () =>
|
||||
new Response(
|
||||
JSON.stringify({
|
||||
jobId: 'job-1',
|
||||
requestId: 'req-1',
|
||||
status: 'running',
|
||||
stage: 'calling_provider',
|
||||
progress: 70,
|
||||
message: 'Calling provider',
|
||||
}),
|
||||
{
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
const promise = generateSubtitlePipeline(
|
||||
new File(['video'], 'clip.mp4', { type: 'video/mp4' }),
|
||||
'English',
|
||||
'doubao',
|
||||
null,
|
||||
fetchMock as unknown as typeof fetch,
|
||||
);
|
||||
const rejection = expect(promise).rejects.toThrow(
|
||||
/timed out while waiting for subtitle generation to complete/i,
|
||||
);
|
||||
|
||||
await vi.runAllTimersAsync();
|
||||
await rejection;
|
||||
});
|
||||
});
|
||||
|
||||
@ -11,6 +11,11 @@ const ARK_FILE_STATUS_TIMEOUT_MS = 120000;
|
||||
const SUBTITLE_JOB_POLL_INTERVAL_MS = 5000;
|
||||
const SUBTITLE_JOB_TIMEOUT_MS = 20 * 60 * 1000;
|
||||
|
||||
const resolvePollTimeoutMs = (value?: number) =>
|
||||
Number.isFinite(value) && (value as number) > 0
|
||||
? Math.floor(value as number)
|
||||
: SUBTITLE_JOB_TIMEOUT_MS;
|
||||
|
||||
interface SubtitleJobResponse extends SubtitleGenerationProgress {
|
||||
error?: string;
|
||||
result?: Partial<SubtitlePipelineResult>;
|
||||
@ -109,10 +114,11 @@ const pollSubtitleJob = async (
|
||||
jobId: string,
|
||||
targetLanguage: string,
|
||||
ttsLanguage: string,
|
||||
pollTimeoutMs: number,
|
||||
fetchImpl: typeof fetch,
|
||||
onProgress?: (progress: SubtitleGenerationProgress) => void,
|
||||
): Promise<SubtitlePipelineResult> => {
|
||||
const deadline = Date.now() + SUBTITLE_JOB_TIMEOUT_MS;
|
||||
const deadline = Date.now() + resolvePollTimeoutMs(pollTimeoutMs);
|
||||
|
||||
while (true) {
|
||||
const resp = await fetchImpl(apiUrl(`/generate-subtitles/${jobId}`), {
|
||||
@ -226,7 +232,14 @@ export const generateSubtitlePipeline = async (
|
||||
}
|
||||
const job = parsed.data as unknown as SubtitleJobResponse;
|
||||
onProgress?.(job);
|
||||
return pollSubtitleJob(job.jobId, targetLanguage, resolvedTtsLanguage, fetchImpl, onProgress);
|
||||
return pollSubtitleJob(
|
||||
job.jobId,
|
||||
targetLanguage,
|
||||
resolvedTtsLanguage,
|
||||
job.pollTimeoutMs ?? SUBTITLE_JOB_TIMEOUT_MS,
|
||||
fetchImpl,
|
||||
onProgress,
|
||||
);
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
@ -250,5 +263,12 @@ export const generateSubtitlePipeline = async (
|
||||
throw error;
|
||||
}
|
||||
onProgress?.(parsed.data);
|
||||
return pollSubtitleJob(parsed.data.jobId, targetLanguage, resolvedTtsLanguage, fetchImpl, onProgress);
|
||||
return pollSubtitleJob(
|
||||
parsed.data.jobId,
|
||||
targetLanguage,
|
||||
resolvedTtsLanguage,
|
||||
parsed.data.pollTimeoutMs ?? SUBTITLE_JOB_TIMEOUT_MS,
|
||||
fetchImpl,
|
||||
onProgress,
|
||||
);
|
||||
};
|
||||
|
||||
@ -66,6 +66,7 @@ export interface SubtitleGenerationProgress {
|
||||
stage: SubtitleJobStage;
|
||||
progress: number;
|
||||
message: string;
|
||||
pollTimeoutMs?: number;
|
||||
}
|
||||
|
||||
export interface TextStyles {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user