1 /* eslint-disable @typescript-eslint/lines-between-class-members */
3 /* eslint-disable @typescript-eslint/no-unused-vars */
5 /* eslint-disable @typescript-eslint/no-use-before-define */
6 import type { CacheId, DownloadResult, LlmFile } from '@proton/llm/lib/downloader';
8 export type PromiseResolve = (value: PromiseLike<void> | void) => void;
10 export type PromiseReject = (reason?: any) => void;
12 export interface LlmManager {
13 // prefer passing a canvas, it will allow us to get some info using WebGL
14 startDownload: (updateProgress: DownloadProgressCallback, assistantConfig: AssistantConfig) => Promise<boolean>; // returns whether it completed
15 cancelDownload: () => void;
16 loadOnGpu: (assistantConfig: AssistantConfig) => Promise<LlmModel>;
17 isDownloaded: (assistantConfig: AssistantConfig, setLlmStatus?: boolean) => Promise<boolean>;
20 export interface LlmModel {
21 unload: () => Promise<void>;
22 performAction: (action: Action, callback: GenerationCallback) => Promise<RunningAction>;
25 export interface RunningAction {
26 isRunning: () => boolean;
27 isDone: () => boolean;
28 isCancelled: () => boolean;
30 cancel: () => boolean;
31 waitForCompletion(): Promise<void>;
34 export type GenerationCallbackDetails = {
38 export type GenerationCallback = (fulltext: string, details?: GenerationCallbackDetails) => void;
42 * Here is the classification for the different actions:
45 * proofread } "predefined }
46 * shorten } refine actions" } "refine actions"
49 * The types below indicate this hierarchy, along with optional info
50 * like the refine location.
53 type ActionOptions = {
54 userInputFormat?: 'plaintext' | 'markdown';
55 assistantOutputFormat?: 'plaintext' | 'markdown';
58 // "Write Full Email": initial generation of an email based on a user prompt.
59 export type WriteFullEmailAction = {
60 type: 'writeFullEmail';
67 // Identifies a substring to refine along with its context. Only for refine actions.
68 // Usually, this will be a selection inside the generated text.
69 export type RefineLocation = {
70 fullEmail: string; // `fullEmail.slice(idxStart, idxEnd)` is the part to rephrase
71 idxStart: number; // beginning of part to rephrase
72 idxEnd: number; // end of part to rephrase
75 // "Custom Refine" refers to the reformulation of an already-generated email, or part of it,
76 // with a custom request written by the user (e.g. "make it formal").
77 export type CustomRefineAction = PartialCustomRefineAction & RefineLocation;
78 export type PartialCustomRefineAction = {
80 prompt: string; // user-submitted instruction of what to do with this text
83 // "Proofread" action button.
84 export type ProofreadAction = PartialProofreadAction & RefineLocation;
85 export type PartialProofreadAction = {
89 // "Shorten" action button.
90 export type ShortenAction = PartialShortenAction & RefineLocation;
91 export type PartialShortenAction = {
95 // "Formal" action button.
96 export type FormalAction = PartialFormalAction & RefineLocation;
97 export type PartialFormalAction = {
101 // "Friendly" action button.
102 export type FriendlyAction = PartialFriendlyAction & RefineLocation;
103 export type PartialFriendlyAction = {
107 // "Expand" action button.
108 export type ExpandAction = PartialExpandAction & RefineLocation;
109 export type PartialExpandAction = {
113 export type PartialRefineAction =
114 | PartialProofreadAction
115 | PartialShortenAction
116 | PartialFormalAction
117 | PartialFriendlyAction
118 | PartialExpandAction
119 | PartialCustomRefineAction;
120 export type RefineAction = PartialRefineAction & RefineLocation;
121 export type PredefinedRefineAction = ProofreadAction | ShortenAction | FormalAction | FriendlyAction | ExpandAction;
122 export type Action = WriteFullEmailAction | RefineAction;
124 export type PredefinedRefineActionType = PredefinedRefineAction['type'];
125 export type RefineActionType = RefineAction['type'];
126 export type ActionType = Action['type'];
128 export function isPredefinedRefineActionType(value: any): value is PredefinedRefineActionType {
130 value === 'shorten' || value === 'proofread' || value === 'formal' || value === 'friendly' || value === 'expand'
134 export function isRefineActionType(value: any): value is RefineActionType {
135 return value === 'customRefine' || isPredefinedRefineActionType(value);
138 // A function to monitor the overall download progress.
140 // `info.estimatedTotalBytes` can change over time, because there are a few
141 // files whose size is unknown until we start downloading them. That said,
142 // it shouldn't be far from reality anyway, because we know the size of the
143 // biggest files upfront.
145 // If the download is stopped and then resume, this progress will take into
146 // account the files already cached and start from that number, not from zero.
147 export type DownloadProgressCallback = (info: DownloadProgressInfo) => void;
148 export type DownloadProgressInfo = {
149 receivedFiles: number;
151 receivedBytes: number;
152 estimatedTotalBytes: number;
155 export interface AssistantModel {
160 VRAMRequiredMB: number;
161 LowResourceRequired: boolean;
162 RequiredFeatures: string[];
165 export interface AssistantConfigModel {
167 model_download_url: string;
169 model_lib_url: string;
170 vram_required_MB: number;
171 low_resource_required: boolean;
172 required_features: string[];
175 export interface AssistantConfig {
176 model_list: AssistantConfigModel[];
177 use_web_worker: boolean;
180 export enum OpenedAssistantStatus {
181 EXPANDED = 'expanded',
182 COLLAPSED = 'collapsed',
185 export type OpenedAssistant = {
187 status: OpenedAssistantStatus;
191 * Events sent from or to the assistant iframe
193 export enum AssistantEvent {
194 // Messages from parent to iframe
195 START_DOWNLOAD = 'start-download',
196 PAUSE_DOWNLOAD = 'pause-download',
198 // Messages from iframe to parent
199 IFRAME_READY = 'iframe-ready',
200 DOWNLOAD_DATA = 'download-data',
201 DOWNLOAD_PROGRESS = 'download-progress',
202 DOWNLOAD_ERROR = 'download-error',
205 interface StartDownloadMessage {
206 type: AssistantEvent.START_DOWNLOAD;
208 config: AssistantConfig;
209 modelVariant: string;
210 filesToIgnore: LlmFile[];
214 interface PauseDownloadMessage {
215 type: AssistantEvent.PAUSE_DOWNLOAD;
218 interface IframeReady {
219 type: AssistantEvent.IFRAME_READY;
222 interface DownloadedChunkMessage {
223 type: AssistantEvent.DOWNLOAD_DATA;
225 downloadResult: DownloadResult;
228 expectedMd5?: string;
233 interface DownloadProgressMessage {
234 type: AssistantEvent.DOWNLOAD_PROGRESS;
236 progress: DownloadProgressInfo;
240 interface DownloadErrorMessage {
241 type: AssistantEvent.DOWNLOAD_ERROR;
247 export type ParentToIframeMessage = StartDownloadMessage | PauseDownloadMessage;
249 export type IframeToParentMessage =
251 | DownloadedChunkMessage
252 | DownloadProgressMessage
253 | DownloadErrorMessage;