-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #195 from mikepsinn/develop
llm library and started conversation2measurements library
- Loading branch information
Showing
7 changed files
with
107 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { Measurement } from "@/types/models/Measurement"; | ||
import {textCompletion} from "@/lib/llm"; | ||
|
||
// IMPORTANT! Set the runtime to edge | ||
export const runtime = 'edge'; | ||
|
||
export function conversation2MeasurementsPrompt(statement: string, | ||
localDateTime: string | null | undefined, | ||
previousStatements: string | null | undefined): string { | ||
|
||
|
||
if(!localDateTime) { | ||
const now = new Date(); | ||
localDateTime = now.toISOString().slice(0, 19); | ||
} | ||
return ` | ||
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. | ||
Convert the responses to the following JSON format | ||
[ | ||
\t{ | ||
\t\t"combinationOperation" : "SUM", | ||
\t\t"startAt" : "{ISO_DATETIME_IN_UTC}", | ||
\t\t"unitName" : "grams", | ||
\t\t"value" : "5", | ||
\t\t"variableCategoryName" : "Treatments", | ||
\t\t"variableName" : "NMN", | ||
\t\t"note" : "{MAYBE_THE_ORIGINAL_STATEMENT_FOR_REFERENCE}" | ||
\t} | ||
] | ||
That would be the result if they said, "I took 5 grams of NMN." | ||
For ratings, use the unit \`/5\`. The \`unitName\` should never be an empty string. | ||
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. | ||
Your responses should be in JSON format and have 2 properties called data and message. The message property should contain the message to the user. The data property should contain an array of measurement objects created from the last user response. | ||
${previousStatements ? `The following are the previous statements: | ||
${previousStatements}` : ''} | ||
// Use the current local datetime ${localDateTime} to determine startDateLocal. If specified, also determine startTimeLocal, endDateLocal, and endTimeLocal or just leave them null.\`\`\` | ||
The following is a user request: | ||
""" | ||
${statement} | ||
""" | ||
The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined: | ||
`; | ||
} | ||
|
||
export async function conversation2measurements(statement: string, | ||
localDateTime: string | null | undefined, | ||
previousStatements: string | null | undefined): Promise<Measurement[]> { | ||
let promptText = conversation2MeasurementsPrompt(statement, localDateTime, previousStatements); | ||
const maxTokenLength = 1500; | ||
if(promptText.length > maxTokenLength) { | ||
// truncate to less than 1500 characters | ||
promptText = promptText.slice(0, maxTokenLength); | ||
|
||
} | ||
const str = await textCompletion(promptText, "json_object"); | ||
const measurements: Measurement[] = []; | ||
let jsonArray = JSON.parse(str); | ||
jsonArray.measurements.forEach((measurement: Measurement) => { | ||
measurements.push(measurement); | ||
}); | ||
return measurements; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import OpenAI from 'openai'; | ||
// Create an OpenAI API client (that's edge-friendly!) | ||
const openai = new OpenAI({ | ||
apiKey: process.env.OPENAI_API_KEY || '', | ||
}); | ||
|
||
export async function textCompletion(promptText: string, returnType: "text" | "json_object"): Promise<string> { | ||
|
||
// Ask OpenAI for a streaming chat completion given the prompt | ||
const response = await openai.chat.completions.create({ | ||
model: 'gpt-4-turbo', | ||
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}, | ||
], | ||
response_format: { type: returnType }, | ||
}); | ||
|
||
if(!response.choices[0].message.content) { | ||
throw new Error('No content in response'); | ||
} | ||
|
||
return response.choices[0].message.content; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.