aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2025-01-16 12:00:52 -0500
committerbobzel <zzzman@gmail.com>2025-01-16 12:00:52 -0500
commitb0903079ab0abbc65e927d70ee0f6bb593865869 (patch)
tree4f2060b5ed8d3ef6cefa477fe84479778ccc9e33
parenta5fd5986acfa15d1442e9fa96b1af5c2131452da (diff)
fixed style references for generating ai images. fixed some error cases.
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss1
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx5
-rw-r--r--src/client/views/nodes/DocumentView.scss1
-rw-r--r--src/client/views/nodes/ImageBox.tsx56
-rw-r--r--src/client/views/smartdraw/DrawingFillHandler.tsx45
-rw-r--r--src/server/ApiManagers/FireflyManager.ts86
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 =>