fix(server): realtime module not loaded (#14952)

#### PR Dependency Tree


* **PR #14952** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Refactor**
* Optimized workspace invite link fetching by separating it from general
workspace configuration queries for improved performance.
* Reorganized transcription-related backend modules to better separate
concerns and enable real-time functionality.

* **Chores**
* Updated generated GraphQL types and iOS query definitions to reflect
API changes.

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/toeverything/AFFiNE/pull/14952)

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-05-12 18:54:42 +08:00
committed by GitHub
parent ac6d0d35af
commit a1d150a748
18 changed files with 246 additions and 104 deletions
@@ -20,13 +20,13 @@ import { CopilotProviderType } from '../providers/types';
import { ActionRuntimeBridge } from '../runtime/action-runtime-bridge';
import { TaskPolicy } from '../runtime/task-policy';
import { CopilotStorage } from '../storage';
import { taskToJob, type TranscriptionJob } from './job';
import {
TranscriptActionResultContract,
TranscriptPayloadSchema,
} from './schema';
import type {
AudioBlobInfos,
TranscriptionPayload,
TranscriptionPayloadV2,
TranscriptionSubmitInput,
} from './types';
@@ -36,27 +36,6 @@ const TRANSCRIPT_ACTION_ID = 'transcript.audio.gemini';
const TRANSCRIPT_ACTION_VERSION = 'v1';
const TRANSCRIPT_STRATEGY = 'gemini';
export type TranscriptionJob = {
id: string;
status: AiJobStatus;
infos?: AudioBlobInfos;
transcription?: TranscriptionPayload;
};
function taskStatusToPublicStatus(status: string): AiJobStatus {
switch (status) {
case 'pending':
return AiJobStatus.pending;
case 'running':
return AiJobStatus.running;
case 'ready':
case 'settled':
return AiJobStatus.finished;
default:
return AiJobStatus.failed;
}
}
@Injectable()
export class CopilotTranscriptionService {
constructor(
@@ -85,33 +64,6 @@ export class CopilotTranscriptionService {
};
}
private taskToJob(
task: {
id: string;
status: string;
protectedResult: unknown;
} | null,
mapStatus: (status: string) => AiJobStatus = taskStatusToPublicStatus
): TranscriptionJob | null {
if (!task) {
return null;
}
const status = mapStatus(task.status);
const ret: TranscriptionJob = {
id: task.id,
status,
};
if (task.protectedResult) {
const parsed = TranscriptPayloadSchema.safeParse(task.protectedResult);
ret.infos = parsed.success ? (parsed.data.infos ?? []) : [];
if (task.status === 'settled' && parsed.success) {
ret.transcription = parsed.data;
}
}
return ret;
}
private async resolveTranscriptStrategy(userId: string, strategy?: string) {
if (strategy && strategy !== TRANSCRIPT_STRATEGY) {
throw new BadRequestException(
@@ -327,7 +279,7 @@ export class CopilotTranscriptionService {
}
if (task.status === 'settled') {
return this.taskToJob(task);
return taskToJob(task);
}
await this.access?.assertQuotaOrByok({
@@ -337,7 +289,7 @@ export class CopilotTranscriptionService {
});
const settled = await this.models.copilotTranscriptTask.settle(task.id);
return this.taskToJob(settled);
return taskToJob(settled);
}
async queryTask(
@@ -352,10 +304,7 @@ export class CopilotTranscriptionService {
taskId,
blobId
);
if (task) {
return this.taskToJob(task);
}
return null;
return taskToJob(task);
}
@OnJob('copilot.transcript.task.submit')