aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/apis/gpt/GPT.ts26
-rw-r--r--src/client/views/TagsView.tsx2
-rw-r--r--src/client/views/collections/CollectionCardDeckView.scss5
-rw-r--r--src/client/views/collections/CollectionCardDeckView.tsx60
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx49
5 files changed, 101 insertions, 41 deletions
diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index cf3a28a8e..d96972784 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -16,10 +16,10 @@ enum GPTCallType {
PRONUNCIATION = 'pronunciation',
DRAW = 'draw',
COLOR = 'color',
- RUBRIC = 'rubric',
- TYPE = 'type',
- SUBSET = 'subset',
- INFO = 'info',
+ RUBRIC = 'rubric', // needs to be filled in below
+ TYPE = 'type', // needs to be filled in below
+ SUBSET = 'subset', // needs to be filled in below
+ INFO = 'info', // needs to be filled in below
TEMPLATE = 'template',
VIZSUM = 'vizsum',
VIZSUM2 = 'vizsum2',
@@ -84,6 +84,18 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
temp: 0.1, //0.3
prompt: "BRIEFLY (<50 words) describe any differences between the rubric and the user's answer answer in second person. If there are no differences, say correct",
},
+ type: {
+ model: 'gpt-4-turbo',
+ maxTokens: 512,
+ temp: 0.5,
+ prompt: '',
+ },
+ info: {
+ model: 'gpt-4-turbo',
+ maxTokens: 512,
+ temp: 0.5,
+ prompt: '',
+ },
template: {
model: 'gpt-4-turbo',
maxTokens: 512,
@@ -131,8 +143,12 @@ let lastResp = '';
* @returns AI Output
*/
const gptAPICall = async (inputTextIn: string, callType: GPTCallType, prompt?: string, dontCache?: boolean) => {
- const inputText = [GPTCallType.SUMMARY, GPTCallType.FLASHCARD, GPTCallType.QUIZ, GPTCallType.STACK].includes(callType) ? inputTextIn + '.' : inputTextIn;
+ const inputText = inputTextIn + ([GPTCallType.SUMMARY, GPTCallType.FLASHCARD, GPTCallType.QUIZ, GPTCallType.STACK].includes(callType) ? '.' : '');
const opts = callTypeMap[callType];
+ if (!opts) {
+ console.log('The query type:' + callType + ' requires a configuration.');
+ return 'Error connecting with API.';
+ }
if (lastCall === inputText && dontCache !== true) return lastResp;
try {
lastCall = inputText;
diff --git a/src/client/views/TagsView.tsx b/src/client/views/TagsView.tsx
index 73f404596..9e936ea54 100644
--- a/src/client/views/TagsView.tsx
+++ b/src/client/views/TagsView.tsx
@@ -9,7 +9,7 @@ import { emptyFunction } from '../../Utils';
import { Doc, DocListCast, Field, Opt, StrListCast } from '../../fields/Doc';
import { DocData } from '../../fields/DocSymbols';
import { List } from '../../fields/List';
-import { DocCast, NumCast, StrCast } from '../../fields/Types';
+import { DocCast, StrCast } from '../../fields/Types';
import { DocumentType } from '../documents/DocumentTypes';
import { DragManager } from '../util/DragManager';
import { SnappingManager } from '../util/SnappingManager';
diff --git a/src/client/views/collections/CollectionCardDeckView.scss b/src/client/views/collections/CollectionCardDeckView.scss
index 5283601bf..79c53db08 100644
--- a/src/client/views/collections/CollectionCardDeckView.scss
+++ b/src/client/views/collections/CollectionCardDeckView.scss
@@ -28,11 +28,14 @@
.collectionCardView-cardwrapper {
display: grid;
- grid-template-columns: repeat(10, 1fr);
transform-origin: left 50%;
align-items: center;
z-index: 0; // so that setting z-index of active card doesn't make it land on top of things outside of the card-wrapper
}
+.collectionCardView-cardSizeDragger {
+ position: absolute;
+ top: 0;
+}
.no-card-span {
position: relative;
diff --git a/src/client/views/collections/CollectionCardDeckView.tsx b/src/client/views/collections/CollectionCardDeckView.tsx
index 836a5a2c3..800eb4914 100644
--- a/src/client/views/collections/CollectionCardDeckView.tsx
+++ b/src/client/views/collections/CollectionCardDeckView.tsx
@@ -1,8 +1,9 @@
-import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, trace } from 'mobx';
+import { IReactionDisposer, ObservableMap, action, computed, makeObservable, observable, reaction, runInAction, trace } from 'mobx';
import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
import * as React from 'react';
-import { ClientUtils, DashColor, imageUrlToBase64, returnFalse, returnNever, returnZero } from '../../../ClientUtils';
+import * as CSS from 'csstype';
+import { ClientUtils, DashColor, imageUrlToBase64, returnFalse, returnNever, returnZero, setupMoveUpEvents } from '../../../ClientUtils';
import { emptyFunction } from '../../../Utils';
import { Doc, DocListCast, Opt } from '../../../fields/Doc';
import { Animation, DocData } from '../../../fields/DocSymbols';
@@ -18,7 +19,7 @@ import { DragManager } from '../../util/DragManager';
import { dropActionType } from '../../util/DropActionTypes';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
-import { undoable } from '../../util/UndoManager';
+import { undoable, UndoManager } from '../../util/UndoManager';
import { PinDocView, PinProps } from '../PinFuncs';
import { StyleProp } from '../StyleProp';
import { TagItem } from '../TagsView';
@@ -27,6 +28,8 @@ import { FocusViewOptions } from '../nodes/FocusViewOptions';
import { GPTPopup, GPTPopupMode } from '../pdf/GPTPopup/GPTPopup';
import './CollectionCardDeckView.scss';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { SettingsManager } from '../../util/SettingsManager';
enum cardSortings {
Time = 'time',
@@ -52,12 +55,13 @@ export class CollectionCardView extends CollectionSubView() {
private _oldWheel: HTMLElement | null = null;
private _dropped = false; // set when a card doc has just moved and the drop method has been called - prevents the pointerUp method from hiding doc decorations (which needs to be done when clicking on a card to animate it to front/center)
private _setCurDocScript = () => ScriptField.MakeScript('scriptContext.layoutDoc._card_curDoc=this', { scriptContext: 'any' })!;
+ private _draggerRef = React.createRef<HTMLDivElement>();
@observable _forceChildXf = 0;
@observable _hoveredNodeIndex = -1;
@observable _docRefs = new ObservableMap<Doc, DocumentView>();
- @observable _maxRowCount = 10;
@observable _docDraggedIndex: number = -1;
+ @observable _cursor: CSS.Property.Cursor = 'ew-resize';
constructor(props: SubCollectionViewProps) {
super(props);
@@ -74,6 +78,12 @@ export class CollectionCardView extends CollectionSubView() {
// prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
};
+ @computed get cardWidth() {
+ return NumCast(this.layoutDoc._cardWidth, 50);
+ }
+ @computed get _maxRowCount() {
+ return Math.ceil(this.cardDeckWidth / this.cardWidth);
+ }
/**
* Callback to ensure gpt's text versions of the child docs are updated
*/
@@ -167,6 +177,14 @@ export class CollectionCardView extends CollectionSubView() {
return this._props.NativeDimScaling?.() || 1;
}
+ @computed get xMargin() {
+ return NumCast(this.layoutDoc._xMargin, Math.max(3, 0.05 * this._props.PanelWidth()));
+ }
+
+ @computed get cardDeckWidth() {
+ return this._props.PanelWidth() - 2 * this.xMargin;
+ }
+
/**
* When in quiz mode, randomly selects a document
*/
@@ -505,7 +523,6 @@ export class CollectionCardView extends CollectionSubView() {
const normalizedItem = item.trim();
// find the corresponding Doc in the textToDoc map
const doc = this._textToDoc.get(normalizedItem);
-
if (doc) {
switch (questionType) {
case '6':
@@ -513,9 +530,7 @@ export class CollectionCardView extends CollectionSubView() {
break;
case '1': {
const allHotKeys = Doc.MyFilterHotKeys;
-
let myTag = '';
-
if (tag) {
for (let i = 0; i < allHotKeys.length; i++) {
// bcz: CHECK THIS CODE OUT -- SOMETHING CHANGED
@@ -526,7 +541,7 @@ export class CollectionCardView extends CollectionSubView() {
}
}
- if (myTag != '') {
+ if (myTag) {
doc[myTag] = true;
}
}
@@ -591,6 +606,26 @@ export class CollectionCardView extends CollectionSubView() {
}
});
+ cardSizerDown = (e: React.PointerEvent) => {
+ runInAction(() => {
+ this._cursor = 'grabbing';
+ });
+ const batch = UndoManager.StartBatch('card view size');
+ setupMoveUpEvents(
+ this,
+ e,
+ (e: PointerEvent, down: number[], delta: number[]) => {
+ this.layoutDoc._cardWidth = Math.max(10, delta[0] < 0 ? Math.floor(this.cardWidth + delta[0]) : Math.ceil(this.cardWidth + delta[0]));
+ return false;
+ },
+ action(() => {
+ this._cursor = 'ew-resize';
+ batch.end();
+ }),
+ emptyFunction
+ );
+ };
+
/**
* turns off the _dropped flag at the end of a drag/drop, or releases the focused Doc if a different Doc is clicked
*/
@@ -701,6 +736,7 @@ export class CollectionCardView extends CollectionSubView() {
<div
className="collectionCardView-cardwrapper"
style={{
+ gridTemplateColumns: `repeat(${this._maxRowCount}, 1fr)`,
gridAutoRows: `${100 / this.numRows}%`,
height: `${this.cardSpacing}%`,
}}>
@@ -717,6 +753,14 @@ export class CollectionCardView extends CollectionSubView() {
{this.flashCardUI(this.curDoc, this.docViewProps, this.answered)}
</div>
</div>
+
+ <div
+ className="collectionCardView-cardSizeDragger"
+ onPointerDown={this.cardSizerDown}
+ ref={this._draggerRef}
+ style={{ display: this._props.isContentActive() ? undefined : 'none', cursor: this._cursor, color: SettingsManager.userColor, left: `${this.cardWidth + this.xMargin}px` }}>
+ <FontAwesomeIcon icon="arrows-alt-h" />
+ </div>
</div>
);
}
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index 22ca9dcd7..4028ef479 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -1,6 +1,6 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button, IconButton, Type } from '@dash/components';
-import { action, makeObservable, observable } from 'mobx';
+import { action, makeObservable, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { CgClose, CgCornerUpLeft } from 'react-icons/cg';
@@ -37,10 +37,8 @@ export enum GPTQuizType {
MULTIPLE = 2,
}
-interface GPTPopupProps {}
-
@observer
-export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
+export class GPTPopup extends ObservableReactComponent<object> {
// eslint-disable-next-line no-use-before-define
static Instance: GPTPopup;
private messagesEndRef: React.RefObject<HTMLDivElement>;
@@ -188,16 +186,9 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
this.setLoading(true);
this.setSortDone(false);
- const quizType = this.quizMode;
-
const selected = DocumentView.SelectedDocs().lastElement();
const questionText = 'Question: ' + StrCast(selected['gptInputText']);
-
- if (StrCast(selected['gptRubric']) === '') {
- const rubricText = 'Rubric: ' + (await this.generateRubric(StrCast(selected['gptInputText']), selected));
- }
-
const rubricText = 'Rubric: ' + StrCast(selected['gptRubric']);
const queryText = questionText + ' UserAnswer: ' + this.quizAnswer + '. ' + 'Rubric' + rubricText;
@@ -214,7 +205,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
this.setLoading(false);
this.setSortDone(true);
} catch (err) {
- console.error('GPT call failed');
+ console.error('GPT call failed', err);
}
if (this.onQuizRandom) {
@@ -234,7 +225,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
doc['gptRubric'] = res;
return res;
} catch (err) {
- console.error('GPT call failed');
+ console.error('GPT call failed', err);
}
};
@@ -262,7 +253,6 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
* Generates a response to the user's question depending on the type of their question
*/
generateCard = async () => {
- console.log(this.chatSortPrompt + 'USER PROMPT');
this.setLoading(true);
this.setSortDone(false);
@@ -271,10 +261,8 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
}
try {
- // const res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
const questionType = await gptAPICall(this.chatSortPrompt, GPTCallType.TYPE);
const questionNumber = questionType.split(' ')[0];
- console.log(questionType);
let res = '';
switch (questionNumber) {
@@ -287,10 +275,12 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
res = await gptAPICall(this.sortDesc, GPTCallType.SORT, this.chatSortPrompt);
break;
default:
- const selected = DocumentView.SelectedDocs().lastElement();
- const questionText = StrCast(selected!['gptInputText']);
+ {
+ const selected = DocumentView.SelectedDocs().lastElement();
+ const questionText = StrCast(selected?.gptInputText);
- res = await gptAPICall(questionText, GPTCallType.INFO, this.chatSortPrompt);
+ res = await gptAPICall(questionText, GPTCallType.INFO, this.chatSortPrompt);
+ }
break;
}
@@ -308,7 +298,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
// Set the extracted explanation to sortRespText
this.setSortRespText(explanation);
- this.conversationArray.push(this.sortRespText);
+ runInAction(() => this.conversationArray.push(this.sortRespText));
this.scrollToBottom();
console.log(res);
@@ -448,7 +438,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
private getPreviewUrl = (source: string) => source.split('.').join('_m.');
- constructor(props: GPTPopupProps) {
+ constructor(props: object) {
super(props);
makeObservable(this);
GPTPopup.Instance = this;
@@ -515,18 +505,25 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
</div>
);
- handleKeyPress = async (e: React.KeyboardEvent, isSort: boolean) => {
+ @action
+ handleKeyPress = (e: React.KeyboardEvent, isSort: boolean) => {
if (e.key === 'Enter') {
e.stopPropagation();
if (isSort) {
this.conversationArray.push(this.chatSortPrompt);
- await this.generateCard();
- this.chatSortPrompt = '';
+ this.generateCard().then(
+ action(() => {
+ this.chatSortPrompt = '';
+ })
+ );
} else {
this.conversationArray.push(this.quizAnswer);
- await this.generateQuiz();
- this.quizAnswer = '';
+ this.generateQuiz().then(
+ action(() => {
+ this.quizAnswer = '';
+ })
+ );
}
this.scrollToBottom();