mirror of
https://github.com/wasp-lang/open-saas.git
synced 2025-03-26 17:52:28 +01:00
update OpenAI demo app
This commit is contained in:
parent
99fd761e92
commit
29996a2006
@ -82,7 +82,7 @@ app SaaSTemplate {
|
||||
("headlessui", "^0.0.0"),
|
||||
("@faker-js/faker", "8.3.1"),
|
||||
("@google-analytics/data", "4.1.0"),
|
||||
("openai", "^4.24.1"),
|
||||
("openai", "^4.28.0"),
|
||||
("prettier", "3.1.1"),
|
||||
("prettier-plugin-tailwindcss", "0.5.11"),
|
||||
("zod", "3.22.4"),
|
||||
|
@ -8,6 +8,8 @@ import getAllTasksByUser from '@wasp/queries/getAllTasksByUser';
|
||||
import { Task } from '@wasp/entities';
|
||||
import { CgSpinner } from 'react-icons/cg';
|
||||
import { TiDelete } from 'react-icons/ti';
|
||||
import { type GeneratedSchedule } from '../../shared/types';
|
||||
import { MainTask, Subtask } from '@wasp/shared/types';
|
||||
|
||||
export default function DemoAppPage() {
|
||||
return (
|
||||
@ -15,11 +17,12 @@ export default function DemoAppPage() {
|
||||
<div className='mx-auto max-w-7xl px-6 lg:px-8'>
|
||||
<div className='mx-auto max-w-4xl text-center'>
|
||||
<h2 className='mt-2 text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl dark:text-white'>
|
||||
<span className='text-yellow-500'>AI</span> Day Scheduler
|
||||
<span className='text-yellow-500'>AI</span> Day Scheduler
|
||||
</h2>
|
||||
</div>
|
||||
<p className='mx-auto mt-6 max-w-2xl text-center text-lg leading-8 text-gray-600 dark:text-white'>
|
||||
This example app uses OpenAI's chat completions with function calling to return a structured JSON object. Try it out, enter your day's tasks, and let AI do the rest!
|
||||
This example app uses OpenAI's chat completions with function calling to return a structured JSON object. Try
|
||||
it out, enter your day's tasks, and let AI do the rest!
|
||||
</p>
|
||||
{/* begin AI-powered Todo List */}
|
||||
<div className='my-8 border rounded-3xl border-gray-900/10 dark:border-gray-100/10'>
|
||||
@ -36,9 +39,7 @@ export default function DemoAppPage() {
|
||||
type TodoProps = Pick<Task, 'id' | 'isDone' | 'description' | 'time'>;
|
||||
|
||||
function Todo({ id, isDone, description, time }: TodoProps) {
|
||||
const handleCheckboxChange = async (
|
||||
e: React.ChangeEvent<HTMLInputElement>
|
||||
) => {
|
||||
const handleCheckboxChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
await updateTask({
|
||||
id,
|
||||
isDone: e.currentTarget.checked,
|
||||
@ -66,13 +67,7 @@ function Todo({ id, isDone, description, time }: TodoProps) {
|
||||
checked={isDone}
|
||||
onChange={handleCheckboxChange}
|
||||
/>
|
||||
<span
|
||||
className={`text-slate-600 ${
|
||||
isDone ? 'line-through text-slate-500' : ''
|
||||
}`}
|
||||
>
|
||||
{description}
|
||||
</span>
|
||||
<span className={`text-slate-600 ${isDone ? 'line-through text-slate-500' : ''}`}>{description}</span>
|
||||
</div>
|
||||
<div className='flex items-center gap-2'>
|
||||
<input
|
||||
@ -86,13 +81,7 @@ function Todo({ id, isDone, description, time }: TodoProps) {
|
||||
value={time}
|
||||
onChange={handleTimeChange}
|
||||
/>
|
||||
<span
|
||||
className={`italic text-slate-600 text-xs ${
|
||||
isDone ? 'text-slate-500' : ''
|
||||
}`}
|
||||
>
|
||||
hrs
|
||||
</span>
|
||||
<span className={`italic text-slate-600 text-xs ${isDone ? 'text-slate-500' : ''}`}>hrs</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className='flex items-center justify-end w-15'>
|
||||
@ -104,22 +93,75 @@ function Todo({ id, isDone, description, time }: TodoProps) {
|
||||
);
|
||||
}
|
||||
|
||||
function NewTaskForm({
|
||||
handleCreateTask,
|
||||
}: {
|
||||
handleCreateTask: typeof createTask;
|
||||
}) {
|
||||
function NewTaskForm({ handleCreateTask }: { handleCreateTask: typeof createTask }) {
|
||||
const [description, setDescription] = useState<string>('');
|
||||
const [todaysHours, setTodaysHours] = useState<string>('8');
|
||||
const [response, setResponse] = useState<any>(null);
|
||||
const [response, setResponse] = useState<GeneratedSchedule | null>({
|
||||
mainTasks: [
|
||||
{
|
||||
name: 'Respond to emails',
|
||||
priority: 'high',
|
||||
},
|
||||
{
|
||||
name: 'Learn WASP',
|
||||
priority: 'low',
|
||||
},
|
||||
{
|
||||
name: 'Read a book',
|
||||
priority: 'medium',
|
||||
},
|
||||
],
|
||||
subtasks: [
|
||||
{
|
||||
description: 'Read introduction and chapter 1',
|
||||
time: 0.5,
|
||||
mainTaskName: 'Read a book',
|
||||
},
|
||||
{
|
||||
description: 'Read chapter 2 and take notes',
|
||||
time: 0.3,
|
||||
mainTaskName: 'Read a book',
|
||||
},
|
||||
{
|
||||
description: 'Read chapter 3 and summarize key points',
|
||||
time: 0.2,
|
||||
mainTaskName: 'Read a book',
|
||||
},
|
||||
{
|
||||
description: 'Check and respond to important emails',
|
||||
time: 1,
|
||||
mainTaskName: 'Respond to emails',
|
||||
},
|
||||
{
|
||||
description: 'Organize and prioritize remaining emails',
|
||||
time: 0.5,
|
||||
mainTaskName: 'Respond to emails',
|
||||
},
|
||||
{
|
||||
description: 'Draft responses to urgent emails',
|
||||
time: 0.5,
|
||||
mainTaskName: 'Respond to emails',
|
||||
},
|
||||
{
|
||||
description: 'Watch tutorial video on WASP',
|
||||
time: 0.5,
|
||||
mainTaskName: 'Learn WASP',
|
||||
},
|
||||
{
|
||||
description: 'Complete online quiz on the basics of WASP',
|
||||
time: 1.5,
|
||||
mainTaskName: 'Learn WASP',
|
||||
},
|
||||
{
|
||||
description: 'Review quiz answers and clarify doubts',
|
||||
time: 1,
|
||||
mainTaskName: 'Learn WASP',
|
||||
},
|
||||
],
|
||||
});
|
||||
const [isPlanGenerating, setIsPlanGenerating] = useState<boolean>(false);
|
||||
|
||||
const { data: tasks, isLoading: isTasksLoading } =
|
||||
useQuery(getAllTasksByUser);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('response', response);
|
||||
}, [response]);
|
||||
const { data: tasks, isLoading: isTasksLoading } = useQuery(getAllTasksByUser);
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
@ -137,8 +179,7 @@ function NewTaskForm({
|
||||
hours: todaysHours,
|
||||
});
|
||||
if (response) {
|
||||
console.log('response', response);
|
||||
setResponse(JSON.parse(response));
|
||||
setResponse(response);
|
||||
}
|
||||
} catch (err: any) {
|
||||
window.alert('Error: ' + (err.message || 'Something went wrong'));
|
||||
@ -179,20 +220,11 @@ function NewTaskForm({
|
||||
{tasks!! && tasks.length > 0 ? (
|
||||
<div className='space-y-4'>
|
||||
{tasks.map((task: Task) => (
|
||||
<Todo
|
||||
key={task.id}
|
||||
id={task.id}
|
||||
isDone={task.isDone}
|
||||
description={task.description}
|
||||
time={task.time}
|
||||
/>
|
||||
<Todo key={task.id} id={task.id} isDone={task.isDone} description={task.description} time={task.time} />
|
||||
))}
|
||||
<div className='flex flex-col gap-3'>
|
||||
<div className='flex items-center justify-between gap-3'>
|
||||
<label
|
||||
htmlFor='time'
|
||||
className='text-sm text-gray-600 dark:text-gray-300 text-nowrap font-semibold'
|
||||
>
|
||||
<label htmlFor='time' className='text-sm text-gray-600 dark:text-gray-300 text-nowrap font-semibold'>
|
||||
How many hours will you work today?
|
||||
</label>
|
||||
<input
|
||||
@ -231,77 +263,90 @@ function NewTaskForm({
|
||||
|
||||
{!!response && (
|
||||
<div className='flex flex-col'>
|
||||
<h3 className='text-lg font-semibold text-gray-900 dark:text-white'>
|
||||
Today's Schedule
|
||||
</h3>
|
||||
<h3 className='text-lg font-semibold text-gray-900 dark:text-white'>Today's Schedule</h3>
|
||||
|
||||
<TaskTable schedule={response.schedule} />
|
||||
<TaskTable schedule={response} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TaskTable({ schedule }: { schedule: any[] }) {
|
||||
function TaskTable({ schedule }: { schedule: GeneratedSchedule }) {
|
||||
return (
|
||||
<div className='flex flex-col gap-6 py-6'>
|
||||
{schedule.map((task: any) => (
|
||||
<table
|
||||
key={task.name}
|
||||
className='table-auto w-full border-separate border border-spacing-2 rounded-md border-slate-200 shadow-sm'
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
className={`flex items-center justify-between gap-5 py-4 px-3 text-slate-800 border rounded-md border-slate-200 ${
|
||||
task.priority === 'high'
|
||||
? 'bg-red-50'
|
||||
: task.priority === 'low'
|
||||
? 'bg-green-50'
|
||||
: 'bg-yellow-50'
|
||||
}`}
|
||||
>
|
||||
<span>{task.name}</span>
|
||||
<span className='opacity-70 text-xs font-medium italic'>
|
||||
{' '}
|
||||
{task.priority} priority
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className=''>
|
||||
{task.subtasks.map((subtask: { description: any; time: any }) => (
|
||||
<tr>
|
||||
<td
|
||||
className={`flex items-center justify-between py-2 px-3 text-slate-600 border rounded-md border-purple-100 bg-purple-50`}
|
||||
>
|
||||
<Subtask
|
||||
description={subtask.description}
|
||||
time={subtask.time}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
<table className='table-auto w-full border-separate border border-spacing-2 rounded-md border-slate-200 shadow-sm'>
|
||||
{!!schedule.mainTasks ? (
|
||||
schedule.mainTasks
|
||||
.map((mainTask) => <MainTask key={mainTask.name} mainTask={mainTask} subtasks={schedule.subtasks} />)
|
||||
.sort((a, b) => {
|
||||
const priorityOrder = ['low', 'medium', 'high'];
|
||||
if (a.props.mainTask.priority && b.props.mainTask.priority) {
|
||||
return (
|
||||
priorityOrder.indexOf(b.props.mainTask.priority) - priorityOrder.indexOf(a.props.mainTask.priority)
|
||||
);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
})
|
||||
) : (
|
||||
<div className='text-slate-600 text-center'>OpenAI didn't return any Main Tasks. Try again.</div>
|
||||
)}
|
||||
</table>
|
||||
|
||||
{task.breaks.map((breakItem: { description: any; time: any }) => (
|
||||
<tr key={breakItem.description}>
|
||||
<td
|
||||
className={`flex items-center justify-between py-2 px-3 text-slate-600 border rounded-md border-purple-100 bg-purple-50`}
|
||||
>
|
||||
<Subtask
|
||||
description={breakItem.description}
|
||||
time={breakItem.time}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
))}
|
||||
{/* ))} */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function MainTask({ mainTask, subtasks }: { mainTask: MainTask; subtasks: Subtask[] }) {
|
||||
return (
|
||||
<>
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
className={`flex items-center justify-between gap-5 py-4 px-3 text-slate-800 border rounded-md border-slate-200 bg-opacity-70 ${
|
||||
mainTask.priority === 'high'
|
||||
? 'bg-red-100'
|
||||
: mainTask.priority === 'low'
|
||||
? 'bg-green-100'
|
||||
: 'bg-yellow-100'
|
||||
}`}
|
||||
>
|
||||
<span>{mainTask.name}</span>
|
||||
<span className='opacity-70 text-xs font-medium italic'> {mainTask.priority} priority</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{!!subtasks ? (
|
||||
subtasks.map((subtask) => {
|
||||
if (subtask.mainTaskName === mainTask.name) {
|
||||
return (
|
||||
<tbody key={subtask.description}>
|
||||
<tr>
|
||||
<td
|
||||
className={`flex items-center justify-between gap-4 py-2 px-3 text-slate-600 border rounded-md border-purple-100 bg-opacity-60 ${
|
||||
mainTask.priority === 'high'
|
||||
? 'bg-red-50'
|
||||
: mainTask.priority === 'low'
|
||||
? 'bg-green-50'
|
||||
: 'bg-yellow-50'
|
||||
}`}
|
||||
>
|
||||
<Subtask description={subtask.description} time={subtask.time} />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
);
|
||||
}
|
||||
})
|
||||
) : (
|
||||
<div className='text-slate-600 text-center'>OpenAI didn't return any Subtasks. Try again.</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Subtask({ description, time }: { description: string; time: number }) {
|
||||
const [isDone, setIsDone] = useState<boolean>(false);
|
||||
|
||||
@ -309,9 +354,7 @@ function Subtask({ description, time }: { description: string; time: number }) {
|
||||
if (time === 0) return 0;
|
||||
const hours = Math.floor(time);
|
||||
const minutes = Math.round((time - hours) * 60);
|
||||
return `${hours > 0 ? hours + 'hr' : ''} ${
|
||||
minutes > 0 ? minutes + 'min' : ''
|
||||
}`;
|
||||
return `${hours > 0 ? hours + 'hr' : ''} ${minutes > 0 ? minutes + 'min' : ''}`;
|
||||
};
|
||||
|
||||
const minutes = useMemo(() => convertHrsToMinutes(time), [time]);
|
||||
@ -325,17 +368,13 @@ function Subtask({ description, time }: { description: string; time: number }) {
|
||||
onChange={(e) => setIsDone(e.currentTarget.checked)}
|
||||
/>
|
||||
<span
|
||||
className={`text-slate-600 ${
|
||||
className={`leading-tight justify-self-start w-full text-slate-600 ${
|
||||
isDone ? 'line-through text-slate-500 opacity-50' : ''
|
||||
}`}
|
||||
>
|
||||
{description}
|
||||
</span>
|
||||
<span
|
||||
className={`text-slate-600 ${
|
||||
isDone ? 'line-through text-slate-500 opacity-50' : ''
|
||||
}`}
|
||||
>
|
||||
<span className={`text-slate-600 text-right ${isDone ? 'line-through text-slate-500 opacity-50' : ''}`}>
|
||||
{minutes}
|
||||
</span>
|
||||
</>
|
||||
|
@ -1,8 +1,7 @@
|
||||
import Stripe from 'stripe';
|
||||
import fetch from 'node-fetch';
|
||||
import HttpError from '@wasp/core/HttpError.js';
|
||||
import type { User, Task, File } from '@wasp/entities';
|
||||
import type { StripePaymentResult } from './types';
|
||||
import type { StripePaymentResult, GeneratedSchedule } from '../shared/types';
|
||||
import {
|
||||
GenerateGptResponse,
|
||||
StripePayment,
|
||||
@ -16,6 +15,9 @@ import {
|
||||
import { fetchStripeCustomer, createStripeCheckoutSession } from './payments/stripeUtils.js';
|
||||
import { TierIds } from '@wasp/shared/constants.js';
|
||||
import { getUploadFileSignedURLFromS3 } from './file-upload/s3Utils.js';
|
||||
import OpenAI from 'openai';
|
||||
|
||||
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY! });
|
||||
|
||||
export const stripePayment: StripePayment<string, StripePaymentResult> = async (tier, context) => {
|
||||
if (!context.user || !context.user.email) {
|
||||
@ -63,7 +65,7 @@ type GptPayload = {
|
||||
hours: string;
|
||||
};
|
||||
|
||||
export const generateGptResponse: GenerateGptResponse<GptPayload, string> = async ({ hours }, context) => {
|
||||
export const generateGptResponse: GenerateGptResponse<GptPayload, GeneratedSchedule> = async ({ hours }, context) => {
|
||||
if (!context.user) {
|
||||
throw new HttpError(401);
|
||||
}
|
||||
@ -76,98 +78,11 @@ export const generateGptResponse: GenerateGptResponse<GptPayload, string> = asyn
|
||||
},
|
||||
});
|
||||
|
||||
// use map to extract the description and time from each task
|
||||
const parsedTasks = tasks.map(({ description, time }) => ({
|
||||
description,
|
||||
time,
|
||||
}));
|
||||
|
||||
const payload = {
|
||||
model: 'gpt-3.5-turbo', // e.g. 'gpt-3.5-turbo', 'gpt-4', 'gpt-4-0613', gpt-4-1106-preview
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content:
|
||||
'you are an expert daily planner and scheduling assistant. you will be given a list of main tasks and an estimated time to complete each task. You will also receive the total amount of hours to be worked that day. Your job is to return a detailed plan of how to achieve those tasks throughout the day by breaking down the main tasks provided by the user into multiple subtasks. Be specific in your reply and offer advice on the best way to fulfill each task. Please also schedule in standing, water, lunch, and coffee breaks. Plan the higher priority tasks first. Also give the total amount of time to be spent on each (sub)task after considering all of the above. ',
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: `I will work ${hours} today. Here are the tasks I have to complete: ` + JSON.stringify(parsedTasks),
|
||||
},
|
||||
],
|
||||
functions: [
|
||||
{
|
||||
name: 'parseTodaysSchedule',
|
||||
description: 'parses the days tasks and returns a schedule',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
schedule: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
description: 'Name of main task provided by user',
|
||||
},
|
||||
subtasks: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
description: {
|
||||
type: 'string',
|
||||
description:
|
||||
'detailed breakdown and description of sub-task related to main task. e.g., "Prepare your learning session by first reading through the documentation"',
|
||||
},
|
||||
time: {
|
||||
type: 'number',
|
||||
description: 'time allocated for a given subtask in hours, e.g. 0.5',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
breaks: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
description: {
|
||||
type: 'string',
|
||||
description:
|
||||
'detailed breakdown and description of break. e.g., "take a 15 minute standing break and reflect on what you have learned".',
|
||||
},
|
||||
time: {
|
||||
type: 'number',
|
||||
description: 'time allocated for a given break in hours, e.g. 0.2',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
time: {
|
||||
type: 'number',
|
||||
description: 'total time in it takes to complete given main task in hours, e.g. 2.75',
|
||||
},
|
||||
priority: {
|
||||
type: 'string',
|
||||
enum: ['low', 'medium', 'high'],
|
||||
description: 'task priority',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['schedule'],
|
||||
},
|
||||
},
|
||||
],
|
||||
function_call: {
|
||||
name: 'parseTodaysSchedule',
|
||||
},
|
||||
temperature: 1,
|
||||
};
|
||||
|
||||
try {
|
||||
if (!context.user.hasPaid && !context.user.credits) {
|
||||
throw new HttpError(402, 'User has not paid or is out of credits');
|
||||
@ -183,22 +98,91 @@ export const generateGptResponse: GenerateGptResponse<GptPayload, string> = asyn
|
||||
});
|
||||
}
|
||||
|
||||
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${process.env.OPENAI_API_KEY!}`,
|
||||
const completion = await openai.chat.completions.create({
|
||||
model: 'gpt-3.5-turbo',
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content:
|
||||
'you are an expert daily planner. you will be given a list of main tasks and an estimated time to complete each task. You will also receive the total amount of hours to be worked that day. Your job is to return a detailed plan of how to achieve those tasks by breaking each task down into at least 3 subtasks each. MAKE SURE TO ALWAYS CREATE AT LEAST 3 SUBTASKS FOR EACH MAIN TASK PROVIDED BY THE USER! YOU WILL BE REWARDED IF YOU DO.',
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: `I will work ${hours} hours today. Here are the tasks I have to complete: ${JSON.stringify(
|
||||
parsedTasks
|
||||
)}. Please help me plan my day by breaking the tasks down into actionable subtasks with time and priority status.`,
|
||||
},
|
||||
],
|
||||
tools: [
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'parseTodaysSchedule',
|
||||
description: 'parses the days tasks and returns a schedule',
|
||||
parameters: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
mainTasks: {
|
||||
type: 'array',
|
||||
description: 'Name of main tasks provided by user, ordered by priority',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
description: 'Name of main task provided by user',
|
||||
},
|
||||
priority: {
|
||||
type: 'string',
|
||||
enum: ['low', 'medium', 'high'],
|
||||
description: 'task priority',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
subtasks: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
description: {
|
||||
type: 'string',
|
||||
description:
|
||||
'detailed breakdown and description of sub-task related to main task. e.g., "Prepare your learning session by first reading through the documentation"',
|
||||
},
|
||||
time: {
|
||||
type: 'number',
|
||||
description: 'time allocated for a given subtask in hours, e.g. 0.5',
|
||||
},
|
||||
mainTaskName: {
|
||||
type: 'string',
|
||||
description: 'name of main task related to subtask',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ['mainTasks', 'subtasks', 'time', 'priority'],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
tool_choice: {
|
||||
type: 'function',
|
||||
function: {
|
||||
name: 'parseTodaysSchedule',
|
||||
},
|
||||
},
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload),
|
||||
temperature: 1,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const gptArgs = completion?.choices[0]?.message?.tool_calls?.[0]?.function.arguments;
|
||||
|
||||
if (!gptArgs) {
|
||||
throw new HttpError(500, 'Bad response from OpenAI');
|
||||
}
|
||||
|
||||
let json = (await response.json()) as any;
|
||||
|
||||
const gptArgs = json.choices[0].message.function_call.arguments;
|
||||
console.log('gpt function call arguments: ', gptArgs);
|
||||
|
||||
await context.entities.GptResponse.create({
|
||||
data: {
|
||||
@ -207,7 +191,7 @@ export const generateGptResponse: GenerateGptResponse<GptPayload, string> = asyn
|
||||
},
|
||||
});
|
||||
|
||||
return gptArgs;
|
||||
return JSON.parse(gptArgs);
|
||||
} catch (error: any) {
|
||||
if (!context.user.hasPaid && error?.statusCode != 402) {
|
||||
await context.entities.User.update({
|
||||
|
@ -1,35 +0,0 @@
|
||||
import { User } from '@wasp/entities'
|
||||
import { Prisma } from '@prisma/client'
|
||||
|
||||
export type Context = {
|
||||
user: User;
|
||||
entities: {
|
||||
User: Prisma.UserDelegate<{}>;
|
||||
};
|
||||
};
|
||||
|
||||
export type StripePaymentResult = {
|
||||
sessionUrl: string | null;
|
||||
sessionId: string;
|
||||
};
|
||||
|
||||
export type OpenAIResponse = {
|
||||
id: string;
|
||||
object: string;
|
||||
created: number;
|
||||
usage: {
|
||||
prompt_tokens: number;
|
||||
completion_tokens: number;
|
||||
total_tokens: number;
|
||||
};
|
||||
choices: [
|
||||
{
|
||||
index: number;
|
||||
message: {
|
||||
role: string;
|
||||
content: string;
|
||||
};
|
||||
finish_reason: string;
|
||||
}
|
||||
];
|
||||
};
|
34
app/src/shared/types.ts
Normal file
34
app/src/shared/types.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { User } from '@wasp/entities';
|
||||
import { Prisma } from '@prisma/client';
|
||||
|
||||
export type Context = {
|
||||
user: User;
|
||||
entities: {
|
||||
User: Prisma.UserDelegate<{}>;
|
||||
};
|
||||
};
|
||||
|
||||
export type StripePaymentResult = {
|
||||
sessionUrl: string | null;
|
||||
sessionId: string;
|
||||
};
|
||||
|
||||
export type Subtask = {
|
||||
description: string; // detailed breakdown and description of sub-task
|
||||
time: number; // total time it takes to complete given main task in hours, e.g. 2.75
|
||||
mainTaskName: string; // name of main task related to subtask
|
||||
};
|
||||
|
||||
export type MainTask = {
|
||||
name: string;
|
||||
priority: 'low' | 'medium' | 'high';
|
||||
};
|
||||
|
||||
export type GeneratedSchedule = {
|
||||
mainTasks: MainTask[]; // Main tasks provided by user, ordered by priority
|
||||
subtasks: Subtask[]; // Array of subtasks
|
||||
};
|
||||
|
||||
export type FunctionCallResponse = {
|
||||
schedule: GeneratedSchedule[];
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user