diff options
Diffstat (limited to 'src')
6 files changed, 101 insertions, 93 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index 82887a7a5..6dabcb8b2 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -326,7 +326,6 @@ .collectionFreeFormView-aiView-regenerate-container { text-align: start; font-weight: normal; - padding: 5px; width: 100%; display: flex; .collectionFreeformView-aiView-subtitle { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 0d593f97f..eeb97bf15 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -2209,7 +2209,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection placeholder={this._drawingFillInput || StrCast(this.Document.title) || 'Describe image'} type="text" value={this._drawingFillInput} - onChange={action(e => this._canInteract && (this._drawingFillInput = e.target.value))} + onChange={action(e => {this._drawingFillInput = e.target.value})} /> <div className="collectionfreeformview-aiView-strength"> Similarity @@ -2228,7 +2228,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection onChange={action((e, val) => (this._fireflyRefStrength = val as number))} valueLabelDisplay="auto" /> - Reference Strength </div> <Button text="Send" @@ -2257,7 +2256,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection aria-label="Edit instructions input" type="text" value={this._regenInput} - onChange={action(e => this._canInteract && (this._regenInput = e.target.value))} + onChange={action(e => {this._regenInput = e.target.value})} placeholder="..under development.." /> <Button diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss index e71f391c6..cd813cb67 100644 --- a/src/client/views/nodes/DocumentView.scss +++ b/src/client/views/nodes/DocumentView.scss @@ -281,7 +281,6 @@ .documentView-editorView { width: 100%; - overflow-y: scroll; scrollbar-width: thin; justify-items: center; background-color: rgb(223, 223, 223); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index ec6ce8c2a..82d8ea5f1 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -13,7 +13,7 @@ import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { ObjectField } from '../../../fields/ObjectField'; -import { Cast, ImageCast, NumCast, RTFCast, StrCast } from '../../../fields/Types'; +import { Cast, DocCast, ImageCast, NumCast, RTFCast, StrCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; import { emptyFunction } from '../../../Utils'; @@ -540,34 +540,31 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { protected _inputWidth = 50; protected _sideBtnMaxPanelPct = 0.12; @observable _filterFunc: ((doc: Doc) => boolean) | undefined = undefined; + @observable private _fireflyRefStrength = 0; @computed get contentScaling() { return this.ScreenToLocalBoxXf().Scale; } // prettier-ignore @computed get maxWidgetSize() { return Math.min(this._btnWidth * this.contentScaling, (this._props.fitWidth?.(this.Document) && this._props.PanelWidth() > NumCast(this.layoutDoc._width) ? 1 : this._sideBtnMaxPanelPct) * NumCast(this.layoutDoc.width, 1)); } // prettier-ignore @computed get uiBtnScaling() { return this.maxWidgetSize / this._btnWidth; } // prettier-ignore @computed get uiInputScaling() { return this.maxWidgetSize / this._inputWidth; } // prettier-ignore - componentAIViewHistory = () => { - const imgs: FireflyImageData[] = this.dataDoc.ai_firefly_history ? JSON.parse(StrCast(this.dataDoc.ai_firefly_history)) : []; - return ( - <div className="imageBox-aiView-history"> - <Button text="Clear History" type={Type.SEC} size={Size.XSMALL} /> - {this._prevImgs.map(img => ( - <div key={img.pathname}> - <img - className="imageBox-aiView-img" - src={ClientUtils.prepend(img.pathname.replace(extname(img.pathname), '_s' + extname(img.pathname)))} - onClick={() => { - this.dataDoc[this.fieldKey] = new ImageField(img.pathname); - this.dataDoc.ai_firefly_prompt = img.prompt; - this.dataDoc.ai_firefly_seed = img.seed; - }} - /> - <span>{img.prompt}</span> - </div> - ))} - </div> - ); - }; - @observable private _fireflyRefStrength = 0; + componentAIViewHistory = () => ( + <div className="imageBox-aiView-history"> + <Button text="Clear History" type={Type.SEC} size={Size.XSMALL} /> + {this._prevImgs.map(img => ( + <div key={img.pathname}> + <img + className="imageBox-aiView-img" + src={ClientUtils.prepend(img.pathname.replace(extname(img.pathname), '_s' + extname(img.pathname)))} + onClick={() => { + this.dataDoc[this.fieldKey] = new ImageField(img.pathname); + this.dataDoc.ai_firefly_prompt = img.prompt; + this.dataDoc.ai_firefly_seed = img.seed; + }} + /> + <span>{img.prompt}</span> + </div> + ))} + </div> + ); componentAIView = () => { const field = this.dataDoc[this.fieldKey] instanceof ImageField ? Cast(this.dataDoc[this.fieldKey], ImageField, null) : new ImageField(String(this.dataDoc[this.fieldKey])); @@ -611,7 +608,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { onClick={action(async () => { this._regenerateLoading = true; if (this._fireflyRefStrength) { - DrawingFillHandler.drawingToImage(this.props.Document, this._fireflyRefStrength, this._regenInput || StrCast(this.Document.title))?.then( + DrawingFillHandler.drawingToImage(this.props.Document, this._fireflyRefStrength, this._regenInput || StrCast(this.Document.title), this.Document)?.then( action(() => { this._regenerateLoading = false; }) @@ -640,7 +637,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { <div className="imageBox-aiView-options-container"> <span className="imageBox-aiView-subtitle"> More Options: </span> <div className="imageBox-aiView-options"> - {showRegenerate && ( + {SmartDrawHandler.Instance.ShowRegenerate && ( <text className="imageBox-aiView-subtitle" style={{ transform: `scale(${this.uiBtnScaling})` }}> More Options: </text> @@ -692,7 +689,12 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { }).then((info: 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); + const genratedDocs = this.Document.generatedDocs + ? DocCast(this.Document.generatedDocs) + : Docs.Create.MasonryDocument([], { _width: 400, _height: 400, x: NumCast(this.Document.x) + NumCast(this.Document.width), y: NumCast(this.Document.y) }); + Doc.AddDocToList(genratedDocs, undefined, img); + this.Document[DocData].generatedDocs = genratedDocs; + if (!DocumentView.getFirstDocumentView(genratedDocs)) this._props.addDocTab(genratedDocs, OpenWhere.addRight); }); }} /> diff --git a/src/client/views/smartdraw/DrawingFillHandler.tsx b/src/client/views/smartdraw/DrawingFillHandler.tsx index cd15d19d5..6f2d1cbe6 100644 --- a/src/client/views/smartdraw/DrawingFillHandler.tsx +++ b/src/client/views/smartdraw/DrawingFillHandler.tsx @@ -1,7 +1,7 @@ import { imageUrlToBase64 } from '../../../ClientUtils'; import { Doc } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; -import { DocCast, ImageCast } from '../../../fields/Types'; +import { DocCast, ImageCast, NumCast } from '../../../fields/Types'; import { Upload } from '../../../server/SharedMediaTypes'; import { gptDescribeImage } from '../../apis/gpt/GPT'; import { Docs } from '../../documents/Documents'; @@ -12,13 +12,15 @@ import { AspectRatioLimits, FireflyDimensionsMap, FireflyImageDimensions, Firefl const DashDropboxId = '2m86iveqdr9vzsa'; export class DrawingFillHandler { - static drawingToImage = async (drawing: Doc, strength: number, user_prompt: string) => { + static drawingToImage = async (drawing: Doc, strength: number, user_prompt: string, styleDoc?: Doc) => { 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)); - const styleDocs = Doc.Links(drawing) - .map(link => Doc.getOppositeAnchor(link, drawing)) - .map(anchor => anchor && DocCast(anchor.embedContainer)); + const styleDocs = styleDoc + ? [styleDoc] + : Doc.Links(drawing) + .map(link => Doc.getOppositeAnchor(link, drawing)) + .map(anchor => anchor && DocCast(anchor.embedContainer)); const styleRef = styleDocs.filter(doc => doc !== undefined && doc.type === 'image').lastElement(); let styleUrl: string | undefined; if (styleRef) { @@ -47,25 +49,26 @@ export class DrawingFillHandler { const structureUrl = `${hrefParts.slice(0, -1).join('.')}_o.${hrefParts.lastElement()}`; return imageUrlToBase64(structureUrl) .then(gptDescribeImage) - .then(prompt => - Networking.PostToServer('/queryFireflyImageFromStructure', { prompt: `${user_prompt || prompt}`, width: dims.width, height: dims.height, structure: structureUrl, strength, presets: styles, styleUrl }) - .then((info: Upload.ImageInformation) => - DocumentViewInternal.addDocTabFunc( - Docs.Create.ImageDocument(info.accessPaths.agnostic.client, { - ai: 'firefly', - title: user_prompt || prompt, - ai_firefly_prompt: user_prompt || prompt, - _width: 500, - data_nativeWidth: info.nativeWidth, - data_nativeHeight: info.nativeHeight, - }), - OpenWhere.addRight - ) - ) + .then((prompt, newPrompt = user_prompt || prompt) => + Networking.PostToServer('/queryFireflyImageFromStructure', { prompt: `${newPrompt}`, width: dims.width, height: dims.height, structure: structureUrl, strength, presets: styles, styleUrl }) + .then((info: Upload.ImageInformation) => { + const img = Docs.Create.ImageDocument(info.accessPaths.agnostic.client, { + ai: 'firefly', + title: newPrompt, + ai_firefly_prompt: newPrompt, + _width: 500, + data_nativeWidth: info.nativeWidth, + data_nativeHeight: info.nativeHeight, + }); + const genratedDocs = drawing.generatedDocs ? DocCast(drawing.generatedDocs) : Docs.Create.MasonryDocument([], { _width: 400, _height: 400, x: NumCast(drawing.x) + NumCast(drawing.width), y: NumCast(drawing.y) }); + drawing[DocData].generatedDocs = genratedDocs; + Doc.AddDocToList(genratedDocs, undefined, img); + if (!DocumentView.getFirstDocumentView(genratedDocs)) DocumentViewInternal.addDocTabFunc(genratedDocs, OpenWhere.addRight); + }) .catch(e => { if (e.toString().includes('Dropbox') && confirm('Create image failed. Try authorizing DropBox?\r\n' + e.toString().replace(/^[^"]*/, ''))) { window.open(`https://www.dropbox.com/oauth2/authorize?client_id=${DashDropboxId}&response_type=code&token_access_type=offline&redirect_uri=http://localhost:1050/refreshDropbox`, '_blank')?.focus(); - } + } else alert(e.toString()); }) ); // prettier-ignore:q } diff --git a/src/server/ApiManagers/FireflyManager.ts b/src/server/ApiManagers/FireflyManager.ts index 700b275d4..f49cf4132 100644 --- a/src/server/ApiManagers/FireflyManager.ts +++ b/src/server/ApiManagers/FireflyManager.ts @@ -35,8 +35,10 @@ export default class FireflyManager extends ApiManager { ['Authorization', `Bearer ${data.access_token}`], ], body: JSON.stringify({ - prompt: prompt, - size: { width: width, height: height }, + prompt, + // detailLevel: 'preview', + // modelVersion: 'image3_fast', + size: { width, height }, structure: !structureUrl ? undefined : { @@ -51,16 +53,18 @@ export default class FireflyManager extends ApiManager { imageReference : !styleUrl ? undefined : { - source: { uploadId: styleUrl }, + source: { url: styleUrl }, } } }), }) - .then(response2 => response2.json().then(json => JSON.stringify((json.outputs?.[0] as { image: { url: string } })?.image))) - .catch(error => { - console.error('Error:', error); - return ''; - }) + .then(response2 => response2.json().then(json => + { + if (json.outputs?.length) + return JSON.stringify((json.outputs?.[0] as { image: { url: string } } ?? {})?.image); + throw new Error(JSON.stringify(json)); + }) + ) ) ); @@ -127,13 +131,7 @@ export default class FireflyManager extends ApiManager { ], body: body, }) - .then(response2 => - response2.json().then(json => { - const seed = json.outputs?.[0]?.seed; - const url = json.outputs?.[0]?.image?.url; - return { seed, url }; - }) - ) + .then(response2 => response2.json().then(json => ({ seed: json.outputs?.[0]?.seed, url: json.outputs?.[0]?.image?.url }))) .catch(error => { console.error('Error:', error); return undefined; @@ -290,33 +288,42 @@ export default class FireflyManager extends ApiManager { register({ method: Method.POST, subscription: '/queryFireflyImageFromStructure', - secureHandler: async ({ req, res }) => { - (req.body.styleRef ? this.uploadImageToDropbox(req.body.styleRef, req.user as DashUserModel) : Promise.resolve(undefined)) - .then(styleUrl => { - if (styleUrl instanceof Error) { - _invalid(res, styleUrl.message); - throw new Error('Error uploading images to dropbox'); - } - return this.uploadImageToDropbox(req.body.structure, req.user as DashUserModel).then(structureUrl => { - if (structureUrl instanceof Error) { - _invalid(res, structureUrl.message); + secureHandler: ({ req, res }) => + new Promise<void>(resolver => { + (req.body.styleUrl ? this.uploadImageToDropbox(req.body.styleUrl, req.user as DashUserModel) : Promise.resolve(undefined)) + .then(styleUrl => { + if (styleUrl instanceof Error) { + _invalid(res, styleUrl.message); throw new Error('Error uploading images to dropbox'); } - return { styleUrl, structureUrl }; - }); - }) - .then(uploads => - this.generateImageFromStructure(req.body.prompt, req.body.width, req.body.height, uploads.structureUrl, req.body.strength, req.body.presets, req.body.styleUrl).then(fire => { - DashUploadUtils.UploadImage(JSON.parse(fire ?? '').url).then(info => { - if (info instanceof Error) _invalid(res, info.message); - else _success(res, info); - }); + this.uploadImageToDropbox(req.body.structure, req.user as DashUserModel) + .then(structureUrl => { + if (structureUrl instanceof Error) { + _invalid(res, structureUrl.message); + throw new Error('Error uploading images to dropbox'); + } + return { styleUrl, structureUrl }; + }) + .then(uploads => + this.generateImageFromStructure(req.body.prompt, req.body.width, req.body.height, uploads.structureUrl, req.body.strength, req.body.presets, uploads.styleUrl) + .then(fire => + DashUploadUtils.UploadImage(JSON.parse(fire ?? '').url).then(info => { + if (info instanceof Error) _invalid(res, info.message); + else _success(res, info); + resolver(); + }) + ) + .catch(e => { + _invalid(res, e.message); + resolver(); + }) + ); }) - ) - .catch(() => { - /* do nothing */ - }); - }, + .catch(() => { + /* do nothing */ + resolver(); + }); + }), }); register({ method: Method.POST, @@ -333,7 +340,6 @@ export default class FireflyManager extends ApiManager { register({ method: Method.POST, subscription: '/queryFireflyImageText', - // eslint-disable-next-line @typescript-eslint/no-unused-vars secureHandler: ({ req, res }) => fetch(req.body.file).then(json => json.blob().then(file => |