mirror of
https://github.com/ianarawjo/ChainForge.git
synced 2025-03-14 08:16:37 +00:00
Choose plot column in table view of response inspector (#106)
* Make vars in inspect table view multiline * Choose var to use for columns in table view of resp inspector * Only default to prompt var as column if num vars > 1 * Rebuild react and update package version
This commit is contained in:
parent
ee1dc09954
commit
a27d092ccc
@ -1,15 +1,15 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "/static/css/main.b5856613.css",
|
||||
"main.js": "/static/js/main.d97188e6.js",
|
||||
"main.css": "/static/css/main.fe68699e.css",
|
||||
"main.js": "/static/js/main.ec9948b8.js",
|
||||
"static/js/787.4c72bb55.chunk.js": "/static/js/787.4c72bb55.chunk.js",
|
||||
"index.html": "/index.html",
|
||||
"main.b5856613.css.map": "/static/css/main.b5856613.css.map",
|
||||
"main.d97188e6.js.map": "/static/js/main.d97188e6.js.map",
|
||||
"main.fe68699e.css.map": "/static/css/main.fe68699e.css.map",
|
||||
"main.ec9948b8.js.map": "/static/js/main.ec9948b8.js.map",
|
||||
"787.4c72bb55.chunk.js.map": "/static/js/787.4c72bb55.chunk.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.b5856613.css",
|
||||
"static/js/main.d97188e6.js"
|
||||
"static/css/main.fe68699e.css",
|
||||
"static/js/main.ec9948b8.js"
|
||||
]
|
||||
}
|
@ -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.d97188e6.js"></script><link href="/static/css/main.b5856613.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.ec9948b8.js"></script><link href="/static/css/main.fe68699e.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -5,7 +5,7 @@
|
||||
* be deployed in multiple locations.
|
||||
*/
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { Collapse, Radio, MultiSelect, Group, Table } from '@mantine/core';
|
||||
import { Collapse, Radio, MultiSelect, Group, Table, NativeSelect } from '@mantine/core';
|
||||
import { useDisclosure } from '@mantine/hooks';
|
||||
import { IconTable, IconSitemap } from '@tabler/icons-react';
|
||||
import * as XLSX from 'xlsx';
|
||||
@ -128,12 +128,16 @@ const LLMResponseInspector = ({ jsonResponses, wideFormat }) => {
|
||||
const [receivedResponsesOnce, setReceivedResponsesOnce] = useState(false);
|
||||
|
||||
// The type of view to use to display responses. Can be either hierarchy or table.
|
||||
const [viewFormat, setViewFormat] = useState("hierarchy");
|
||||
const [viewFormat, setViewFormat] = useState(wideFormat ? "table" : "hierarchy");
|
||||
|
||||
// The MultiSelect so people can dynamically set what vars they care about
|
||||
const [multiSelectVars, setMultiSelectVars] = useState([]);
|
||||
const [multiSelectValue, setMultiSelectValue] = useState([]);
|
||||
|
||||
// The var name to use for columns in the table view
|
||||
const [tableColVar, setTableColVar] = useState("LLM");
|
||||
const [userSelectedTableCol, setUserSelectedTableCol] = useState(false);
|
||||
|
||||
// Global lookup for what color to use per LLM
|
||||
const getColorForLLMAndSetIfNotFound = useStore((state) => state.getColorForLLMAndSetIfNotFound);
|
||||
|
||||
@ -161,6 +165,14 @@ const LLMResponseInspector = ({ jsonResponses, wideFormat }) => {
|
||||
{value: `${name}`, label: name}
|
||||
)).concat({value: 'LLM', label: 'LLM'});
|
||||
setMultiSelectVars(msvars);
|
||||
|
||||
// If only one LLM is present, and user hasn't manually selected one to plot,
|
||||
// and there's more than one prompt variable as input, default to plotting the
|
||||
// first found prompt variable as columns instead:
|
||||
if (!userSelectedTableCol && tableColVar === 'LLM' && found_llms.length === 1 && found_vars.length > 1) {
|
||||
setTableColVar(found_vars[0]);
|
||||
return; // useEffect will replot with the new values
|
||||
}
|
||||
|
||||
// If this is the first time receiving responses, set the multiSelectValue to whatever is the first:
|
||||
if (!receivedResponsesOnce) {
|
||||
@ -244,39 +256,60 @@ const LLMResponseInspector = ({ jsonResponses, wideFormat }) => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// Generate a view of the responses based on the view format set by the user
|
||||
if (viewFormat === "table") {
|
||||
|
||||
// Generate a table, with default columns for: input vars, LLMs queried
|
||||
// First get column names as input vars + LLMs:
|
||||
const colnames = found_vars.concat(found_llms);
|
||||
let var_cols, colnames, getColVal, found_sel_var_vals;
|
||||
if (tableColVar === 'LLM') {
|
||||
var_cols = found_vars;
|
||||
getColVal = (r => r.llm);
|
||||
found_sel_var_vals = found_llms;
|
||||
colnames = var_cols.concat(found_llms);
|
||||
} else {
|
||||
var_cols = found_vars.filter(v => v !== tableColVar)
|
||||
.concat(found_llms.length > 1 ? ['LLM'] : []); // only add LLM column if num LLMs > 1
|
||||
getColVal = (r => r.vars[tableColVar]);
|
||||
|
||||
// Get the unique values for the selected variable
|
||||
found_sel_var_vals = Array.from(responses.reduce((acc, res_obj) => {
|
||||
acc.add(tableColVar in res_obj.vars ? res_obj.vars[tableColVar] : '(unspecified)');
|
||||
return acc;
|
||||
}, new Set()));
|
||||
colnames = var_cols.concat(found_sel_var_vals);
|
||||
}
|
||||
|
||||
const getVar = (r, v) => v === 'LLM' ? r.llm : r.vars[v];
|
||||
|
||||
// Then group responses by prompts. Each prompt will become a separate row of the table (will be treated as unique)
|
||||
const responses_by_prompt = groupResponsesBy(responses, (r => r.prompt))[0];
|
||||
let responses_by_prompt = groupResponsesBy(responses, (r => var_cols.map(v => getVar(r, v)).join('|')))[0];
|
||||
|
||||
const rows = Object.entries(responses_by_prompt).map(([prompt, resp_objs], idx) => {
|
||||
// We assume here that prompt input vars will be the same across all responses in this bundle,
|
||||
// so we just take the value of the first one per each varname:
|
||||
const vars_cols = found_vars.map(v => v in resp_objs[0].vars ? resp_objs[0].vars[v] : '(unspecified)');
|
||||
const resp_objs_by_llm = groupResponsesBy(resp_objs, r => r.llm)[0];
|
||||
const llm_cols = found_llms.map(llm => {
|
||||
if (llm in resp_objs_by_llm) {
|
||||
const rs = resp_objs_by_llm[llm];
|
||||
const var_cols_vals = var_cols.map(v => {
|
||||
const val = (v === 'LLM') ? resp_objs[0].llm : resp_objs[0].vars[v];
|
||||
return (val !== undefined) ? val : '(unspecified)';
|
||||
});
|
||||
const resp_objs_by_col_var = groupResponsesBy(resp_objs, getColVal)[0];
|
||||
const sel_var_cols = found_sel_var_vals.map(val => {
|
||||
if (val in resp_objs_by_col_var) {
|
||||
const rs = resp_objs_by_col_var[val];
|
||||
if (rs.length > 1)
|
||||
console.warn(`Found more than one response object for LLM ${llm} for the same prompt. Only displaying first...`);
|
||||
console.warn(`Found more than one response object for LLM ${val} for the same prompt. Only displaying first...`);
|
||||
// Return response divs as response box here:
|
||||
return generateResponseBoxes(rs, found_vars, 100)[0];
|
||||
return generateResponseBoxes(rs, var_cols, 100)[0];
|
||||
} else {
|
||||
console.warn(`Could not find response object for LLM: ${llm}`);
|
||||
return (<span>(not queried)</span>);
|
||||
console.warn(`Could not find response object for column variable ${tableColVar} with value ${val}`);
|
||||
return (<i>(no data)</i>);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<tr key={idx} style={{borderBottom: '8px solid #eee'}}>
|
||||
{vars_cols.map(c => (<td style={{backgroundColor: 'rgb(224, 244, 250)', paddingTop: '10px', borderRight: '1px solid #cde', fontWeight: '500'}}>{c}</td>))}
|
||||
{llm_cols.map((c, i) => (<td style={{paddingTop: '8px', paddingBottom: '20px', borderRight: '1px solid #eee'}}>{c}</td>))}
|
||||
{var_cols_vals.map(c => (<td className='inspect-table-var'>{c}</td>))}
|
||||
{sel_var_cols.map((c, i) => (<td className='inspect-table-llm-resp'>{c}</td>))}
|
||||
</tr>
|
||||
);
|
||||
});
|
||||
@ -366,7 +399,7 @@ const LLMResponseInspector = ({ jsonResponses, wideFormat }) => {
|
||||
setResponses(divs);
|
||||
}
|
||||
|
||||
}, [multiSelectValue, jsonResponses, wideFormat, viewFormat]);
|
||||
}, [multiSelectValue, jsonResponses, wideFormat, viewFormat, tableColVar]);
|
||||
|
||||
// When the user clicks an item in the drop-down,
|
||||
// we want to autoclose the multiselect drop-down:
|
||||
@ -383,17 +416,29 @@ const LLMResponseInspector = ({ jsonResponses, wideFormat }) => {
|
||||
{wideFormat ?
|
||||
<Radio.Group
|
||||
name="viewFormat"
|
||||
defaultValue="hierarchy"
|
||||
value={viewFormat}
|
||||
onChange={setViewFormat}
|
||||
>
|
||||
<Group mt="0px" mb='xs'>
|
||||
<Radio value="hierarchy" label={<span><IconSitemap size='10pt' style={{marginBottom: '-1px'}}/> Hierarchy</span>} />
|
||||
<Radio value="table" label={<span><IconTable size='10pt' style={{marginBottom: '-1px'}}/> Table</span>} />
|
||||
<Radio value="hierarchy" label={<span><IconSitemap size='10pt' style={{marginBottom: '-1px'}}/> Hierarchy</span>} />
|
||||
</Group>
|
||||
</Radio.Group>
|
||||
: <></>}
|
||||
|
||||
{viewFormat === "table" ?
|
||||
<NativeSelect
|
||||
value={tableColVar}
|
||||
onChange={(event) => {
|
||||
setTableColVar(event.currentTarget.value);
|
||||
setUserSelectedTableCol(true);
|
||||
}}
|
||||
data={multiSelectVars}
|
||||
label="Select the main variable to use for columns:"
|
||||
mb="sm"
|
||||
/>
|
||||
: <></>}
|
||||
|
||||
{wideFormat === false || viewFormat === "hierarchy" ?
|
||||
<div>
|
||||
<MultiSelect ref={multiSelectRef}
|
||||
|
@ -19,13 +19,13 @@ const LLMResponseInspectorModal = forwardRef((props, ref) => {
|
||||
}));
|
||||
|
||||
return (
|
||||
<Modal size='80%' keepMounted opened={opened} onClose={close} closeOnClickOutside={true} style={{position: 'relative', 'left': '-100px'}} title={
|
||||
<Modal size='90%' keepMounted opened={opened} onClose={close} closeOnClickOutside={true} style={{position: 'relative', 'left': '-100px'}} title={
|
||||
<div><span>Response Inspector</span><button className="custom-button" style={{marginTop: 'auto', marginRight: '14px', float: 'right'}} onClick={() => exportToExcel(props.jsonResponses)}>Export data to Excel</button></div>
|
||||
} styles={{ title: {justifyContent: 'space-between', width: '100%'} }} >
|
||||
{ props.prompt !== undefined ?
|
||||
<p className="inspect-modal-prompt-box"><span className='inspect-modal-prompt-prefix'>Root Prompt: </span> <span className="inspect-modal-prompt-text">{props.prompt}</span></p>
|
||||
: <></>}
|
||||
<div className="inspect-modal-response-container" style={{padding: '6px'}}>
|
||||
<div className="inspect-modal-response-container" style={{padding: '6px', overflow: 'scroll'}}>
|
||||
<LLMResponseInspector jsonResponses={props.jsonResponses} wideFormat={true} />
|
||||
</div>
|
||||
</Modal>
|
||||
|
@ -284,6 +284,18 @@
|
||||
.inspect-modal-response-container .num-same-responses {
|
||||
font-size: 10pt;
|
||||
}
|
||||
.inspect-table-var {
|
||||
background-color: rgb(224, 244, 250);
|
||||
padding-top: 10px;
|
||||
border-right: 1px solid #cde;
|
||||
font-weight: 500;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.inspect-table-llm-resp {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 20px;
|
||||
border-right: 1px solid #eee;
|
||||
}
|
||||
.response-group-component-header:hover {
|
||||
color: #05e;
|
||||
cursor: pointer;
|
||||
|
Loading…
x
Reference in New Issue
Block a user