aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/apis/gpt/GPT.ts2
-rw-r--r--src/client/documents/DocUtils.ts4
-rw-r--r--src/client/util/CurrentUserUtils.ts3
-rw-r--r--src/client/views/TagsView.scss4
-rw-r--r--src/client/views/TagsView.tsx2
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx11
-rw-r--r--src/client/views/global/globalScripts.ts4
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx2
-rw-r--r--src/client/views/nodes/IconTagBox.scss2
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx57
10 files changed, 44 insertions, 47 deletions
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<TagItemProps> {
}
}
}
- doc[DocData].tags = new List<string>((doc[DocData].tags as List<string>).filter(label => label !== tag));
+ doc[DocData].tags = new List<string>(StrListCast(doc[DocData].tags).filter(label => label !== tag));
};
private _ref: React.RefObject<HTMLDivElement>;
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<FieldViewProps>()
* 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<object> {
@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<object> {
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<object> {
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<object> {
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<object> {
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<object> {
<IconButton color={StrCast(SettingsManager.userVariantColor)} tooltip="back" icon={<CgCornerUpLeft size="16px" />} onClick={() => (this.mode = GPTPopupMode.CARD)} style={{ right: '50px', position: 'absolute' }} />
)}
<Toggle
- tooltip="clear filters"
+ tooltip="Clear Chat filter"
toggleType={ToggleType.BUTTON}
type={Type.PRIM}
- toggleStatus={this.collectionDoc?.childFilters ? true : false}
- text={this.collectionDoc?.childFilters ? 'filtered' : ''}
+ toggleStatus={Doc.hasDocFilter(this.collectionDoc, 'tags', '#chat')}
+ text={Doc.hasDocFilter(this.collectionDoc, 'tags', '#chat') ? 'filtered' : ''}
color="red"
- onClick={() => this.collectionDoc && (this.collectionDoc.childFilters = undefined)}
+ onClick={() => this.collectionDoc && Doc.setDocFilter(this.collectionDoc, 'tags', '#chat', 'remove')}
/>
<IconButton
color={StrCast(SettingsManager.userVariantColor)}
@@ -738,7 +731,7 @@ export class GPTPopup extends ObservableReactComponent<object> {
}
return (
- <div className="summary-box" style={{ display: this.visible ? 'flex' : 'none' }}>
+ <div className="summary-box" style={{ display: this.Visible ? 'flex' : 'none' }}>
{content}
<div className="resize-handle" />
</div>