Add # special fill variables to prompt templating.

This commit is contained in:
Ian Arawjo 2023-08-01 11:34:51 -04:00
parent ece74e696e
commit 4730009a1c
12 changed files with 71 additions and 17 deletions

View File

@ -1,15 +1,15 @@
{
"files": {
"main.css": "/static/css/main.a4e8271c.css",
"main.js": "/static/js/main.b59fa9d7.js",
"main.js": "/static/js/main.05c73878.js",
"static/js/787.4c72bb55.chunk.js": "/static/js/787.4c72bb55.chunk.js",
"index.html": "/index.html",
"main.a4e8271c.css.map": "/static/css/main.a4e8271c.css.map",
"main.b59fa9d7.js.map": "/static/js/main.b59fa9d7.js.map",
"main.05c73878.js.map": "/static/js/main.05c73878.js.map",
"787.4c72bb55.chunk.js.map": "/static/js/787.4c72bb55.chunk.js.map"
},
"entrypoints": [
"static/css/main.a4e8271c.css",
"static/js/main.b59fa9d7.js"
"static/js/main.05c73878.js"
]
}

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><script async src="https://www.googletagmanager.com/gtag/js?id=G-RN3FDBLMCR"></script><script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","G-RN3FDBLMCR")</script><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="A visual programming environment for prompt engineering"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>ChainForge</title><script defer="defer" src="/static/js/main.b59fa9d7.js"></script><link href="/static/css/main.a4e8271c.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><script async src="https://www.googletagmanager.com/gtag/js?id=G-RN3FDBLMCR"></script><script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag("js",new Date),gtag("config","G-RN3FDBLMCR")</script><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="A visual programming environment for prompt engineering"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>ChainForge</title><script defer="defer" src="/static/js/main.05c73878.js"></script><link href="/static/css/main.a4e8271c.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

View File

@ -239,7 +239,7 @@ const EvaluatorNode = ({ data, id }) => {
const showResponseInspector = useCallback(() => {
if (inspectModal && inspectModal.current && lastResponses)
inspectModal.current.trigger();
inspectModal.current.trigger();
}, [inspectModal, lastResponses]);
const default_header = (progLang === 'python') ?

View File

@ -55,7 +55,7 @@ const LLMEvaluatorNode = ({ data, id }) => {
const handleError = (err) => {
setStatus('error');
setProgress(undefined);
alertModal.current.trigger(err);
alertModal.current.trigger(err?.error || err);
};
// Fetch info about the number of queries we'll need to make

View File

@ -29,7 +29,7 @@ const defaultColumns = [
},
{
key: 'answer',
header: 'Expected Answer',
header: 'Expected',
},
];

View File

@ -28,6 +28,10 @@ export const extractBracketedSubstrings = (text) => {
}
prev_c = c;
}
// Ignore any varnames that begin with the special character #:
capture_groups = capture_groups.filter(s => (s.length === 0 || s[0] !== '#'))
return capture_groups;
};

View File

@ -916,7 +916,9 @@ export async function evalWithLLM(id: string,
// We need to keep track of the index of each response in the response object.
// We can generate var dicts with metadata to store the indices:
let inputs = resp_objs.map((obj, i) => obj.responses.map((r: string, j: number) => ({text: r, fill_history: {}, metavars: { i, j }}))).flat();
let inputs = resp_objs.map((obj, __i) => obj.responses.map(
(r: string, __j: number) => ({text: r, fill_history: obj.vars, metavars: { ...obj.metavars, __i, __j }})
)).flat();
// Now run all inputs through the LLM grader!:
const {responses, errors} = await queryLLM(`eval-${id}-${cache_id}`, [llm], 1, root_prompt, { input: inputs }, undefined, undefined, undefined, progress_listener);
@ -928,15 +930,15 @@ export async function evalWithLLM(id: string,
// Now we need to apply each response as an eval_res (a score) back to each response object,
// using the aforementioned mapping metadata:
responses.forEach((r: StandardizedLLMResponse) => {
let resp_obj = resp_objs[r.metavars.i];
let resp_obj = resp_objs[r.metavars.__i];
if (resp_obj.eval_res !== undefined)
resp_obj.eval_res.items[r.metavars.j] = r.responses[0];
resp_obj.eval_res.items[r.metavars.__j] = r.responses[0];
else {
resp_obj.eval_res = {
items: [],
dtype: 'Categorical',
};
resp_obj.eval_res.items[r.metavars.j] = r.responses[0];
resp_obj.eval_res.items[r.metavars.__j] = r.responses[0];
}
});

View File

@ -115,6 +115,33 @@ export class StringTemplate {
return false;
}
/**
* Finds all unfilled variables in the template string.
*
* For instance, if the string is "The {place} had {food}",
* then ["place", "food"] will be returned.
*/
get_vars(): Array<string> {
let template = this.val;
let varnames: Array<string> = [];
let prev_c = '';
let group_start_idx = -1;
for (let i = 0; i < template.length; i += 1) {
const c = template.charAt(i);
if (prev_c !== '\\') { // Skip escaped braces
if (group_start_idx === -1 && c === '{') // Identify the start of a capture {group}
group_start_idx = i;
else if (group_start_idx > -1 && c === '}') { // Identify the end of a capture {group}
if (group_start_idx + 1 < i) // Ignore {} empty braces
varnames.push(template.substring(group_start_idx+1, i));
group_start_idx = -1;
}
}
prev_c = c;
}
return varnames;
}
toString(): string {
return this.val;
}
@ -352,8 +379,29 @@ export class PromptPermutationGenerator {
return true; // done
}
for (let p of this._gen_perm(template, Object.keys(paramDict), paramDict))
for (let p of this._gen_perm(template, Object.keys(paramDict), paramDict)) {
// Special variables {#...} denotes filling a variable from a matching var in fill_history or metavars.
// Find any special variables:
const unfilled_vars = (new StringTemplate(p.template)).get_vars();
let special_vars_to_fill: {[key: string]: string} = {};
for (const v of unfilled_vars) {
if (v.length > 0 && v[0] === '#') { // special template variables must begin with #
const svar = v.substring(1);
if (svar in p.fill_history)
special_vars_to_fill[v] = p.fill_history[svar];
else if (svar in p.metavars)
special_vars_to_fill[v] = p.metavars[svar];
else
console.warn(`Could not find a value to fill special var ${v} in prompt template.`);
}
}
// Fill any special variables, using the fill history of the template in question:
if (Object.keys(special_vars_to_fill).length > 0)
p.template = new StringTemplate(p.template).safe_substitute(special_vars_to_fill);
// Yield the final prompt template
yield p;
}
return true; // done
}
}

View File

@ -6,7 +6,7 @@ def readme():
setup(
name='chainforge',
version='0.2.5',
version='0.2.5.1',
packages=find_packages(),
author="Ian Arawjo",
description="A Visual Programming Environment for Prompt Engineering",