aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/apis/gpt/GPT.ts5
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx16
-rw-r--r--src/client/views/pdf/GPTPopup/GPTPopup.tsx62
3 files changed, 59 insertions, 24 deletions
diff --git a/src/client/apis/gpt/GPT.ts b/src/client/apis/gpt/GPT.ts
index 82436c42b..97a332294 100644
--- a/src/client/apis/gpt/GPT.ts
+++ b/src/client/apis/gpt/GPT.ts
@@ -33,7 +33,7 @@ const callTypeMap: { [type: string]: GPTCallOpts } = {
* @param inputText Text to process
* @returns AI Output
*/
-const gptAPICall = async (inputText: string, callType: GPTCallType) => {
+const gptAPICall = async (inputText: string, callType: GPTCallType, prompt?: any) => {
if (callType === GPTCallType.SUMMARY) inputText += '.';
const opts: GPTCallOpts = callTypeMap[callType];
try {
@@ -43,8 +43,9 @@ const gptAPICall = async (inputText: string, callType: GPTCallType) => {
};
const openai = new OpenAI(configuration);
+ let usePrompt = prompt? prompt: opts.prompt;
let messages: ChatCompletionMessageParam[] = [
- { role: 'system', content: opts.prompt },
+ { role: 'system', content: usePrompt },
{ role: 'user', content: inputText },
];
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 33b7dddfc..0a7fe59a5 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -29,7 +29,6 @@ import { PieChart } from './components/PieChart';
import { TableBox } from './components/TableBox';
import { Checkbox } from '@mui/material';
import { ContextMenu } from '../../ContextMenu';
-import { GPTCallType, gptAPICall } from '../../../apis/gpt/GPT';
export enum DataVizView {
TABLE = 'table',
@@ -415,20 +414,13 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() im
askGPT = action(async () => {
- GPTPopup.Instance.setVisible(true);
GPTPopup.Instance.setSidebarId('data_sidebar');
GPTPopup.Instance.addDoc = this.sidebarAddDocument;
GPTPopup.Instance.setMode(GPTPopupMode.DATA);
- GPTPopup.Instance.setLoading(true);
- try {
- let data = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href);
- let input = JSON.stringify(data);
- let res = await gptAPICall(input, GPTCallType.DATA);
- GPTPopup.Instance.setText(res || 'Something went wrong.');
- } catch (err) {
- console.error(err);
- }
- GPTPopup.Instance.setLoading(false);
+ let data = DataVizBox.dataset.get(CsvCast(this.dataDoc[this.fieldKey]).url.href);
+ let input = JSON.stringify(data);
+ GPTPopup.Instance.setDataJson(input);
+ GPTPopup.Instance.generateDataAnalysis();
});
render() {
diff --git a/src/client/views/pdf/GPTPopup/GPTPopup.tsx b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
index 8c575748f..6301721e8 100644
--- a/src/client/views/pdf/GPTPopup/GPTPopup.tsx
+++ b/src/client/views/pdf/GPTPopup/GPTPopup.tsx
@@ -1,5 +1,5 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Button, IconButton, Type } from 'browndash-components';
+import { Button, EditableText, IconButton, Size, Type } from 'browndash-components';
import { action, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
@@ -28,6 +28,7 @@ interface GPTPopupProps {}
@observer
export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
static Instance: GPTPopup;
+ @observable private chatMode: boolean = false;
@observable
public visible: boolean = false;
@@ -53,6 +54,13 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
public setSelectedText = (text: string) => {
this.selectedText = text;
};
+ @observable
+ public dataJson: string = '';
+ public dataChatPrompt: string | null = null;
+ @action
+ public setDataJson = (text: string) => {
+ this.dataJson = text;
+ };
@observable
public imgDesc: string = '';
@@ -86,6 +94,7 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
@action
public setDone = (done: boolean) => {
this.done = done;
+ this.chatMode = false;
};
// change what can be a ref into a ref
@@ -153,6 +162,18 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
GPTPopup.Instance.setLoading(false);
}
+ generateDataAnalysis = async () => {
+ GPTPopup.Instance.setVisible(true);
+ GPTPopup.Instance.setLoading(true);
+ try {
+ let res = await gptAPICall(this.dataJson, GPTCallType.DATA, this.dataChatPrompt);
+ GPTPopup.Instance.setText(res || 'Something went wrong.');
+ } catch (err) {
+ console.error(err);
+ }
+ GPTPopup.Instance.setLoading(false);
+ }
+
/**
* Transfers the summarization text to a sidebar annotation text document.
*/
@@ -197,6 +218,16 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
DocUtils.MakeLink(textAnchor, newDoc, { link_relationship: 'Image Prompt' });
};
+ /**
+ * Creates a chatbox for analyzing data so that users can ask specific questions.
+ */
+ private chatWithAI = () => {
+ this.chatMode = true;
+ }
+ dataPromptChanged = action((e: React.ChangeEvent<HTMLInputElement>) => {
+ this.dataChatPrompt = e.target.value;
+ });
+
private getPreviewUrl = (source: string) => source.split('.').join('_m.');
constructor(props: GPTPopupProps) {
@@ -310,22 +341,33 @@ export class GPTPopup extends ObservableReactComponent<GPTPopupProps> {
</div>
{!this.loading && (
<div className="btns-wrapper">
- {this.done ? (
+ {this.done?
+ this.chatMode?(
+ <input
+ defaultValue=""
+ autoComplete="off"
+ onChange={this.dataPromptChanged}
+ onKeyDown={e => {
+ e.key === 'Enter' ? this.generateDataAnalysis() : null;
+ e.stopPropagation();
+ }}
+ type="text"
+ placeholder="Ask GPT a question about the data..."
+ id="search-input"
+ className="searchBox-input"
+ style={{width: "100%"}}
+ />
+ )
+ :(
<>
<Button tooltip="Transfer to text" text="Transfer To Text" onClick={this.transferToText} color={StrCast(Doc.UserDoc().userVariantColor)} type={Type.TERT} />
+ <Button tooltip="Chat with AI" text="Chat with AI" onClick={this.chatWithAI} color={StrCast(Doc.UserDoc().userVariantColor)} type={Type.TERT} />
</>
) : (
<div className="summarizing">
<span>Summarizing</span>
<ReactLoading type="bubbles" color="#bcbcbc" width={20} height={20} />
- <Button
- text="Stop Animation"
- onClick={() => {
- this.setDone(true);
- }}
- color={StrCast(Doc.UserDoc().userVariantColor)}
- type={Type.TERT}
- />
+ <Button text="Stop Animation" onClick={() => {this.setDone(true);}} color={StrCast(Doc.UserDoc().userVariantColor)} type={Type.TERT}/>
</div>
)}
</div>