Skip to content

Commit

Permalink
Added zero shot parser
Browse files Browse the repository at this point in the history
  • Loading branch information
valkjsaaa committed Nov 13, 2023
1 parent e0fcfa3 commit 160488f
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 3 deletions.
2 changes: 1 addition & 1 deletion lib/nl/__test__/nl-parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ test('Parser complex', async () => {
'order the same burger that I ordered at mcDonald last time'
);
return expect(parsed).toBe(
'Order.current().addFoods(foods: Order.all().matching(field: .restaurant, value: Restaurant.all().matching(field: .name, value: "mcDonald")[0]).sort(field: .dateTime, ascending: false)[0].foods.matching(field: .name, value: "burger"))'
'Order.current().addFoods(foods: [Order.all().matching(field: .restaurant, value: Restaurant.all().matching(field: .name, value: "mcDonald")[0]).sort(field: .dateTime, ascending: false)[0].foods.matching(field: .name, value: "burger")[0]])'
);
});

Expand Down
23 changes: 22 additions & 1 deletion lib/nl/nl-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class NlParser {
this.openAiApi = new OpenAIApi(configuration);
}

async parse(nl: string): Promise<string | null> {
async oldParse(nl: string): Promise<string | null> {
const prompt = this.prompt.prompt(nl);
const response = await this.openAiApi.createCompletion({
model: "code-davinci-002",
Expand All @@ -31,6 +31,27 @@ export class NlParser {
return await response.data.choices[0]?.text.trim();
}

async parse(nl: string): Promise<string | null> {
const prompt = this.prompt.zero_shot_prompt(nl);
const response = await this.openAiApi.createChatCompletion({
model: "gpt-4",
temperature: 0,
top_p: 1,
n: 1,
stream: false,
max_tokens: 256,
presence_penalty: 0,
frequency_penalty: 0,
messages: [
{
role: "user",
content: prompt,
},
],
});
return response.data.choices[0]?.message.content.replaceAll("`", "").trim();
}

async parseGpt4(nl: string): Promise<string | null> {
const prompt = this.prompt.prompt(nl);
const response = await this.openAiApi.createChatCompletion({
Expand Down
13 changes: 12 additions & 1 deletion lib/nl/prompt-gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ import {
pre_section_separator,
user_interaction_prequel,
user_interaction_prompt,
parse_issues,
parse_issues, parseCodePrompt
} from "./prompt-res";
import { ClassDescriptor, GenieObject } from "../dsl-descriptor";

export interface PromptGen {
prompt(user_utterance: string): string;
zero_shot_prompt(user_utterance: string): string;

response_prompt(
user_utterance: string,
Expand Down Expand Up @@ -51,12 +52,22 @@ export class BasicPromptGen {
return prompt;
}

zero_shot_prompt_basic(): string {
return parseCodePrompt(this.prompt_basic())
}

prompt(user_utterance: string): string {
let prompt = this.prompt_basic();
prompt += `${user_interaction_prompt(user_utterance)}`;
return prompt;
}

zero_shot_prompt(user_utterance: string): string {
let prompt = this.zero_shot_prompt_basic();
prompt += `${user_interaction_prompt(user_utterance)}`;
return prompt;
}

response_prompt(
user_utterance: string,
parsed: string,
Expand Down
98 changes: 98 additions & 0 deletions lib/nl/prompt-res.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,101 @@ export const parse_issues = `
// 1. Use "Array[index]" instead of index related functions. For example, "hotels[0]" instead of "hotels.first()"
// 2. Use "setProperty(value) instead of "property = value". For example, "hotel.setName(123)" instead of "hotel.name = 123"
// 3. Use ";" between multiple function calls. For example, "hotel.setName(123); hotel.setDesc(123)"`

const exampleDeveloperClasses = `
// Here are all the function that we have
extension Array<Type> {
// find items with matching field in an array
Array<Type> matching(field: Field, value: Type);
// find items with field in an array that contains a specific value
Array<Type> contains(field: Field, value: Type);
// find items with exact field in an array
Array<Type> equals(field: Field, value: Type);
// find items with field between two values in an array
Array<Type> between(field: Field, from: Type, to: Type);
// sort an array based on a specific field in ascending or descending order
Array<Type> sort(field: Field, ascending: bool);
}
class Counter {
string name;
string type;
int count;
static float Version;
static Counter GetCounter(name: string);
void increment();
void decrement();
static Counter[] All();
static Counter Current();
}
// Here are all the examples that we have
user: increment
parsed: Counter.Current().increment()
user: what is the count
parsed: Counter.Current().count
user: what is the count of potato
parsed: Counter.GetCounter(name: "potato").count
user: increment potato counter
parsed: Counter.GetCounter(name: "potato").increment()
user: show me all vegetables counters
parsed: Counter.All().matching(field: .type, value: "vegetable")
`

export function parseCodePrompt(appBasicPrompt: string): string {
return `
Below are the developer class definitions, methods, and their descriptions as the comments of an example app.
After that, code parses from another app using ReactGenieDSL will be given.
A code parse is a voice command the user gives to be parsed into code that completes the requested action.
BEGIN
\`
${exampleDeveloperClasses}
\`
END
Note that all function calls have to have explicit parameter names in ReactGenieDSL.
For example:
\`
parsed: Counter.All().matching(.type, "vegetable")
\`
Is INCORRECT.
This is correct:
\`
parsed: Counter.All().matching(field: .type, value: "vegetable")
\`
And here is the developer classes and (optionally) code parses for this app in ReactGenieDSL:\n
BEGIN
\`
${appBasicPrompt}
\`
END
For code translation using \`ReactGenieDSL\`, follow these guidelines:
1. **Formatting**: directly output code; do not put in any code blocks. Output in a single line and separate multiple statements/queries with \`;\` if needed.
2. **Be creative**: Don't use existing functions for unsupported features/out of range parameters. Introduce undeclared function, class, or method for user requests not in existing functions is encouraged. Make sure the function/property/class name is descriptive.
3. **Don't answer user's queries**: Please translate user's queries (how long will it take) into code to retrieve info, rather than answering the query directly. E.g., "What is the count?" should be \`Counter.All().count()\`, not \`Counter.CreateCounter(count: 1)\`.
4. **Current is only for what the user is pointing or seeing**: "Order me this computer" would be \`ShoppingItem.Current()\`, but "Order my favorite item" should be \`ShoppingItem.Favourite()\`.
5. **Indexing**: An array can be indexed using bracket notation. E.g., \`Counter.All()[0]\` for the first element, \`Counter.All()[-1]\` for the last element. ReactGenieDSL does not support first/last as a function.
6. **No math operations**: ReactGenieDSL does not support math operations. Use \`1.plus(1)\` instead of \`1 + 1\`.
7. **Array operations**: No map or lambda expressions, functions are automatically distributed to elements. Instead of \`Counter.map(c => c.name)\`, use \`Counter.All().name\`.
8. **No class constructor**: ReactGenieDSL do not have default constructors. Some class have custom constructors starting with \`Create\`, if not, this class cannot be created by the user like an option can only be selected.
9. **Setter instead of assignment**: \`ReactGenieDSL\` prohibits assignments for selections or changes. All code should be function calls (setter). E.g., use Good: \`Counter.setCount(number: 1)\`/\`Payment.select(payment: "MasterCard")\`
New user interaction:
`;
}

0 comments on commit 160488f

Please sign in to comment.