@goscribe/server 1.5.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/context.d.ts +14 -1
- package/dist/context.js +23 -2
- package/dist/generated/prisma/client.d.ts +224 -0
- package/dist/generated/prisma/client.js +34 -0
- package/dist/generated/prisma/commonInputTypes.d.ts +941 -0
- package/dist/generated/prisma/commonInputTypes.js +10 -0
- package/dist/generated/prisma/enums.d.ts +67 -0
- package/dist/generated/prisma/enums.js +66 -0
- package/dist/generated/prisma/internal/class.d.ts +539 -0
- package/dist/generated/prisma/internal/class.js +49 -0
- package/dist/generated/prisma/internal/prismaNamespace.d.ts +3924 -0
- package/dist/generated/prisma/internal/prismaNamespace.js +557 -0
- package/dist/generated/prisma/models/ActivityLog.d.ts +1847 -0
- package/dist/generated/prisma/models/ActivityLog.js +1 -0
- package/dist/generated/prisma/models/Artifact.d.ts +2345 -0
- package/dist/generated/prisma/models/Artifact.js +1 -0
- package/dist/generated/prisma/models/ArtifactVersion.d.ts +1550 -0
- package/dist/generated/prisma/models/ArtifactVersion.js +1 -0
- package/dist/generated/prisma/models/Channel.d.ts +1257 -0
- package/dist/generated/prisma/models/Channel.js +1 -0
- package/dist/generated/prisma/models/Chat.d.ts +1339 -0
- package/dist/generated/prisma/models/Chat.js +1 -0
- package/dist/generated/prisma/models/CopilotConversation.d.ts +1450 -0
- package/dist/generated/prisma/models/CopilotConversation.js +1 -0
- package/dist/generated/prisma/models/CopilotMessage.d.ts +1179 -0
- package/dist/generated/prisma/models/CopilotMessage.js +1 -0
- package/dist/generated/prisma/models/FileAsset.d.ts +1832 -0
- package/dist/generated/prisma/models/FileAsset.js +1 -0
- package/dist/generated/prisma/models/Flashcard.d.ts +1460 -0
- package/dist/generated/prisma/models/Flashcard.js +1 -0
- package/dist/generated/prisma/models/FlashcardProgress.d.ts +1782 -0
- package/dist/generated/prisma/models/FlashcardProgress.js +1 -0
- package/dist/generated/prisma/models/Folder.d.ts +1685 -0
- package/dist/generated/prisma/models/Folder.js +1 -0
- package/dist/generated/prisma/models/IdempotencyRecord.d.ts +1319 -0
- package/dist/generated/prisma/models/IdempotencyRecord.js +1 -0
- package/dist/generated/prisma/models/Invoice.d.ts +1586 -0
- package/dist/generated/prisma/models/Invoice.js +1 -0
- package/dist/generated/prisma/models/KnowledgeBase.d.ts +1721 -0
- package/dist/generated/prisma/models/KnowledgeBase.js +1 -0
- package/dist/generated/prisma/models/KnowledgeBaseChunk.d.ts +1333 -0
- package/dist/generated/prisma/models/KnowledgeBaseChunk.js +1 -0
- package/dist/generated/prisma/models/KnowledgeBaseDocument.d.ts +1695 -0
- package/dist/generated/prisma/models/KnowledgeBaseDocument.js +1 -0
- package/dist/generated/prisma/models/Notification.d.ts +1992 -0
- package/dist/generated/prisma/models/Notification.js +1 -0
- package/dist/generated/prisma/models/PasswordResetToken.d.ts +1210 -0
- package/dist/generated/prisma/models/PasswordResetToken.js +1 -0
- package/dist/generated/prisma/models/Plan.d.ts +1431 -0
- package/dist/generated/prisma/models/Plan.js +1 -0
- package/dist/generated/prisma/models/PlanLimit.d.ts +1328 -0
- package/dist/generated/prisma/models/PlanLimit.js +1 -0
- package/dist/generated/prisma/models/PodcastSegment.d.ts +1564 -0
- package/dist/generated/prisma/models/PodcastSegment.js +1 -0
- package/dist/generated/prisma/models/ResourcePrice.d.ts +1008 -0
- package/dist/generated/prisma/models/ResourcePrice.js +1 -0
- package/dist/generated/prisma/models/Role.d.ts +1065 -0
- package/dist/generated/prisma/models/Role.js +1 -0
- package/dist/generated/prisma/models/Session.d.ts +1105 -0
- package/dist/generated/prisma/models/Session.js +1 -0
- package/dist/generated/prisma/models/StripeEvent.d.ts +1081 -0
- package/dist/generated/prisma/models/StripeEvent.js +1 -0
- package/dist/generated/prisma/models/StudyGuideComment.d.ts +1321 -0
- package/dist/generated/prisma/models/StudyGuideComment.js +1 -0
- package/dist/generated/prisma/models/StudyGuideHighlight.d.ts +1629 -0
- package/dist/generated/prisma/models/StudyGuideHighlight.js +1 -0
- package/dist/generated/prisma/models/Subscription.d.ts +1677 -0
- package/dist/generated/prisma/models/Subscription.js +1 -0
- package/dist/generated/prisma/models/User.d.ts +7559 -0
- package/dist/generated/prisma/models/User.js +1 -0
- package/dist/generated/prisma/models/UserCredit.d.ts +1249 -0
- package/dist/generated/prisma/models/UserCredit.js +1 -0
- package/dist/generated/prisma/models/VerificationToken.d.ts +946 -0
- package/dist/generated/prisma/models/VerificationToken.js +1 -0
- package/dist/generated/prisma/models/WorksheetPreset.d.ts +1433 -0
- package/dist/generated/prisma/models/WorksheetPreset.js +1 -0
- package/dist/generated/prisma/models/WorksheetQuestion.d.ts +1491 -0
- package/dist/generated/prisma/models/WorksheetQuestion.js +1 -0
- package/dist/generated/prisma/models/WorksheetQuestionProgress.d.ts +1620 -0
- package/dist/generated/prisma/models/WorksheetQuestionProgress.js +1 -0
- package/dist/generated/prisma/models/Workspace.d.ts +3620 -0
- package/dist/generated/prisma/models/Workspace.js +1 -0
- package/dist/generated/prisma/models/WorkspaceInvitation.d.ts +1490 -0
- package/dist/generated/prisma/models/WorkspaceInvitation.js +1 -0
- package/dist/generated/prisma/models/WorkspaceKnowledgeBase.d.ts +1410 -0
- package/dist/generated/prisma/models/WorkspaceKnowledgeBase.js +1 -0
- package/dist/generated/prisma/models/WorkspaceMember.d.ts +1326 -0
- package/dist/generated/prisma/models/WorkspaceMember.js +1 -0
- package/dist/generated/prisma/models.d.ts +39 -0
- package/dist/generated/prisma/models.js +1 -0
- package/dist/lib/ai/index.d.ts +3 -2
- package/dist/lib/ai/index.js +3 -2
- package/dist/lib/ai/llm-client.d.ts +1 -0
- package/dist/lib/ai/llm-client.js +17 -0
- package/dist/routers/_app.d.ts +40 -80
- package/dist/routers/auth.js +1 -1
- package/dist/routers/flashcards.d.ts +12 -1
- package/dist/routers/payment.d.ts +1 -12
- package/dist/routers/workspace.d.ts +27 -67
- package/dist/routers/workspace.js +1 -0
- package/dist/services/billing/payment.service.d.ts +1 -12
- package/dist/services/billing/payment.service.js +3 -6
- package/dist/services/billing/usage.service.d.ts +30 -10
- package/dist/services/billing/usage.service.js +87 -15
- package/dist/services/content/copilot.service.js +15 -29
- package/dist/services/content/flashcard-progress.service.js +9 -9
- package/dist/services/content/flashcard.service.d.ts +45 -1
- package/dist/services/content/flashcard.service.js +81 -68
- package/dist/services/content/media-analysis.service.js +27 -27
- package/dist/services/content/worksheet-generation.service.test.js +2 -2
- package/dist/services/workspace/workspace.service.d.ts +23 -67
- package/dist/services/workspace/workspace.service.js +69 -62
- package/dist/src/context.d.ts +27 -0
- package/dist/src/context.js +33 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +1 -0
- package/dist/src/lib/ai/config.d.ts +20 -0
- package/dist/src/lib/ai/config.js +31 -0
- package/dist/src/lib/ai/embedding-client.d.ts +8 -0
- package/dist/src/lib/ai/embedding-client.js +30 -0
- package/dist/src/lib/ai/index.d.ts +48 -0
- package/dist/src/lib/ai/index.js +29 -0
- package/dist/src/lib/ai/inference-backend/client.d.ts +28 -0
- package/dist/src/lib/ai/inference-backend/client.js +301 -0
- package/dist/src/lib/ai/inference-backend/mocks.d.ts +12 -0
- package/dist/src/lib/ai/inference-backend/mocks.js +133 -0
- package/dist/src/lib/ai/inference-backend/types.d.ts +44 -0
- package/dist/src/lib/ai/inference-backend/types.js +1 -0
- package/dist/src/lib/ai/json-parse.d.ts +2 -0
- package/dist/src/lib/ai/json-parse.js +34 -0
- package/dist/src/lib/ai/llm-client.d.ts +7 -0
- package/dist/src/lib/ai/llm-client.js +36 -0
- package/dist/src/lib/ai/mock.d.ts +2 -0
- package/dist/src/lib/ai/mock.js +10 -0
- package/dist/src/lib/ai/types.d.ts +9 -0
- package/dist/src/lib/ai/types.js +1 -0
- package/dist/src/lib/auth.d.ts +36 -0
- package/dist/src/lib/auth.js +117 -0
- package/dist/src/lib/chunking.d.ts +19 -0
- package/dist/src/lib/chunking.js +47 -0
- package/dist/src/lib/constants.d.ts +13 -0
- package/dist/src/lib/constants.js +12 -0
- package/dist/src/lib/curated-kb-seed.d.ts +12 -0
- package/dist/src/lib/curated-kb-seed.js +155 -0
- package/dist/src/lib/email.d.ts +11 -0
- package/dist/src/lib/email.js +152 -0
- package/dist/src/lib/embeddings.d.ts +2 -0
- package/dist/src/lib/embeddings.js +1 -0
- package/dist/src/lib/ensure-curated-kb-catalog.d.ts +6 -0
- package/dist/src/lib/ensure-curated-kb-catalog.js +53 -0
- package/dist/src/lib/env.d.ts +41 -0
- package/dist/src/lib/env.js +57 -0
- package/dist/src/lib/errors.d.ts +33 -0
- package/dist/src/lib/errors.js +78 -0
- package/dist/src/lib/file.d.ts +0 -0
- package/dist/src/lib/file.js +1 -0
- package/dist/src/lib/inference.d.ts +1 -0
- package/dist/src/lib/inference.js +1 -0
- package/dist/src/lib/kb-meta.d.ts +8 -0
- package/dist/src/lib/kb-meta.js +77 -0
- package/dist/src/lib/logger.d.ts +62 -0
- package/dist/src/lib/logger.js +364 -0
- package/dist/src/lib/pdf.d.ts +11 -0
- package/dist/src/lib/pdf.js +11 -0
- package/dist/src/lib/prisma.d.ts +3 -0
- package/dist/src/lib/prisma.js +15 -0
- package/dist/src/lib/pusher.d.ts +38 -0
- package/dist/src/lib/pusher.js +170 -0
- package/dist/src/lib/retry.d.ts +15 -0
- package/dist/src/lib/retry.js +37 -0
- package/dist/src/lib/storage.d.ts +11 -0
- package/dist/src/lib/storage.js +71 -0
- package/dist/src/lib/stripe.d.ts +10 -0
- package/dist/src/lib/stripe.js +36 -0
- package/dist/src/lib/validation.d.ts +51 -0
- package/dist/src/lib/validation.js +64 -0
- package/dist/src/lib/workspace-kb.d.ts +5 -0
- package/dist/src/lib/workspace-kb.js +7 -0
- package/dist/src/repositories/artifact.repository.d.ts +64 -0
- package/dist/src/repositories/artifact.repository.js +40 -0
- package/dist/src/repositories/base.repository.d.ts +14 -0
- package/dist/src/repositories/base.repository.js +14 -0
- package/dist/src/repositories/invitation.repository.d.ts +104 -0
- package/dist/src/repositories/invitation.repository.js +44 -0
- package/dist/src/repositories/notification.repository.d.ts +76 -0
- package/dist/src/repositories/notification.repository.js +44 -0
- package/dist/src/repositories/user.repository.d.ts +84 -0
- package/dist/src/repositories/user.repository.js +37 -0
- package/dist/src/repositories/workspace-member.repository.d.ts +35 -0
- package/dist/src/repositories/workspace-member.repository.js +31 -0
- package/dist/src/repositories/workspace.repository.d.ts +101 -0
- package/dist/src/repositories/workspace.repository.js +79 -0
- package/dist/src/routers/_app.d.ts +3464 -0
- package/dist/src/routers/_app.js +36 -0
- package/dist/src/routers/admin.d.ts +358 -0
- package/dist/src/routers/admin.js +105 -0
- package/dist/src/routers/annotations.d.ts +219 -0
- package/dist/src/routers/annotations.js +29 -0
- package/dist/src/routers/artifactVersions.d.ts +65 -0
- package/dist/src/routers/artifactVersions.js +14 -0
- package/dist/src/routers/auth.d.ts +161 -0
- package/dist/src/routers/auth.js +97 -0
- package/dist/src/routers/chat.d.ts +170 -0
- package/dist/src/routers/chat.js +32 -0
- package/dist/src/routers/copilot.d.ts +200 -0
- package/dist/src/routers/copilot.js +52 -0
- package/dist/src/routers/flashcards.d.ts +336 -0
- package/dist/src/routers/flashcards.js +93 -0
- package/dist/src/routers/knowledgeBase.d.ts +421 -0
- package/dist/src/routers/knowledgeBase.js +118 -0
- package/dist/src/routers/members.d.ts +169 -0
- package/dist/src/routers/members.js +47 -0
- package/dist/src/routers/notifications.d.ts +99 -0
- package/dist/src/routers/notifications.js +25 -0
- package/dist/src/routers/payment.d.ts +80 -0
- package/dist/src/routers/payment.js +21 -0
- package/dist/src/routers/podcast.d.ts +287 -0
- package/dist/src/routers/podcast.js +34 -0
- package/dist/src/routers/studyguide.d.ts +36 -0
- package/dist/src/routers/studyguide.js +8 -0
- package/dist/src/routers/worksheets.d.ts +429 -0
- package/dist/src/routers/worksheets.js +139 -0
- package/dist/src/routers/workspace.d.ts +563 -0
- package/dist/src/routers/workspace.js +104 -0
- package/dist/src/scripts/purge-deleted-users.d.ts +1 -0
- package/dist/src/scripts/purge-deleted-users.js +148 -0
- package/dist/src/server.d.ts +1 -0
- package/dist/src/server.js +190 -0
- package/dist/src/services/activity/activity-human-description.service.d.ts +13 -0
- package/dist/src/services/activity/activity-human-description.service.js +221 -0
- package/dist/src/services/activity/activity-human-description.service.test.d.ts +1 -0
- package/dist/src/services/activity/activity-human-description.service.test.js +16 -0
- package/dist/src/services/activity/activity-log.service.d.ts +87 -0
- package/dist/src/services/activity/activity-log.service.js +276 -0
- package/dist/src/services/activity/activity-log.service.test.d.ts +1 -0
- package/dist/src/services/activity/activity-log.service.test.js +27 -0
- package/dist/src/services/admin/admin.service.d.ts +270 -0
- package/dist/src/services/admin/admin.service.js +476 -0
- package/dist/src/services/ai/ai-session.service.d.ts +5 -0
- package/dist/src/services/ai/ai-session.service.js +4 -0
- package/dist/src/services/artifacts/annotation.service.d.ts +177 -0
- package/dist/src/services/artifacts/annotation.service.js +154 -0
- package/dist/src/services/artifacts/artifact-version.service.d.ts +38 -0
- package/dist/src/services/artifacts/artifact-version.service.js +129 -0
- package/dist/src/services/artifacts/chat.service.d.ts +127 -0
- package/dist/src/services/artifacts/chat.service.js +182 -0
- package/dist/src/services/artifacts/study-guide.service.d.ts +18 -0
- package/dist/src/services/artifacts/study-guide.service.js +65 -0
- package/dist/src/services/auth/auth.service.d.ts +94 -0
- package/dist/src/services/auth/auth.service.js +368 -0
- package/dist/src/services/base.service.d.ts +14 -0
- package/dist/src/services/base.service.js +14 -0
- package/dist/src/services/billing/payment.service.d.ts +44 -0
- package/dist/src/services/billing/payment.service.js +365 -0
- package/dist/src/services/billing/subscription.service.d.ts +37 -0
- package/dist/src/services/billing/subscription.service.js +654 -0
- package/dist/src/services/billing/usage.service.d.ts +47 -0
- package/dist/src/services/billing/usage.service.js +149 -0
- package/dist/src/services/content/copilot.service.d.ts +113 -0
- package/dist/src/services/content/copilot.service.js +439 -0
- package/dist/src/services/content/flashcard-progress.service.d.ts +159 -0
- package/dist/src/services/content/flashcard-progress.service.js +432 -0
- package/dist/src/services/content/flashcard.service.d.ts +184 -0
- package/dist/src/services/content/flashcard.service.js +339 -0
- package/dist/src/services/content/media-analysis.service.d.ts +23 -0
- package/dist/src/services/content/media-analysis.service.js +404 -0
- package/dist/src/services/content/podcast.service.d.ts +267 -0
- package/dist/src/services/content/podcast.service.js +653 -0
- package/dist/src/services/content/worksheet-content.service.d.ts +37 -0
- package/dist/src/services/content/worksheet-content.service.js +84 -0
- package/dist/src/services/content/worksheet-content.service.test.d.ts +1 -0
- package/dist/src/services/content/worksheet-content.service.test.js +69 -0
- package/dist/src/services/content/worksheet-generation.service.d.ts +91 -0
- package/dist/src/services/content/worksheet-generation.service.js +95 -0
- package/dist/src/services/content/worksheet-generation.service.test.d.ts +1 -0
- package/dist/src/services/content/worksheet-generation.service.test.js +20 -0
- package/dist/src/services/content/worksheet.service.d.ts +347 -0
- package/dist/src/services/content/worksheet.service.js +599 -0
- package/dist/src/services/knowledge/knowledge-base.service.d.ts +316 -0
- package/dist/src/services/knowledge/knowledge-base.service.js +544 -0
- package/dist/src/services/members/invitation.service.d.ts +66 -0
- package/dist/src/services/members/invitation.service.js +348 -0
- package/dist/src/services/members/member.service.d.ts +36 -0
- package/dist/src/services/members/member.service.js +193 -0
- package/dist/src/services/notifications/notification.service.d.ts +214 -0
- package/dist/src/services/notifications/notification.service.js +550 -0
- package/dist/src/services/notifications/notification.service.test.d.ts +1 -0
- package/dist/src/services/notifications/notification.service.test.js +87 -0
- package/dist/src/services/workspace/workspace-analytics.service.d.ts +24 -0
- package/dist/src/services/workspace/workspace-analytics.service.js +95 -0
- package/dist/src/services/workspace/workspace-kb.service.d.ts +40 -0
- package/dist/src/services/workspace/workspace-kb.service.js +184 -0
- package/dist/src/services/workspace/workspace.service.d.ts +263 -0
- package/dist/src/services/workspace/workspace.service.js +401 -0
- package/dist/src/trpc.d.ts +60 -0
- package/dist/src/trpc.js +217 -0
- package/dist/src/types/index.d.ts +126 -0
- package/dist/src/types/index.js +1 -0
- package/dist/trpc.d.ts +12 -4
- package/dist/trpc.js +5 -11
- package/package.json +8 -9
- package/prisma/schema.prisma +3 -4
- package/prisma/seed.mjs +5 -2
- package/prisma.config.ts +16 -0
- package/src/context.ts +33 -3
- package/src/lib/ai/index.ts +3 -0
- package/src/lib/ai/llm-client.ts +23 -0
- package/src/lib/prisma.ts +18 -9
- package/src/routers/auth.ts +1 -1
- package/src/routers/workspace.ts +4 -0
- package/src/scripts/purge-deleted-users.ts +1 -3
- package/src/services/billing/payment.service.ts +3 -6
- package/src/services/billing/usage.service.ts +190 -77
- package/src/services/content/copilot.service.ts +23 -32
- package/src/services/content/flashcard-progress.service.ts +12 -9
- package/src/services/content/flashcard.service.ts +89 -66
- package/src/services/content/media-analysis.service.ts +34 -29
- package/src/services/content/worksheet-generation.service.test.ts +2 -2
- package/src/services/workspace/workspace.service.ts +73 -66
- package/src/trpc.ts +5 -13
- package/tsconfig.json +3 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { MarkScheme, UserMarkScheme } from '../../../types/index.js';
|
|
2
|
+
import type { AISession, PodcastSpeaker, ProcessFileResult, StudyGuideSegment, WorksheetGenerationOptions, BackendGenerationOptions } from './types.js';
|
|
3
|
+
export declare class InferenceBackendClient {
|
|
4
|
+
private sessions;
|
|
5
|
+
private get uploadUrl();
|
|
6
|
+
private postCommand;
|
|
7
|
+
private buildForm;
|
|
8
|
+
private withRag;
|
|
9
|
+
initSession(workspaceId: string, user: string): Promise<AISession>;
|
|
10
|
+
processFile(sessionId: string, _user: string, fileUrl: string, fileType: 'image' | 'pdf', maxPages?: number): Promise<ProcessFileResult>;
|
|
11
|
+
generateStudyGuide(sessionId: string, user: string, opts?: BackendGenerationOptions): Promise<string>;
|
|
12
|
+
generateFlashcardQuestions(sessionId: string, user: string, numQuestions: number, difficulty: 'easy' | 'medium' | 'hard', prompt?: string, opts?: BackendGenerationOptions): Promise<string>;
|
|
13
|
+
generateWorksheetQuestions(sessionId: string, user: string, numQuestions: number, difficulty: 'EASY' | 'MEDIUM' | 'HARD', options?: WorksheetGenerationOptions): Promise<string>;
|
|
14
|
+
checkWorksheetQuestions(sessionId: string, user: string, question: string, answer: string, markScheme: MarkScheme): Promise<UserMarkScheme>;
|
|
15
|
+
generatePodcastStructure(sessionId: string, user: string, title: string, description: string, prompt: string, speakers: PodcastSpeaker[]): Promise<any>;
|
|
16
|
+
generatePodcastAudioFromText(sessionId: string, user: string, podcastId: string, segmentIndex: number, text: string, speakers: PodcastSpeaker[], voiceId?: string): Promise<any>;
|
|
17
|
+
generatePodcastImage(sessionId: string, user: string, summary: string): Promise<string>;
|
|
18
|
+
segmentStudyGuide(sessionId: string, user: string, studyGuide: string): Promise<StudyGuideSegment[]>;
|
|
19
|
+
validateSegmentSummary(sessionId: string, user: string, segmentContent: string, studentResponse: string, studyGuide: string): Promise<{
|
|
20
|
+
valid: boolean;
|
|
21
|
+
feedback: string;
|
|
22
|
+
}>;
|
|
23
|
+
getSession(sessionId: string): AISession | undefined;
|
|
24
|
+
getSessionsByUserAndWorkspace(_userId: string, workspaceId: string): AISession[];
|
|
25
|
+
deleteSession(sessionId: string): boolean;
|
|
26
|
+
checkHealth(): Promise<boolean>;
|
|
27
|
+
}
|
|
28
|
+
export declare const inferenceBackend: InferenceBackendClient;
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { TRPCError } from '@trpc/server';
|
|
2
|
+
import { getInferenceBackendUploadUrl, aiConfig, tryGetInferenceBackendUploadUrl } from '../config.js';
|
|
3
|
+
import { isAiMockMode, mockDelay } from '../mock.js';
|
|
4
|
+
import { parseJsonField } from '../json-parse.js';
|
|
5
|
+
import { withRetry } from '../../retry.js';
|
|
6
|
+
import { logger } from '../../logger.js';
|
|
7
|
+
import { mockFlashcards, mockPodcastAudio, mockPodcastStructure, mockProcessFile, mockSegmentSummaryValidation, mockStudyGuide, mockStudyGuideSegmentation, mockWorksheet, } from './mocks.js';
|
|
8
|
+
export class InferenceBackendClient {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.sessions = new Map();
|
|
11
|
+
}
|
|
12
|
+
get uploadUrl() {
|
|
13
|
+
return getInferenceBackendUploadUrl();
|
|
14
|
+
}
|
|
15
|
+
async postCommand(formData, options) {
|
|
16
|
+
const { label, timeoutMs = 300000, retries = 3 } = options;
|
|
17
|
+
return withRetry(async () => {
|
|
18
|
+
const controller = new AbortController();
|
|
19
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
20
|
+
try {
|
|
21
|
+
const response = await fetch(this.uploadUrl, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
body: formData,
|
|
24
|
+
signal: controller.signal,
|
|
25
|
+
});
|
|
26
|
+
clearTimeout(timeoutId);
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
const errorText = await response.text().catch(() => '');
|
|
29
|
+
throw new Error(`AI backend error (${response.status}): ${errorText || response.statusText}`);
|
|
30
|
+
}
|
|
31
|
+
return (await response.json());
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
clearTimeout(timeoutId);
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
}, { maxRetries: retries, timeoutMs, label });
|
|
38
|
+
}
|
|
39
|
+
buildForm(command, fields = {}) {
|
|
40
|
+
const formData = new FormData();
|
|
41
|
+
formData.append('command', command);
|
|
42
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
43
|
+
formData.append(key, value);
|
|
44
|
+
}
|
|
45
|
+
return formData;
|
|
46
|
+
}
|
|
47
|
+
withRag(fields, opts) {
|
|
48
|
+
if (opts?.ragContext?.trim()) {
|
|
49
|
+
return { ...fields, rag_context: opts.ragContext.trim() };
|
|
50
|
+
}
|
|
51
|
+
return fields;
|
|
52
|
+
}
|
|
53
|
+
async initSession(workspaceId, user) {
|
|
54
|
+
await mockDelay();
|
|
55
|
+
const sessionId = workspaceId;
|
|
56
|
+
if (isAiMockMode()) {
|
|
57
|
+
logger.info(`[ai] mock initSession workspace=${workspaceId}`);
|
|
58
|
+
const session = {
|
|
59
|
+
id: sessionId,
|
|
60
|
+
workspaceId,
|
|
61
|
+
status: 'initialized',
|
|
62
|
+
files: [],
|
|
63
|
+
createdAt: new Date(),
|
|
64
|
+
updatedAt: new Date(),
|
|
65
|
+
};
|
|
66
|
+
this.sessions.set(sessionId, session);
|
|
67
|
+
return session;
|
|
68
|
+
}
|
|
69
|
+
const result = await this.postCommand(this.buildForm('init_session', { session: sessionId, user }), { label: 'initSession' });
|
|
70
|
+
if (!result.message) {
|
|
71
|
+
throw new TRPCError({
|
|
72
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
73
|
+
message: 'AI backend returned no session message',
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
const session = {
|
|
77
|
+
id: sessionId,
|
|
78
|
+
workspaceId,
|
|
79
|
+
status: 'initialized',
|
|
80
|
+
files: [],
|
|
81
|
+
createdAt: new Date(),
|
|
82
|
+
updatedAt: new Date(),
|
|
83
|
+
};
|
|
84
|
+
this.sessions.set(sessionId, session);
|
|
85
|
+
return session;
|
|
86
|
+
}
|
|
87
|
+
async processFile(sessionId, _user, fileUrl, fileType, maxPages) {
|
|
88
|
+
await mockDelay();
|
|
89
|
+
if (isAiMockMode()) {
|
|
90
|
+
logger.info(`[ai] mock processFile session=${sessionId} type=${fileType}`);
|
|
91
|
+
return mockProcessFile(fileType);
|
|
92
|
+
}
|
|
93
|
+
const fields = { fileUrl, fileType };
|
|
94
|
+
if (maxPages)
|
|
95
|
+
fields.maxPages = maxPages.toString();
|
|
96
|
+
try {
|
|
97
|
+
const result = await this.postCommand(this.buildForm('process_file', fields), { label: 'processFile' });
|
|
98
|
+
if (result.status === 'error') {
|
|
99
|
+
throw new Error(result.error || 'File processing failed');
|
|
100
|
+
}
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
105
|
+
logger.error(`[ai] processFile failed: ${message}`);
|
|
106
|
+
return {
|
|
107
|
+
status: 'error',
|
|
108
|
+
textContent: null,
|
|
109
|
+
imageDescriptions: [],
|
|
110
|
+
comprehensiveDescription: null,
|
|
111
|
+
pageCount: 0,
|
|
112
|
+
error: message,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async generateStudyGuide(sessionId, user, opts) {
|
|
117
|
+
await mockDelay();
|
|
118
|
+
if (isAiMockMode()) {
|
|
119
|
+
logger.info(`[ai] mock generateStudyGuide session=${sessionId}`);
|
|
120
|
+
return mockStudyGuide();
|
|
121
|
+
}
|
|
122
|
+
const result = await this.postCommand(this.buildForm('generate_study_guide', this.withRag({ session: sessionId, user }, opts)), { label: 'generateStudyGuide' });
|
|
123
|
+
if (!result.markdown) {
|
|
124
|
+
throw new Error('AI backend returned empty study guide');
|
|
125
|
+
}
|
|
126
|
+
return result.markdown;
|
|
127
|
+
}
|
|
128
|
+
async generateFlashcardQuestions(sessionId, user, numQuestions, difficulty, prompt, opts) {
|
|
129
|
+
await mockDelay();
|
|
130
|
+
if (isAiMockMode()) {
|
|
131
|
+
logger.info(`[ai] mock generateFlashcardQuestions session=${sessionId}`);
|
|
132
|
+
return JSON.stringify(mockFlashcards(numQuestions, difficulty));
|
|
133
|
+
}
|
|
134
|
+
const fields = {
|
|
135
|
+
session: sessionId,
|
|
136
|
+
user,
|
|
137
|
+
num_questions: numQuestions.toString(),
|
|
138
|
+
difficulty,
|
|
139
|
+
};
|
|
140
|
+
if (prompt)
|
|
141
|
+
fields.prompt = prompt;
|
|
142
|
+
const result = await this.postCommand(this.buildForm('generate_flashcard_questions', this.withRag(fields, opts)), { label: 'generateFlashcardQuestions' });
|
|
143
|
+
const parsed = JSON.parse(result.flashcards);
|
|
144
|
+
if (Array.isArray(parsed))
|
|
145
|
+
return JSON.stringify(parsed);
|
|
146
|
+
return JSON.stringify(parsed.flashcards ?? []);
|
|
147
|
+
}
|
|
148
|
+
async generateWorksheetQuestions(sessionId, user, numQuestions, difficulty, options) {
|
|
149
|
+
await mockDelay();
|
|
150
|
+
if (isAiMockMode()) {
|
|
151
|
+
logger.info(`[ai] mock generateWorksheetQuestions session=${sessionId}`);
|
|
152
|
+
return JSON.stringify(mockWorksheet(numQuestions, difficulty, options));
|
|
153
|
+
}
|
|
154
|
+
const fields = {
|
|
155
|
+
session: sessionId,
|
|
156
|
+
user,
|
|
157
|
+
num_questions: numQuestions.toString(),
|
|
158
|
+
difficulty,
|
|
159
|
+
mode: options?.mode ?? 'practice',
|
|
160
|
+
};
|
|
161
|
+
if (options?.mcqRatio !== undefined) {
|
|
162
|
+
fields.mcq_ratio = String(options.mcqRatio);
|
|
163
|
+
}
|
|
164
|
+
if (options?.questionTypes?.length) {
|
|
165
|
+
fields.question_types = JSON.stringify(options.questionTypes);
|
|
166
|
+
}
|
|
167
|
+
if (options?.prompt) {
|
|
168
|
+
fields.worksheet_prompt = options.prompt;
|
|
169
|
+
}
|
|
170
|
+
const result = await this.postCommand(this.buildForm('generate_worksheet_questions', this.withRag(fields, { ragContext: options?.ragContext })), { label: 'generateWorksheetQuestions' });
|
|
171
|
+
return result.worksheet;
|
|
172
|
+
}
|
|
173
|
+
async checkWorksheetQuestions(sessionId, user, question, answer, markScheme) {
|
|
174
|
+
const result = await this.postCommand(this.buildForm('mark_worksheet_questions', {
|
|
175
|
+
session: sessionId,
|
|
176
|
+
user,
|
|
177
|
+
question,
|
|
178
|
+
answer,
|
|
179
|
+
mark_scheme: JSON.stringify(markScheme),
|
|
180
|
+
}), { label: 'checkWorksheetQuestions', retries: 2 });
|
|
181
|
+
return parseJsonField(result.marking, 'marking');
|
|
182
|
+
}
|
|
183
|
+
async generatePodcastStructure(sessionId, user, title, description, prompt, speakers) {
|
|
184
|
+
await mockDelay();
|
|
185
|
+
if (isAiMockMode()) {
|
|
186
|
+
logger.info(`[ai] mock generatePodcastStructure session=${sessionId}`);
|
|
187
|
+
return mockPodcastStructure(title, speakers);
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
return await this.postCommand(this.buildForm('generate_podcast_structure', {
|
|
191
|
+
user,
|
|
192
|
+
session: sessionId,
|
|
193
|
+
title,
|
|
194
|
+
description,
|
|
195
|
+
prompt,
|
|
196
|
+
speakers: JSON.stringify(speakers),
|
|
197
|
+
}), { label: 'generatePodcastStructure' });
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
throw new TRPCError({
|
|
201
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
202
|
+
message: `Failed to generate podcast structure: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async generatePodcastAudioFromText(sessionId, user, podcastId, segmentIndex, text, speakers, voiceId) {
|
|
207
|
+
await mockDelay();
|
|
208
|
+
if (isAiMockMode()) {
|
|
209
|
+
logger.info(`[ai] mock generatePodcastAudio session=${sessionId}`);
|
|
210
|
+
return mockPodcastAudio(user, sessionId, podcastId, segmentIndex, text);
|
|
211
|
+
}
|
|
212
|
+
const fields = {
|
|
213
|
+
user,
|
|
214
|
+
session: sessionId,
|
|
215
|
+
podcast_id: podcastId,
|
|
216
|
+
segment_index: segmentIndex.toString(),
|
|
217
|
+
text,
|
|
218
|
+
speakers: JSON.stringify(speakers),
|
|
219
|
+
};
|
|
220
|
+
if (voiceId)
|
|
221
|
+
fields.voice_id = voiceId;
|
|
222
|
+
try {
|
|
223
|
+
return await this.postCommand(this.buildForm('generate_podcast_audio_from_text', fields), { label: 'generatePodcastAudioFromText' });
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
throw new TRPCError({
|
|
227
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
228
|
+
message: `Failed to generate podcast audio: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async generatePodcastImage(sessionId, user, summary) {
|
|
233
|
+
const result = await this.postCommand(this.buildForm('generate_podcast_image', {
|
|
234
|
+
session: sessionId,
|
|
235
|
+
user,
|
|
236
|
+
summary,
|
|
237
|
+
}), { label: 'generatePodcastImage' });
|
|
238
|
+
return result.image_key;
|
|
239
|
+
}
|
|
240
|
+
async segmentStudyGuide(sessionId, user, studyGuide) {
|
|
241
|
+
if (isAiMockMode()) {
|
|
242
|
+
return mockStudyGuideSegmentation();
|
|
243
|
+
}
|
|
244
|
+
const result = await this.postCommand(this.buildForm('generate_study_guide_segmentation', {
|
|
245
|
+
session: sessionId,
|
|
246
|
+
user,
|
|
247
|
+
study_guide: studyGuide,
|
|
248
|
+
}), { label: 'segmentStudyGuide' });
|
|
249
|
+
return result.segmentation;
|
|
250
|
+
}
|
|
251
|
+
async validateSegmentSummary(sessionId, user, segmentContent, studentResponse, studyGuide) {
|
|
252
|
+
if (isAiMockMode()) {
|
|
253
|
+
return mockSegmentSummaryValidation();
|
|
254
|
+
}
|
|
255
|
+
const result = await this.postCommand(this.buildForm('validate_segment_summary', {
|
|
256
|
+
session: sessionId,
|
|
257
|
+
user,
|
|
258
|
+
segment_content: segmentContent,
|
|
259
|
+
student_response: studentResponse,
|
|
260
|
+
study_guide: studyGuide,
|
|
261
|
+
}), { label: 'validateSegmentSummary' });
|
|
262
|
+
return result.feedback;
|
|
263
|
+
}
|
|
264
|
+
getSession(sessionId) {
|
|
265
|
+
return this.sessions.get(sessionId);
|
|
266
|
+
}
|
|
267
|
+
getSessionsByUserAndWorkspace(_userId, workspaceId) {
|
|
268
|
+
return Array.from(this.sessions.values()).filter((session) => session.workspaceId === workspaceId);
|
|
269
|
+
}
|
|
270
|
+
deleteSession(sessionId) {
|
|
271
|
+
return this.sessions.delete(sessionId);
|
|
272
|
+
}
|
|
273
|
+
async checkHealth() {
|
|
274
|
+
await mockDelay();
|
|
275
|
+
if (isAiMockMode()) {
|
|
276
|
+
logger.info('[ai] mock health check');
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
const uploadUrl = tryGetInferenceBackendUploadUrl();
|
|
280
|
+
if (!uploadUrl)
|
|
281
|
+
return false;
|
|
282
|
+
try {
|
|
283
|
+
const response = await fetch(uploadUrl, {
|
|
284
|
+
method: 'POST',
|
|
285
|
+
body: new FormData(),
|
|
286
|
+
});
|
|
287
|
+
return response.ok;
|
|
288
|
+
}
|
|
289
|
+
catch (error) {
|
|
290
|
+
logger.error('[ai] health check failed', error);
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
export const inferenceBackend = new InferenceBackendClient();
|
|
296
|
+
if (aiConfig.inferenceBackend.url) {
|
|
297
|
+
logger.info(`[ai] inference backend: ${aiConfig.inferenceBackend.url}`);
|
|
298
|
+
}
|
|
299
|
+
if (isAiMockMode()) {
|
|
300
|
+
logger.info('[ai] mock mode enabled (DONT_TEST_INFERENCE=true)');
|
|
301
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ProcessFileResult, PodcastSpeaker, StudyGuideSegment, WorksheetGenerationOptions } from './types.js';
|
|
2
|
+
export declare function mockStudyGuide(): string;
|
|
3
|
+
export declare function mockFlashcards(numQuestions: number, difficulty: 'easy' | 'medium' | 'hard'): unknown[];
|
|
4
|
+
export declare function mockWorksheet(numQuestions: number, difficulty: 'EASY' | 'MEDIUM' | 'HARD', options?: WorksheetGenerationOptions): object;
|
|
5
|
+
export declare function mockProcessFile(fileType: 'image' | 'pdf'): ProcessFileResult;
|
|
6
|
+
export declare function mockPodcastStructure(title: string, speakers: PodcastSpeaker[]): object;
|
|
7
|
+
export declare function mockPodcastAudio(user: string, sessionId: string, podcastId: string, segmentIndex: number, text: string): object;
|
|
8
|
+
export declare function mockStudyGuideSegmentation(): StudyGuideSegment[];
|
|
9
|
+
export declare function mockSegmentSummaryValidation(): {
|
|
10
|
+
valid: boolean;
|
|
11
|
+
feedback: string;
|
|
12
|
+
};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
export function mockStudyGuide() {
|
|
2
|
+
return `# Mock Study Guide
|
|
3
|
+
|
|
4
|
+
## Overview
|
|
5
|
+
This is a mock study guide generated for testing purposes.
|
|
6
|
+
|
|
7
|
+
## Key Concepts
|
|
8
|
+
1. **Concept A**: Mock concept derived from uploaded materials
|
|
9
|
+
2. **Concept B**: Another mock concept with explanations
|
|
10
|
+
3. **Concept C**: A third concept with examples
|
|
11
|
+
|
|
12
|
+
## Summary
|
|
13
|
+
Mock study guide for local development when \`DONT_TEST_INFERENCE=true\`.`;
|
|
14
|
+
}
|
|
15
|
+
export function mockFlashcards(numQuestions, difficulty) {
|
|
16
|
+
return Array.from({ length: numQuestions }, (_, i) => ({
|
|
17
|
+
id: `mock-flashcard-${i + 1}`,
|
|
18
|
+
question: `Mock question ${i + 1}: What is the main concept covered in this material?`,
|
|
19
|
+
answer: `Mock answer ${i + 1}: Sample answer based on uploaded content.`,
|
|
20
|
+
difficulty,
|
|
21
|
+
category: `Mock Category ${(i % 3) + 1}`,
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
export function mockWorksheet(numQuestions, difficulty, options) {
|
|
25
|
+
const mode = options?.mode ?? 'practice';
|
|
26
|
+
const isQuiz = mode === 'quiz';
|
|
27
|
+
return {
|
|
28
|
+
title: isQuiz ? `Mock Quiz - ${difficulty}` : `Mock Worksheet - ${difficulty} Level`,
|
|
29
|
+
description: 'Mock generated content',
|
|
30
|
+
difficulty,
|
|
31
|
+
estimatedTime: `${numQuestions * 2} min`,
|
|
32
|
+
problems: Array.from({ length: numQuestions }, (_, i) => {
|
|
33
|
+
if (isQuiz) {
|
|
34
|
+
return {
|
|
35
|
+
question: `Mock MCQ ${i + 1}: What is 2+2?`,
|
|
36
|
+
answer: '1',
|
|
37
|
+
type: 'MULTIPLE_CHOICE',
|
|
38
|
+
options: ['3', '4', '5', '6'],
|
|
39
|
+
mark_scheme: {
|
|
40
|
+
points: [{ point: 1, requirements: 'Select correct option' }],
|
|
41
|
+
totalPoints: 1,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
question: `Mock question ${i + 1}: Explain a concept.`,
|
|
47
|
+
answer: 'Mock answer',
|
|
48
|
+
type: 'TEXT',
|
|
49
|
+
options: [],
|
|
50
|
+
mark_scheme: {
|
|
51
|
+
points: [{ point: 1, requirements: 'Clear explanation' }],
|
|
52
|
+
totalPoints: 1,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function mockProcessFile(fileType) {
|
|
59
|
+
const mockPageCount = fileType === 'pdf' ? 15 : 1;
|
|
60
|
+
return {
|
|
61
|
+
status: 'success',
|
|
62
|
+
textContent: `Mock extracted text content from ${fileType} file.`,
|
|
63
|
+
imageDescriptions: Array.from({ length: mockPageCount }, (_, i) => ({
|
|
64
|
+
page: i + 1,
|
|
65
|
+
description: `Page ${i + 1} contains educational content with diagrams and text.`,
|
|
66
|
+
hasVisualContent: true,
|
|
67
|
+
})),
|
|
68
|
+
comprehensiveDescription: `DOCUMENT SUMMARY (${mockPageCount} ${mockPageCount === 1 ? 'page' : 'pages'})\n\nTEXT CONTENT:\nMock extracted text content...`,
|
|
69
|
+
pageCount: mockPageCount,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export function mockPodcastStructure(title, speakers) {
|
|
73
|
+
const voiceId = speakers[0]?.id || 'mock-voice-1';
|
|
74
|
+
return {
|
|
75
|
+
success: true,
|
|
76
|
+
structure: {
|
|
77
|
+
episodeTitle: `${title} - AI Generated Episode`,
|
|
78
|
+
totalEstimatedDuration: '15 minutes',
|
|
79
|
+
segments: [
|
|
80
|
+
{
|
|
81
|
+
title: 'Welcome & Introduction',
|
|
82
|
+
content: "HOST: Welcome to today's episode!\nGUEST: Thanks for having me!\nHOST: Let's dive into the topic.",
|
|
83
|
+
speaker: 'dialogue',
|
|
84
|
+
voiceId,
|
|
85
|
+
keyPoints: ['Introduction', 'What to expect'],
|
|
86
|
+
estimatedDuration: '3 minutes',
|
|
87
|
+
order: 1,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
title: 'Main Discussion',
|
|
91
|
+
content: 'This is the main content section where we explore the key concepts in detail.',
|
|
92
|
+
speaker: 'host',
|
|
93
|
+
voiceId,
|
|
94
|
+
keyPoints: ['Key concept 1', 'Key concept 2'],
|
|
95
|
+
estimatedDuration: '8 minutes',
|
|
96
|
+
order: 2,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
title: 'Conclusion & Takeaways',
|
|
100
|
+
content: "HOST: Let's wrap up what we've learned today.\nGUEST: The main takeaway is...\nHOST: Thanks for joining us!",
|
|
101
|
+
speaker: 'dialogue',
|
|
102
|
+
voiceId,
|
|
103
|
+
keyPoints: ['Summary', 'Next steps'],
|
|
104
|
+
estimatedDuration: '4 minutes',
|
|
105
|
+
order: 3,
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
export function mockPodcastAudio(user, sessionId, podcastId, segmentIndex, text) {
|
|
112
|
+
const isDialogue = text.includes('HOST:') || text.includes('GUEST:');
|
|
113
|
+
return {
|
|
114
|
+
success: true,
|
|
115
|
+
segmentIndex,
|
|
116
|
+
objectKey: `${user}/${sessionId}/podcasts/${podcastId}/segment_${segmentIndex}.mp3`,
|
|
117
|
+
duration: 45 + Math.floor(Math.random() * 30),
|
|
118
|
+
type: isDialogue ? 'dialogue' : 'monologue',
|
|
119
|
+
...(isDialogue ? { partCount: 4 } : {}),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
export function mockStudyGuideSegmentation() {
|
|
123
|
+
return [
|
|
124
|
+
{ hint: 'Overview', content: 'Mock segment 1 content' },
|
|
125
|
+
{ hint: 'Key concepts', content: 'Mock segment 2 content' },
|
|
126
|
+
];
|
|
127
|
+
}
|
|
128
|
+
export function mockSegmentSummaryValidation() {
|
|
129
|
+
return {
|
|
130
|
+
valid: true,
|
|
131
|
+
feedback: 'Mock validation feedback for local development.',
|
|
132
|
+
};
|
|
133
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface AISession {
|
|
2
|
+
id: string;
|
|
3
|
+
workspaceId: string;
|
|
4
|
+
status: 'initialized' | 'processing' | 'ready' | 'error';
|
|
5
|
+
files: string[];
|
|
6
|
+
instructionText?: string;
|
|
7
|
+
createdAt: Date;
|
|
8
|
+
updatedAt: Date;
|
|
9
|
+
}
|
|
10
|
+
export interface ProcessFileResult {
|
|
11
|
+
status: 'success' | 'error';
|
|
12
|
+
textContent: string | null;
|
|
13
|
+
imageDescriptions: Array<{
|
|
14
|
+
page: number;
|
|
15
|
+
description: string;
|
|
16
|
+
hasVisualContent: boolean;
|
|
17
|
+
}>;
|
|
18
|
+
comprehensiveDescription: string | null;
|
|
19
|
+
pageCount: number;
|
|
20
|
+
error?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface PodcastSpeaker {
|
|
23
|
+
id: string;
|
|
24
|
+
role: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface WorksheetGenerationOptions {
|
|
28
|
+
mode?: 'practice' | 'quiz';
|
|
29
|
+
mcqRatio?: number;
|
|
30
|
+
questionTypes?: string[];
|
|
31
|
+
prompt?: string;
|
|
32
|
+
ragContext?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface BackendGenerationOptions {
|
|
35
|
+
ragContext?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface StudyGuideSegment {
|
|
38
|
+
hint: string;
|
|
39
|
+
content: string;
|
|
40
|
+
}
|
|
41
|
+
export interface SegmentSummaryValidation {
|
|
42
|
+
valid: boolean;
|
|
43
|
+
feedback: string;
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export function extractJson(content) {
|
|
2
|
+
const fencedMatch = content.match(/```json\s*([\s\S]*?)```/i);
|
|
3
|
+
if (fencedMatch?.[1]) {
|
|
4
|
+
try {
|
|
5
|
+
return JSON.parse(fencedMatch[1]);
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
// fall through
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const objectMatch = content.match(/\{[\s\S]*\}/);
|
|
12
|
+
if (objectMatch?.[0]) {
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(objectMatch[0]);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
export function parseJsonField(value, field) {
|
|
23
|
+
if (typeof value === 'string') {
|
|
24
|
+
return JSON.parse(value);
|
|
25
|
+
}
|
|
26
|
+
if (value && typeof value === 'object' && field in value) {
|
|
27
|
+
const nested = value[field];
|
|
28
|
+
if (typeof nested === 'string') {
|
|
29
|
+
return JSON.parse(nested);
|
|
30
|
+
}
|
|
31
|
+
return nested;
|
|
32
|
+
}
|
|
33
|
+
throw new Error(`Expected JSON field "${field}" in AI response`);
|
|
34
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ChatCompletion } from 'openai/resources/chat/completions';
|
|
2
|
+
import type { ChatMessage, CompleteOptions } from './types.js';
|
|
3
|
+
export declare function complete(messages: ChatMessage[], options?: CompleteOptions): Promise<ChatCompletion>;
|
|
4
|
+
export declare function completeText(messages: ChatMessage[], options?: CompleteOptions): Promise<string>;
|
|
5
|
+
export declare function streamComplete(messages: ChatMessage[], onDelta: (delta: string) => void | Promise<void>, options?: CompleteOptions): Promise<string>;
|
|
6
|
+
/** @deprecated Use `complete()` from the ai module instead. */
|
|
7
|
+
export default complete;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import OpenAI from 'openai';
|
|
2
|
+
import { aiConfig } from './config.js';
|
|
3
|
+
const client = new OpenAI({
|
|
4
|
+
apiKey: aiConfig.llm.apiKey,
|
|
5
|
+
baseURL: aiConfig.llm.baseUrl,
|
|
6
|
+
});
|
|
7
|
+
export async function complete(messages, options = {}) {
|
|
8
|
+
return client.chat.completions.create({
|
|
9
|
+
model: options.model ?? aiConfig.llm.model,
|
|
10
|
+
messages,
|
|
11
|
+
...(options.temperature !== undefined ? { temperature: options.temperature } : {}),
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export async function completeText(messages, options = {}) {
|
|
15
|
+
const response = await complete(messages, options);
|
|
16
|
+
return response.choices?.[0]?.message?.content ?? '';
|
|
17
|
+
}
|
|
18
|
+
export async function streamComplete(messages, onDelta, options = {}) {
|
|
19
|
+
const stream = await client.chat.completions.create({
|
|
20
|
+
model: options.model ?? aiConfig.llm.model,
|
|
21
|
+
messages,
|
|
22
|
+
stream: true,
|
|
23
|
+
...(options.temperature !== undefined ? { temperature: options.temperature } : {}),
|
|
24
|
+
});
|
|
25
|
+
let content = '';
|
|
26
|
+
for await (const chunk of stream) {
|
|
27
|
+
const delta = chunk.choices?.[0]?.delta?.content ?? '';
|
|
28
|
+
if (!delta)
|
|
29
|
+
continue;
|
|
30
|
+
content += delta;
|
|
31
|
+
await onDelta(delta);
|
|
32
|
+
}
|
|
33
|
+
return content;
|
|
34
|
+
}
|
|
35
|
+
/** @deprecated Use `complete()` from the ai module instead. */
|
|
36
|
+
export default complete;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { aiConfig } from './config.js';
|
|
2
|
+
export function isAiMockMode() {
|
|
3
|
+
return aiConfig.inferenceBackend.mockEnabled;
|
|
4
|
+
}
|
|
5
|
+
export async function mockDelay() {
|
|
6
|
+
const delay = aiConfig.inferenceBackend.mockDelayMs;
|
|
7
|
+
if (delay > 0) {
|
|
8
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication utilities for custom HMAC-based cookie verification.
|
|
3
|
+
*
|
|
4
|
+
* This module provides secure authentication using HMAC-SHA256 signatures
|
|
5
|
+
* to verify user identity through signed cookies.
|
|
6
|
+
*
|
|
7
|
+
* @fileoverview Custom authentication system with HMAC cookie verification
|
|
8
|
+
* @author Scribe Team
|
|
9
|
+
* @version 1.0.0
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Represents the result of successful authentication verification.
|
|
13
|
+
*/
|
|
14
|
+
export interface AuthResult {
|
|
15
|
+
/** The authenticated user's unique identifier */
|
|
16
|
+
userId: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Verifies a custom HMAC-signed authentication cookie.
|
|
20
|
+
*
|
|
21
|
+
* The cookie format is: `base64(userId).hex(hmacSHA256(base64(userId), secret))`
|
|
22
|
+
*
|
|
23
|
+
* @param cookieValue - The raw cookie value to verify, or undefined if no cookie exists
|
|
24
|
+
* @returns Authentication result with userId if valid, null if invalid or missing
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* const result = verifyCustomAuthCookie("dXNlcjEyMw.abc123def456...");
|
|
29
|
+
* if (result) {
|
|
30
|
+
* console.log(`Authenticated user: ${result.userId}`);
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @throws {Error} Never throws - returns null for all error conditions
|
|
35
|
+
*/
|
|
36
|
+
export declare function verifyCustomAuthCookie(cookieValue: string | undefined): AuthResult | null;
|