From 383b0487d5268bd860e514feddf09f4f3eb2fe3f Mon Sep 17 00:00:00 2001 From: eleanor-park Date: Thu, 2 Jan 2025 01:13:50 -0500 Subject: made drawing fill automatically size images --- src/client/views/smartdraw/FireflyConstants.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/client/views/smartdraw/FireflyConstants.ts (limited to 'src/client/views/smartdraw/FireflyConstants.ts') diff --git a/src/client/views/smartdraw/FireflyConstants.ts b/src/client/views/smartdraw/FireflyConstants.ts new file mode 100644 index 000000000..f51305fba --- /dev/null +++ b/src/client/views/smartdraw/FireflyConstants.ts @@ -0,0 +1,20 @@ +export enum FireflyImageDimensions { + Square = 'square', + Landscape = 'landscape', + Portrait = 'portrait', + Widescreen = 'widescreen', +} + +export const FireflyDimensionsMap = { + square: { width: 2048, height: 2048 }, + landscape: { width: 2304, height: 1792 }, + portrait: { width: 1792, height: 2304 }, + widescreen: { width: 2688, height: 1536 }, +}; + +export const AspectRatioLimits = { + square: 1, + landscape: 1.167, + portrait: 0.875, + widescreen: 1.472, +}; -- cgit v1.2.3-70-g09d2 From 6e7cb570f9bad527cd4772bb5c715dd588fb77df Mon Sep 17 00:00:00 2001 From: eleanor-park Date: Thu, 2 Jan 2025 22:39:25 -0500 Subject: tags can now be used as style presets --- src/client/apis/gpt/GPT.ts | 2 +- src/client/views/DocumentButtonBar.tsx | 18 ++++++++++++++++++ src/client/views/nodes/DocumentView.tsx | 2 ++ src/client/views/smartdraw/DrawingFillHandler.tsx | 10 +++++++--- src/client/views/smartdraw/FireflyConstants.ts | 22 ++++++++++++++++++++++ src/server/ApiManagers/FireflyManager.ts | 7 +++++-- 6 files changed, 55 insertions(+), 6 deletions(-) (limited to 'src/client/views/smartdraw/FireflyConstants.ts') diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index 9241eb120..4b0d58cc1 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -260,7 +260,7 @@ const gptDescribeImage = async (image: string): Promise => { content: [ { type: 'text', - text: `Identify what this drawing is, naming as many elements and their location in the drawing as possible`, + text: `Briefly identify what this drawing is, naming all the drawing elements and their location within the image. Do not include anything about the drawing style.`, }, { type: 'image_url', diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 32bf67df1..b7033af3f 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -314,6 +314,23 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => ( ); } + @computed + get aiEditorButton() { + const targetDoc = this.view0?.Document; + return !targetDoc ? null : ( + Edit with AI}> +
{ + CalendarManager.Instance.open(this.view0, targetDoc); + }}> + +
+
+ ); + } + @observable _isRecording = false; _stopFunc: () => void = emptyFunction; @computed @@ -484,6 +501,7 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (
{this.pinButton}
{this.recordButton}
{this.calendarButton}
+
{this.aiEditorButton}
{this.keywordButton}
{!Doc.UserDoc().documentLinksButton_fullMenu ? null :
{this.shareButton}
}
{this.menuButton}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 8519cda3c..048b92c71 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1400,6 +1400,8 @@ export class DocumentView extends DocComponent() { NativeHeight = () => this.effectiveNativeHeight; PanelWidth = () => this.panelWidth; PanelHeight = () => this.panelHeight; + ReducedPanelWidth = () => this.panelWidth / 2; + ReducedPanelHeight = () => this.panelWidth / 2; NativeDimScaling = () => this.nativeScaling; hideLinkCount = () => !!this.hideLinkButton; isHovering = () => this._isHovering; diff --git a/src/client/views/smartdraw/DrawingFillHandler.tsx b/src/client/views/smartdraw/DrawingFillHandler.tsx index 7a95e27c2..52652d377 100644 --- a/src/client/views/smartdraw/DrawingFillHandler.tsx +++ b/src/client/views/smartdraw/DrawingFillHandler.tsx @@ -8,10 +8,13 @@ import { Docs } from '../../documents/Documents'; import { Networking } from '../../Network'; import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; import { OpenWhere } from '../nodes/OpenWhere'; -import { AspectRatioLimits, FireflyDimensionsMap, FireflyImageDimensions } from './FireflyConstants'; +import { AspectRatioLimits, FireflyDimensionsMap, FireflyImageDimensions, FireflyStylePresets } from './FireflyConstants'; export class DrawingFillHandler { - static drawingToImage = (drawing: Doc, strength: number, prompt: string) => + static drawingToImage = (drawing: Doc, strength: number, prompt: string) => { + const docData = drawing[DocData]; + const tags: string[] = ((docData?.tags as unknown as string[]) ?? []).map(tag => tag.slice(1)) ?? []; + const styles = tags.filter(tag => FireflyStylePresets.has(tag)); DocumentView.GetDocImage(drawing)?.then(imageField => { if (imageField) { const aspectRatio = (drawing.width as number) / (drawing.height as number); @@ -31,11 +34,12 @@ export class DrawingFillHandler { imageUrlToBase64(structureUrl) .then((hrefBase64: string) => gptDescribeImage(hrefBase64)) .then((prompt: string) => { - Networking.PostToServer('/queryFireflyImageFromStructure', { prompt: prompt, width: dims.width, height: dims.height, structureUrl, strength }).then((info: Upload.ImageInformation) => + Networking.PostToServer('/queryFireflyImageFromStructure', { prompt: prompt, width: dims.width, height: dims.height, structureUrl: structureUrl, strength: strength, styles: styles }).then((info: Upload.ImageInformation) => DocumentViewInternal.addDocTabFunc(Docs.Create.ImageDocument(info.accessPaths.agnostic.client, { ai_generated: true, nativeWidth: dims.width, nativeHeight: dims.height }), OpenWhere.addRight) ); // prettier-ignore }); } return false; }); + }; } diff --git a/src/client/views/smartdraw/FireflyConstants.ts b/src/client/views/smartdraw/FireflyConstants.ts index f51305fba..3574039e4 100644 --- a/src/client/views/smartdraw/FireflyConstants.ts +++ b/src/client/views/smartdraw/FireflyConstants.ts @@ -18,3 +18,25 @@ export const AspectRatioLimits = { portrait: 0.875, widescreen: 1.472, }; + +// prettier-ignore +export const FireflyStylePresets = + new Set(['graphic', 'wireframe', + 'vector_look','bw','cool_colors','golden','monochromatic','muted_color','toned_image','vibrant_colors','warm_tone','closeup', + 'knolling','landscape_photography','macrophotography','photographed_through_window','shallow_depth_of_field','shot_from_above', + 'shot_from_below','surface_detail','wide_angle','beautiful','bohemian','chaotic','dais','divine','eclectic','futuristic','kitschy', + 'nostalgic','simple','antique_photo','bioluminescent','bokeh','color_explosion','dark','faded_image','fisheye','gomori_photography', + 'grainy_film','iridescent','isometric','misty','neon','otherworldly_depiction','ultraviolet','underwater', 'backlighting', + 'dramatic_light', 'golden_hour', 'harsh_light','long','low_lighting','multiexposure','studio_light','surreal_lighting', + '3d_patterns','charcoal','claymation','fabric','fur','guilloche_patterns','layered_paper','marble_sculpture','made_of_metal', + 'origami','paper_mache','polka','strange_patterns','wood_carving','yarn','art_deco','art_nouveau','baroque','bauhaus', + 'constructivism','cubism','cyberpunk','fantasy','fauvism', 'film_noir','glitch_art','impressionism','industrialism','maximalism', + 'minimalism','modern_art','modernism','neo','pointillism','psychedelic','science_fiction','steampunk','surrealism','synthetism', + 'synthwave','vaporwave','acrylic_paint','bold_lines','chiaroscuro','color_shift_art','daguerreotype','digital_fractal', + 'doodle_drawing','double_exposure_portrait','fresco','geometric_pen','halftone','ink','light_painting','line_drawing','linocut', + 'oil_paint','paint_spattering','painting','palette_knife','photo_manipulation','scribble_texture','sketch','splattering', + 'stippling_drawing','watercolor','3d','anime','cartoon','cinematic','comic_book','concept_art','cyber_matrix','digital_art', + 'flat_design','geometric','glassmorphism','glitch_graphic','graffiti','hyper_realistic','interior_design','line_gradient', + 'low_poly','newspaper_collage','optical_illusion','pattern_pixel','pixel_art','pop_art','product_photo','psychedelic_background', + 'psychedelic_wonderland','scandinavian','splash_images','stamp','trompe_loeil' + ]); diff --git a/src/server/ApiManagers/FireflyManager.ts b/src/server/ApiManagers/FireflyManager.ts index 4c4aac5e0..cb5d7c1da 100644 --- a/src/server/ApiManagers/FireflyManager.ts +++ b/src/server/ApiManagers/FireflyManager.ts @@ -20,9 +20,10 @@ export default class FireflyManager extends ApiManager { return undefined; }); - generateImageFromStructure = (prompt: string = 'a realistic illustration of a cat coding', width: number = 2048, height: number = 2048, structureUrl: string, strength: number = 50) => + generateImageFromStructure = (prompt: string = 'a realistic illustration of a cat coding', width: number = 2048, height: number = 2048, structureUrl: string, strength: number = 50, styles: string[]) => this.getBearerToken().then(response => response?.json().then((data: { access_token: string }) => + //prettier-ignore fetch('https://firefly-api.adobe.io/v3/images/generate', { method: 'POST', headers: [ @@ -42,6 +43,8 @@ export default class FireflyManager extends ApiManager { source: { url: structureUrl }, }, }, + //prettier-ignore + style: { presets: styles } }), }) .then(response2 => response2.json().then(json => JSON.stringify((json.outputs?.[0] as { image: { url: string } })?.image))) @@ -227,7 +230,7 @@ export default class FireflyManager extends ApiManager { subscription: '/queryFireflyImageFromStructure', secureHandler: async ({ req, res }) => this.uploadImageToDropbox(req.body.structureUrl).then(uploadUrl => - this.generateImageFromStructure(req.body.prompt, req.body.width, req.body.height, uploadUrl, req.body.strength).then(fire => + this.generateImageFromStructure(req.body.prompt, req.body.width, req.body.height, uploadUrl, req.body.strength, req.body.styles).then(fire => DashUploadUtils.UploadImage(JSON.parse(fire ?? '').url).then(info => { if (info instanceof Error) _invalid(res, info.message); else _success(res, info); -- cgit v1.2.3-70-g09d2 From 7ec6b821746eeaf139799044013b45578619a7ed Mon Sep 17 00:00:00 2001 From: eleanor-park Date: Tue, 7 Jan 2025 21:13:33 -0500 Subject: updated ai image editor past image dialogue --- src/client/views/nodes/ImageBox.tsx | 24 +++++++++++++++--------- src/client/views/smartdraw/FireflyConstants.ts | 7 +++++++ src/client/views/smartdraw/SmartDrawHandler.tsx | 9 +++++---- 3 files changed, 27 insertions(+), 13 deletions(-) (limited to 'src/client/views/smartdraw/FireflyConstants.ts') diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 09daea6bb..a1fa9a283 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -45,6 +45,7 @@ import { Button } from 'browndash-components'; import { SettingsManager } from '../../util/SettingsManager'; import { AiOutlineSend } from 'react-icons/ai'; import { returnEmptyDocViewList } from '../StyleProvider'; +import { FireflyImageData } from '../smartdraw/FireflyConstants'; export class ImageEditorData { // eslint-disable-next-line no-use-before-define @@ -533,7 +534,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { @observable private _regenInput = ''; @observable private _canInteract = true; @observable private _regenerateLoading = false; - @observable private _prevImgs: { href: string; pathname: string }[] = []; + @observable private _prevImgs: FireflyImageData[] = []; componentAIViewHistory = () => { return ( @@ -544,6 +545,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { src={img.href} onClick={() => { this.dataDoc[this.fieldKey] = new ImageField(img.pathname); + this.dataDoc.ai_firefly_prompt = img.prompt; + this.dataDoc.ai_firefly_seed = img.seed; }} /> ))} @@ -580,14 +583,17 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { onClick={undoable( action(async () => { this._regenerateLoading = true; - SmartDrawHandler.Instance.regenerate([this.Document], undefined, undefined, this._regenInput, true).then(newDocs => { - const url = newDocs[0]; - const imgField = new ImageField(url); - this._prevImgs.length === 0 && this._prevImgs.push({ href: this.paths.lastElement(), pathname: field.url.pathname }); - this.dataDoc[this.fieldKey] = imgField; - this._prevImgs.unshift({ href: this.paths.lastElement(), pathname: url }); - this._regenerateLoading = false; - this._regenInput = ''; + SmartDrawHandler.Instance.regenerate([this.Document], undefined, undefined, this._regenInput, true).then(newImgs => { + if (newImgs[0]) { + const url = newImgs[0].pathname; + const imgField = new ImageField(url); + this._prevImgs.length === 0 && + this._prevImgs.push({ prompt: StrCast(this.dataDoc.ai_firefly_prompt), seed: NumCast(this.dataDoc.ai_firefly_seed), href: this.paths.lastElement(), pathname: field.url.pathname }); + this.dataDoc[this.fieldKey] = imgField; + this._prevImgs.unshift({ prompt: newImgs[0].prompt, seed: newImgs[0].seed, href: this.paths.lastElement(), pathname: url }); + this._regenerateLoading = false; + this._regenInput = ''; + } }); }), 'regenerate image' diff --git a/src/client/views/smartdraw/FireflyConstants.ts b/src/client/views/smartdraw/FireflyConstants.ts index 3574039e4..1f1781617 100644 --- a/src/client/views/smartdraw/FireflyConstants.ts +++ b/src/client/views/smartdraw/FireflyConstants.ts @@ -1,3 +1,10 @@ +export interface FireflyImageData { + prompt: string; + seed: number | undefined; + pathname: string; + href?: string; +} + export enum FireflyImageDimensions { Square = 'square', Landscape = 'landscape', diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx index 13a93367c..5ebe2e358 100644 --- a/src/client/views/smartdraw/SmartDrawHandler.tsx +++ b/src/client/views/smartdraw/SmartDrawHandler.tsx @@ -25,7 +25,7 @@ import { ActiveInkArrowEnd, ActiveInkArrowStart, ActiveInkDash, ActiveInkFillCol import './SmartDrawHandler.scss'; import { Networking } from '../../Network'; import { OpenWhere } from '../nodes/OpenWhere'; -import { FireflyDimensionsMap, FireflyImageDimensions } from './FireflyConstants'; +import { FireflyDimensionsMap, FireflyImageDimensions, FireflyImageData } from './FireflyConstants'; export interface DrawingOptions { text: string; @@ -267,23 +267,24 @@ export class SmartDrawHandler extends ObservableReactComponent { /** * Calls Firefly API to create an image based on user input */ - createImageWithFirefly = (input: string, seed?: number, changeInPlace?: boolean) => { + createImageWithFirefly = (input: string, seed?: number, changeInPlace?: boolean): Promise => { this._lastInput.text = input; const dims = FireflyDimensionsMap[this._imgDims]; return Networking.PostToServer('/queryFireflyImage', { prompt: input, width: dims.width, height: dims.height, seed: seed }).then(img => { if (!changeInPlace) { + const seed = img.accessPaths.agnostic.client.match(/\/(\d+)upload/)[1]; const imgDoc: Doc = Docs.Create.ImageDocument(img.accessPaths.agnostic.client, { title: input.match(/^(.*?)~~~.*$/)?.[1] || input, nativeWidth: dims.width, nativeHeight: dims.height, ai: 'firefly', - ai_firefly_seed: img.accessPaths.agnostic.client.match(/\/(\d+)upload/)[1], + ai_firefly_seed: seed, ai_firefly_prompt: input, }); DocumentViewInternal.addDocTabFunc(imgDoc, OpenWhere.addRight); this._selectedDocs.push(imgDoc); } - return img.accessPaths.agnostic.client; + return { prompt: input, seed: seed, pathname: img.accessPaths.agnostic.client }; }); }; -- cgit v1.2.3-70-g09d2 From a9a1a6a507616a77f70d6525dab5027f5b7a60e6 Mon Sep 17 00:00:00 2001 From: bobzel Date: Wed, 26 Feb 2025 20:48:51 -0500 Subject: added typing to PostToServer calls. made smartDraw popup create images locally. --- src/client/Network.ts | 2 +- src/client/apis/GoogleAuthenticationManager.tsx | 27 ++++--- .../apis/google_docs/GoogleApiClientUtils.ts | 19 ++--- .../apis/google_docs/GooglePhotosClientUtils.ts | 18 ++--- src/client/util/Import & Export/ImageUtils.ts | 4 +- src/client/util/PingManager.ts | 2 +- src/client/util/SettingsManager.tsx | 3 +- src/client/views/collections/CollectionSubView.tsx | 3 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 5 +- .../views/nodes/DataVizBox/DocCreatorMenu.tsx | 3 +- src/client/views/nodes/ImageBox.tsx | 20 +++-- .../views/nodes/RecordingBox/RecordingView.tsx | 3 +- .../views/nodes/chatbot/tools/CreateCSVTool.ts | 4 +- .../views/nodes/chatbot/tools/ImageCreationTool.ts | 4 +- src/client/views/nodes/chatbot/tools/RAGTool.ts | 2 +- src/client/views/nodes/chatbot/tools/SearchTool.ts | 8 +- src/client/views/pdf/GPTPopup/GPTPopup.tsx | 13 ++- src/client/views/smartdraw/FireflyConstants.ts | 5 ++ src/client/views/smartdraw/SmartDrawHandler.tsx | 94 ++++++++++------------ 19 files changed, 123 insertions(+), 116 deletions(-) (limited to 'src/client/views/smartdraw/FireflyConstants.ts') diff --git a/src/client/Network.ts b/src/client/Network.ts index 323a2648c..a2ecf1bea 100644 --- a/src/client/Network.ts +++ b/src/client/Network.ts @@ -22,7 +22,7 @@ export namespace Networking { }, body: body ? JSON.stringify(body) : undefined, }).then(async response => { - if (response.ok) return response.json(); + if (response.ok) return response.json() as object; return await response.text().then(text => ({ error: '' + response.status + ':' + response.statusText + '-' + text })); }); diff --git a/src/client/apis/GoogleAuthenticationManager.tsx b/src/client/apis/GoogleAuthenticationManager.tsx index 5269f763b..94ce42d8d 100644 --- a/src/client/apis/GoogleAuthenticationManager.tsx +++ b/src/client/apis/GoogleAuthenticationManager.tsx @@ -11,7 +11,8 @@ const AuthenticationUrl = 'https://accounts.google.com/o/oauth2/v2/auth'; const prompt = 'Paste authorization code here...'; @observer -export class GoogleAuthenticationManager extends React.Component<{}> { +export class GoogleAuthenticationManager extends React.Component { + // eslint-disable-next-line no-use-before-define public static Instance: GoogleAuthenticationManager; private authenticationLink: Opt = undefined; @observable private openState = false; @@ -19,7 +20,7 @@ export class GoogleAuthenticationManager extends React.Component<{}> { @observable private showPasteTargetState = false; @observable private success: Opt = undefined; @observable private displayLauncher = true; - @observable private credentials: any; + @observable private credentials: { user_info: { name: string; picture: string }; access_token: string } | undefined = undefined; private disposer: Opt; private set isOpen(value: boolean) { @@ -35,25 +36,25 @@ export class GoogleAuthenticationManager extends React.Component<{}> { } public fetchOrGenerateAccessToken = async (displayIfFound = false) => { - let response: any = await Networking.FetchFromServer('/readGoogleAccessToken'); + const response = await Networking.FetchFromServer('/readGoogleAccessToken'); // if this is an authentication url, activate the UI to register the new access token if (new RegExp(AuthenticationUrl).test(response)) { this.isOpen = true; this.authenticationLink = response; - return new Promise(async resolve => { + return new Promise(resolve => { this.disposer?.(); this.disposer = reaction( () => this.authenticationCode, async authenticationCode => { if (authenticationCode && /\d{1}\/[\w-]{55}/.test(authenticationCode)) { this.disposer?.(); - const response = await Networking.PostToServer('/writeGoogleAccessToken', { authenticationCode }); + const response2 = await Networking.PostToServer('/writeGoogleAccessToken', { authenticationCode }); runInAction(() => { this.success = true; - this.credentials = response; + this.credentials = response2 as { user_info: { name: string; picture: string }; access_token: string }; }); this.resetState(); - resolve(response.access_token); + resolve((response2 as { access_token: string }).access_token); } } ); @@ -61,16 +62,16 @@ export class GoogleAuthenticationManager extends React.Component<{}> { } // otherwise, we already have a valid, stored access token and user info - response = JSON.parse(response); + const response2 = JSON.parse(response) as { user_info: { name: string; picture: string }; access_token: string }; if (displayIfFound) { runInAction(() => { this.success = true; - this.credentials = response; + this.credentials = response2; }); this.resetState(-1, -1); this.isOpen = true; } - return response.access_token; + return (response2 as { access_token: string }).access_token; }; resetState = action((visibleForMS: number = 3000, fadesOutInMS: number = 500) => { @@ -106,7 +107,7 @@ export class GoogleAuthenticationManager extends React.Component<{}> { } }); - constructor(props: {}) { + constructor(props: object) { super(props); GoogleAuthenticationManager.Instance = this; } @@ -128,8 +129,8 @@ export class GoogleAuthenticationManager extends React.Component<{}> { {this.showPasteTargetState ? (this.authenticationCode = e.currentTarget.value))} placeholder={prompt} /> : null} {this.credentials ? ( <> - - Welcome to Dash, {this.credentials.userInfo.name} + + Welcome to Dash, {this.credentials.user_info.name}
{ diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts index 0b303eacf..c1ac352b1 100644 --- a/src/client/apis/google_docs/GoogleApiClientUtils.ts +++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts @@ -1,7 +1,5 @@ -/* eslint-disable no-restricted-syntax */ /* eslint-disable no-use-before-define */ import { docs_v1 as docsV1 } from 'googleapis'; -// eslint-disable-next-line node/no-deprecated-api import { isArray } from 'util'; import { EditorState } from 'prosemirror-state'; import { Opt } from '../../../fields/Doc'; @@ -37,7 +35,7 @@ export namespace GoogleApiClientUtils { text: string | string[]; requests: docsV1.Schema$Request[]; } - export type IdHandler = (id: DocumentId) => any; + export type IdHandler = (id: DocumentId) => unknown; export type CreationResult = Opt; export type ReadLinesResult = Opt<{ title?: string; bodyLines?: string[] }>; export type ReadResult = { title: string; body: string }; @@ -145,7 +143,7 @@ export namespace GoogleApiClientUtils { if (paragraphs.length) { const target = paragraphs[paragraphs.length - 1]; if (target.paragraph && target.paragraph.elements) { - length = target.paragraph.elements.length; + const length = target.paragraph.elements.length; if (length) { const final = target.paragraph.elements[length - 1]; return final.endIndex ? final.endIndex - 1 : undefined; @@ -208,13 +206,13 @@ export namespace GoogleApiClientUtils { }); export const setStyle = async (options: UpdateOptions) => { - const replies: any = await update({ + const replies = await update({ documentId: options.documentId, requests: options.requests, }); - if ('errors' in replies) { + if (replies && 'errors' in replies) { console.log('Write operation failed:'); - console.log(replies.errors.map((error: any) => error.message)); + console.log(replies); //.errors.map((error: any) => error.message)); } return replies; }; @@ -229,7 +227,6 @@ export namespace GoogleApiClientUtils { const { mode } = options; if (!(index && mode === WriteMode.Insert)) { const schema = await retrieve({ documentId }); - // eslint-disable-next-line no-cond-assign if (!schema || !(index = Utils.endOf(schema))) { return undefined; } @@ -258,10 +255,10 @@ export namespace GoogleApiClientUtils { return undefined; } requests.push(...options.content.requests); - const replies: any = await update({ documentId, requests }); - if ('errors' in replies) { + const replies = await update({ documentId, requests }); + if (replies && 'errors' in replies) { console.log('Write operation failed:'); - console.log(replies.errors.map((error: any) => error.message)); + console.log(replies); // .errors.map((error: any) => error.message)); } return replies; }; diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts index b238f07e9..4b86a8341 100644 --- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts +++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts @@ -1,5 +1,5 @@ /* eslint-disable no-use-before-define */ -import Photos = require('googlephotos'); +import Photos from 'googlephotos'; import { AssertionError } from 'assert'; import { EditorState } from 'prosemirror-state'; import { ClientUtils } from '../../../ClientUtils'; @@ -118,7 +118,7 @@ export namespace GooglePhotos { } export namespace Import { - export type CollectionConstructor = (data: Array, options: DocumentOptions, ...args: any) => Doc; + export type CollectionConstructor = (data: Array, options: DocumentOptions, ...args: unknown[]) => Doc; export const CollectionFromSearch = async (constructor: CollectionConstructor, requested: Opt>): Promise => { await GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken(); @@ -147,7 +147,7 @@ export namespace GooglePhotos { values.forEach(async value => { const searched = (await ContentSearch({ included: [value] }))?.mediaItems?.map(({ id }) => id); searched?.forEach(async id => { - const image = await Cast(idMapping[id], Doc); + const image = await Cast(idMapping[id as string], Doc); if (image) { const key = image[Id]; const tags = tagMapping.get(key); @@ -193,7 +193,7 @@ export namespace GooglePhotos { } export interface SearchResponse { - mediaItems: any[]; + mediaItems: MediaItem[]; nextPageToken: string; } @@ -204,7 +204,7 @@ export namespace GooglePhotos { const found = 0; do { // eslint-disable-next-line no-await-in-loop - const response: any = await photos.mediaItems.search(albumId, pageSize, nextPageTokenStored); + const response = await photos.mediaItems.search(albumId, pageSize, nextPageTokenStored); mediaItems.push(...response.mediaItems); nextPageTokenStored = response.nextPageToken; } while (found); @@ -278,9 +278,9 @@ export namespace GooglePhotos { return undefined; }; - export const WriteMediaItemsToServer = async (body: { mediaItems: any[] }): Promise => { + export const WriteMediaItemsToServer = async (body: { mediaItems: MediaItem[] }): Promise => { const uploads = await Networking.PostToServer('/googlePhotosMediaGet', body); - return uploads; + return uploads as UploadInformation[]; }; export const UploadThenFetch = async (sources: Doc[], album?: AlbumReference, descriptionKey = 'caption') => { @@ -320,7 +320,7 @@ export namespace GooglePhotos { }); if (media.length) { const results = await Networking.PostToServer('/googlePhotosMediaPost', { media, album }); - return results; + return results as Opt; } return undefined; }; @@ -331,7 +331,7 @@ export namespace GooglePhotos { if (typeof target === 'string') { description = target; } else if (target instanceof RichTextField) { - description = RichTextUtils.ToPlainText(EditorState.fromJSON(new FormattedTextBox({} as any).config, JSON.parse(target.Data))); + description = RichTextUtils.ToPlainText(EditorState.fromJSON(FormattedTextBox.MakeConfig(undefined, undefined), JSON.parse(target.Data))); } return description; }; diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index f73149fdc..43807397f 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -8,9 +8,9 @@ import { Upload } from '../../../server/SharedMediaTypes'; import { Networking } from '../../Network'; export namespace ImageUtils { - export const ExtractImgInfo = async (document: Doc): Promise => { + export const ExtractImgInfo = async (document: Doc) => { const field = Cast(document.data, ImageField); - return field ? Networking.PostToServer('/inspectImage', { source: field.url.href }) : undefined; + return field ? (Networking.PostToServer('/inspectImage', { source: field.url.href }) as Promise) : undefined; }; export const AssignImgInfo = (document: Doc, data?: Upload.InspectionResults) => { diff --git a/src/client/util/PingManager.ts b/src/client/util/PingManager.ts index 170632836..0e4f8cab0 100644 --- a/src/client/util/PingManager.ts +++ b/src/client/util/PingManager.ts @@ -29,7 +29,7 @@ export class PingManager { }); Networking.PostToServer('/ping', { date: new Date() }) .then(res => { - SnappingManager.SetServerVersion(res.message); + SnappingManager.SetServerVersion((res as { message: string }).message); !this.IsBeating && setIsBeating(true); }) .catch(() => this.IsBeating && setIsBeating(false)); diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index 5d041f7b4..6ea242fc3 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -598,7 +598,8 @@ export class SettingsManager extends React.Component { }); } else { const passwordBundle = { curr_pass: this._curr_password, new_pass: this._new_password, new_confirm: this._new_confirm }; - const { error } = await Networking.PostToServer('/internalResetPassword', passwordBundle); + const reset = await Networking.PostToServer('/internalResetPassword', passwordBundle); + const { error } = reset as { error: { msg: string }[] }; runInAction(() => { this._passwordResultText = error ? 'Error: ' + error[0].msg + '...' : 'Password successfully updated!'; }); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index b40cd2761..ca830aa6f 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -28,6 +28,7 @@ import { FieldViewProps } from '../nodes/FieldView'; import { DocumentView, DocumentViewProps } from '../nodes/DocumentView'; import { FlashcardPracticeUI } from './FlashcardPracticeUI'; import { OpenWhere, OpenWhereMod } from '../nodes/OpenWhere'; +import { Upload } from '../../../server/SharedMediaTypes'; export enum docSortings { Time = 'time', @@ -407,7 +408,7 @@ export function CollectionSubView() { const imgSrc = img.split('src="')[1].split('"')[0]; const imgOpts = { ...options, _width: 300 }; if (imgSrc.startsWith('data:image') && imgSrc.includes('base64')) { - const result = (await Networking.PostToServer('/uploadRemoteImage', { sources: [imgSrc] })).lastElement(); + const result = ((await Networking.PostToServer('/uploadRemoteImage', { sources: [imgSrc] })) as Upload.ImageInformation[]).lastElement(); const newImgSrc = result.accessPaths.agnostic.client.indexOf('dashblobstore') === -1 // ? ClientUtils.prepend(result.accessPaths.agnostic.client) diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3c31b584e..b33c267ee 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1291,7 +1291,7 @@ export class CollectionFreeFormView extends CollectionSubView { + addDrawing = (doc: Doc, opts: DrawingOptions, gptRes: string, x?: number, y?: number) => { const docData = doc[DocData]; docData.title = opts.text.match(/^(.*?)~~~.*$/)?.[1] || opts.text; docData._width = opts.size; @@ -1302,6 +1302,9 @@ export class CollectionFreeFormView extends CollectionSubView { const res = await gptImageCall(prompt); if (res) { - const result = await Networking.PostToServer('/uploadRemoteImage', { sources: res }); + const result = (await Networking.PostToServer('/uploadRemoteImage', { sources: res })) as Upload.FileInformation[]; const source = ClientUtils.prepend(result[0].accessPaths.agnostic.client); return source; } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index b6b0e4a8a..9395863d8 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -36,7 +36,7 @@ import { OverlayView } from '../OverlayView'; import { AnchorMenu } from '../pdf/AnchorMenu'; import { PinDocView, PinProps } from '../PinFuncs'; import { DrawingFillHandler } from '../smartdraw/DrawingFillHandler'; -import { FireflyImageData } from '../smartdraw/FireflyConstants'; +import { FireflyImageData, isFireflyImageData } from '../smartdraw/FireflyConstants'; import { SmartDrawHandler } from '../smartdraw/SmartDrawHandler'; import { StickerPalette } from '../smartdraw/StickerPalette'; import { StyleProp } from '../StyleProp'; @@ -354,7 +354,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { const ext = extname(file); return file.replace(ext, (this._error ? '_o' : this._curSuffix) + ext); })(ImageCast(this.Document[Doc.LayoutFieldKey(this.Document)])?.url.href), - }).then((info: Upload.ImageInformation) => { + }).then(res => { + const info = res as Upload.ImageInformation; const img = Docs.Create.ImageDocument(info.accessPaths.agnostic.client, { title: 'expand:' + this.Document.title }); DocUtils.assignImageInfo(info, img); this._props.addDocTab(img, OpenWhere.addRight); @@ -627,14 +628,15 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { } else SmartDrawHandler.Instance.regenerate([this.Document], undefined, undefined, this._regenInput || StrCast(this.Document.title), true).then( action(newImgs => { - if (newImgs[0] && !(newImgs[0] instanceof Doc)) { - const url = newImgs[0].pathname; + const firstImg = newImgs[0]; + if (isFireflyImageData(firstImg)) { + const url = firstImg.pathname; const imgField = new ImageField(url); this._prevImgs.length === 0 && this._prevImgs.push({ prompt: StrCast(this.dataDoc.ai_firefly_prompt), seed: this.dataDoc.ai_firefly_seed as number, href: this.paths.lastElement(), pathname: field.url.pathname }); - this._prevImgs.unshift({ prompt: newImgs[0].prompt, seed: newImgs[0].seed, pathname: url }); + this._prevImgs.unshift({ prompt: firstImg.prompt, seed: firstImg.seed, pathname: url }); this.dataDoc.ai_firefly_history = JSON.stringify(this._prevImgs); - this.dataDoc.ai_firefly_prompt = newImgs[0].prompt; + this.dataDoc.ai_firefly_prompt = firstImg.prompt; this.dataDoc[this.fieldKey] = imgField; this._regenerateLoading = false; this._regenInput = ''; @@ -688,7 +690,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { const ext = extname(file); return file.replace(ext, (this._error ? '_o' : this._curSuffix) + ext); })(ImageCast(this.Document[Doc.LayoutFieldKey(this.Document)])?.url.href), - }).then((info: Upload.ImageInformation) => { + }).then(res => { + const info = res as Upload.ImageInformation; const img = Docs.Create.ImageDocument(info.accessPaths.agnostic.client, { title: 'expand:' + this.Document.title }); DocUtils.assignImageInfo(info, img); const genratedDocs = this.Document.generatedDocs @@ -741,7 +744,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent() { focus = (anchor: Doc, options: FocusViewOptions) => (anchor.type === DocumentType.CONFIG ? undefined : this._ffref.current?.focus(anchor, options)); renderedPixelDimensions = async () => { - const { nativeWidth: width, nativeHeight: height } = await Networking.PostToServer('/inspectImage', { source: this.paths[0] }); + const res = await Networking.PostToServer('/inspectImage', { source: this.paths[0] }); + const { nativeWidth: width, nativeHeight: height } = res as { nativeWidth: number; nativeHeight: number }; return { width, height }; }; savedAnnotations = () => this._savedAnnotations; diff --git a/src/client/views/nodes/RecordingBox/RecordingView.tsx b/src/client/views/nodes/RecordingBox/RecordingView.tsx index 37ffca2d6..e7a6193d4 100644 --- a/src/client/views/nodes/RecordingBox/RecordingView.tsx +++ b/src/client/views/nodes/RecordingBox/RecordingView.tsx @@ -1,4 +1,3 @@ -/* eslint-disable react/button-has-type */ import * as React from 'react'; import { useEffect, useRef, useState } from 'react'; import { IconContext } from 'react-icons'; @@ -72,7 +71,7 @@ export function RecordingView(props: IRecordingViewProps) { const serverPaths: string[] = (await Networking.UploadFilesToServer(videoFiles.map(file => ({ file })))).map(res => (res.result instanceof Error ? '' : res.result.accessPaths.agnostic.server)); // concat the segments together using post call - const result: Upload.AccessPathInfo | Error = await Networking.PostToServer('/concatVideos', serverPaths); + const result = (await Networking.PostToServer('/concatVideos', serverPaths)) as Upload.AccessPathInfo | Error; !(result instanceof Error) ? props.setResult(result, concatPres || undefined) : console.error('video conversion failed'); })(); } diff --git a/src/client/views/nodes/chatbot/tools/CreateCSVTool.ts b/src/client/views/nodes/chatbot/tools/CreateCSVTool.ts index e8ef3fbfe..290c48d6c 100644 --- a/src/client/views/nodes/chatbot/tools/CreateCSVTool.ts +++ b/src/client/views/nodes/chatbot/tools/CreateCSVTool.ts @@ -38,10 +38,10 @@ export class CreateCSVTool extends BaseTool { async execute(args: ParametersType): Promise { try { console.log('Creating CSV file:', args.filename, ' with data:', args.csvData); - const { fileUrl, id } = await Networking.PostToServer('/createCSV', { + const { fileUrl, id } = (await Networking.PostToServer('/createCSV', { filename: args.filename, data: args.csvData, - }); + })) as { fileUrl: string; id: string }; this._handleCSVResult(fileUrl, args.filename, id, args.csvData); diff --git a/src/client/views/nodes/chatbot/tools/ImageCreationTool.ts b/src/client/views/nodes/chatbot/tools/ImageCreationTool.ts index dc6140871..e92d87dfd 100644 --- a/src/client/views/nodes/chatbot/tools/ImageCreationTool.ts +++ b/src/client/views/nodes/chatbot/tools/ImageCreationTool.ts @@ -37,9 +37,9 @@ export class ImageCreationTool extends BaseTool { console.log(`Generating image for prompt: ${image_prompt}`); // Create an array of promises, each one handling a search for a query try { - const { result, url } = await Networking.PostToServer('/generateImage', { + const { result, url } = (await Networking.PostToServer('/generateImage', { image_prompt, - }); + })) as { result: Upload.FileInformation & Upload.InspectionResults; url: string }; console.log('Image generation result:', result); this._createImage(result, { text: RTFCast(image_prompt) }); return url diff --git a/src/client/views/nodes/chatbot/tools/RAGTool.ts b/src/client/views/nodes/chatbot/tools/RAGTool.ts index 2db61c768..ef374ed22 100644 --- a/src/client/views/nodes/chatbot/tools/RAGTool.ts +++ b/src/client/views/nodes/chatbot/tools/RAGTool.ts @@ -75,7 +75,7 @@ export class RAGTool extends BaseTool { async getFormattedChunks(relevantChunks: RAGChunk[]): Promise { try { - const { formattedChunks } = await Networking.PostToServer('/formatChunks', { relevantChunks }); + const { formattedChunks } = await Networking.PostToServer('/formatChunks', { relevantChunks }) as { formattedChunks: Observation[]} if (!formattedChunks) { throw new Error('Failed to format chunks'); diff --git a/src/client/views/nodes/chatbot/tools/SearchTool.ts b/src/client/views/nodes/chatbot/tools/SearchTool.ts index 5fc6ab768..6a11407a5 100644 --- a/src/client/views/nodes/chatbot/tools/SearchTool.ts +++ b/src/client/views/nodes/chatbot/tools/SearchTool.ts @@ -41,15 +41,15 @@ export class SearchTool extends BaseTool { // Create an array of promises, each one handling a search for a query const searchPromises = queries.map(async query => { try { - const { results } = await Networking.PostToServer('/getWebSearchResults', { + const { results } = (await Networking.PostToServer('/getWebSearchResults', { query, max_results: this._max_results, - }); + })) as { results: { url: string; snippet: string }[] }; const data = results.map((result: { url: string; snippet: string }) => { const id = uuidv4(); this._addLinkedUrlDoc(result.url, id); return { - type: 'text', + type: 'text' as const, text: `${result.url}${result.snippet}`, }; }); @@ -58,7 +58,7 @@ export class SearchTool extends BaseTool { console.log(error); return [ { - type: 'text', + type: 'text' as const, text: `An error occurred while performing the web search for query: ${query}`, }, ]; diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index efddfb841..f4ab2f41c 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -21,11 +21,13 @@ import { DictationButton } from '../../DictationButton'; import { ObservableReactComponent } from '../../ObservableReactComponent'; import { TagItem } from '../../TagsView'; import { ChatSortField, docSortings } from '../../collections/CollectionSubView'; -import { DocumentView } from '../../nodes/DocumentView'; +import { DocumentView, DocumentViewInternal } from '../../nodes/DocumentView'; import { SmartDrawHandler } from '../../smartdraw/SmartDrawHandler'; import { AnchorMenu } from '../AnchorMenu'; import './GPTPopup.scss'; import { FireflyImageDimensions } from '../../smartdraw/FireflyConstants'; +import { Upload } from '../../../../server/SharedMediaTypes'; +import { OpenWhere } from '../../nodes/OpenWhere'; export enum GPTPopupMode { SUMMARY, // summary of seleted document text @@ -210,7 +212,12 @@ export class GPTPopup extends ObservableReactComponent { // ); // } else∂ return SmartDrawHandler.CreateWithFirefly(imgDesc, FireflyImageDimensions.Square, 0) - .then(action(() => (this._userPrompt = ''))) + .then( + action(doc => { + doc instanceof Doc && DocumentViewInternal.addDocTabFunc(doc, OpenWhere.addRight); + this._userPrompt = ''; + }) + ) .catch(e => { alert(e); return undefined; @@ -259,7 +266,7 @@ export class GPTPopup extends ObservableReactComponent { .then(imageUrls => imageUrls?.[0] ? Networking.PostToServer('/uploadRemoteImage', { sources: [imageUrls[0]] }).then(res => { - const source = ClientUtils.prepend(res[0].accessPaths.agnostic.client); + const source = ClientUtils.prepend((res as Upload.FileInformation[])[0].accessPaths.agnostic.client); return this.setImgUrls([[imageUrls[0]!, source]]); }) : undefined diff --git a/src/client/views/smartdraw/FireflyConstants.ts b/src/client/views/smartdraw/FireflyConstants.ts index 1f1781617..8cc9e36a5 100644 --- a/src/client/views/smartdraw/FireflyConstants.ts +++ b/src/client/views/smartdraw/FireflyConstants.ts @@ -5,6 +5,11 @@ export interface FireflyImageData { href?: string; } +export function isFireflyImageData(obj: unknown): obj is FireflyImageData { + const tobj = obj as FireflyImageData; + return typeof obj === 'object' && obj !== null && typeof tobj.pathname === 'string' && typeof tobj.prompt === 'string' && typeof tobj.seed === 'number'; +} + export enum FireflyImageDimensions { Square = 'square', Landscape = 'landscape', diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx index 9d67d111b..532391ac6 100644 --- a/src/client/views/smartdraw/SmartDrawHandler.tsx +++ b/src/client/views/smartdraw/SmartDrawHandler.tsx @@ -23,10 +23,10 @@ import { SVGToBezier, SVGType } from '../../util/bezierFit'; import { InkingStroke } from '../InkingStroke'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { MarqueeView } from '../collections/collectionFreeForm'; -import { ActiveInkArrowEnd, ActiveInkArrowStart, ActiveInkBezierApprox, ActiveInkColor, ActiveInkDash, ActiveInkFillColor, ActiveInkWidth, ActiveIsInkMask, DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; -import { OpenWhere } from '../nodes/OpenWhere'; +import { ActiveInkArrowEnd, ActiveInkArrowStart, ActiveInkBezierApprox, ActiveInkColor, ActiveInkDash, ActiveInkFillColor, ActiveInkWidth, ActiveIsInkMask, DocumentView } from '../nodes/DocumentView'; import { FireflyDimensionsMap, FireflyImageData, FireflyImageDimensions } from './FireflyConstants'; import './SmartDrawHandler.scss'; +import { Upload } from '../../../server/SharedMediaTypes'; export interface DrawingOptions { text: string; @@ -60,7 +60,6 @@ export class SmartDrawHandler extends ObservableReactComponent { private _lastInput: DrawingOptions = { text: '', complexity: 5, size: 350, autoColor: true, x: 0, y: 0 }; private _lastResponse: string = ''; private _selectedDocs: Doc[] = []; - private _errorOccurredOnce = false; @observable private _display: boolean = false; @observable private _pageX: number = 0; @@ -95,7 +94,7 @@ export class SmartDrawHandler extends ObservableReactComponent { CollectionFreeForm, FormattedTextBox, StickerPalette) to define how a drawing document should be added or removed in their respective locations (to the freeform canvas, to the sticker palette's preview, etc.) */ - public AddDrawing: (doc: Doc, opts: DrawingOptions, gptRes: string) => void = unimplementedFunction; + public AddDrawing: (doc: Doc, opts: DrawingOptions, gptRes: string, x?: number, y?: number) => void = unimplementedFunction; public RemoveDrawing: (useLastContainer: boolean, doc?: Doc) => void = unimplementedFunction; /** * This creates the ink document that represents a drawing, so it goes through the strokes that make up the drawing, @@ -206,16 +205,15 @@ export class SmartDrawHandler extends ObservableReactComponent { this._isLoading = true; this._canInteract = false; if (this.ShowRegenerate) { - await this.regenerate(this._selectedDocs); - runInAction(() => { - this._selectedDocs = []; - this._regenInput = ''; - this._showEditBox = false; - }); + await this.regenerate(this._selectedDocs).then( + action(() => { + this._selectedDocs = []; + this._regenInput = ''; + this._showEditBox = false; + }) + ); } else { - runInAction(() => { - this._showOptions = false; - }); + this._showOptions = false; try { if (this._generateImage) { await this.createImageWithFirefly(this._userInput); @@ -224,18 +222,8 @@ export class SmartDrawHandler extends ObservableReactComponent { await this.drawWithGPT({ X: this._pageX, Y: this._pageY }, this._userInput, this._complexity, this._size, this._autoColor); } this.hideSmartDrawHandler(); - - runInAction(() => { - this.ShowRegenerate = true; - }); } catch (err) { - if (this._errorOccurredOnce) { - console.error('GPT call failed', err); - this._errorOccurredOnce = false; - } else { - this._errorOccurredOnce = true; - await this.handleSendClick(); - } + console.error('GPT call failed', err); } } runInAction(() => { @@ -256,7 +244,6 @@ export class SmartDrawHandler extends ObservableReactComponent { const drawingDoc = strokeData && this.CreateDrawingDoc(strokeData.data, strokeData.lastInput, strokeData.lastRes); drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, res); drawingDoc && this._selectedDocs.push(drawingDoc); - this._errorOccurredOnce = false; return strokeData; } else { console.error('GPT call failed'); @@ -270,7 +257,10 @@ export class SmartDrawHandler extends ObservableReactComponent { */ createImageWithFirefly = (input: string, seed?: number): Promise => { this._lastInput.text = input; - return SmartDrawHandler.CreateWithFirefly(input, this._imgDims, seed); + return SmartDrawHandler.CreateWithFirefly(input, this._imgDims, seed).then(doc => { + doc instanceof Doc && this.AddDrawing(doc, this._lastInput, input, this._pageX, this._pageY); + return doc; + }); }; /** * Calls Firefly API to create an image based on user input */ @@ -281,9 +271,11 @@ export class SmartDrawHandler extends ObservableReactComponent { public static ReCreateWithFirefly(input: string, imgDims: FireflyImageDimensions, seed?: number): Promise { const dims = FireflyDimensionsMap[imgDims]; return Networking.PostToServer('/queryFireflyImage', { prompt: input, width: dims.width, height: dims.height, seed }) - .then(img => { - if (img.error) { - alert('recreate image failed: ' + img.error); + .then(res => { + const img = res as Upload.FileInformation; + const error = res as { error: string }; + if ('error' in error) { + alert('recreate image failed: ' + error.error); return undefined; } return { prompt: input, seed, pathname: img.accessPaths.agnostic.client }; @@ -296,21 +288,22 @@ export class SmartDrawHandler extends ObservableReactComponent { public static CreateWithFirefly(input: string, imgDims: FireflyImageDimensions, seed?: number): Promise { const dims = FireflyDimensionsMap[imgDims]; return Networking.PostToServer('/queryFireflyImage', { prompt: input, width: dims.width, height: dims.height, seed }) - .then(img => { - if (img.error) { - alert('create image failed: ' + img.error); + .then(res => { + const img = res as Upload.FileInformation; + const error = res as { error: string }; + if ('error' in error) { + alert('create image failed: ' + error.error); return undefined; } - const newseed = img.accessPaths.agnostic.client.match(/\/(\d+)upload/)[1]; + const newseed = img.accessPaths.agnostic.client.match(/\/(\d+)upload/)?.[1]; const imgDoc: Doc = Docs.Create.ImageDocument(img.accessPaths.agnostic.client, { title: input.match(/^(.*?)~~~.*$/)?.[1] || input, nativeWidth: dims.width, nativeHeight: dims.height, ai: 'firefly', - ai_firefly_seed: newseed, + ai_firefly_seed: +(newseed ?? 0), ai_firefly_prompt: input, }); - DocumentViewInternal.addDocTabFunc(imgDoc, OpenWhere.addRight); return imgDoc; }) .catch(e => { @@ -331,26 +324,21 @@ export class SmartDrawHandler extends ObservableReactComponent { return Promise.all( drawingDocs.map(async doc => { switch (doc.type) { - case DocumentType.IMG: - if (this._regenInput) { - // if (this._selectedDoc) { - const newPrompt = doc.ai_firefly_prompt ? `${doc.ai_firefly_prompt} ~~~ ${this._regenInput}` : this._regenInput; - return changeInPlace ? this.recreateImageWithFirefly(newPrompt, NumCast(doc?.ai_firefly_seed)) : this.createImageWithFirefly(newPrompt, NumCast(doc?.ai_firefly_seed)); - // } - } - return changeInPlace - ? this.recreateImageWithFirefly(this._lastInput.text || StrCast(doc.ai_firefly_prompt), NumCast(doc?.ai_firefly_seed)) - : this.createImageWithFirefly(this._lastInput.text || StrCast(doc.ai_firefly_prompt), NumCast(doc?.ai_firefly_seed)); + case DocumentType.IMG: { + const func = changeInPlace ? this.recreateImageWithFirefly : this.createImageWithFirefly; + const newPrompt = doc.ai_firefly_prompt ? `${doc.ai_firefly_prompt} ~~~ ${this._regenInput}` : this._regenInput; + return this._regenInput ? func(newPrompt, NumCast(doc?.ai_firefly_seed)) : func(this._lastInput.text || StrCast(doc.ai_firefly_prompt)); + } case DocumentType.COL: { try { - let res; - if (this._regenInput) { - const prompt = `This is your previously generated svg code: ${this._lastResponse} for the user input "${this._lastInput.text}". Please regenerate it with the provided specifications.`; - res = await gptAPICall(`"${this._regenInput}"`, GPTCallType.DRAW, prompt, true); - this._lastInput.text = `${this._lastInput.text} ~~~ ${this._regenInput}`; - } else { - res = await gptAPICall(`"${this._lastInput.text}", "${this._lastInput.complexity}", "${this._lastInput.size}"`, GPTCallType.DRAW, undefined, true); - } + const res = await (async () => { + if (this._regenInput) { + const prompt = `This is your previously generated svg code: ${this._lastResponse} for the user input "${this._lastInput.text}". Please regenerate it with the provided specifications.`; + this._lastInput.text = `${this._lastInput.text} ~~~ ${this._regenInput}`; + return gptAPICall(`"${this._regenInput}"`, GPTCallType.DRAW, prompt, true); + } + return gptAPICall(`"${this._lastInput.text}", "${this._lastInput.complexity}", "${this._lastInput.size}"`, GPTCallType.DRAW, undefined, true); + })(); if (res) { const strokeData = await this.parseSvg(res, { X: this._lastInput.x, Y: this._lastInput.y }, true, lastInput?.autoColor || this._autoColor); this.RemoveDrawing !== unimplementedFunction && this.RemoveDrawing(true, doc); -- cgit v1.2.3-70-g09d2