From 15abb78a6b0a6d48db636607e86de19804436c61 Mon Sep 17 00:00:00 2001 From: darkskygit Date: Wed, 9 Apr 2025 08:21:19 +0000 Subject: [PATCH] feat(server): support sliced audio (#11562) fix AF-2479 --- .../__tests__/__snapshots__/copilot.e2e.ts.md | 44 ++++++++ .../__snapshots__/copilot.e2e.ts.snap | Bin 840 -> 987 bytes .../server/src/__tests__/copilot.e2e.ts | 75 ++++++++++---- .../server/src/__tests__/utils/copilot.ts | 28 ++++-- packages/backend/server/src/base/error/def.ts | 4 + .../server/src/base/error/errors.gen.ts | 7 ++ .../plugins/copilot/transcript/resolver.ts | 19 ++-- .../src/plugins/copilot/transcript/service.ts | 95 ++++++++++++------ .../src/plugins/copilot/transcript/types.ts | 17 +++- packages/backend/server/src/schema.gql | 3 +- .../copilot-jobs-transcription-add.gql | 4 +- packages/common/graphql/src/graphql/index.ts | 4 +- packages/common/graphql/src/schema.ts | 9 +- packages/frontend/i18n/src/i18n.gen.ts | 4 + packages/frontend/i18n/src/resources/en.json | 1 + 15 files changed, 239 insertions(+), 75 deletions(-) diff --git a/packages/backend/server/src/__tests__/__snapshots__/copilot.e2e.ts.md b/packages/backend/server/src/__tests__/__snapshots__/copilot.e2e.ts.md index a3f684c57c..7a37e06810 100644 --- a/packages/backend/server/src/__tests__/__snapshots__/copilot.e2e.ts.md +++ b/packages/backend/server/src/__tests__/__snapshots__/copilot.e2e.ts.md @@ -88,3 +88,47 @@ Generated by [AVA](https://avajs.dev). ], }, ] + +> should submit audio transcription job + + [ + { + status: 'running', + }, + ] + +> should claim audio transcription job + + [ + { + status: 'claimed', + summary: '[{"a":"A","s":30,"e":45,"t":"Hello, everyone."},{"a":"B","s":46,"e":70,"t":"Hi, thank you for joining the meeting today."}]', + title: '[{"a":"A","s":30,"e":45,"t":"Hello, everyone."},{"a":"B","s":46,"e":70,"t":"Hi, thank you for joining the meeting today."}]', + transcription: [ + { + end: '00:00:45', + speaker: 'A', + start: '00:00:30', + transcription: 'Hello, everyone.', + }, + { + end: '00:01:10', + speaker: 'B', + start: '00:00:46', + transcription: 'Hi, thank you for joining the meeting today.', + }, + { + end: '00:10:45', + speaker: 'A', + start: '00:10:30', + transcription: 'Hello, everyone.', + }, + { + end: '00:11:10', + speaker: 'B', + start: '00:10:46', + transcription: 'Hi, thank you for joining the meeting today.', + }, + ], + }, + ] diff --git a/packages/backend/server/src/__tests__/__snapshots__/copilot.e2e.ts.snap b/packages/backend/server/src/__tests__/__snapshots__/copilot.e2e.ts.snap index bfbd97bfeb660da3dbff1dbf3c7602f71e481bf7..747545f2ce8780fe4ec1e6112082f13cf481e922 100644 GIT binary patch literal 987 zcmV<110?)GRzV%#P za>@TpXCI3Q00000000B+Rl$oJRT%$$Z)URDUAnuaiV77UgGG?ICf#&}Ae1ds+>?R_ z74h&g^ODSFGB3<~(Zte=6@{XB6@-GtKcFWs-t^Q{@#s}g9u#k0C6k%dysVo@SGKg9 zOTKUTzM0?m`+e{CzG*dM6?FBD+tNfPmP4*PY7mFKDYuD5m6CsZf=6sKm=MRdbMbB+5mb0 zJ}VkaZ!`~NV2Dk_t*tH484v?)5Pb{a335Q*St|FW)}k#nXcOm%70*jXb!DQn)SZC4 z3*epw&N&?1&r@(N0c!+YCJUT<7`Pb-D}hRkOiYnK*_Me+g^}FIp&64q{DL zR)yA)HX<=H7EKusUz`^xjO25)E%Idkg| zs;Q>{3;=u$;CleSEY{Yw6>P?;xgSp1Y(=r$4{KJ{YS0-Z-M6BTTK^0}r( zuOG|pe%P`s(HIb#8UXfaP@L1)pF zqf)4X{jiope)=%Tp$c@d8t3O%!=xh7K^pb{u@;}?6MlJ86I$Y|q=O{6ugryf3O#7{ zBE!WXjArIg2|rNHe6?M6tgF3Cz&+a;mRN0Tpdc1ePlmRC=s~Y1(ovCLd+(Yr{D!~h zSA6X^cB&O$`i=Ufif{ae|GJE0RpIgjnT}KqL?v)4xpKR}8qtfFBs}D+5-Yqwj+2DLwNb4$>X+u$q%TERrbSMBwpiMT)L5_CsajRDycJKkZ1t9dS!>kn_s_w+vJA}n z?ou!-|7B}(-*`UvjqLCpZ5xk-^?84uTHoVlecp2nxWIsy8PH(B)kPNQW|F@-wZI#> z1+Ei)Hx4Hj`P(>jvM-!>0N(*#bAYx3e6iRVe{_Jm4)D7JY`8$(J=z${v z7x>8q{<2$2b1g4WvJ?Eym%xaC@t zw^R#_(t z$C->dJNabQpiEgOM#?&Era}%Jo4IHI`}2 z0Db}R$JyStdqBA za2j%|6Wc`Nqt$3QBMX}tHCc_t{pW9Mhn_j>rYwqA&U{?&!j^HaoRDRzmiD0wajfGy z+O6O}jrIWnFa6GNj%a%uN;0W(PW}F2%RHB6+RPt+^*EAIKRS%Mk&XH{d)55E!sR|DXBa7ObFDyweQ zL+$SZ;D-SCH30q$fQ|5<{|6mv-wA=wLO_MUvk>^%U(!A^C?OY%!` { '[{"a":"A","s":30,"e":45,"t":"Hello, everyone."},{"a":"B","s":46,"e":70,"t":"Hi, thank you for joining the meeting today."}]' ); - const job = await submitAudioTranscription( - app, - workspaceId, - 'blobId', - 'test.mp3', - Buffer.from([1, 1]) - ); - t.snapshot( - cleanObject([job], ['id']), - 'should submit audio transcription job' - ); - t.truthy(job.id, 'should have job id'); - - // wait for processing { - let { status } = (await audioTranscription(app, workspaceId, job.id)) || {}; + const job = await submitAudioTranscription(app, workspaceId, '1', '1.mp3', [ + Buffer.from([1, 1]), + ]); + t.snapshot( + cleanObject([job], ['id']), + 'should submit audio transcription job' + ); + t.truthy(job.id, 'should have job id'); - while (status !== 'finished') { - await new Promise(resolve => setTimeout(resolve, 1000)); - ({ status } = (await audioTranscription(app, workspaceId, job.id)) || {}); + // wait for processing + { + let { status } = + (await audioTranscription(app, workspaceId, job.id)) || {}; + + while (status !== 'finished') { + await new Promise(resolve => setTimeout(resolve, 1000)); + ({ status } = + (await audioTranscription(app, workspaceId, job.id)) || {}); + } + } + + { + const result = await claimAudioTranscription(app, job.id); + t.snapshot( + cleanObject([result], ['id']), + 'should claim audio transcription job' + ); } } { - const result = await claimAudioTranscription(app, job.id); + // sliced audio + const job = await submitAudioTranscription(app, workspaceId, '2', '2.mp3', [ + Buffer.from([1, 1]), + Buffer.from([1, 2]), + ]); t.snapshot( - cleanObject([result], ['id']), - 'should claim audio transcription job' + cleanObject([job], ['id']), + 'should submit audio transcription job' ); + t.truthy(job.id, 'should have job id'); + + // wait for processing + { + let { status } = + (await audioTranscription(app, workspaceId, job.id)) || {}; + + while (status !== 'finished') { + await new Promise(resolve => setTimeout(resolve, 1000)); + ({ status } = + (await audioTranscription(app, workspaceId, job.id)) || {}); + } + } + + { + const result = await claimAudioTranscription(app, job.id); + t.snapshot( + cleanObject([result], ['id']), + 'should claim audio transcription job' + ); + } } }); diff --git a/packages/backend/server/src/__tests__/utils/copilot.ts b/packages/backend/server/src/__tests__/utils/copilot.ts index 0f2178ee0c..4d12a1939b 100644 --- a/packages/backend/server/src/__tests__/utils/copilot.ts +++ b/packages/backend/server/src/__tests__/utils/copilot.ts @@ -335,17 +335,17 @@ export async function submitAudioTranscription( workspaceId: string, blobId: string, fileName: string, - content: Buffer + content: Buffer[] ): Promise<{ id: string; status: string }> { - const res = await app + let resp = app .POST('/graphql') .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .field( 'operations', JSON.stringify({ query: ` - mutation submitAudioTranscription($blob: Upload!, $blobId: String!, $workspaceId: String!) { - submitAudioTranscription(blob: $blob, blobId: $blobId, workspaceId: $workspaceId) { + mutation submitAudioTranscription($blob: Upload, $blobs: [Upload!], $blobId: String!, $workspaceId: String!) { + submitAudioTranscription(blob: $blob, blobs: $blobs, blobId: $blobId, workspaceId: $workspaceId) { id status } @@ -353,17 +353,29 @@ export async function submitAudioTranscription( `, variables: { blob: null, + blobs: [], blobId, workspaceId, }, }) ) - .field('map', JSON.stringify({ '0': ['variables.blob'] })) - .attach('0', content, { + .field( + 'map', + JSON.stringify( + Array.from({ length: content.length }).reduce((acc, _, idx) => { + acc[idx.toString()] = [`variables.blobs.${idx}`]; + return acc; + }, {}) + ) + ); + for (const [idx, buffer] of content.entries()) { + resp = resp.attach(idx.toString(), buffer, { filename: fileName, contentType: 'application/octet-stream', - }) - .expect(200); + }); + } + + const res = await resp.expect(200); return res.body.data.submitAudioTranscription; } diff --git a/packages/backend/server/src/base/error/def.ts b/packages/backend/server/src/base/error/def.ts index aeaa40267f..94783b6076 100644 --- a/packages/backend/server/src/base/error/def.ts +++ b/packages/backend/server/src/base/error/def.ts @@ -709,6 +709,10 @@ export const USER_FRIENDLY_ERRORS = { type: 'bad_request', message: () => `Transcription job not found.`, }, + copilot_transcription_audio_not_provided: { + type: 'bad_request', + message: () => `Audio not provided.`, + }, // Quota & Limit errors blob_quota_exceeded: { diff --git a/packages/backend/server/src/base/error/errors.gen.ts b/packages/backend/server/src/base/error/errors.gen.ts index 419982609c..d02b0d72b3 100644 --- a/packages/backend/server/src/base/error/errors.gen.ts +++ b/packages/backend/server/src/base/error/errors.gen.ts @@ -771,6 +771,12 @@ export class CopilotTranscriptionJobNotFound extends UserFriendlyError { } } +export class CopilotTranscriptionAudioNotProvided extends UserFriendlyError { + constructor(message?: string) { + super('bad_request', 'copilot_transcription_audio_not_provided', message); + } +} + export class BlobQuotaExceeded extends UserFriendlyError { constructor(message?: string) { super('quota_exceeded', 'blob_quota_exceeded', message); @@ -1027,6 +1033,7 @@ export enum ErrorNames { COPILOT_EMBEDDING_UNAVAILABLE, COPILOT_TRANSCRIPTION_JOB_EXISTS, COPILOT_TRANSCRIPTION_JOB_NOT_FOUND, + COPILOT_TRANSCRIPTION_AUDIO_NOT_PROVIDED, BLOB_QUOTA_EXCEEDED, STORAGE_QUOTA_EXCEEDED, MEMBER_QUOTA_EXCEEDED, diff --git a/packages/backend/server/src/plugins/copilot/transcript/resolver.ts b/packages/backend/server/src/plugins/copilot/transcript/resolver.ts index 2ea0bd6e84..e261ea0f13 100644 --- a/packages/backend/server/src/plugins/copilot/transcript/resolver.ts +++ b/packages/backend/server/src/plugins/copilot/transcript/resolver.ts @@ -14,6 +14,7 @@ import { AiJobStatus } from '@prisma/client'; import GraphQLUpload from 'graphql-upload/GraphQLUpload.mjs'; import { + CopilotTranscriptionAudioNotProvided, CopilotTranscriptionJobNotFound, type FileUpload, } from '../../../base'; @@ -100,20 +101,27 @@ export class CopilotTranscriptionResolver { @CurrentUser() user: CurrentUser, @Args('workspaceId') workspaceId: string, @Args('blobId') blobId: string, - @Args({ name: 'blob', type: () => GraphQLUpload }) - blob: FileUpload + @Args({ name: 'blob', type: () => GraphQLUpload, nullable: true }) + blob: FileUpload | null, + @Args({ name: 'blobs', type: () => [GraphQLUpload], nullable: true }) + blobs: FileUpload[] | null ): Promise { await this.ac .user(user.id) .workspace(workspaceId) .allowLocal() .assert('Workspace.Copilot'); + // merge blobs + const allBlobs = blob ? [blob, ...(blobs || [])].filter(v => !!v) : blobs; + if (!allBlobs || allBlobs.length === 0) { + throw new CopilotTranscriptionAudioNotProvided(); + } const jobResult = await this.service.submitTranscriptionJob( user.id, workspaceId, blobId, - blob + await Promise.all(allBlobs) ); return this.handleJobResult(jobResult); @@ -136,14 +144,13 @@ export class CopilotTranscriptionResolver { workspaceId, jobId ); - if (!job || !job.url || !job.mimeType) { + if (!job || !job.infos) { throw new CopilotTranscriptionJobNotFound(); } const jobResult = await this.service.executeTranscriptionJob( job.id, - job.url, - job.mimeType + job.infos ); return this.handleJobResult(jobResult); diff --git a/packages/backend/server/src/plugins/copilot/transcript/service.ts b/packages/backend/server/src/plugins/copilot/transcript/service.ts index 3c2b03fccd..0c45c3bc68 100644 --- a/packages/backend/server/src/plugins/copilot/transcript/service.ts +++ b/packages/backend/server/src/plugins/copilot/transcript/service.ts @@ -23,6 +23,7 @@ import { } from '../providers'; import { CopilotStorage } from '../storage'; import { + AudioBlobInfos, TranscriptionPayload, TranscriptionResponseSchema, TranscriptPayloadSchema, @@ -32,8 +33,7 @@ import { readStream } from './utils'; export type TranscriptionJob = { id: string; status: AiJobStatus; - url?: string; - mimeType?: string; + infos?: AudioBlobInfos; transcription?: TranscriptionPayload; }; @@ -52,7 +52,7 @@ export class CopilotTranscriptionService { userId: string, workspaceId: string, blobId: string, - blob: FileUpload + blobs: FileUpload[] ): Promise { if (await this.models.copilotJob.has(userId, workspaceId, blobId)) { throw new CopilotTranscriptionJobExists(); @@ -65,21 +65,24 @@ export class CopilotTranscriptionService { type: AiJobType.transcription, }); - const buffer = await readStream(blob.createReadStream()); - const url = await this.storage.put(userId, workspaceId, blobId, buffer); + const infos: AudioBlobInfos = []; + for (const blob of blobs) { + const buffer = await readStream(blob.createReadStream()); + const url = await this.storage.put(userId, workspaceId, blobId, buffer); + infos.push({ url, mimeType: blob.mimetype }); + } - return await this.executeTranscriptionJob(jobId, url, blob.mimetype); + return await this.executeTranscriptionJob(jobId, infos); } async executeTranscriptionJob( jobId: string, - url: string, - mimeType: string + infos: AudioBlobInfos ): Promise { const status = AiJobStatus.running; const success = await this.models.copilotJob.update(jobId, { status, - payload: { url, mimeType }, + payload: { infos }, }); if (!success) { @@ -88,8 +91,7 @@ export class CopilotTranscriptionService { await this.job.add('copilot.transcript.submit', { jobId, - url, - mimeType, + infos, }); return { id: jobId, status }; @@ -132,8 +134,13 @@ export class CopilotTranscriptionService { const payload = TranscriptPayloadSchema.safeParse(job.payload); if (payload.success) { - ret.url = payload.data.url || undefined; - ret.mimeType = payload.data.mimeType || undefined; + let { url, mimeType, infos } = payload.data; + infos = infos || []; + if (url && mimeType) { + infos.push({ url, mimeType }); + } + + ret.infos = this.mergeInfos(infos, url, mimeType); if (job.status === AiJobStatus.claimed) { ret.transcription = payload.data; } @@ -173,7 +180,24 @@ export class CopilotTranscriptionService { ); } - private convertTime(time: number) { + // TODO(@darkskygit): remove after old server down + private mergeInfos( + infos?: AudioBlobInfos | null, + url?: string | null, + mimeType?: string | null + ) { + if (url && mimeType) { + if (infos) { + infos.push({ url, mimeType }); + } else { + infos = [{ url, mimeType }]; + } + } + return infos || []; + } + + private convertTime(time: number, offset = 0) { + time = time + offset; const minutes = Math.floor(time / 60); const seconds = Math.floor(time % 60); const hours = Math.floor(minutes / 60); @@ -186,29 +210,38 @@ export class CopilotTranscriptionService { @OnJob('copilot.transcript.submit') async transcriptAudio({ jobId, + infos, + // @deprecated url, mimeType, }: Jobs['copilot.transcript.submit']) { try { - const result = await this.chatWithPrompt( - 'Transcript audio', - { - attachments: [url], - params: { mimetype: mimeType }, - }, - TranscriptionResponseSchema - ); + const blobInfos = this.mergeInfos(infos, url, mimeType); + const transcriptions = []; + for (const [idx, { url, mimeType }] of blobInfos.entries()) { + const result = await this.chatWithPrompt( + 'Transcript audio', + { + attachments: [url], + params: { mimetype: mimeType }, + }, + TranscriptionResponseSchema + ); + + const offset = idx * 10 * 60; + const transcription = TranscriptionResponseSchema.parse( + JSON.parse(result) + ).map(t => ({ + speaker: t.a, + start: this.convertTime(t.s, offset), + end: this.convertTime(t.e, offset), + transcription: t.t, + })); + transcriptions.push(transcription); + } - const transcription = TranscriptionResponseSchema.parse( - JSON.parse(result) - ).map(t => ({ - speaker: t.a, - start: this.convertTime(t.s), - end: this.convertTime(t.e), - transcription: t.t, - })); await this.models.copilotJob.update(jobId, { - payload: { transcription }, + payload: { transcription: transcriptions.flat() }, }); await this.job.add('copilot.transcript.summary.submit', { diff --git a/packages/backend/server/src/plugins/copilot/transcript/types.ts b/packages/backend/server/src/plugins/copilot/transcript/types.ts index 97ef51beaa..1c5c320568 100644 --- a/packages/backend/server/src/plugins/copilot/transcript/types.ts +++ b/packages/backend/server/src/plugins/copilot/transcript/types.ts @@ -20,9 +20,17 @@ const TranscriptionItemSchema = z.object({ export const TranscriptionSchema = z.array(TranscriptionItemSchema); +export const AudioBlobInfosSchema = z + .object({ + url: z.string(), + mimeType: z.string(), + }) + .array(); + export const TranscriptPayloadSchema = z.object({ url: z.string().nullable().optional(), mimeType: z.string().nullable().optional(), + infos: AudioBlobInfosSchema.nullable().optional(), title: z.string().nullable().optional(), summary: z.string().nullable().optional(), transcription: TranscriptionSchema.nullable().optional(), @@ -32,6 +40,8 @@ export type TranscriptionItem = z.infer; export type Transcription = z.infer; export type TranscriptionPayload = z.infer; +export type AudioBlobInfos = z.infer; + declare global { interface Events { 'workspace.file.transcript.finished': { @@ -44,8 +54,11 @@ declare global { interface Jobs { 'copilot.transcript.submit': { jobId: string; - url: string; - mimeType: string; + infos?: AudioBlobInfos; + /// @deprecated use `infos` instead + url?: string; + /// @deprecated use `infos` instead + mimeType?: string; }; 'copilot.transcript.summary.submit': { jobId: string; diff --git a/packages/backend/server/src/schema.gql b/packages/backend/server/src/schema.gql index cddbdf248d..a69e6e2d8d 100644 --- a/packages/backend/server/src/schema.gql +++ b/packages/backend/server/src/schema.gql @@ -435,6 +435,7 @@ enum ErrorNames { COPILOT_QUOTA_EXCEEDED COPILOT_SESSION_DELETED COPILOT_SESSION_NOT_FOUND + COPILOT_TRANSCRIPTION_AUDIO_NOT_PROVIDED COPILOT_TRANSCRIPTION_JOB_EXISTS COPILOT_TRANSCRIPTION_JOB_NOT_FOUND CUSTOMER_PORTAL_CREATE_FAILED @@ -1004,7 +1005,7 @@ type Mutation { sendVerifyChangeEmail(callbackUrl: String!, email: String!, token: String!): Boolean! sendVerifyEmail(callbackUrl: String!): Boolean! setBlob(blob: Upload!, workspaceId: String!): String! - submitAudioTranscription(blob: Upload!, blobId: String!, workspaceId: String!): TranscriptionResultType + submitAudioTranscription(blob: Upload, blobId: String!, blobs: [Upload!], workspaceId: String!): TranscriptionResultType """update app configuration""" updateAppConfig(updates: [UpdateAppConfigInput!]!): JSONObject! diff --git a/packages/common/graphql/src/graphql/copilot-jobs-transcription-add.gql b/packages/common/graphql/src/graphql/copilot-jobs-transcription-add.gql index ccfc39a8fa..6a73c2411b 100644 --- a/packages/common/graphql/src/graphql/copilot-jobs-transcription-add.gql +++ b/packages/common/graphql/src/graphql/copilot-jobs-transcription-add.gql @@ -1,5 +1,5 @@ -mutation submitAudioTranscription($workspaceId: String!, $blobId: String!, $blob: Upload!) { - submitAudioTranscription(blob: $blob, blobId: $blobId, workspaceId: $workspaceId) { +mutation submitAudioTranscription($workspaceId: String!, $blobId: String!, $blob: Upload, $blobs: [Upload!]) { + submitAudioTranscription(blob: $blob, blobs: $blobs, blobId: $blobId, workspaceId: $workspaceId) { id status } diff --git a/packages/common/graphql/src/graphql/index.ts b/packages/common/graphql/src/graphql/index.ts index bb76038d36..e31b68fe04 100644 --- a/packages/common/graphql/src/graphql/index.ts +++ b/packages/common/graphql/src/graphql/index.ts @@ -601,9 +601,10 @@ export const getCopilotHistoriesQuery = { export const submitAudioTranscriptionMutation = { id: 'submitAudioTranscriptionMutation' as const, op: 'submitAudioTranscription', - query: `mutation submitAudioTranscription($workspaceId: String!, $blobId: String!, $blob: Upload!) { + query: `mutation submitAudioTranscription($workspaceId: String!, $blobId: String!, $blob: Upload, $blobs: [Upload!]) { submitAudioTranscription( blob: $blob + blobs: $blobs blobId: $blobId workspaceId: $workspaceId ) { @@ -611,7 +612,6 @@ export const submitAudioTranscriptionMutation = { status } }`, - file: true, }; export const claimAudioTranscriptionMutation = { diff --git a/packages/common/graphql/src/schema.ts b/packages/common/graphql/src/schema.ts index ead0af69dd..e8167a5fef 100644 --- a/packages/common/graphql/src/schema.ts +++ b/packages/common/graphql/src/schema.ts @@ -580,6 +580,7 @@ export enum ErrorNames { COPILOT_QUOTA_EXCEEDED = 'COPILOT_QUOTA_EXCEEDED', COPILOT_SESSION_DELETED = 'COPILOT_SESSION_DELETED', COPILOT_SESSION_NOT_FOUND = 'COPILOT_SESSION_NOT_FOUND', + COPILOT_TRANSCRIPTION_AUDIO_NOT_PROVIDED = 'COPILOT_TRANSCRIPTION_AUDIO_NOT_PROVIDED', COPILOT_TRANSCRIPTION_JOB_EXISTS = 'COPILOT_TRANSCRIPTION_JOB_EXISTS', COPILOT_TRANSCRIPTION_JOB_NOT_FOUND = 'COPILOT_TRANSCRIPTION_JOB_NOT_FOUND', CUSTOMER_PORTAL_CREATE_FAILED = 'CUSTOMER_PORTAL_CREATE_FAILED', @@ -1432,8 +1433,9 @@ export interface MutationSetBlobArgs { } export interface MutationSubmitAudioTranscriptionArgs { - blob: Scalars['Upload']['input']; + blob?: InputMaybe; blobId: Scalars['String']['input']; + blobs?: InputMaybe>; workspaceId: Scalars['String']['input']; } @@ -2991,7 +2993,10 @@ export type GetCopilotHistoriesQuery = { export type SubmitAudioTranscriptionMutationVariables = Exact<{ workspaceId: Scalars['String']['input']; blobId: Scalars['String']['input']; - blob: Scalars['Upload']['input']; + blob?: InputMaybe; + blobs?: InputMaybe< + Array | Scalars['Upload']['input'] + >; }>; export type SubmitAudioTranscriptionMutation = { diff --git a/packages/frontend/i18n/src/i18n.gen.ts b/packages/frontend/i18n/src/i18n.gen.ts index 446acdd859..5f0c6e3959 100644 --- a/packages/frontend/i18n/src/i18n.gen.ts +++ b/packages/frontend/i18n/src/i18n.gen.ts @@ -8127,6 +8127,10 @@ export function useAFFiNEI18N(): { * `Transcription job not found.` */ ["error.COPILOT_TRANSCRIPTION_JOB_NOT_FOUND"](): string; + /** + * `Audio not provided.` + */ + ["error.COPILOT_TRANSCRIPTION_AUDIO_NOT_PROVIDED"](): string; /** * `You have exceeded your blob size quota.` */ diff --git a/packages/frontend/i18n/src/resources/en.json b/packages/frontend/i18n/src/resources/en.json index 5c5fe4aefc..00d4c40f02 100644 --- a/packages/frontend/i18n/src/resources/en.json +++ b/packages/frontend/i18n/src/resources/en.json @@ -2010,6 +2010,7 @@ "error.COPILOT_EMBEDDING_UNAVAILABLE": "Embedding feature not available, you may need to install pgvector extension to your database", "error.COPILOT_TRANSCRIPTION_JOB_EXISTS": "Transcription job already exists", "error.COPILOT_TRANSCRIPTION_JOB_NOT_FOUND": "Transcription job not found.", + "error.COPILOT_TRANSCRIPTION_AUDIO_NOT_PROVIDED": "Audio not provided.", "error.BLOB_QUOTA_EXCEEDED": "You have exceeded your blob size quota.", "error.STORAGE_QUOTA_EXCEEDED": "You have exceeded your storage quota.", "error.MEMBER_QUOTA_EXCEEDED": "You have exceeded your workspace member quota.",