Skip to content

Commit

Permalink
Finish chart and code generation
Browse files Browse the repository at this point in the history
  • Loading branch information
Zhiming Zhang committed Jun 16, 2024
2 parents 7505fdd + 59e7770 commit 9647501
Show file tree
Hide file tree
Showing 11 changed files with 375 additions and 123 deletions.
57 changes: 0 additions & 57 deletions src/SidePanel.tsx

This file was deleted.

9 changes: 0 additions & 9 deletions src/__tests__/jupyterlab_apod.spec.ts

This file was deleted.

64 changes: 64 additions & 0 deletions src/components/ChartChoices.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { useState } from 'react';
import { Spin, Pagination, Button } from 'antd';
import { ChartInformation } from '../openai';

const contentStyle: React.CSSProperties = {
padding: 50,
background: 'rgba(0, 0, 0, 0.05)',
borderRadius: 4
};
const content = <div style={contentStyle} />;
const Loading: React.FC = () => (
<Spin tip="Loading" size="large">
{content}
</Spin>
);

export default function ChartChoices({
showCharts,
responseList,
handleCodeGeneration
}: {
showCharts: boolean;
responseList: ChartInformation[];
handleCodeGeneration: (index: number) => void;
}) {
const [listIndex, setListIndex] = useState(0);
const Page: React.FC = () => (
<Pagination
defaultCurrent={listIndex + 1}
total={responseList.length * 10}
onChange={(page, pageSize) => {
setListIndex(page - 1);
}}
/>
);
return (
<div className="container">
{showCharts ? (
<div className="chart-container">
<img
className="chart-image"
src={responseList[listIndex].src}
alt={`Image ${listIndex}`}
/>
<h2>{responseList[listIndex].title}</h2>
<p>{responseList[listIndex].description}</p>
<div className="code-btn">
<Button
type="primary"
onClick={() => {
handleCodeGeneration(responseList.length - listIndex - 1);
}}
>
Show Code
</Button>
</div>
<Page></Page>
</div>
) : (
<Loading></Loading>
)}
</div>
);
}
61 changes: 61 additions & 0 deletions src/components/SidePanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Button } from 'antd';
import FileUpload from './FileUpload';
import { TemperatureSelect } from './TemperatureSelect';
import React, { useState } from 'react';
import { UserPromptInupt } from './UserPromptInput';
import ChartChoices from './ChartChoices';
import { generateChart, ChartInformation } from '../openai';
import { eventCenter } from '../event';

export default function SidePanel() {
let initialList: ChartInformation[] = [];
const [uploadedFile, setUploadedFile] = useState<File | null>(null);
const [generateClicked, setGenerateClicked] = useState(false);
const [showCharts, setShowCharts] = useState(false);
const [responseList, setResponseList] = useState(initialList);

async function handleGenerateClick() {
if (uploadedFile) {
setGenerateClicked(true);
let list = await generateChart(uploadedFile);
setResponseList(list as ChartInformation[]);
setShowCharts(true);
} else {
alert('No file uploaded.');
}
}

async function handleCodeGeneration(index: number) {
setGenerateClicked(false);
eventCenter.emit('addNewCell', index);
}

return (
<div className="container">
{generateClicked ? (
<ChartChoices
showCharts={showCharts}
responseList={responseList}
handleCodeGeneration={handleCodeGeneration}
/>
) : (
<>
<div className="upload">
<FileUpload setFile={setUploadedFile} />
</div>
<div className="user-prompt">
<UserPromptInupt></UserPromptInupt>
</div>
<div className="temperature">
<TemperatureSelect></TemperatureSelect>
</div>
<div className="button-container">
<Button type="primary" onClick={handleGenerateClick}>
Generate
</Button>
</div>
</>
)}
</div>
);
}
10 changes: 5 additions & 5 deletions src/components/TemperatureSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ import { Slider } from 'antd';
import type { SliderSingleProps } from 'antd';

const marks: SliderSingleProps['marks'] = {
0: '0°C',
0: '0',
100: {
style: {
color: '#f50',
color: '#f50'
},
label: <strong>100°C</strong>,
},
label: <strong>2</strong>
}
};

export const TemperatureSelect: React.FC = () => (
<>
<h4>Model Temperature: </h4>
<Slider marks={marks} defaultValue={37} />
</>
);
);
File renamed without changes.
7 changes: 3 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import file_analysis_extension from './file_analysis_extension';
import stderror_renderer from './stderror_render';
import { side_panel } from './SidePanel';
export default [file_analysis_extension, side_panel, stderror_renderer];
import fixError from './fixError';
import { smartVis } from './smartVis';
export default [smartVis, fixError];
131 changes: 131 additions & 0 deletions src/openai.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import OpenAI from 'openai';
import {
TextContentBlock,
ImageFileContentBlock
} from 'openai/resources/beta/threads/messages';
import {
extractTitleContent,
extractDescriptionContent,
extractPythonCode
} from './util';

export interface ChartInformation {
src: string;
title: string;
description: string;
}

let fileName = '';

const openai = new OpenAI({
apiKey: '',
dangerouslyAllowBrowser: true
});

const assistant = await openai.beta.assistants.retrieve(
'asst_SBAKRxzUiVlQxJbHR6RHtkxN'
);

const thread = await openai.beta.threads.create();

export async function generateChart(csvFile: File) {
fileName = csvFile.name;
const file = await openai.files.create({
file: csvFile,
purpose: 'assistants'
});

const prompt = `
Step-1: Generate three different charts for data visualization based on the attached csv file.
Step-2: After each chart is generated, output a short text description for it. The description should stick to the following format:
<Title>Title of the chart</Title>
<Description>This line charts shows......</Description>
`;

await openai.beta.threads.messages.create(thread.id, {
role: 'user',
content: prompt,
attachments: [
{
file_id: file.id,
tools: [{ type: 'code_interpreter' }]
}
]
});

const run = await openai.beta.threads.runs.createAndPoll(thread.id, {
assistant_id: assistant.id
});

if (run.status === 'completed') {
const messages = await openai.beta.threads.messages.list(run.thread_id);
const responseArray: ChartInformation[] = [];
for (let message of messages.data) {
if (message.role === 'assistant' && message.content.length === 2) {
// Get image src from the response
const imageContent = <ImageFileContentBlock>message.content[0];
const src = await getSrcFromFileId(imageContent.image_file.file_id);

// Get title and description from the response
const textContent = <TextContentBlock>message.content[1];
const text = textContent.text.value;
const title = extractTitleContent(text);
const description = extractDescriptionContent(text);

// Put the information together
const response: ChartInformation = {
src: src,
title: title,
description: description
};
responseArray.push(response);
}
}
return responseArray;
} else {
return run.status;
}

/**
* Inputs OpenAI File object's id
* Returns src needed in img label
*/
async function getSrcFromFileId(id: string) {
const imageFile = await openai.files.content(id);
const imageData = await imageFile.arrayBuffer();
let binary = '';
let bytes = new Uint8Array(imageData);
for (let i = 0; i < bytes.byteLength; i++) {
binary += String.fromCharCode(bytes[i]);
}
return 'data:image/png;base64,' + window.btoa(binary);
}
}

export async function generateCode(index: number) {
const prompt = `
Please output the Python for generating the ${index + 1}-th$ chart.
The Python code should contain necessary import like import pandas as pd.
Also it should contain
`;

await openai.beta.threads.messages.create(thread.id, {
role: 'user',
content: prompt
});

const run = await openai.beta.threads.runs.createAndPoll(thread.id, {
assistant_id: assistant.id
});

if (run.status === 'completed') {
const messages = await openai.beta.threads.messages.list(run.thread_id);
const message = messages.data[0];
const textContent = <TextContentBlock>message.content[0];
let code = textContent.text.value;
code = extractPythonCode(code, fileName);
return code;
} else {
return run.status;
}
}
Loading

0 comments on commit 9647501

Please sign in to comment.