From 47e3e54543b2b9a613d0029435794d2265e2a952 Mon Sep 17 00:00:00 2001 From: IEatChili Date: Thu, 16 May 2024 16:49:55 -0700 Subject: feat: added image sorting --- src/client/apis/gpt/GPT.ts | 62 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) (limited to 'src/client/apis') diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index fb51278ae..4240c07b8 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -68,4 +68,64 @@ const gptImageCall = async (prompt: string, n?: number) => { } }; -export { gptAPICall, gptImageCall, GPTCallType }; +const gptGetEmbedding = async (src: string): Promise => { + try { + const configuration: ClientOptions = { + apiKey: process.env.OPENAI_KEY, + dangerouslyAllowBrowser: true, + }; + const openai = new OpenAI(configuration); + const embeddingResponse = await openai.embeddings.create({ + model: 'text-embedding-3-large', + input: [src], + encoding_format: 'float', + dimensions: 256, + }); + + // Assume the embeddingResponse structure is correct; adjust based on actual API response + const embedding = embeddingResponse.data[0].embedding; + return embedding; + } catch (err) { + console.log(err); + return []; + } +}; + +const gptImageLabel = async (src: string): Promise => { + try { + const configuration: ClientOptions = { + apiKey: process.env.OPENAI_KEY, + dangerouslyAllowBrowser: true, + }; + + const openai = new OpenAI(configuration); + const response = await openai.chat.completions.create({ + model: 'gpt-4-vision-preview', + messages: [ + { + role: 'user', + content: [ + { type: 'text', text: 'Give three labels to describe this image.' }, + { + type: 'image_url', + image_url: { + url: `${src}`, + detail: 'low', + }, + }, + ], + }, + ], + }); + if (response.choices[0].message.content) { + return response.choices[0].message.content; + } else { + return 'Missing labels'; + } + } catch (err) { + console.log(err); + return 'Error connecting with API'; + } +}; + +export { gptAPICall, gptImageCall, GPTCallType, gptImageLabel, gptGetEmbedding }; -- cgit v1.2.3-70-g09d2 From a5aa41e60dc72881e1aa2f14743b9f00c1160eed Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 20 May 2024 13:13:11 -0400 Subject: fixed pivotView to provide a white background to docs with no background so that images will show up, and so text doesn't blend in to column. changed image labeling to show a pivot view and assigne metadata instead of creating collections. --- src/Utils.ts | 5 + src/client/apis/gpt/GPT.ts | 5 +- .../views/collections/CollectionCardDeckView.tsx | 65 ++++++------ .../CollectionFreeFormLayoutEngines.tsx | 2 +- .../collectionFreeForm/ImageLabelHandler.tsx | 4 +- .../collections/collectionFreeForm/MarqueeView.tsx | 113 ++++++++------------- 6 files changed, 83 insertions(+), 111 deletions(-) (limited to 'src/client/apis') diff --git a/src/Utils.ts b/src/Utils.ts index 44f1d55c2..23ae38bdb 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -211,6 +211,11 @@ export type Without = Pick>; export type Predicate = (entry: [K, V]) => boolean; +/** + * creates a list of numbers ordered from 0 to 'num' + * @param num range of numbers + * @returns list of values from 0 to num -1 + */ export function numberRange(num: number) { return num > 0 && num < 1000 ? Array.from(Array(num)).map((v, i) => i) : []; } diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index 455352068..7af71a6a2 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -119,7 +119,7 @@ const gptGetEmbedding = async (src: string): Promise => { }); // Assume the embeddingResponse structure is correct; adjust based on actual API response - const embedding = embeddingResponse.data[0].embedding; + const { embedding } = embeddingResponse.data[0]; return embedding; } catch (err) { console.log(err); @@ -155,9 +155,8 @@ const gptImageLabel = async (src: string): Promise => { }); if (response.choices[0].message.content) { return response.choices[0].message.content; - } else { - return 'Missing labels'; } + return 'Missing labels'; } catch (err) { console.log(err); return 'Error connecting with API'; diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx index 6036a2ead..de46180e6 100644 --- a/src/client/views/collections/CollectionCardDeckView.tsx +++ b/src/client/views/collections/CollectionCardDeckView.tsx @@ -161,7 +161,7 @@ export class CollectionCardView extends CollectionSubView() { panelHeight = (layout: Doc) => () => (this.panelWidth() * NumCast(layout._height)) / NumCast(layout._width); onChildDoubleClick = () => ScriptCast(this.layoutDoc.onChildDoubleClick); isContentActive = () => this._props.isSelected() || this._props.isContentActive() || this._props.isAnyChildContentActive(); - isChildContentActive = () => (this.isContentActive() ? true : false); + isChildContentActive = () => !!this.isContentActive(); /** * Returns the degree to rotate a card dependind on the amount of cards in their row and their index in said row @@ -173,10 +173,10 @@ export class CollectionCardView extends CollectionSubView() { const possRotate = -30 + index * (30 / ((amCards - (amCards % 2)) / 2)); const stepMag = Math.abs(-30 + (amCards / 2 - 1) * (30 / ((amCards - (amCards % 2)) / 2))); - if (amCards % 2 == 0 && possRotate == 0) { + if (amCards % 2 === 0 && possRotate === 0) { return possRotate + Math.abs(-30 + (index - 1) * (30 / (amCards / 2))); } - if (amCards % 2 == 0 && index > (amCards + 1) / 2) { + if (amCards % 2 === 0 && index > (amCards + 1) / 2) { return possRotate + stepMag; } @@ -194,10 +194,10 @@ export class CollectionCardView extends CollectionSubView() { if (realIndex > this._maxRowCount - 1) { rowOffset = 400 * ((realIndex - (realIndex % this._maxRowCount)) / this._maxRowCount); } - if (evenOdd == 1 || index < apex - 1) { + if (evenOdd === 1 || index < apex - 1) { return Math.abs(stepMag * (apex - index)) - rowOffset; } - if (index == apex || index == apex - 1) { + if (index === apex || index === apex - 1) { return 0 - rowOffset; } @@ -259,27 +259,26 @@ export class CollectionCardView extends CollectionSubView() { return docs; }; - displayDoc = (doc: Doc, screenToLocalTransform: () => Transform) => { - return ( - r?.ContentDiv && this._docRefs.set(doc, r))} - Document={doc} - NativeWidth={returnZero} - NativeHeight={returnZero} - fitWidth={returnFalse} - onDoubleClickScript={this.onChildDoubleClick} - renderDepth={this._props.renderDepth + 1} - LayoutTemplate={this._props.childLayoutTemplate} - LayoutTemplateString={this._props.childLayoutString} - ScreenToLocalTransform={screenToLocalTransform} //makes sure the box wrapper thing is in the right spot - isContentActive={this.isChildContentActive} - isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive} - PanelWidth={this.panelWidth} - PanelHeight={this.panelHeight(doc)} - /> - ); - }; + displayDoc = (doc: Doc, screenToLocalTransform: () => Transform) => ( + r?.ContentDiv && this._docRefs.set(doc, r))} + Document={doc} + NativeWidth={returnZero} + NativeHeight={returnZero} + fitWidth={returnFalse} + onDoubleClickScript={this.onChildDoubleClick} + renderDepth={this._props.renderDepth + 1} + LayoutTemplate={this._props.childLayoutTemplate} + LayoutTemplateString={this._props.childLayoutString} + ScreenToLocalTransform={screenToLocalTransform} // makes sure the box wrapper thing is in the right spot + isContentActive={this.isChildContentActive} + isDocumentActive={this._props.childDocumentsActive?.() || this.Document._childDocumentsActive ? this._props.isDocumentActive : this.isContentActive} + PanelWidth={this.panelWidth} + PanelHeight={this.panelHeight(doc)} + /> + ); /** * Determines how many cards are in the row of a card at a specific index @@ -296,7 +295,7 @@ export class CollectionCardView extends CollectionSubView() { if (index < totalCards - (totalCards % 10)) { return this._maxRowCount; } - //(3) + // (3) return totalCards % 10; }; /** @@ -335,7 +334,9 @@ export class CollectionCardView extends CollectionSubView() { * @param buttonID * @param doc */ - toggleButton = undoable((buttonID: number, doc: Doc) => this.cardSort_customField && (doc[this.cardSort_customField] = buttonID), 'toggle custom button'); + toggleButton = undoable((buttonID: number, doc: Doc) => { + this.cardSort_customField && (doc[this.cardSort_customField] = buttonID); + }, 'toggle custom button'); /** * A list of the text content of all the child docs. RTF documents will have just their text and pdf documents will have the first 50 words. @@ -346,8 +347,7 @@ export class CollectionCardView extends CollectionSubView() { childPairStringList = () => { const docToText = (doc: Doc) => { switch (doc.type) { - case DocumentType.PDF: const words = StrCast(doc.text).split(/\s+/); - return words.slice(0, 50).join(' '); // first 50 words of pdf text + case DocumentType.PDF: return StrCast(doc.text).split(/\s+/).slice(0, 50).join(' '); // first 50 words of pdf text case DocumentType.IMG: return this.getImageDesc(doc); case DocumentType.RTF: return StrCast(RTFCast(doc.text).Text); default: return StrCast(doc.title); @@ -368,7 +368,7 @@ export class CollectionCardView extends CollectionSubView() { */ getImageDesc = async (image: Doc) => { if (StrCast(image.description)) return StrCast(image.description); // Return existing description - const href = (image.data as URLField).url.href; + const { href } = (image.data as URLField).url; const hrefParts = href.split('.'); const hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`; try { @@ -422,12 +422,13 @@ export class CollectionCardView extends CollectionSubView() { */ renderButtons = (doc: Doc, cardSort: cardSortings) => { if (cardSort !== cardSortings.Custom) return ''; - const amButtons = Math.max(4, this.childDocs?.reduce((set, doc) => this.cardSort_customField && set.add(NumCast(doc[this.cardSort_customField])), new Set()).size ?? 0); + const amButtons = Math.max(4, this.childDocs?.reduce((set, d) => this.cardSort_customField && set.add(NumCast(d[this.cardSort_customField])), new Set()).size ?? 0); const activeButtonIndex = CollectionCardView.getButtonGroup(this.cardSort_customField, doc); const totalWidth = amButtons * 35 + amButtons * 2 * 5 + 6; return (
{numberRange(amButtons).map(i => ( + // eslint-disable-next-line jsx-a11y/control-has-associated-label