Skip to content

Adding healthData sample for TypeChat #166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
Jan 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
db567ad
Adding example healthData for typescript
pcdeadeasy Jan 5, 2024
ade6dfd
changes to readme
pcdeadeasy Jan 5, 2024
093f15f
ongoing work on the example
pcdeadeasy Jan 5, 2024
9e555a9
Merge branch 'main' into ts-healthData
pcdeadeasy Jan 5, 2024
2ab9044
revert back accidental change to translator.py
pcdeadeasy Jan 5, 2024
3e5fd60
fix broken link to input.txt in the readme.md
pcdeadeasy Jan 9, 2024
a71e2f4
Incorporate comments from code review
pcdeadeasy Jan 9, 2024
4c85e90
More code review related edits
pcdeadeasy Jan 9, 2024
3db813a
Marked chat messages private
pcdeadeasy Jan 9, 2024
a5c9f30
Update examples/healthData/src/main.ts
pcdeadeasy Jan 10, 2024
d41dede
Code improvements ...
pcdeadeasy Jan 9, 2024
f191454
Merge branch 'main' into ts-healthData
pcdeadeasy Jan 10, 2024
5a95b98
Update examples/healthData/src/healthDataSchema.ts
pcdeadeasy Jan 11, 2024
73156ae
Update examples/healthData/src/healthDataSchema.ts
pcdeadeasy Jan 11, 2024
fa2c40e
Update examples/healthData/src/healthDataSchema.ts
pcdeadeasy Jan 11, 2024
fef3898
Update examples/healthData/src/healthDataSchema.ts
pcdeadeasy Jan 11, 2024
196763f
Update examples/healthData/src/healthDataSchema.ts
pcdeadeasy Jan 11, 2024
0dc38a6
Update examples/healthData/src/main.ts
pcdeadeasy Jan 11, 2024
395d424
Update examples/healthData/src/main.ts
pcdeadeasy Jan 11, 2024
2314e94
Update examples/healthData/src/translator.ts
pcdeadeasy Jan 11, 2024
0492bb5
Update examples/healthData/src/translator.ts
pcdeadeasy Jan 11, 2024
a6f4774
Update examples/healthData/package.json
pcdeadeasy Jan 11, 2024
e10bd58
Update package.json
pcdeadeasy Jan 11, 2024
70d5956
cosmetic change to the schema
pcdeadeasy Jan 11, 2024
e4daded
Update examples/healthData/src/healthDataSchema.ts
pcdeadeasy Jan 11, 2024
a99efbc
Apply suggestions from code review
DanielRosenwasser Jan 13, 2024
0087b52
chat message's body is an object
pcdeadeasy Jan 13, 2024
6e5474a
fix package.json
pcdeadeasy Jan 13, 2024
b23d25f
update package.json
pcdeadeasy Jan 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions examples/healthData/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Health Data Agent

This example requires GPT-4.

Demonstrates a ***strongly typed*** chat: a natural language interface for entering health information. You work with a *health data agent* to interactively enter your medications or conditions.

The Health Data Agent shows how strongly typed **agents with history** could interact with a user to collect information needed for one or more data types ("form filling").

## Target models

For best and consistent results, use **gpt-4**.

## Try the Health Data Agent

To run the Sentiment example, follow the instructions in the [examples README](../README.md#step-1-configure-your-development-environment).

## Usage

Example prompts can be found in [`input.txt`](./src/input.txt).

For example, given the following input statement:

**Input**:

```console
🤧> I am taking klaritin for my allergies

```

**Output**:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should have something here for consistency with others.

22 changes: 22 additions & 0 deletions examples/healthData/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "health-data",
"version": "0.0.1",
"private": true,
"description": "",
"main": "dist/main.js",
"scripts": {
"build": "tsc -p src",
"postbuild": "copyfiles -u 1 src/**/*Schema.ts src/**/*.txt dist"
},
"author": "",
"license": "MIT",
"dependencies": {
"dotenv": "^16.3.1",
"typechat": "^0.0.10"
},
"devDependencies": {
"@types/node": "^20.3.1",
"copyfiles": "^2.4.1",
"typescript": "^5.1.3"
}
}
68 changes: 68 additions & 0 deletions examples/healthData/src/healthDataSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// The following is a schema definition for enetring health data.

export interface HealthDataResponse {
// ONLY present when ALL required information is known.
// Otherwise, use 'message' to keep asking questions.
data?: HealthData;
// Use this to ask questions and give pertinent responses
message?: string;
// Use this parts of the user request not translated, off topic, etc.
notTranslated?: string;
}

export interface HealthData {
medication?: Medication[];
condition?: Condition[];
other?: OtherHealthData[];
}

// Meds, pills etc.
export interface Medication {
// Fix any spelling mistakes, especially phonetic spelling
name: string;
// E.g. 2 tablets, 1 cup. Required
dose: ApproxQuantity;
// E.g. twice a day. Required
frequency: ApproxQuantity;
// E.g. 50 mg. Required
strength: ApproxQuantity;
}

// Disease, Ailment, Injury, Sickness
export interface Condition {
// Fix any spelling mistakes, especially phonetic spelling
name: string;
// When the condition started.
startDate: ApproxDatetime;
// Always ask for current status of the condition
status: "active" | "recurrence" | "relapse" | "inactive" | "remission" | "resolved" | "unknown";
// If the condition was no longer active
endDate?: ApproxDatetime;
}

// Use for health data that match nothing else. E.g. immunization, blood prssure etc
export interface OtherHealthData {
text: string;
when?: ApproxDatetime;
}

export interface ApproxQuantity {
// Default: "unknown"
displayText: string;
// Only specify if precise quantities are available
quantity?: Quantity;
}

export interface ApproxDatetime {
// Default: "unknown"
displayText: string;
// If precise timestamp can be set
timestamp?: string;
}

export interface Quantity {
// Exact number
value: number;
// Units like mg, kg, cm, pounds, liter, ml, tablet, pill, cup, per-day, per-week, etc.
units: string;
}
63 changes: 63 additions & 0 deletions examples/healthData/src/input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#
# Conversations with a Health Data Agent
# For each conversation:
# You start with the first line
# Then type the next line in response
#

# ================
# USE GPT4
# ================
# Conversation:
i want to record my shingles
August 2016
It lasted 3 months
I also broke my foot
I broke it in high school
2001
The foot took a year to be ok

# Conversation:
klaritin
2 tablets 3 times a day
300 mg
actually that is 1 tablet
@clear

# Conversation:
klaritin
1 pill, morning and before bedtime
Can't remember
Actually, that is 3 tablets
500 mg
@clear

#Conversation
I am taking binadryl now
As needed. Groceery store strength
That is all I have
I also got allergies. Pollen
@clear

# Conversation:
Robotussin
1 cup
Daily, as needed
Robotussin with Codeine
Put down strength as I don't know
@clear

# Conversation:
Hey
Melatonin
1 3mg tablet every night
@clear

# Conversation:
I got the flu
Started 2 weeks ago
Its gone now. Only lasted about a week
I took some sudafed though
I took 2 sudafed twice a day. Regular strength
@clear

51 changes: 51 additions & 0 deletions examples/healthData/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import fs from "fs";
import path from "path";
import dotenv from "dotenv";
import { createHealthDataTranslator } from "./translator";
import { createLanguageModel, processRequests } from "typechat";
import { HealthDataResponse } from "./healthDataSchema";

// TODO: use local .env file.
dotenv.config({ path: path.join(__dirname, "../../../.env") });

const healthInstructions = `
Help me enter my health data step by step.
Ask specific questions to gather required and optional fields
I have not already providedStop asking if I don't know the answer
Automatically fix my spelling mistakes
My health data may be complex: always record and return ALL of it.
Always return a response:
- If you don't understand what I say, ask a question.
- At least respond with an OK message.
`;

const model = createLanguageModel(process.env);
const schema = fs.readFileSync(path.join(__dirname, "healthDataSchema.ts"), "utf8");
const translator = createHealthDataTranslator<HealthDataResponse>(model, schema, "HealthDataResponse",
healthInstructions);

// Process requests interactively or from the input file specified on the command line
processRequests("🤧> ", process.argv[2], async (request) => {
const response = await translator.translate(request);
if (!response.success) {
console.log("Translation Failed ❌");
console.log(`Context: ${response.message}`);
}
else {
const healthData = response.data;
console.log("Translation Succeeded! ✅\n");
console.log("JSON View");
console.log(JSON.stringify(healthData, undefined, 2));

const message = healthData.message;
const notTranslated = healthData.notTranslated;

if (message) {
console.log(`\n📝: ${message}`);
}

if (notTranslated) {
console.log(`\n🤔: I did not understand\n ${notTranslated}`)
}
}
});
76 changes: 76 additions & 0 deletions examples/healthData/src/translator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import {Result, TypeChatLanguageModel, createJsonTranslator, TypeChatJsonTranslator} from "typechat";

type ChatMessage = {
source: "system" | "user" | "assistant";
body: object;
};

export interface TranslatorWithHistory<T extends object> {
_chatHistory: ChatMessage[];
_maxPromptLength: number;
_additionalAgentInstructions: string;
_translator: TypeChatJsonTranslator<T>;
translate(request: string): Promise<Result<T>>;
}

export function createHealthDataTranslator<T extends object>(model: TypeChatLanguageModel, schema: string, typename: string, additionalAgentInstructions: string): TranslatorWithHistory<T> {
const _chatHistory: ChatMessage[] = [];
const _maxPromptLength = 2048;
const _additionalAgentInstructions = additionalAgentInstructions;

const _translator = createJsonTranslator<T>(model, schema, typename);
_translator.createRequestPrompt = createRequestPrompt;

const customtranslator: TranslatorWithHistory<T> = {
_chatHistory,
_maxPromptLength,
_additionalAgentInstructions,
_translator,
translate,
};

return customtranslator;

async function translate(request: string): Promise<Result<T>> {
const response = await _translator.translate(request);
if (response.success) {
_chatHistory.push({ source: "assistant", body: response.data });
}
return response;

}

function createRequestPrompt(intent: string): string {
// TODO: drop history entries if we exceed the max_prompt_length
const historyStr = JSON.stringify(_chatHistory, undefined, 2);

const now = new Date();

const prompt = `
user: You are a service that translates user requests into JSON objects of type "${typename}" according to the following TypeScript definitions:
'''
${schema}
'''

user:
Use precise date and times RELATIVE TO CURRENT DATE: ${now.toLocaleDateString()} CURRENT TIME: ${now.toTimeString().split(' ')[0]}
Also turn ranges like next week and next month into precise dates

user:
${_additionalAgentInstructions}

system:
IMPORTANT CONTEXT for the user request:
${historyStr}

user:
The following is a user request:
'''
${intent}
'''
The following is the user request translated into a JSON object with 2 spaces of indentation and no properties with the value undefined:
"""
`;
return prompt;
}
}
16 changes: 16 additions & 0 deletions examples/healthData/src/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "es2021",
"lib": ["es2021"],
"module": "node16",
"types": ["node"],
"outDir": "../dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"exactOptionalPropertyTypes": true,
"inlineSourceMap": true
}
}
18 changes: 18 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.