Skip to content

Commit 113a947

Browse files
author
Taniya Mathur
committed
feat: add avg cost per page to test results, comparison, and downloads
- Add Avg Cost/Page metric to TestResults key metrics section - Add Avg Cost/Page row to TestComparison performance metrics table - Include avgCostPerPage in CSV and JSON downloads - Computed from existing costBreakdown page counts and totalCost - Update CHANGELOG.md and test-studio.md docs
1 parent a3c3ab9 commit 113a947

4 files changed

Lines changed: 59 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ SPDX-License-Identifier: MIT-0
77

88
### Added
99

10+
- **Average Cost Per Page Metric** — Test results and test comparison views now display an "Avg Cost/Page" metric, calculated from total cost and page counts in the cost breakdown. Also included in CSV and JSON exports from the comparison view.
11+
1012
- **Prompt Preview** — New "Prompt Preview" tab in the Configuration page lets you preview the actual prompts sent to the LLM for each processing step (Classification, Extraction, Assessment, Summarization). Config-derived placeholders are filled in with real values (class names, cleaned JSON Schema), while document-specific placeholders are shown as highlighted markers. Includes token estimates, copy-to-clipboard, and a substitution details panel showing the exact schema sent to the LLM. Helps optimize document class schemas and prompt templates.
1113

1214
- **IDP CLI `chat` Command & SDK `ChatOperation`** — Interactive Agent Companion Chat from the terminal and programmatic SDK access. Runs the same multi-agent orchestrator as the Web UI locally, with real-time streaming and multi-turn conversation support. Includes Analytics Agent, Error Analyzer Agent, and optionally Code Intelligence Agent (`--enable-code-intelligence`). Available as `idp-cli chat --stack-name <stack>` for interactive use, `--prompt` flag for single-shot scripting, and `client.chat.send_message()` in the Python SDK. See `docs/idp-cli.md#chat`.

docs/test-studio.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ For full details on configuration versioning, see [configuration-versions.md](co
484484
- Comprehensive metrics display including:
485485
- **Test run metadata**: Configuration version, duration, context, file counts
486486
- **Overall accuracy and confidence metrics**
487+
- **Cost metrics**: Total cost and average cost per page
487488
- **Accuracy breakdown** (precision, recall, F1-score, false alarm rate, false discovery rate)
488489
- **Field-Level Metrics**: Per-field extraction performance table with columns: Field Name, Accuracy, Precision, Recall, TP, FP, TN, FN
489490
- **Average Document Split Classification Metrics**:

src/ui/src/components/test-studio/TestComparison.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,19 @@ const TestComparison = ({ preSelectedTestRunIds = [] }: TestComparisonProps): Re
302302
run.totalCost !== null && run.totalCost !== undefined ? `$${Number(run.totalCost).toFixed(4)}` : 'N/A',
303303
),
304304
],
305+
[
306+
'Avg Cost/Page',
307+
...Object.values(completeTestRuns).map((run) => {
308+
if (run.totalCost == null || !run.costBreakdown) return 'N/A';
309+
let totalPages = 0;
310+
Object.values(run.costBreakdown as Record<string, Record<string, Record<string, unknown>>>).forEach((services) => {
311+
Object.values(services).forEach((details) => {
312+
if (details.unit === 'pages') totalPages += Number(details.value) || 0;
313+
});
314+
});
315+
return totalPages > 0 ? `$${(Number(run.totalCost) / totalPages).toFixed(4)}` : 'N/A';
316+
}),
317+
],
305318
[
306319
'Average Accuracy',
307320
...Object.values(completeTestRuns).map((run) =>
@@ -624,6 +637,16 @@ const TestComparison = ({ preSelectedTestRunIds = [] }: TestComparisonProps): Re
624637
completedFiles: testRun.completedFiles,
625638
failedFiles: testRun.failedFiles,
626639
totalCost: testRun.totalCost,
640+
avgCostPerPage: (() => {
641+
if (testRun.totalCost == null || !testRun.costBreakdown) return null;
642+
let totalPages = 0;
643+
Object.values(testRun.costBreakdown as Record<string, Record<string, Record<string, unknown>>>).forEach((services) => {
644+
Object.values(services).forEach((details) => {
645+
if (details.unit === 'pages') totalPages += Number(details.value) || 0;
646+
});
647+
});
648+
return totalPages > 0 ? Number(testRun.totalCost) / totalPages : null;
649+
})(),
627650
averageAccuracy: testRun.overallAccuracy,
628651
averageConfidence: testRun.averageConfidence,
629652
averageWeightedOverallScore: (() => {
@@ -818,6 +841,23 @@ const TestComparison = ({ preSelectedTestRunIds = [] }: TestComparisonProps): Re
818841
]),
819842
),
820843
},
844+
{
845+
metric: 'Avg Cost/Page',
846+
...Object.fromEntries(
847+
Object.entries(completeTestRuns).map(([testRunId, testRun]) => {
848+
if (testRun.totalCost == null || !testRun.costBreakdown) return [testRunId, 'N/A'];
849+
let totalPages = 0;
850+
Object.values(testRun.costBreakdown as Record<string, Record<string, Record<string, unknown>>>).forEach(
851+
(services) => {
852+
Object.values(services).forEach((details) => {
853+
if (details.unit === 'pages') totalPages += Number(details.value) || 0;
854+
});
855+
},
856+
);
857+
return [testRunId, totalPages > 0 ? `$${(Number(testRun.totalCost) / totalPages).toFixed(4)}` : 'N/A'];
858+
}),
859+
),
860+
},
821861
{
822862
metric: 'Average Accuracy',
823863
...Object.fromEntries(

src/ui/src/components/test-studio/TestResults.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,18 @@ const TestResults = ({ testRunId, setSelectedTestRunId }: TestResultsProps): Rea
751751

752752
// eslint-disable-next-line @typescript-eslint/no-explicit-any
753753
const costBreakdown: any = results.costBreakdown ? parseCostBreakdown(results.costBreakdown as string) : null;
754+
755+
// Calculate avg cost per page from costBreakdown page counts
756+
const avgCostPerPage = (() => {
757+
if (results.totalCost == null || !costBreakdown) return null;
758+
let totalPages = 0;
759+
Object.values(costBreakdown as Record<string, Record<string, Record<string, unknown>>>).forEach((services) => {
760+
Object.values(services).forEach((details) => {
761+
if (details.unit === 'pages') totalPages += Number(details.value) || 0;
762+
});
763+
});
764+
return totalPages > 0 ? (results.totalCost as number) / totalPages : null;
765+
})();
754766
// eslint-disable-next-line @typescript-eslint/no-explicit-any
755767
const accuracyBreakdown: any = results.accuracyBreakdown ? parseAccuracyBreakdown(results.accuracyBreakdown as string) : null;
756768
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -1012,6 +1024,10 @@ const TestResults = ({ testRunId, setSelectedTestRunId }: TestResultsProps): Rea
10121024
{results.totalCost !== null && results.totalCost !== undefined ? `$${(results.totalCost as number).toFixed(4)}` : 'N/A'}
10131025
</Box>
10141026
</Box>
1027+
<Box>
1028+
<Box variant="awsui-key-label">Avg Cost/Page</Box>
1029+
<Box fontSize="heading-l">{avgCostPerPage !== null ? `$${avgCostPerPage.toFixed(4)}` : 'N/A'}</Box>
1030+
</Box>
10151031
<Box>
10161032
<Box variant="awsui-key-label">Avg Confidence</Box>
10171033
<Box fontSize="heading-l">

0 commit comments

Comments
 (0)