llm-testrunner-components 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -10
- package/dist/cjs/app-globals-CbbEbofA.js +14 -0
- package/dist/cjs/app-globals-CbbEbofA.js.map +1 -0
- package/dist/cjs/{index-CY2lQip_.js → index-D-FySkoV.js} +25 -5
- package/dist/cjs/index-D-FySkoV.js.map +1 -0
- package/dist/cjs/index.cjs.js +159 -66
- package/dist/cjs/index.cjs.js.map +1 -1
- package/dist/cjs/llm-test-runner.cjs.entry.js +1 -1
- package/dist/cjs/llm-testrunner.cjs.js +4 -4
- package/dist/cjs/llm-testrunner.cjs.js.map +1 -1
- package/dist/cjs/loader.cjs.js +3 -3
- package/dist/collection/collection-manifest.json +3 -2
- package/dist/collection/components/llm-test-runner/llm-test-runner.js +152 -72
- package/dist/collection/components/llm-test-runner/llm-test-runner.js.map +1 -1
- package/dist/collection/global/env.js +6 -0
- package/dist/collection/global/env.js.map +1 -0
- package/dist/collection/lib/rate-limited-fetcher/rate-limited-fetcher.js +39 -0
- package/dist/collection/lib/rate-limited-fetcher/rate-limited-fetcher.js.map +1 -0
- package/dist/components/index.js +6 -1650
- package/dist/components/index.js.map +1 -1
- package/dist/components/llm-test-runner.js +1 -1
- package/dist/components/p-CYUbsbxt.js +1770 -0
- package/dist/components/p-CYUbsbxt.js.map +1 -0
- package/dist/esm/app-globals-BOQOUavG.js +12 -0
- package/dist/esm/app-globals-BOQOUavG.js.map +1 -0
- package/dist/esm/{index-DBp-rMPb.js → index-cncubhtM.js} +25 -6
- package/dist/esm/index-cncubhtM.js.map +1 -0
- package/dist/esm/index.js +159 -66
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/llm-test-runner.entry.js +1 -1
- package/dist/esm/llm-testrunner.js +5 -5
- package/dist/esm/llm-testrunner.js.map +1 -1
- package/dist/esm/loader.js +4 -4
- package/dist/llm-testrunner/index.esm.js +1 -1
- package/dist/llm-testrunner/index.esm.js.map +1 -1
- package/dist/llm-testrunner/llm-testrunner.esm.js +1 -1
- package/dist/llm-testrunner/llm-testrunner.esm.js.map +1 -1
- package/dist/llm-testrunner/p-BOQOUavG.js +2 -0
- package/dist/llm-testrunner/p-BOQOUavG.js.map +1 -0
- package/dist/llm-testrunner/p-cncubhtM.js +3 -0
- package/dist/llm-testrunner/p-cncubhtM.js.map +1 -0
- package/dist/llm-testrunner/p-f68fd660.entry.js +2 -0
- package/dist/react/components.d.ts +6 -3
- package/dist/react/components.d.ts.map +1 -1
- package/dist/react/components.js +2 -2
- package/dist/types/components/llm-test-runner/llm-test-runner.d.ts +13 -4
- package/dist/types/components.d.ts +26 -2
- package/dist/types/global/env.d.ts +8 -0
- package/dist/types/lib/rate-limited-fetcher/rate-limited-fetcher.d.ts +10 -0
- package/dist/types/stencil-public-runtime.d.ts +19 -10
- package/package.json +6 -4
- package/dist/cjs/app-globals-V2Kpy_OQ.js +0 -8
- package/dist/cjs/app-globals-V2Kpy_OQ.js.map +0 -1
- package/dist/cjs/index-CY2lQip_.js.map +0 -1
- package/dist/esm/app-globals-DQuL1Twl.js +0 -6
- package/dist/esm/app-globals-DQuL1Twl.js.map +0 -1
- package/dist/esm/index-DBp-rMPb.js.map +0 -1
- package/dist/llm-testrunner/p-DBp-rMPb.js +0 -3
- package/dist/llm-testrunner/p-DBp-rMPb.js.map +0 -1
- package/dist/llm-testrunner/p-DQuL1Twl.js +0 -2
- package/dist/llm-testrunner/p-DQuL1Twl.js.map +0 -1
- package/dist/llm-testrunner/p-ed2ea423.entry.js +0 -2
- /package/dist/llm-testrunner/{p-ed2ea423.entry.js.map → p-f68fd660.entry.js.map} +0 -0
|
@@ -2,8 +2,10 @@ import { h } from "@stencil/core";
|
|
|
2
2
|
import { LLMEvaluationEngine } from "../../lib/evaluation/evaluation-engine";
|
|
3
3
|
import { v4 as uuidv4 } from "uuid";
|
|
4
4
|
import { ErrorMessage } from "../error-message/error-message";
|
|
5
|
+
import { RateLimitedFetcher } from "../../lib/rate-limited-fetcher/rate-limited-fetcher";
|
|
5
6
|
export class LLMTestRunner {
|
|
6
|
-
|
|
7
|
+
llmRequest;
|
|
8
|
+
delayMs = 500;
|
|
7
9
|
testCases = [
|
|
8
10
|
{
|
|
9
11
|
id: '1',
|
|
@@ -17,15 +19,10 @@ export class LLMTestRunner {
|
|
|
17
19
|
error = '';
|
|
18
20
|
fileInput;
|
|
19
21
|
isExportingTestSuite = false;
|
|
22
|
+
isExportingTestResults = false;
|
|
20
23
|
evaluationEngine;
|
|
21
|
-
|
|
22
|
-
async componentWillLoad() {
|
|
24
|
+
componentWillLoad() {
|
|
23
25
|
this.evaluationEngine = new LLMEvaluationEngine();
|
|
24
|
-
console.log('🔍 componentWillLoad - apiKey:', this.apiKey ? 'SET' : 'NOT SET');
|
|
25
|
-
console.log('🔍 componentWillLoad - apiKey value:', this.apiKey);
|
|
26
|
-
if (!this.apiKey) {
|
|
27
|
-
throw new Error('API key is required. Please provide the apiKey prop: <llm-test-runner apiKey="your-api-key" />');
|
|
28
|
-
}
|
|
29
26
|
}
|
|
30
27
|
componentDidLoad() {
|
|
31
28
|
}
|
|
@@ -46,28 +43,39 @@ export class LLMTestRunner {
|
|
|
46
43
|
}
|
|
47
44
|
async runSingleTest(testCase) {
|
|
48
45
|
console.log('🚀 Starting test for question:', testCase.question);
|
|
46
|
+
const startTime = Date.now();
|
|
49
47
|
this.updateTestCase(testCase.id, { isRunning: true });
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
this.llmRequest.emit({
|
|
50
|
+
prompt: testCase.question,
|
|
51
|
+
resolve: async (aiResponse) => {
|
|
52
|
+
console.log('✅ AI call completed for test case:', testCase.id);
|
|
53
|
+
const endTime = Date.now();
|
|
54
|
+
const responseTime = endTime - startTime;
|
|
55
|
+
this.updateTestCase(testCase.id, {
|
|
56
|
+
isRunning: false,
|
|
57
|
+
output: aiResponse,
|
|
58
|
+
error: null,
|
|
59
|
+
responseTime: responseTime
|
|
60
|
+
});
|
|
61
|
+
await this.evaluateResponse({
|
|
62
|
+
...testCase,
|
|
63
|
+
output: aiResponse,
|
|
64
|
+
responseTime: responseTime
|
|
65
|
+
});
|
|
66
|
+
resolve();
|
|
67
|
+
},
|
|
68
|
+
reject: (error) => {
|
|
69
|
+
console.error('❌ Error in runSingleTest:', error);
|
|
70
|
+
this.updateTestCase(testCase.id, {
|
|
71
|
+
isRunning: false,
|
|
72
|
+
output: null,
|
|
73
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
74
|
+
});
|
|
75
|
+
reject(error);
|
|
76
|
+
}
|
|
69
77
|
});
|
|
70
|
-
}
|
|
78
|
+
});
|
|
71
79
|
}
|
|
72
80
|
deleteTestCase(id) {
|
|
73
81
|
this.testCases = this.testCases.filter(tc => tc.id !== id);
|
|
@@ -106,38 +114,6 @@ export class LLMTestRunner {
|
|
|
106
114
|
this.updateTestCase(testCaseId, { expectedSourceLinks: newLinks });
|
|
107
115
|
}
|
|
108
116
|
}
|
|
109
|
-
async callGeminiAPI(prompt) {
|
|
110
|
-
console.log('🔍 callGeminiAPI - apiKey:', this.apiKey ? 'SET' : 'NOT SET');
|
|
111
|
-
console.log('🔍 callGeminiAPI - apiKey value:', this.apiKey ? `${this.apiKey.substring(0, 10)}...` : 'undefined');
|
|
112
|
-
if (!this.apiKey) {
|
|
113
|
-
throw new Error('API key is required. Please provide the apiKey prop.');
|
|
114
|
-
}
|
|
115
|
-
const requestBody = {
|
|
116
|
-
contents: [{
|
|
117
|
-
parts: [{
|
|
118
|
-
text: prompt
|
|
119
|
-
}]
|
|
120
|
-
}]
|
|
121
|
-
};
|
|
122
|
-
const response = await fetch(`${this.apiUrl}?key=${this.apiKey}`, {
|
|
123
|
-
method: 'POST',
|
|
124
|
-
headers: {
|
|
125
|
-
'Content-Type': 'application/json',
|
|
126
|
-
},
|
|
127
|
-
body: JSON.stringify(requestBody)
|
|
128
|
-
});
|
|
129
|
-
if (!response.ok) {
|
|
130
|
-
const errorData = await response.json().catch(() => ({}));
|
|
131
|
-
throw new Error(errorData.error?.message || `HTTP error! status: ${response.status}`);
|
|
132
|
-
}
|
|
133
|
-
const data = await response.json();
|
|
134
|
-
if (data.candidates && data.candidates[0] && data.candidates[0].content) {
|
|
135
|
-
return data.candidates[0].content.parts[0].text;
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
throw new Error('Unexpected response format from Gemini API');
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
117
|
async evaluateResponse(testCase) {
|
|
142
118
|
if (!testCase.output) {
|
|
143
119
|
console.warn('⚠️ No output to evaluate for test case:', testCase.id);
|
|
@@ -159,13 +135,21 @@ export class LLMTestRunner {
|
|
|
159
135
|
}
|
|
160
136
|
async runAllTests() {
|
|
161
137
|
this.isRunningAll = true;
|
|
138
|
+
const tasks = [];
|
|
162
139
|
for (const testCase of this.testCases) {
|
|
163
140
|
if (!testCase.isRunning && testCase.question.trim()) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
141
|
+
tasks.push(() => this.runSingleTest(testCase).catch(err => {
|
|
142
|
+
console.error(`⚠️ Test case ${testCase.id} failed`, err);
|
|
143
|
+
}));
|
|
167
144
|
}
|
|
168
145
|
}
|
|
146
|
+
try {
|
|
147
|
+
const fetcher = new RateLimitedFetcher(this.delayMs);
|
|
148
|
+
await fetcher.runAll(tasks);
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
console.error('⚠️ Error running all tests:', err);
|
|
152
|
+
}
|
|
169
153
|
this.isRunningAll = false;
|
|
170
154
|
}
|
|
171
155
|
generateId() {
|
|
@@ -248,8 +232,78 @@ export class LLMTestRunner {
|
|
|
248
232
|
this.isExportingTestSuite = false;
|
|
249
233
|
}
|
|
250
234
|
}
|
|
235
|
+
async handleExportTestResults() {
|
|
236
|
+
this.isExportingTestResults = true;
|
|
237
|
+
try {
|
|
238
|
+
// Create CSV content with the required fields
|
|
239
|
+
const csvRows = [];
|
|
240
|
+
// Add header row
|
|
241
|
+
const headers = [
|
|
242
|
+
'Question',
|
|
243
|
+
'Expected Keywords',
|
|
244
|
+
'Generated Keywords',
|
|
245
|
+
'Keywords Match',
|
|
246
|
+
'Expected Source Links',
|
|
247
|
+
'Generated Source Links',
|
|
248
|
+
'Source Links Match',
|
|
249
|
+
'Response Time (s)'
|
|
250
|
+
];
|
|
251
|
+
csvRows.push(headers.join(','));
|
|
252
|
+
// Add data rows
|
|
253
|
+
this.testCases.forEach(testCase => {
|
|
254
|
+
const expectedKeywords = testCase.expectedKeywords.join('; ');
|
|
255
|
+
const expectedSourceLinks = testCase.expectedSourceLinks.join('; ');
|
|
256
|
+
let generatedKeywords = '';
|
|
257
|
+
let generatedSourceLinks = '';
|
|
258
|
+
let keywordsMatch = '';
|
|
259
|
+
let sourceLinksMatch = '';
|
|
260
|
+
if (testCase.evaluationResult) {
|
|
261
|
+
const foundKeywords = testCase.evaluationResult.keywordMatches
|
|
262
|
+
.filter(match => match.found)
|
|
263
|
+
.map(match => match.keyword);
|
|
264
|
+
const foundSourceLinks = testCase.evaluationResult.sourceLinkMatches
|
|
265
|
+
.filter(match => match.found)
|
|
266
|
+
.map(match => match.link);
|
|
267
|
+
generatedKeywords = foundKeywords.join('; ');
|
|
268
|
+
generatedSourceLinks = foundSourceLinks.join('; ');
|
|
269
|
+
// Calculate match percentages
|
|
270
|
+
const keywordMatchCount = testCase.evaluationResult.keywordMatches.filter(m => m.found).length;
|
|
271
|
+
const totalKeywords = testCase.evaluationResult.keywordMatches.length;
|
|
272
|
+
const sourceLinkMatchCount = testCase.evaluationResult.sourceLinkMatches.filter(m => m.found).length;
|
|
273
|
+
const totalSourceLinks = testCase.evaluationResult.sourceLinkMatches.length;
|
|
274
|
+
keywordsMatch = totalKeywords > 0 ? `${keywordMatchCount}/${totalKeywords}` : 'N/A';
|
|
275
|
+
sourceLinksMatch = totalSourceLinks > 0 ? `${sourceLinkMatchCount}/${totalSourceLinks}` : 'N/A';
|
|
276
|
+
}
|
|
277
|
+
const responseTime = testCase.responseTime ? (testCase.responseTime / 1000).toFixed(3) : 'N/A';
|
|
278
|
+
const row = [
|
|
279
|
+
this.escapeCsvField(testCase.question),
|
|
280
|
+
this.escapeCsvField(expectedKeywords),
|
|
281
|
+
this.escapeCsvField(generatedKeywords),
|
|
282
|
+
keywordsMatch,
|
|
283
|
+
this.escapeCsvField(expectedSourceLinks),
|
|
284
|
+
this.escapeCsvField(generatedSourceLinks),
|
|
285
|
+
sourceLinksMatch,
|
|
286
|
+
responseTime
|
|
287
|
+
];
|
|
288
|
+
csvRows.push(row.join(','));
|
|
289
|
+
});
|
|
290
|
+
const csvContent = csvRows.join('\n');
|
|
291
|
+
// Added a small delay to show the loading state
|
|
292
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
293
|
+
this.downloadFile(csvContent, 'test-results.csv', 'text/csv');
|
|
294
|
+
}
|
|
295
|
+
finally {
|
|
296
|
+
this.isExportingTestResults = false;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
escapeCsvField(field) {
|
|
300
|
+
if (field.includes(',') || field.includes('"') || field.includes('\n')) {
|
|
301
|
+
return `"${field.replace(/"/g, '""')}"`;
|
|
302
|
+
}
|
|
303
|
+
return field;
|
|
304
|
+
}
|
|
251
305
|
render() {
|
|
252
|
-
return (h("div", { key: '
|
|
306
|
+
return (h("div", { key: 'beb2ab78108fede00c5d759d1ac5c98ae7f037d0', class: "test-runner-container" }, h("header", { key: 'd09b424069227500ffffcab8724b48d91705baab', class: "test-runner-header" }, h("div", { key: '368ef117a1c2cc0be0446e2d373e38e0af1c2040', class: "header-left" }, h("input", { key: '74346a634b36e9d04f75817495834983d970306c', class: "hidden", type: "file", ref: (el) => (this.fileInput = el), onChange: (e) => this.handleFileChange(e), accept: ".json,application/json" }), h("button", { key: 'e095ff9de105cb281e60f70de02fb0de8a0f6478', class: "btn btn-secondary", onClick: () => this.handleFileSelect() }, h("span", { key: '6f828f297867ae54baf1f89c9dbce611eba2056a', class: "icon" }, "\u2191"), "Import Test Suite"), h("button", { key: '5682dc8f70edac9fdf33b394677a6859555c039b', class: "btn btn-secondary", onClick: () => this.handleExportTestSuite(), disabled: this.isExportingTestSuite }, h("span", { key: 'a1e8d3170ce39e499160e578e3e02d39cd0da9d7', class: "icon" }, this.isExportingTestSuite ? '⏳' : '↓'), this.isExportingTestSuite ? 'Exporting...' : 'Export Test Suite')), h("div", { key: 'af96ea230b04f4f6ce8e3488a1f8f7f2a01e74c0', class: "header-right" }, h("button", { key: 'a90bfb3421f5e2e5112b3642ddf81cf19372e0ad', class: "btn btn-secondary" }, h("span", { key: '79611828e5dc1ad53998a74fca10a1a05c5d2a4e', class: "icon" }, "\u2699\uFE0F"), "Prompt Editor"), h("button", { key: '451367ce26183a58add0902e1de2d29b4933add4', class: "btn btn-secondary", onClick: () => this.handleExportTestResults(), disabled: this.isExportingTestResults }, h("span", { key: '11f791f2071b58e0800d14ac7e6bebba67421449', class: "icon" }, this.isExportingTestResults ? '⏳' : '↓'), this.isExportingTestResults ? 'Exporting...' : 'Export Test Results'), h("button", { key: '3cbf7626ccc5f171cdc6fd7ce3750ea3786218aa', class: "btn btn-primary", onClick: () => this.runAllTests(), disabled: this.isRunningAll }, this.isRunningAll ? 'Running...' : 'Run All'))), h(ErrorMessage, { key: 'ffdd72a1db1f45c5db158d2df0be64dc978fa930', message: this.error, onClear: () => (this.error = '') }), h("div", { key: '64edd5c84c4b566f90d1860f6d6bf5aeafb7ae0f', class: "test-runner-content" }, h("div", { key: '4be27d07a13d88611b5fc54b05e826c790fd2145', class: "column-headers" }, h("div", { key: 'eeb9ace5e63b80359d2decb1b42461f77cfe98cf', class: "column-header" }, "Input"), h("div", { key: 'c70cc5af0aaca2636eee298dfaa4da81799df6cf', class: "column-header" }, "Output"), h("div", { key: '9ca69fddafe7267bf5b8b12601e2cf64d65a58e1', class: "column-header" }, "Evaluation"), h("div", { key: 'b800841828c22a6aad0345e58b47f71469594792', class: "column-header" }, "Actions")), h("div", { key: 'da186e25c2111474f65b89a017158bffdbc83e03', class: "test-cases" }, this.testCases.map((testCase) => (h("div", { class: "test-case-row", key: testCase.id }, h("div", { class: "input-column" }, h("div", { class: "input-group" }, h("label", null, "Question"), h("textarea", { value: testCase.question, onInput: (e) => this.updateTestCase(testCase.id, {
|
|
253
307
|
question: e.target.value
|
|
254
308
|
}), placeholder: "Enter your question here...", rows: 3 })), h("div", { class: "keywords-group" }, h("label", null, "Expected keywords"), h("div", { class: "tags-container" }, testCase.expectedKeywords.map((keyword, index) => (h("span", { class: "tag", key: index }, keyword, h("button", { class: "tag-remove", onClick: () => this.removeKeyword(testCase.id, index) }, "\u00D7")))), h("input", { type: "text", placeholder: "New item...", onKeyDown: (e) => {
|
|
255
309
|
if (e.key === 'Enter') {
|
|
@@ -261,7 +315,7 @@ export class LLMTestRunner {
|
|
|
261
315
|
this.addSourceLink(testCase.id, e.target.value);
|
|
262
316
|
e.target.value = '';
|
|
263
317
|
}
|
|
264
|
-
} })))), h("div", { class: "output-column" }, testCase.output ? (h("div", { class: "output-content" }, testCase.output)) : (h("div", { class: "output-placeholder" }, testCase.isRunning ? 'Running...' : ''))), h("div", { class: "evaluation-column" }, testCase.evaluationResult ? (h("div", { class: "evaluation-result" }, h("div", { class: `evaluation-status ${testCase.evaluationResult.passed ? 'passed' : 'failed'}` }, testCase.evaluationResult.passed ? '✅ PASSED' : '❌ FAILED'), h("div", { class: "evaluation-details" }, "Keywords: ", testCase.evaluationResult.keywordMatches.filter(m => m.found).length, "/", testCase.evaluationResult.keywordMatches.length, " found"))) : (h("div", { class: "evaluation-placeholder" }, testCase.isRunning ? 'Evaluating...' : ''))), h("div", { class: "actions-column" }, h("button", { class: "btn btn-icon btn-run", onClick: () => this.runSingleTest(testCase), disabled: testCase.isRunning || !testCase.question.trim(), title: !testCase.question.trim() ? "Enter a question first" : "Run this test" }, testCase.isRunning ? '⏳' : '▶️'), h("button", { class: "btn btn-icon btn-delete", onClick: () => this.deleteTestCase(testCase.id), title: "Delete this test" }, "\uD83D\uDDD1\uFE0F")))))), h("div", { key: '
|
|
318
|
+
} })))), h("div", { class: "output-column" }, testCase.output ? (h("div", { class: "output-content" }, testCase.output)) : (h("div", { class: "output-placeholder" }, testCase.isRunning ? 'Running...' : ''))), h("div", { class: "evaluation-column" }, testCase.evaluationResult ? (h("div", { class: "evaluation-result" }, h("div", { class: `evaluation-status ${testCase.evaluationResult.passed ? 'passed' : 'failed'}` }, testCase.evaluationResult.passed ? '✅ PASSED' : '❌ FAILED'), h("div", { class: "evaluation-details" }, "Keywords: ", testCase.evaluationResult.keywordMatches.filter(m => m.found).length, "/", testCase.evaluationResult.keywordMatches.length, " found"))) : (h("div", { class: "evaluation-placeholder" }, testCase.isRunning ? 'Evaluating...' : ''))), h("div", { class: "actions-column" }, h("button", { class: "btn btn-icon btn-run", onClick: () => this.runSingleTest(testCase), disabled: testCase.isRunning || !testCase.question.trim(), title: !testCase.question.trim() ? "Enter a question first" : "Run this test" }, testCase.isRunning ? '⏳' : '▶️'), h("button", { class: "btn btn-icon btn-delete", onClick: () => this.deleteTestCase(testCase.id), title: "Delete this test" }, "\uD83D\uDDD1\uFE0F")))))), h("div", { key: '2d4446b15a31adfbaf88b3d46fcbb3cf314f8861', class: "add-test-case" }, h("button", { key: '737e9d856db0f9090923bef718bb9bfde974b950', class: "btn btn-outline", onClick: () => this.addNewTestCase() }, "+ Add Question")))));
|
|
265
319
|
}
|
|
266
320
|
static get is() { return "llm-test-runner"; }
|
|
267
321
|
static get encapsulation() { return "shadow"; }
|
|
@@ -277,16 +331,16 @@ export class LLMTestRunner {
|
|
|
277
331
|
}
|
|
278
332
|
static get properties() {
|
|
279
333
|
return {
|
|
280
|
-
"
|
|
281
|
-
"type": "
|
|
334
|
+
"delayMs": {
|
|
335
|
+
"type": "number",
|
|
282
336
|
"mutable": false,
|
|
283
337
|
"complexType": {
|
|
284
|
-
"original": "
|
|
285
|
-
"resolved": "
|
|
338
|
+
"original": "number",
|
|
339
|
+
"resolved": "number",
|
|
286
340
|
"references": {}
|
|
287
341
|
},
|
|
288
342
|
"required": false,
|
|
289
|
-
"optional":
|
|
343
|
+
"optional": true,
|
|
290
344
|
"docs": {
|
|
291
345
|
"tags": [],
|
|
292
346
|
"text": ""
|
|
@@ -294,7 +348,8 @@ export class LLMTestRunner {
|
|
|
294
348
|
"getter": false,
|
|
295
349
|
"setter": false,
|
|
296
350
|
"reflect": false,
|
|
297
|
-
"attribute": "
|
|
351
|
+
"attribute": "delay-ms",
|
|
352
|
+
"defaultValue": "500"
|
|
298
353
|
}
|
|
299
354
|
};
|
|
300
355
|
}
|
|
@@ -303,8 +358,33 @@ export class LLMTestRunner {
|
|
|
303
358
|
"testCases": {},
|
|
304
359
|
"isRunningAll": {},
|
|
305
360
|
"error": {},
|
|
306
|
-
"isExportingTestSuite": {}
|
|
361
|
+
"isExportingTestSuite": {},
|
|
362
|
+
"isExportingTestResults": {}
|
|
307
363
|
};
|
|
308
364
|
}
|
|
365
|
+
static get events() {
|
|
366
|
+
return [{
|
|
367
|
+
"method": "llmRequest",
|
|
368
|
+
"name": "llmRequest",
|
|
369
|
+
"bubbles": true,
|
|
370
|
+
"cancelable": true,
|
|
371
|
+
"composed": true,
|
|
372
|
+
"docs": {
|
|
373
|
+
"tags": [],
|
|
374
|
+
"text": ""
|
|
375
|
+
},
|
|
376
|
+
"complexType": {
|
|
377
|
+
"original": "LLMRequestPayload",
|
|
378
|
+
"resolved": "LLMRequestPayload",
|
|
379
|
+
"references": {
|
|
380
|
+
"LLMRequestPayload": {
|
|
381
|
+
"location": "local",
|
|
382
|
+
"path": "/Users/akhilan/Documents/work/llm-testrunner/packages/stencil-library/src/components/llm-test-runner/llm-test-runner.tsx",
|
|
383
|
+
"id": "src/components/llm-test-runner/llm-test-runner.tsx::LLMRequestPayload"
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}];
|
|
388
|
+
}
|
|
309
389
|
}
|
|
310
390
|
//# sourceMappingURL=llm-test-runner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"llm-test-runner.js","sourceRoot":"","sources":["../../../src/components/llm-test-runner/llm-test-runner.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component, State, Prop, h } from '@stencil/core';\nimport { LLMEvaluationEngine } from '../../lib/evaluation/evaluation-engine';\nimport { EvaluationRequest, EvaluationResult } from '../../lib/evaluation/types';\nimport { v4 as uuidv4 } from 'uuid';\nimport { ErrorMessage } from '../error-message/error-message';\n\nexport interface TestCase {\n id: string;\n question: string;\n expectedKeywords: string[];\n expectedSourceLinks: string[];\n output?: string;\n isRunning?: boolean;\n error?: string;\n evaluationResult?: EvaluationResult;\n}\n\n@Component({\n tag: 'llm-test-runner',\n styleUrl: 'llm-test-runner.css',\n shadow: true,\n})\nexport class LLMTestRunner {\n @Prop() apiKey: string;\n \n @State() testCases: TestCase[] = [\n {\n id: '1',\n question: '',\n expectedKeywords: [],\n expectedSourceLinks: [],\n isRunning: false\n }\n ];\n @State() isRunningAll: boolean = false;\n @State() error: string = '';\n\n private fileInput!: HTMLInputElement;\n @State() isExportingTestSuite: boolean = false;\n\n private evaluationEngine: LLMEvaluationEngine;\n private apiUrl: string = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent';\n\n async componentWillLoad() {\n this.evaluationEngine = new LLMEvaluationEngine();\n \n console.log('🔍 componentWillLoad - apiKey:', this.apiKey ? 'SET' : 'NOT SET');\n console.log('🔍 componentWillLoad - apiKey value:', this.apiKey);\n \n if (!this.apiKey) {\n throw new Error('API key is required. Please provide the apiKey prop: <llm-test-runner apiKey=\"your-api-key\" />');\n }\n }\n\n\n componentDidLoad() {\n }\n\n disconnectedCallback() {\n }\n\n private addNewTestCase() {\n const newTestCase: TestCase = {\n id: this.generateId(),\n question: '',\n expectedKeywords: [],\n expectedSourceLinks: [],\n isRunning: false\n };\n this.testCases = [...this.testCases, newTestCase];\n }\n\n private updateTestCase(id: string, updates: Partial<TestCase>) {\n this.testCases = this.testCases.map(tc => \n tc.id === id ? { ...tc, ...updates } : tc\n );\n }\n\n private async runSingleTest(testCase: TestCase) {\n console.log('🚀 Starting test for question:', testCase.question);\n \n this.updateTestCase(testCase.id, { isRunning: true });\n \n try {\n const aiResponse = await this.callGeminiAPI(testCase.question);\n console.log('✅ AI call completed for test case:', testCase.id);\n \n this.updateTestCase(testCase.id, {\n isRunning: false,\n output: aiResponse,\n error: null\n });\n \n await this.evaluateResponse({\n ...testCase,\n output: aiResponse\n });\n \n } catch (error) {\n console.error('❌ Error in runSingleTest:', error);\n this.updateTestCase(testCase.id, {\n isRunning: false,\n output: null,\n error: error instanceof Error ? error.message : 'Unknown error'\n });\n }\n }\n\n private deleteTestCase(id: string) {\n this.testCases = this.testCases.filter(tc => tc.id !== id);\n }\n\n private addKeyword(testCaseId: string, keyword: string) {\n if (keyword.trim()) {\n const testCase = this.testCases.find(tc => tc.id === testCaseId);\n if (testCase) {\n this.updateTestCase(testCaseId, {\n expectedKeywords: [...testCase.expectedKeywords, keyword.trim()]\n });\n }\n }\n }\n\n private removeKeyword(testCaseId: string, index: number) {\n const testCase = this.testCases.find(tc => tc.id === testCaseId);\n if (testCase) {\n const newKeywords = testCase.expectedKeywords.filter((_, i) => i !== index);\n this.updateTestCase(testCaseId, { expectedKeywords: newKeywords });\n }\n }\n\n private addSourceLink(testCaseId: string, link: string) {\n if (link.trim()) {\n const testCase = this.testCases.find(tc => tc.id === testCaseId);\n if (testCase) {\n this.updateTestCase(testCaseId, {\n expectedSourceLinks: [...testCase.expectedSourceLinks, link.trim()]\n });\n }\n }\n }\n\n private removeSourceLink(testCaseId: string, index: number) {\n const testCase = this.testCases.find(tc => tc.id === testCaseId);\n if (testCase) {\n const newLinks = testCase.expectedSourceLinks.filter((_, i) => i !== index);\n this.updateTestCase(testCaseId, { expectedSourceLinks: newLinks });\n }\n }\n\n private async callGeminiAPI(prompt: string): Promise<string> {\n console.log('🔍 callGeminiAPI - apiKey:', this.apiKey ? 'SET' : 'NOT SET');\n console.log('🔍 callGeminiAPI - apiKey value:', this.apiKey ? `${this.apiKey.substring(0, 10)}...` : 'undefined');\n \n if (!this.apiKey) {\n throw new Error('API key is required. Please provide the apiKey prop.');\n }\n\n const requestBody = {\n contents: [{\n parts: [{\n text: prompt\n }]\n }]\n };\n\n const response = await fetch(`${this.apiUrl}?key=${this.apiKey}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody)\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData.error?.message || `HTTP error! status: ${response.status}`);\n }\n\n const data = await response.json();\n \n if (data.candidates && data.candidates[0] && data.candidates[0].content) {\n return data.candidates[0].content.parts[0].text;\n } else {\n throw new Error('Unexpected response format from Gemini API');\n }\n }\n\n private async evaluateResponse(testCase: TestCase): Promise<void> {\n if (!testCase.output) {\n console.warn('⚠️ No output to evaluate for test case:', testCase.id);\n return;\n }\n\n const evaluationRequest: EvaluationRequest = {\n testCaseId: testCase.id,\n question: testCase.question,\n expectedKeywords: testCase.expectedKeywords,\n expectedSourceLinks: testCase.expectedSourceLinks,\n actualResponse: testCase.output\n };\n\n await this.evaluationEngine.evaluateResponse(evaluationRequest, (result: EvaluationResult) => {\n console.log('📊 Evaluation result received:', result);\n \n this.updateTestCase(testCase.id, {\n evaluationResult: result\n });\n });\n }\n\n private async runAllTests() {\n this.isRunningAll = true;\n \n for (const testCase of this.testCases) {\n if (!testCase.isRunning && testCase.question.trim()) {\n await this.runSingleTest(testCase);\n // Delay between tests to avoid rate limiting\n await new Promise(resolve => setTimeout(resolve, 1000));\n }\n }\n this.isRunningAll = false;\n }\n\n private generateId(): string {\n return uuidv4();\n }\n\n private handleFileSelect(): void {\n this.fileInput.click();\n }\n\n private async handleFileChange(event: Event): Promise<void> {\n const target = event.target as HTMLInputElement;\n const file = target.files?.[0];\n\n // Immediately clear the input value to allow for a new upload.\n target.value = '';\n\n if (!file) {\n this.error = 'No file selected.';\n return;\n }\n\n const isJsonType = file.type === 'application/json';\n const isJsonExtension = file.name.toLowerCase().endsWith('.json');\n if (!isJsonType && !isJsonExtension) {\n this.error = 'Invalid file type. Please select a JSON file.';\n return;\n }\n\n this.error = '';\n\n try {\n const content = await this.readFileAsync(file);\n const fileContent = JSON.parse(content);\n\n if (!Array.isArray(fileContent)) {\n throw new Error(\"Invalid JSON structure. Expected a JSON array.\");\n } \n const importedTestCases: TestCase[] = fileContent.map((item) => ({\n id: this.generateId(),\n question: item.question || '',\n expectedKeywords: Array.isArray(item.expectedKeywords) ? item.expectedKeywords : [],\n expectedSourceLinks: Array.isArray(item.expectedSourceLinks) ? item.expectedSourceLinks : [],\n isRunning: false\n }));\n this.testCases = importedTestCases; \n } catch (err) {\n this.error = err?.message || 'Error processing file. Please ensure it is a valid JSON array.';\n console.error('File Processing Error:', err);\n }\n }\n\n private readFileAsync(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = () => reject(reader.error);\n reader.readAsText(file);\n });\n }\n\n private downloadFile(content: string, filename: string, mimeType: string) {\n const blob = new Blob([content], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n }\n\n private async handleExportTestSuite() {\n this.isExportingTestSuite = true;\n try {\n // Exporting only input data (question, expected keywords, expected source links)\n const exportData = this.testCases.map(testCase => ({\n id: testCase.id,\n question: testCase.question,\n expectedKeywords: testCase.expectedKeywords,\n expectedSourceLinks: testCase.expectedSourceLinks\n }));\n\n const jsonContent = JSON.stringify(exportData, null, 2);\n\n // Added a small delay to show the loading state\n await new Promise(resolve => setTimeout(resolve, 500));\n\n this.downloadFile(jsonContent, 'test-suite.json', 'application/json');\n } finally {\n this.isExportingTestSuite = false;\n }\n }\n\n render() {\n return (\n <div class=\"test-runner-container\">\n <header class=\"test-runner-header\">\n <div class=\"header-left\">\n <input\n class=\"hidden\"\n type=\"file\"\n ref={(el) => (this.fileInput = el as HTMLInputElement)}\n onChange={(e) => this.handleFileChange(e)}\n accept=\".json,application/json\"\n />\n <button class=\"btn btn-secondary\" onClick={() => this.handleFileSelect()}>\n <span class=\"icon\">↑</span>\n Import Test Suite\n </button>\n <button\n class=\"btn btn-secondary\"\n onClick={() => this.handleExportTestSuite()}\n disabled={this.isExportingTestSuite}\n >\n <span class=\"icon\">\n {this.isExportingTestSuite ? '⏳' : '↓'}\n </span>\n {this.isExportingTestSuite ? 'Exporting...' : 'Export Test Suite'}\n </button>\n </div>\n \n <div class=\"header-right\">\n <button class=\"btn btn-secondary\">\n <span class=\"icon\">⚙️</span>\n Prompt Editor\n </button>\n <button class=\"btn btn-secondary\">\n <span class=\"icon\">↓</span>\n Export Test Results\n </button>\n <button \n class=\"btn btn-primary\" \n onClick={() => this.runAllTests()}\n disabled={this.isRunningAll}\n >\n {this.isRunningAll ? 'Running...' : 'Run All'}\n </button>\n </div>\n </header>\n <ErrorMessage\n message={this.error}\n onClear={() => (this.error = '')}\n />\n <div class=\"test-runner-content\">\n <div class=\"column-headers\">\n <div class=\"column-header\">Input</div>\n <div class=\"column-header\">Output</div>\n <div class=\"column-header\">Evaluation</div>\n <div class=\"column-header\">Actions</div>\n </div>\n\n <div class=\"test-cases\">\n {this.testCases.map((testCase) => (\n <div class=\"test-case-row\" key={testCase.id}>\n <div class=\"input-column\">\n <div class=\"input-group\">\n <label>Question</label>\n <textarea\n value={testCase.question}\n onInput={(e) => this.updateTestCase(testCase.id, { \n question: (e.target as HTMLTextAreaElement).value \n })}\n placeholder=\"Enter your question here...\"\n rows={3}\n ></textarea>\n </div>\n \n <div class=\"keywords-group\">\n <label>Expected keywords</label>\n <div class=\"tags-container\">\n {testCase.expectedKeywords.map((keyword, index) => (\n <span class=\"tag\" key={index}>\n {keyword}\n <button \n class=\"tag-remove\" \n onClick={() => this.removeKeyword(testCase.id, index)}\n >×</button>\n </span>\n ))}\n <input\n type=\"text\"\n placeholder=\"New item...\"\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n this.addKeyword(testCase.id, (e.target as HTMLInputElement).value);\n (e.target as HTMLInputElement).value = '';\n }\n }}\n />\n </div>\n </div>\n \n <div class=\"links-group\">\n <label>Expected source links</label>\n <div class=\"links-container\">\n {testCase.expectedSourceLinks.map((link, index) => (\n <div class=\"link-item\" key={index}>\n <a href={link} target=\"_blank\" rel=\"noopener noreferrer\">{link}</a>\n <button \n class=\"link-remove\" \n onClick={() => this.removeSourceLink(testCase.id, index)}\n >×</button>\n </div>\n ))}\n <input\n type=\"url\"\n placeholder=\"New item...\"\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n this.addSourceLink(testCase.id, (e.target as HTMLInputElement).value);\n (e.target as HTMLInputElement).value = '';\n }\n }}\n />\n </div>\n </div>\n </div>\n\n <div class=\"output-column\">\n {testCase.output ? (\n <div class=\"output-content\">\n {testCase.output}\n </div>\n ) : (\n <div class=\"output-placeholder\">\n {testCase.isRunning ? 'Running...' : ''}\n </div>\n )}\n </div>\n\n <div class=\"evaluation-column\">\n {testCase.evaluationResult ? (\n <div class=\"evaluation-result\">\n <div class={`evaluation-status ${testCase.evaluationResult.passed ? 'passed' : 'failed'}`}>\n {testCase.evaluationResult.passed ? '✅ PASSED' : '❌ FAILED'}\n </div>\n <div class=\"evaluation-details\">\n Keywords: {testCase.evaluationResult.keywordMatches.filter(m => m.found).length}/{testCase.evaluationResult.keywordMatches.length} found\n </div>\n </div>\n ) : (\n <div class=\"evaluation-placeholder\">\n {testCase.isRunning ? 'Evaluating...' : ''}\n </div>\n )}\n </div>\n\n <div class=\"actions-column\">\n <button \n class=\"btn btn-icon btn-run\"\n onClick={() => this.runSingleTest(testCase)}\n disabled={testCase.isRunning || !testCase.question.trim()}\n title={!testCase.question.trim() ? \"Enter a question first\" : \"Run this test\"}\n >\n {testCase.isRunning ? '⏳' : '▶️'}\n </button>\n <button \n class=\"btn btn-icon btn-delete\"\n onClick={() => this.deleteTestCase(testCase.id)}\n title=\"Delete this test\"\n >\n 🗑️\n </button>\n </div>\n </div>\n ))}\n </div>\n\n <div class=\"add-test-case\">\n <button class=\"btn btn-outline\" onClick={() => this.addNewTestCase()}>\n + Add Question\n </button>\n </div>\n </div>\n </div>\n );\n }\n}"]}
|
|
1
|
+
{"version":3,"file":"llm-test-runner.js","sourceRoot":"","sources":["../../../src/components/llm-test-runner/llm-test-runner.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Component, State, Prop, h, EventEmitter, Event } from '@stencil/core';\nimport { LLMEvaluationEngine } from '../../lib/evaluation/evaluation-engine';\nimport { EvaluationRequest, EvaluationResult } from '../../lib/evaluation/types';\nimport { v4 as uuidv4 } from 'uuid';\nimport { ErrorMessage } from '../error-message/error-message';\nimport { RateLimitedFetcher } from '../../lib/rate-limited-fetcher/rate-limited-fetcher';\n\nexport interface TestCase {\n id: string;\n question: string;\n expectedKeywords: string[];\n expectedSourceLinks: string[];\n output?: string;\n isRunning?: boolean;\n error?: string;\n evaluationResult?: EvaluationResult;\n responseTime?: number; // Time taken by the callback to execute in milliseconds\n}\n\nexport interface LLMRequestPayload {\n prompt: string;\n resolve: (result: string) => void;\n reject: (err: any) => void;\n}\n\n@Component({\n tag: 'llm-test-runner',\n styleUrl: 'llm-test-runner.css',\n shadow: true,\n})\nexport class LLMTestRunner {\n @Event() llmRequest: EventEmitter<LLMRequestPayload>;\n @Prop() delayMs?: number = 500; \n @State() testCases: TestCase[] = [\n {\n id: '1',\n question: '',\n expectedKeywords: [],\n expectedSourceLinks: [],\n isRunning: false\n }\n ];\n @State() isRunningAll: boolean = false;\n @State() error: string = '';\n\n private fileInput!: HTMLInputElement;\n @State() isExportingTestSuite: boolean = false;\n @State() isExportingTestResults: boolean = false;\n\n private evaluationEngine: LLMEvaluationEngine;\n\n componentWillLoad() {\n this.evaluationEngine = new LLMEvaluationEngine();\n }\n\n componentDidLoad() {\n }\n\n disconnectedCallback() {\n }\n\n private addNewTestCase() {\n const newTestCase: TestCase = {\n id: this.generateId(),\n question: '',\n expectedKeywords: [],\n expectedSourceLinks: [],\n isRunning: false\n };\n this.testCases = [...this.testCases, newTestCase];\n }\n\n private updateTestCase(id: string, updates: Partial<TestCase>) {\n this.testCases = this.testCases.map(tc => \n tc.id === id ? { ...tc, ...updates } : tc\n );\n }\n\n private async runSingleTest(testCase: TestCase): Promise<void> {\n console.log('🚀 Starting test for question:', testCase.question);\n const startTime = Date.now();\n this.updateTestCase(testCase.id, { isRunning: true });\n return new Promise<void>((resolve, reject) => {\n this.llmRequest.emit({\n prompt: testCase.question,\n resolve: async (aiResponse: string) => {\n console.log('✅ AI call completed for test case:', testCase.id);\n const endTime = Date.now();\n const responseTime = endTime - startTime;\n this.updateTestCase(testCase.id, {\n isRunning: false,\n output: aiResponse,\n error: null,\n responseTime: responseTime\n });\n\n await this.evaluateResponse({\n ...testCase,\n output: aiResponse,\n responseTime: responseTime\n });\n resolve()\n },\n reject: (error: any) => {\n console.error('❌ Error in runSingleTest:', error);\n this.updateTestCase(testCase.id, {\n isRunning: false,\n output: null,\n error: error instanceof Error ? error.message : 'Unknown error'\n });\n reject(error);\n }\n });\n })\n }\n\n private deleteTestCase(id: string) {\n this.testCases = this.testCases.filter(tc => tc.id !== id);\n }\n\n private addKeyword(testCaseId: string, keyword: string) {\n if (keyword.trim()) {\n const testCase = this.testCases.find(tc => tc.id === testCaseId);\n if (testCase) {\n this.updateTestCase(testCaseId, {\n expectedKeywords: [...testCase.expectedKeywords, keyword.trim()]\n });\n }\n }\n }\n\n private removeKeyword(testCaseId: string, index: number) {\n const testCase = this.testCases.find(tc => tc.id === testCaseId);\n if (testCase) {\n const newKeywords = testCase.expectedKeywords.filter((_, i) => i !== index);\n this.updateTestCase(testCaseId, { expectedKeywords: newKeywords });\n }\n }\n\n private addSourceLink(testCaseId: string, link: string) {\n if (link.trim()) {\n const testCase = this.testCases.find(tc => tc.id === testCaseId);\n if (testCase) {\n this.updateTestCase(testCaseId, {\n expectedSourceLinks: [...testCase.expectedSourceLinks, link.trim()]\n });\n }\n }\n }\n\n private removeSourceLink(testCaseId: string, index: number) {\n const testCase = this.testCases.find(tc => tc.id === testCaseId);\n if (testCase) {\n const newLinks = testCase.expectedSourceLinks.filter((_, i) => i !== index);\n this.updateTestCase(testCaseId, { expectedSourceLinks: newLinks });\n }\n }\n\n private async evaluateResponse(testCase: TestCase): Promise<void> {\n if (!testCase.output) {\n console.warn('⚠️ No output to evaluate for test case:', testCase.id);\n return;\n }\n\n const evaluationRequest: EvaluationRequest = {\n testCaseId: testCase.id,\n question: testCase.question,\n expectedKeywords: testCase.expectedKeywords,\n expectedSourceLinks: testCase.expectedSourceLinks,\n actualResponse: testCase.output\n };\n\n await this.evaluationEngine.evaluateResponse(evaluationRequest, (result: EvaluationResult) => {\n console.log('📊 Evaluation result received:', result);\n \n this.updateTestCase(testCase.id, {\n evaluationResult: result\n });\n });\n }\n\n private async runAllTests() {\n this.isRunningAll = true;\n const tasks = [];\n for (const testCase of this.testCases) {\n if (!testCase.isRunning && testCase.question.trim()) {\n tasks.push(() => this.runSingleTest(testCase).catch(err => {\n console.error(`⚠️ Test case ${testCase.id} failed`, err);\n }))\n }\n }\n try {\n const fetcher = new RateLimitedFetcher(this.delayMs);\n await fetcher.runAll(tasks);\n } catch (err) {\n console.error('⚠️ Error running all tests:', err);\n }\n this.isRunningAll = false;\n }\n\n private generateId(): string {\n return uuidv4();\n }\n\n private handleFileSelect(): void {\n this.fileInput.click();\n }\n\n private async handleFileChange(event: Event): Promise<void> {\n const target = event.target as HTMLInputElement;\n const file = target.files?.[0];\n\n // Immediately clear the input value to allow for a new upload.\n target.value = '';\n\n if (!file) {\n this.error = 'No file selected.';\n return;\n }\n\n const isJsonType = file.type === 'application/json';\n const isJsonExtension = file.name.toLowerCase().endsWith('.json');\n if (!isJsonType && !isJsonExtension) {\n this.error = 'Invalid file type. Please select a JSON file.';\n return;\n }\n\n this.error = '';\n\n try {\n const content = await this.readFileAsync(file);\n const fileContent = JSON.parse(content);\n\n if (!Array.isArray(fileContent)) {\n throw new Error(\"Invalid JSON structure. Expected a JSON array.\");\n } \n const importedTestCases: TestCase[] = fileContent.map((item) => ({\n id: this.generateId(),\n question: item.question || '',\n expectedKeywords: Array.isArray(item.expectedKeywords) ? item.expectedKeywords : [],\n expectedSourceLinks: Array.isArray(item.expectedSourceLinks) ? item.expectedSourceLinks : [],\n isRunning: false\n }));\n this.testCases = importedTestCases; \n } catch (err) {\n this.error = err?.message || 'Error processing file. Please ensure it is a valid JSON array.';\n console.error('File Processing Error:', err);\n }\n }\n\n private readFileAsync(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as string);\n reader.onerror = () => reject(reader.error);\n reader.readAsText(file);\n });\n }\n\n private downloadFile(content: string, filename: string, mimeType: string) {\n const blob = new Blob([content], { type: mimeType });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n URL.revokeObjectURL(url);\n }\n\n private async handleExportTestSuite() {\n this.isExportingTestSuite = true;\n try {\n // Exporting only input data (question, expected keywords, expected source links)\n const exportData = this.testCases.map(testCase => ({\n id: testCase.id,\n question: testCase.question,\n expectedKeywords: testCase.expectedKeywords,\n expectedSourceLinks: testCase.expectedSourceLinks\n }));\n\n const jsonContent = JSON.stringify(exportData, null, 2);\n\n // Added a small delay to show the loading state\n await new Promise(resolve => setTimeout(resolve, 500));\n\n this.downloadFile(jsonContent, 'test-suite.json', 'application/json');\n } finally {\n this.isExportingTestSuite = false;\n }\n }\n\n private async handleExportTestResults() {\n this.isExportingTestResults = true;\n try {\n // Create CSV content with the required fields\n const csvRows = [];\n \n // Add header row\n const headers = [\n 'Question',\n 'Expected Keywords',\n 'Generated Keywords',\n 'Keywords Match',\n 'Expected Source Links',\n 'Generated Source Links',\n 'Source Links Match',\n 'Response Time (s)'\n ];\n csvRows.push(headers.join(','));\n \n // Add data rows\n this.testCases.forEach(testCase => {\n const expectedKeywords = testCase.expectedKeywords.join('; ');\n const expectedSourceLinks = testCase.expectedSourceLinks.join('; ');\n \n let generatedKeywords = '';\n let generatedSourceLinks = '';\n let keywordsMatch = '';\n let sourceLinksMatch = '';\n \n if (testCase.evaluationResult) {\n const foundKeywords = testCase.evaluationResult.keywordMatches\n .filter(match => match.found)\n .map(match => match.keyword);\n const foundSourceLinks = testCase.evaluationResult.sourceLinkMatches\n .filter(match => match.found)\n .map(match => match.link);\n \n generatedKeywords = foundKeywords.join('; ');\n generatedSourceLinks = foundSourceLinks.join('; ');\n \n // Calculate match percentages\n const keywordMatchCount = testCase.evaluationResult.keywordMatches.filter(m => m.found).length;\n const totalKeywords = testCase.evaluationResult.keywordMatches.length;\n const sourceLinkMatchCount = testCase.evaluationResult.sourceLinkMatches.filter(m => m.found).length;\n const totalSourceLinks = testCase.evaluationResult.sourceLinkMatches.length;\n \n keywordsMatch = totalKeywords > 0 ? `${keywordMatchCount}/${totalKeywords}` : 'N/A';\n sourceLinksMatch = totalSourceLinks > 0 ? `${sourceLinkMatchCount}/${totalSourceLinks}` : 'N/A';\n }\n \n const responseTime = testCase.responseTime ? (testCase.responseTime / 1000).toFixed(3) : 'N/A';\n \n const row = [\n this.escapeCsvField(testCase.question),\n this.escapeCsvField(expectedKeywords),\n this.escapeCsvField(generatedKeywords),\n keywordsMatch,\n this.escapeCsvField(expectedSourceLinks),\n this.escapeCsvField(generatedSourceLinks), \n sourceLinksMatch,\n responseTime\n ];\n \n csvRows.push(row.join(','));\n });\n \n const csvContent = csvRows.join('\\n');\n \n // Added a small delay to show the loading state\n await new Promise(resolve => setTimeout(resolve, 500));\n \n this.downloadFile(csvContent, 'test-results.csv', 'text/csv');\n } finally {\n this.isExportingTestResults = false;\n }\n }\n\n private escapeCsvField(field: string): string {\n if (field.includes(',') || field.includes('\"') || field.includes('\\n')) {\n return `\"${field.replace(/\"/g, '\"\"')}\"`;\n }\n return field;\n }\n\n render() {\n return (\n <div class=\"test-runner-container\">\n <header class=\"test-runner-header\">\n <div class=\"header-left\">\n <input\n class=\"hidden\"\n type=\"file\"\n ref={(el) => (this.fileInput = el as HTMLInputElement)}\n onChange={(e) => this.handleFileChange(e)}\n accept=\".json,application/json\"\n />\n <button class=\"btn btn-secondary\" onClick={() => this.handleFileSelect()}>\n <span class=\"icon\">↑</span>\n Import Test Suite\n </button>\n <button\n class=\"btn btn-secondary\"\n onClick={() => this.handleExportTestSuite()}\n disabled={this.isExportingTestSuite}\n >\n <span class=\"icon\">\n {this.isExportingTestSuite ? '⏳' : '↓'}\n </span>\n {this.isExportingTestSuite ? 'Exporting...' : 'Export Test Suite'}\n </button>\n </div>\n \n <div class=\"header-right\">\n <button class=\"btn btn-secondary\">\n <span class=\"icon\">⚙️</span>\n Prompt Editor\n </button>\n <button \n class=\"btn btn-secondary\"\n onClick={() => this.handleExportTestResults()}\n disabled={this.isExportingTestResults}\n >\n <span class=\"icon\">\n {this.isExportingTestResults ? '⏳' : '↓'}\n </span>\n {this.isExportingTestResults ? 'Exporting...' : 'Export Test Results'}\n </button>\n <button \n class=\"btn btn-primary\" \n onClick={() => this.runAllTests()}\n disabled={this.isRunningAll}\n >\n {this.isRunningAll ? 'Running...' : 'Run All'}\n </button>\n </div>\n </header>\n <ErrorMessage\n message={this.error}\n onClear={() => (this.error = '')}\n />\n <div class=\"test-runner-content\">\n <div class=\"column-headers\">\n <div class=\"column-header\">Input</div>\n <div class=\"column-header\">Output</div>\n <div class=\"column-header\">Evaluation</div>\n <div class=\"column-header\">Actions</div>\n </div>\n\n <div class=\"test-cases\">\n {this.testCases.map((testCase) => (\n <div class=\"test-case-row\" key={testCase.id}>\n <div class=\"input-column\">\n <div class=\"input-group\">\n <label>Question</label>\n <textarea\n value={testCase.question}\n onInput={(e) => this.updateTestCase(testCase.id, { \n question: (e.target as HTMLTextAreaElement).value \n })}\n placeholder=\"Enter your question here...\"\n rows={3}\n ></textarea>\n </div>\n \n <div class=\"keywords-group\">\n <label>Expected keywords</label>\n <div class=\"tags-container\">\n {testCase.expectedKeywords.map((keyword, index) => (\n <span class=\"tag\" key={index}>\n {keyword}\n <button \n class=\"tag-remove\" \n onClick={() => this.removeKeyword(testCase.id, index)}\n >×</button>\n </span>\n ))}\n <input\n type=\"text\"\n placeholder=\"New item...\"\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n this.addKeyword(testCase.id, (e.target as HTMLInputElement).value);\n (e.target as HTMLInputElement).value = '';\n }\n }}\n />\n </div>\n </div>\n \n <div class=\"links-group\">\n <label>Expected source links</label>\n <div class=\"links-container\">\n {testCase.expectedSourceLinks.map((link, index) => (\n <div class=\"link-item\" key={index}>\n <a href={link} target=\"_blank\" rel=\"noopener noreferrer\">{link}</a>\n <button \n class=\"link-remove\" \n onClick={() => this.removeSourceLink(testCase.id, index)}\n >×</button>\n </div>\n ))}\n <input\n type=\"url\"\n placeholder=\"New item...\"\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n this.addSourceLink(testCase.id, (e.target as HTMLInputElement).value);\n (e.target as HTMLInputElement).value = '';\n }\n }}\n />\n </div>\n </div>\n </div>\n\n <div class=\"output-column\">\n {testCase.output ? (\n <div class=\"output-content\">\n {testCase.output}\n </div>\n ) : (\n <div class=\"output-placeholder\">\n {testCase.isRunning ? 'Running...' : ''}\n </div>\n )}\n </div>\n\n <div class=\"evaluation-column\">\n {testCase.evaluationResult ? (\n <div class=\"evaluation-result\">\n <div class={`evaluation-status ${testCase.evaluationResult.passed ? 'passed' : 'failed'}`}>\n {testCase.evaluationResult.passed ? '✅ PASSED' : '❌ FAILED'}\n </div>\n <div class=\"evaluation-details\">\n Keywords: {testCase.evaluationResult.keywordMatches.filter(m => m.found).length}/{testCase.evaluationResult.keywordMatches.length} found\n </div>\n </div>\n ) : (\n <div class=\"evaluation-placeholder\">\n {testCase.isRunning ? 'Evaluating...' : ''}\n </div>\n )}\n </div>\n\n <div class=\"actions-column\">\n <button \n class=\"btn btn-icon btn-run\"\n onClick={() => this.runSingleTest(testCase)}\n disabled={testCase.isRunning || !testCase.question.trim()}\n title={!testCase.question.trim() ? \"Enter a question first\" : \"Run this test\"}\n >\n {testCase.isRunning ? '⏳' : '▶️'}\n </button>\n <button \n class=\"btn btn-icon btn-delete\"\n onClick={() => this.deleteTestCase(testCase.id)}\n title=\"Delete this test\"\n >\n 🗑️\n </button>\n </div>\n </div>\n ))}\n </div>\n\n <div class=\"add-test-case\">\n <button class=\"btn btn-outline\" onClick={() => this.addNewTestCase()}>\n + Add Question\n </button>\n </div>\n </div>\n </div>\n );\n }\n}"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/global/env.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,OAAO;IACZ,MAAM,CAAC,GAAG,GAAG;QACX,OAAO,EAAE,oBAAoB;KAC9B,CAAC;AACJ,CAAC","sourcesContent":["declare global {\n interface Window {\n env: {\n API_KEY: string;\n };\n }\n}\n\nexport default function () {\n window.env = {\n API_KEY: '__GEMINI_API_KEY__'\n };\n}"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export class RateLimitedFetcher {
|
|
2
|
+
queue = [];
|
|
3
|
+
delay; // delay in milliseconds
|
|
4
|
+
intervalId;
|
|
5
|
+
constructor(delayMs) {
|
|
6
|
+
this.delay = delayMs;
|
|
7
|
+
}
|
|
8
|
+
startQueue() {
|
|
9
|
+
if (this.intervalId)
|
|
10
|
+
return;
|
|
11
|
+
this.intervalId = setInterval(() => {
|
|
12
|
+
const task = this.queue.shift();
|
|
13
|
+
if (task)
|
|
14
|
+
task();
|
|
15
|
+
if (this.queue.length === 0) {
|
|
16
|
+
this.stop();
|
|
17
|
+
}
|
|
18
|
+
}, this.delay);
|
|
19
|
+
}
|
|
20
|
+
schedule(task) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
this.queue.push(() => {
|
|
23
|
+
task().then(resolve).catch(reject);
|
|
24
|
+
});
|
|
25
|
+
this.startQueue();
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
stop() {
|
|
29
|
+
if (this.intervalId) {
|
|
30
|
+
clearInterval(this.intervalId);
|
|
31
|
+
this.intervalId = undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async runAll(tasks) {
|
|
35
|
+
const promises = tasks.map(task => this.schedule(task));
|
|
36
|
+
return Promise.all(promises);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=rate-limited-fetcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limited-fetcher.js","sourceRoot":"","sources":["../../../src/lib/rate-limited-fetcher/rate-limited-fetcher.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,kBAAkB;IACrB,KAAK,GAAmB,EAAE,CAAC;IAC3B,KAAK,CAAS,CAAC,wBAAwB;IACvC,UAAU,CAAO;IAEzB,YAAY,OAAe;QACzB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC;IACvB,CAAC;IAEO,UAAU;QAChB,IAAI,IAAI,CAAC,UAAU;YAAE,OAAO;QAC5B,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;YACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YAChC,IAAI,IAAI;gBAAE,IAAI,EAAE,CAAC;YACjB,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,CAAC;QACH,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACjB,CAAC;IAEM,QAAQ,CAAI,IAAsB;QACvC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE;gBACnB,IAAI,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YACrC,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,CAAC,CAAC,CAAC;IACL,CAAC;IAEM,IAAI;QACT,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC;QAC9B,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,MAAM,CAAI,KAA8B;QACnD,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QACxD,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;CACF","sourcesContent":["export class RateLimitedFetcher {\n private queue: (() => void)[] = [];\n private delay: number; // delay in milliseconds\n private intervalId?: any;\n\n constructor(delayMs: number) {\n this.delay = delayMs;\n }\n\n private startQueue() {\n if (this.intervalId) return;\n this.intervalId = setInterval(() => {\n const task = this.queue.shift();\n if (task) task();\n if (this.queue.length === 0) {\n this.stop();\n }\n }, this.delay);\n }\n\n public schedule<T>(task: () => Promise<T>): Promise<T> {\n return new Promise((resolve, reject) => {\n this.queue.push(() => {\n task().then(resolve).catch(reject);\n });\n this.startQueue(); \n });\n }\n\n public stop() {\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = undefined;\n }\n }\n\n public async runAll<T>(tasks: Array<() => Promise<T>>): Promise<T[]> {\n const promises = tasks.map(task => this.schedule(task));\n return Promise.all(promises);\n }\n}\n"]}
|