From 1e673454f8cabf894e8dfec36734d2cb41caa7b1 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 3 Feb 2025 10:23:56 -0500 Subject: changed filter 'check' to be exact match and 'match' to be substring. fixed GPTpopup filtering to use a #chat tag instead of a chatFilter field. --- src/client/apis/gpt/GPT.ts | 2 +- src/client/documents/DocUtils.ts | 4 +- src/client/util/CurrentUserUtils.ts | 3 +- src/client/views/TagsView.scss | 4 +- src/client/views/TagsView.tsx | 2 +- .../views/collections/CollectionCardDeckView.tsx | 11 +++-- src/client/views/global/globalScripts.ts | 4 +- src/client/views/nodes/ComparisonBox.tsx | 2 +- src/client/views/nodes/IconTagBox.scss | 2 - src/client/views/pdf/GPTPopup/GPTPopup.tsx | 57 ++++++++++------------ 10 files changed, 44 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts index 269a4284a..1894bb4df 100644 --- a/src/client/apis/gpt/GPT.ts +++ b/src/client/apis/gpt/GPT.ts @@ -42,7 +42,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = { model: 'gpt-4o', maxTokens: 2048, temp: 0.7, - prompt: 'Create a stack of flashcards out of this text with each question and answer labeled as question and answer. Create a title that represents the question in just a few words and label it "title". For some questions, ask "what is this image of" but tailored to stacks theme and the image and write a keyword that represents the image and label it "keyword". Otherwise, write none. Do not label each flashcard and do not include asterisks.', + prompt: 'Create a stack of at least 10 flashcards out of this text with each question and answer labeled as question and answer. Each flashcard should have a title that represents the question in just a few words and label it "title". For some questions, ask "what is this image of" but tailored to stacks theme and the image and write a keyword that represents the image and label it "keyword". Otherwise, write none. Do not label each flashcard and do not include asterisks.', }, completion: { model: 'gpt-4-turbo', maxTokens: 256, temp: 0.5, prompt: "You are a helpful assistant. Answer the user's prompt." }, diff --git a/src/client/documents/DocUtils.ts b/src/client/documents/DocUtils.ts index d11a3e235..23032b62e 100644 --- a/src/client/documents/DocUtils.ts +++ b/src/client/documents/DocUtils.ts @@ -72,9 +72,9 @@ export namespace DocUtils { } const vals = StrListCast(fieldVal); // list typing is very imperfect. casting to a string list doesn't mean that the entries will actually be strings if (vals.length) { - return vals.some(v => typeof v === 'string' && v.includes(value as string)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring + return vals.some(v => typeof v === 'string' && v === (value as string)); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring } - return Field.toString(fieldVal as FieldType).includes(value as string); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring + return Field.toString(fieldVal as FieldType) === (value as string); // bcz: arghh: Todo: comparison should be parameterized as exact, or substring } /** * @param docs diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index b75961575..0fd09b479 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -728,7 +728,8 @@ pie title Minerals in my tap water this.filterBtnDesc("Star", "star"), this.filterBtnDesc("Like", "heart"), this.filterBtnDesc("Todo", "bolt"), - this.filterBtnDesc("Idea", "cloud") + this.filterBtnDesc("Idea", "cloud"), + this.filterBtnDesc("Chat", "robot") ]; return [ { title:"Options",isSystem: true,icon: "gear", toolTip:"Click to customize list of filter buttons", btnType: ButtonType.ClickButton, expertMode: false, toolType:"-opts-",funcs: {}, scripts: { onClick: '{ return setTagFilter(this.toolType, false,_readOnly_);}'}}, diff --git a/src/client/views/TagsView.scss b/src/client/views/TagsView.scss index 303a08e1e..b21d303fb 100644 --- a/src/client/views/TagsView.scss +++ b/src/client/views/TagsView.scss @@ -12,7 +12,7 @@ .tagsView-list { display: flex; flex-wrap: wrap; - height: inherit; + height: 1; .iconButton-container { min-height: unset !important; } @@ -58,7 +58,7 @@ } .tagsView-editing-box { - margin-top: 8px; + margin-top: 20px; } .tagsView-input-box { diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx index 9e936ea54..b70e21918 100644 --- a/src/client/views/TagsView.tsx +++ b/src/client/views/TagsView.tsx @@ -146,7 +146,7 @@ export class TagItem extends ObservableReactComponent { } } } - doc[DocData].tags = new List((doc[DocData].tags as List).filter(label => label !== tag)); + doc[DocData].tags = new List(StrListCast(doc[DocData].tags).filter(label => label !== tag)); }; private _ref: React.RefObject; diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx index f24673c39..43464e50c 100644 --- a/src/client/views/collections/CollectionCardDeckView.tsx +++ b/src/client/views/collections/CollectionCardDeckView.tsx @@ -85,6 +85,10 @@ export class CollectionCardView extends CollectionSubView() { }); componentDidMount() { + this._disposers.chatVis = reaction( + () => GPTPopup.Instance.Visible, + vis => !vis && this.onGptHide() + ); GPTPopup.Instance.setRegenerateCallback(this.Document, this.childPairStringListAndUpdateSortDesc); this._props.setContentViewBox?.(this); // if card deck moves, then the child doc views are hidden so their screen to local transforms will return empty rectangles @@ -106,6 +110,7 @@ export class CollectionCardView extends CollectionSubView() { ); } + onGptHide = () => Doc.setDocFilter(this.Document, 'tags', '#chat', 'remove'); componentWillUnmount() { GPTPopup.Instance.setSortDesc(''); GPTPopup.Instance.onSortComplete = undefined; @@ -445,7 +450,7 @@ export class CollectionCardView extends CollectionSubView() { if (questionType === '2' || questionType === '4') { this.childDocs.forEach(d => { - d.chatFilter = false; + TagItem.removeTagFromDoc(d, '#chat'); }); } @@ -471,8 +476,8 @@ export class CollectionCardView extends CollectionSubView() { break; case '2': case '4': - doc.chatFilter = true; - Doc.setDocFilter(DocCast(this.Document), 'chatFilter', true, 'check'); + TagItem.addTagToDoc(doc, '#chat'); + Doc.setDocFilter(this.Document, 'tags', '#chat', 'check'); break; } } else { diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts index b02eabab0..b44292164 100644 --- a/src/client/views/global/globalScripts.ts +++ b/src/client/views/global/globalScripts.ts @@ -223,9 +223,9 @@ ScriptingGlobals.add(function showFreeform( setDoc: (doc: Doc, dv: DocumentView) => { doc[Doc.LayoutFieldKey(doc)+"_sort_desc"] = true; }, }], ['toggle-chat', { - checkResult: (doc: Doc) => GPTPopup.Instance.visible, + checkResult: (doc: Doc) => GPTPopup.Instance.Visible, setDoc: (doc: Doc, dv: DocumentView) => { - if (GPTPopup.Instance.visible){ + if (GPTPopup.Instance.Visible){ doc[Doc.LayoutFieldKey(doc)+"_sort"] = ''; GPTPopup.Instance.setVisible(false); diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx index f5291a4c1..53fbd11c5 100644 --- a/src/client/views/nodes/ComparisonBox.tsx +++ b/src/client/views/nodes/ComparisonBox.tsx @@ -510,7 +510,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent() * Calls GPT for each flashcard type. */ askGPT = async (callType: GPTCallType) => { - const questionText = 'Question: ' + this.frontText; + const questionText = this.frontText; const queryText = questionText + (callType == GPTCallType.QUIZ ? ' UserAnswer: ' + this._inputValue + '. ' + ' Rubric: ' + this.backText : ''); this.loading = true; diff --git a/src/client/views/nodes/IconTagBox.scss b/src/client/views/nodes/IconTagBox.scss index 90cc06092..c79d662f4 100644 --- a/src/client/views/nodes/IconTagBox.scss +++ b/src/client/views/nodes/IconTagBox.scss @@ -10,8 +10,6 @@ gap: 5px; padding-left: 5px; padding-right: 5px; - padding-top: 2px; - padding-bottom: 2px; button { pointer-events: auto; diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx index da0cbea7a..f5a9f9e6a 100644 --- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx +++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx @@ -46,9 +46,9 @@ export class GPTPopup extends ObservableReactComponent { @observable private chatMode: boolean = false; private correlatedColumns: string[] = []; - @observable public visible: boolean = false; + @observable public Visible: boolean = false; @action public setVisible = (vis: boolean) => { - this.visible = vis; + this.Visible = vis; }; @observable public loading: boolean = false; @action public setLoading = (loading: boolean) => { @@ -114,8 +114,8 @@ export class GPTPopup extends ObservableReactComponent { this.sortDesc = t; }; - @observable onSortComplete?: (sortResult: string, questionType: string, tag?: string) => void; - @observable onQuizRandom?: () => void; + onSortComplete?: (sortResult: string, questionType: string, tag?: string) => void; + onQuizRandom?: () => void; @observable cardsDoneLoading = false; @observable collectionDoc: Doc | undefined = undefined; @@ -154,30 +154,27 @@ export class GPTPopup extends ObservableReactComponent { generateQuiz = async () => { this.setLoading(true); - const selected = DocumentView.SelectedDocs().lastElement(); + await this.regenerateCallback?.(); - const questionText = 'Question: ' + StrCast(selected.gptInputText); - const rubricText = 'Rubric: ' + StrCast(selected.gptRubric); - const queryText = questionText + ' UserAnswer: ' + this.quizAnswer + '. ' + rubricText; + const selected = DocumentView.SelectedDocs().lastElement(); + if (!StrCast(selected.gptRubric)) { + await this.generateRubric(StrCast(selected.gptInputText), selected); + } try { - const res = await gptAPICall(queryText, GPTCallType.QUIZ); - if (!res) { - console.error('GPT call failed'); - return; - } - console.log(res); - this.setQuizResp(res); - this.conversationArray.push(res); + const res = await gptAPICall('Question: ' + StrCast(selected.gptInputText) + ' UserAnswer: ' + this.quizAnswer + '. Rubric: ' + StrCast(selected.gptRubric), GPTCallType.QUIZ); + if (res) { + this.setQuizResp(res); + this.conversationArray.push(res); - this.setLoading(false); + this.setLoading(false); + this.onQuizRandom?.(); + } else { + console.error('GPT provided no response'); + } } catch (err) { console.error('GPT call failed', err); } - - if (this.onQuizRandom) { - this.onQuizRandom(); - } }; /** @@ -223,9 +220,7 @@ export class GPTPopup extends ObservableReactComponent { generateCard = async () => { this.setLoading(true); - if (this.regenerateCallback) { - await this.regenerateCallback(); - } + await this.regenerateCallback?.(); try { const questionType = await gptAPICall(this.chatSortPrompt, GPTCallType.TYPE); @@ -442,9 +437,7 @@ export class GPTPopup extends ObservableReactComponent { onClick={() => { this.conversationArray = ['Define the selected card!']; this.setMode(GPTPopupMode.QUIZ); - if (this.onQuizRandom) { - this.onQuizRandom(); - } + this.onQuizRandom?.(); }} color={StrCast(Doc.UserDoc().userVariantColor)} type={Type.TERT} @@ -694,13 +687,13 @@ export class GPTPopup extends ObservableReactComponent { } onClick={() => (this.mode = GPTPopupMode.CARD)} style={{ right: '50px', position: 'absolute' }} /> )} this.collectionDoc && (this.collectionDoc.childFilters = undefined)} + onClick={() => this.collectionDoc && Doc.setDocFilter(this.collectionDoc, 'tags', '#chat', 'remove')} /> { } return ( -
+
{content}
-- cgit v1.2.3-70-g09d2