From f281933795d44cefb828afda168a5305ec5852c7 Mon Sep 17 00:00:00 2001 From: "Mike P. Sinn" Date: Mon, 6 May 2024 16:12:56 -0500 Subject: [PATCH] getNextQuestion function, moved LLM date extractor to LLM library --- .../api/conversation2measurements/route.ts | 18 --------- apps/nextjs/lib/conversation2measurements.ts | 39 ++++++++++++++++++- apps/nextjs/lib/dateTimeWithTimezone.ts | 16 -------- apps/nextjs/lib/llm.ts | 26 ++++++++++++- apps/nextjs/lib/text2measurements.ts | 4 +- 5 files changed, 63 insertions(+), 40 deletions(-) diff --git a/apps/nextjs/app/api/conversation2measurements/route.ts b/apps/nextjs/app/api/conversation2measurements/route.ts index 093c865f0..954597bea 100644 --- a/apps/nextjs/app/api/conversation2measurements/route.ts +++ b/apps/nextjs/app/api/conversation2measurements/route.ts @@ -18,21 +18,3 @@ try { return handleError(error, "conversation2measurements") } } - -export async function GET(req: NextRequest) { - const urlParams = Object.fromEntries(new URL(req.url).searchParams); - const statement = urlParams.statement as string; - const previousStatements = urlParams.previousStatements as string | null | undefined; - let timeZoneOffset; - if(urlParams.timeZoneOffset){timeZoneOffset = parseInt(urlParams.timeZoneOffset);} - const utcDateTime = urlParams.utcDateTime as string | null | undefined; - - try { - const measurements = await conversation2measurements(statement, utcDateTime, timeZoneOffset, previousStatements); - const userId = await getUserId(); - if(userId){await postMeasurements(measurements, userId)} - return NextResponse.json({ success: true, measurements: measurements }); - } catch (error) { - return handleError(error, "conversation2measurements") - } -} diff --git a/apps/nextjs/lib/conversation2measurements.ts b/apps/nextjs/lib/conversation2measurements.ts index 7fe0ed196..51f642012 100644 --- a/apps/nextjs/lib/conversation2measurements.ts +++ b/apps/nextjs/lib/conversation2measurements.ts @@ -1,6 +1,7 @@ -import { Measurement } from "@/types/models/Measurement"; +import {Measurement} from "@/types/models/Measurement"; import {textCompletion} from "@/lib/llm"; import {convertToLocalDateTime, getUtcDateTime} from "@/lib/dateTimeWithTimezone"; +import {text2measurements} from "@/lib/text2measurements"; // IMPORTANT! Set the runtime to edge export const runtime = 'edge'; @@ -76,3 +77,39 @@ export async function conversation2measurements(statement: string, }); return measurements; } + +export async function getNextQuestion(currentStatement: string, previousStatements: string | null | undefined): Promise { + let promptText = ` + You are a robot designed to collect diet, treatment, and symptom data from the user. + +Immediately begin asking the user the following questions +- What did you eat today? +- What did you drink today? +- What treatments did you take today? +- Rate all your symptoms on a scale of 1 to 5. + +Also, after asking each question and getting a response, check if there's anything else the user want to add to the first question response. For instance, after getting a response to "What did you eat today?", your next question should be, "Did you eat anything else today?". If they respond in the negative, move on to the next question. + +Here is the current user statement: + ${currentStatement} + + Here are the previous statements in the conversation: ${previousStatements} + `; + + return await textCompletion(promptText, "text"); +} + +export async function haveConversation(statement: string, + utcDateTime: string, + timeZoneOffset: number, + previousStatements: string | null | undefined): Promise<{ + questionForUser: string; + measurements: Measurement[] +}> { + let questionForUser = await getNextQuestion(statement, previousStatements); + const measurements = await text2measurements(statement, utcDateTime, timeZoneOffset); + return { + questionForUser, + measurements + } +} diff --git a/apps/nextjs/lib/dateTimeWithTimezone.ts b/apps/nextjs/lib/dateTimeWithTimezone.ts index 142141b5f..89a1aa79b 100644 --- a/apps/nextjs/lib/dateTimeWithTimezone.ts +++ b/apps/nextjs/lib/dateTimeWithTimezone.ts @@ -1,5 +1,3 @@ -import {textCompletion} from "@/lib/llm"; - export function getUtcDateTimeWithTimezone() { const date = new Date(); const timezoneOffset = date.getTimezoneOffset(); @@ -35,17 +33,3 @@ export function convertToLocalDateTime(utcDateTime: string | number | Date, time return localDate.toISOString(); } -export async function getDateTimeFromStatement(statement: string): Promise { - const currentDate = getUtcDateTime(); - const promptText = ` - estimate the date and time of the user statement based on the current date and time ${currentDate} - and the following user statement: -\`\`\` -${statement} -\`\`\` - Return a single string in the format "YYYY-MM-DDThh:mm:ss"`; - let result = await textCompletion(promptText, "text"); - // Remove quote marks - result = result.replace(/['"]+/g, ''); - return result; -} diff --git a/apps/nextjs/lib/llm.ts b/apps/nextjs/lib/llm.ts index c9c4a11ec..0ba5e3d04 100644 --- a/apps/nextjs/lib/llm.ts +++ b/apps/nextjs/lib/llm.ts @@ -1,4 +1,5 @@ import OpenAI from 'openai'; +import {getUtcDateTime} from "@/lib/dateTimeWithTimezone"; // Create an OpenAI API client (that's edge-friendly!) const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY || '', @@ -12,8 +13,15 @@ export async function textCompletion(promptText: string, returnType: "text" | "j stream: false, //max_tokens: 150, messages: [ - {"role": "system", "content": `You are a helpful assistant that translates user requests into JSON objects`}, - {role: "user", "content": promptText}, + { + role: "system", + content: `You are a helpful assistant that translates user requests into JSON objects` + }, + { + role: "user", // user = the dFDA app + content: promptText + }, + ], response_format: { type: returnType }, }); @@ -25,3 +33,17 @@ export async function textCompletion(promptText: string, returnType: "text" | "j return response.choices[0].message.content; } +export async function getDateTimeFromStatement(statement: string): Promise { + const currentDate = getUtcDateTime(); + const promptText = ` + estimate the date and time of the user statement based on the current date and time ${currentDate} + and the following user statement: +\`\`\` +${statement} +\`\`\` + Return a single string in the format "YYYY-MM-DDThh:mm:ss"`; + let result = await textCompletion(promptText, "text"); + // Remove quote marks + result = result.replace(/['"]+/g, ''); + return result; +} diff --git a/apps/nextjs/lib/text2measurements.ts b/apps/nextjs/lib/text2measurements.ts index d80313f27..6f1549a69 100644 --- a/apps/nextjs/lib/text2measurements.ts +++ b/apps/nextjs/lib/text2measurements.ts @@ -1,11 +1,9 @@ import {Measurement} from "@/types/models/Measurement"; -import {textCompletion} from "@/lib/llm"; +import {getDateTimeFromStatement, textCompletion} from "@/lib/llm"; import {getUserId} from "@/lib/getUserId"; import {postMeasurements} from "@/lib/dfda"; import { convertToLocalDateTime, - convertToUTC, getDateTimeFromStatement, - getUtcDateTime, throwErrorIfDateInFuture } from "@/lib/dateTimeWithTimezone";