llm-testrunner-components 1.0.5 → 1.0.7

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.
Files changed (71) hide show
  1. package/README.md +3 -48
  2. package/dist/cjs/index.cjs.js +24610 -60
  3. package/dist/cjs/index.cjs.js.map +1 -1
  4. package/dist/collection/components/llm-test-runner/llm-test-runner.css +14 -2
  5. package/dist/collection/components/llm-test-runner/llm-test-runner.js +38 -9
  6. package/dist/collection/components/llm-test-runner/llm-test-runner.js.map +1 -1
  7. package/dist/collection/lib/evaluation/constant.js +4 -0
  8. package/dist/collection/lib/evaluation/constant.js.map +1 -0
  9. package/dist/collection/lib/evaluation/constants/evaluation-approach.js +6 -0
  10. package/dist/collection/lib/evaluation/constants/evaluation-approach.js.map +1 -0
  11. package/dist/collection/lib/evaluation/evaluation-engine.js +28 -44
  12. package/dist/collection/lib/evaluation/evaluation-engine.js.map +1 -1
  13. package/dist/collection/lib/evaluation/evaluators/exact/exact.js +51 -0
  14. package/dist/collection/lib/evaluation/evaluators/exact/exact.js.map +1 -0
  15. package/dist/collection/lib/evaluation/evaluators/rouge1-evaluator.js +82 -0
  16. package/dist/collection/lib/evaluation/evaluators/rouge1-evaluator.js.map +1 -0
  17. package/dist/collection/lib/evaluation/evaluators/rougeL-evaluator.js +73 -0
  18. package/dist/collection/lib/evaluation/evaluators/rougeL-evaluator.js.map +1 -0
  19. package/dist/collection/lib/evaluation/evaluators/rougeL-evaluator.test.js +313 -0
  20. package/dist/collection/lib/evaluation/evaluators/rougeL-evaluator.test.js.map +1 -0
  21. package/dist/collection/lib/evaluation/evaluators/semantic/SemanticEvaluator.js +63 -0
  22. package/dist/collection/lib/evaluation/evaluators/semantic/SemanticEvaluator.js.map +1 -0
  23. package/dist/collection/lib/evaluation/evaluators/semantic/evaluate-keywords.js +56 -0
  24. package/dist/collection/lib/evaluation/evaluators/semantic/evaluate-keywords.js.map +1 -0
  25. package/dist/collection/lib/evaluation/evaluators/semantic/index.js +7 -0
  26. package/dist/collection/lib/evaluation/evaluators/semantic/index.js.map +1 -0
  27. package/dist/collection/lib/evaluation/evaluators/semantic/model-loader.js +15 -0
  28. package/dist/collection/lib/evaluation/evaluators/semantic/model-loader.js.map +1 -0
  29. package/dist/collection/lib/evaluation/evaluators/semantic/similarity-utils.js +16 -0
  30. package/dist/collection/lib/evaluation/evaluators/semantic/similarity-utils.js.map +1 -0
  31. package/dist/collection/lib/evaluation/evaluators/semantic/tests/evaluate-keywords.test.js +65 -0
  32. package/dist/collection/lib/evaluation/evaluators/semantic/tests/evaluate-keywords.test.js.map +1 -0
  33. package/dist/collection/lib/evaluation/evaluators/semantic/text-utils.js +5 -0
  34. package/dist/collection/lib/evaluation/evaluators/semantic/text-utils.js.map +1 -0
  35. package/dist/collection/lib/evaluation/rouge1-evaluator.test.js +118 -0
  36. package/dist/collection/lib/evaluation/rouge1-evaluator.test.js.map +1 -0
  37. package/dist/collection/lib/evaluation/types.js.map +1 -1
  38. package/dist/collection/lib/rate-limited-fetcher/rate-limited-fetcher.js +6 -6
  39. package/dist/collection/lib/rate-limited-fetcher/rate-limited-fetcher.js.map +1 -1
  40. package/dist/collection/types/evaluation.js +6 -0
  41. package/dist/collection/types/evaluation.js.map +1 -0
  42. package/dist/components/index.js +1 -1
  43. package/dist/components/llm-test-runner.js +1 -1
  44. package/dist/components/p-lpWX1sHl.js +26319 -0
  45. package/dist/components/p-lpWX1sHl.js.map +1 -0
  46. package/dist/esm/index.js +24609 -60
  47. package/dist/esm/index.js.map +1 -1
  48. package/dist/llm-testrunner/index.esm.js +6 -1
  49. package/dist/llm-testrunner/index.esm.js.map +1 -1
  50. package/dist/types/components/llm-test-runner/llm-test-runner.d.ts +4 -1
  51. package/dist/types/lib/evaluation/constant.d.ts +3 -0
  52. package/dist/types/lib/evaluation/constants/evaluation-approach.d.ts +4 -0
  53. package/dist/types/lib/evaluation/evaluation-engine.d.ts +0 -4
  54. package/dist/types/lib/evaluation/evaluators/exact/exact.d.ts +3 -0
  55. package/dist/types/lib/evaluation/evaluators/rouge1-evaluator.d.ts +17 -0
  56. package/dist/types/lib/evaluation/evaluators/rougeL-evaluator.d.ts +2 -0
  57. package/dist/types/lib/evaluation/evaluators/rougeL-evaluator.test.d.ts +1 -0
  58. package/dist/types/lib/evaluation/evaluators/semantic/SemanticEvaluator.d.ts +6 -0
  59. package/dist/types/lib/evaluation/evaluators/semantic/evaluate-keywords.d.ts +7 -0
  60. package/dist/types/lib/evaluation/evaluators/semantic/index.d.ts +2 -0
  61. package/dist/types/lib/evaluation/evaluators/semantic/model-loader.d.ts +1 -0
  62. package/dist/types/lib/evaluation/evaluators/semantic/similarity-utils.d.ts +1 -0
  63. package/dist/types/lib/evaluation/evaluators/semantic/tests/evaluate-keywords.test.d.ts +1 -0
  64. package/dist/types/lib/evaluation/evaluators/semantic/text-utils.d.ts +1 -0
  65. package/dist/types/lib/evaluation/rouge1-evaluator.test.d.ts +1 -0
  66. package/dist/types/lib/evaluation/types.d.ts +19 -0
  67. package/dist/types/lib/rate-limited-fetcher/rate-limited-fetcher.d.ts +1 -1
  68. package/dist/types/types/evaluation.d.ts +10 -0
  69. package/package.json +10 -6
  70. package/dist/components/p-CYUbsbxt.js +0 -1770
  71. package/dist/components/p-CYUbsbxt.js.map +0 -1
@@ -285,11 +285,11 @@
285
285
  }
286
286
 
287
287
  /* Keywords and Links */
288
- .keywords-group, .links-group {
288
+ .keywords-group, .links-group, .approach{
289
289
  margin-bottom: 16px;
290
290
  }
291
291
 
292
- .keywords-group label, .links-group label {
292
+ .keywords-group label, .links-group label, .approach label {
293
293
  display: block;
294
294
  margin-bottom: 8px;
295
295
  font-weight: 500;
@@ -335,6 +335,18 @@
335
335
  background: rgba(30, 64, 175, 0.1);
336
336
  }
337
337
 
338
+ .approach-select select {
339
+ border: 1px solid #cfd2da;
340
+ border-radius: 6px;
341
+ font-size: 14px;
342
+ font-weight: 500;
343
+ padding: 4px 8px;
344
+ outline: none;
345
+ background: transparent;
346
+ width: 145px;
347
+ color: #616975;
348
+ }
349
+
338
350
  .link-item {
339
351
  display: flex;
340
352
  align-items: center;
@@ -3,6 +3,7 @@ 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
5
  import { RateLimitedFetcher } from "../../lib/rate-limited-fetcher/rate-limited-fetcher";
6
+ import { EvaluationApproachValues } from "../../types/evaluation";
6
7
  export class LLMTestRunner {
7
8
  llmRequest;
8
9
  delayMs = 500;
@@ -12,6 +13,9 @@ export class LLMTestRunner {
12
13
  question: '',
13
14
  expectedKeywords: [],
14
15
  expectedSourceLinks: [],
16
+ evaluationParameters: {
17
+ approach: 'exact',
18
+ },
15
19
  isRunning: false
16
20
  }
17
21
  ];
@@ -34,6 +38,9 @@ export class LLMTestRunner {
34
38
  question: '',
35
39
  expectedKeywords: [],
36
40
  expectedSourceLinks: [],
41
+ evaluationParameters: {
42
+ approach: 'exact'
43
+ },
37
44
  isRunning: false
38
45
  };
39
46
  this.testCases = [...this.testCases, newTestCase];
@@ -42,14 +49,12 @@ export class LLMTestRunner {
42
49
  this.testCases = this.testCases.map(tc => tc.id === id ? { ...tc, ...updates } : tc);
43
50
  }
44
51
  async runSingleTest(testCase) {
45
- console.log('🚀 Starting test for question:', testCase.question);
46
52
  const startTime = Date.now();
47
53
  this.updateTestCase(testCase.id, { isRunning: true });
48
54
  return new Promise((resolve, reject) => {
49
55
  this.llmRequest.emit({
50
56
  prompt: testCase.question,
51
57
  resolve: async (aiResponse) => {
52
- console.log('✅ AI call completed for test case:', testCase.id);
53
58
  const endTime = Date.now();
54
59
  const responseTime = endTime - startTime;
55
60
  this.updateTestCase(testCase.id, {
@@ -66,7 +71,6 @@ export class LLMTestRunner {
66
71
  resolve();
67
72
  },
68
73
  reject: (error) => {
69
- console.error('❌ Error in runSingleTest:', error);
70
74
  this.updateTestCase(testCase.id, {
71
75
  isRunning: false,
72
76
  output: null,
@@ -80,6 +84,16 @@ export class LLMTestRunner {
80
84
  deleteTestCase(id) {
81
85
  this.testCases = this.testCases.filter(tc => tc.id !== id);
82
86
  }
87
+ updateApproach(testCase, approach) {
88
+ if (testCase) {
89
+ this.updateTestCase(testCase.id, {
90
+ evaluationParameters: {
91
+ ...testCase.evaluationParameters,
92
+ approach: approach
93
+ }
94
+ });
95
+ }
96
+ }
83
97
  addKeyword(testCaseId, keyword) {
84
98
  if (keyword.trim()) {
85
99
  const testCase = this.testCases.find(tc => tc.id === testCaseId);
@@ -124,7 +138,8 @@ export class LLMTestRunner {
124
138
  question: testCase.question,
125
139
  expectedKeywords: testCase.expectedKeywords,
126
140
  expectedSourceLinks: testCase.expectedSourceLinks,
127
- actualResponse: testCase.output
141
+ actualResponse: testCase.output,
142
+ evaluationParameters: testCase.evaluationParameters
128
143
  };
129
144
  await this.evaluationEngine.evaluateResponse(evaluationRequest, (result) => {
130
145
  console.log('📊 Evaluation result received:', result);
@@ -185,6 +200,10 @@ export class LLMTestRunner {
185
200
  question: item.question || '',
186
201
  expectedKeywords: Array.isArray(item.expectedKeywords) ? item.expectedKeywords : [],
187
202
  expectedSourceLinks: Array.isArray(item.expectedSourceLinks) ? item.expectedSourceLinks : [],
203
+ evaluationParameters: {
204
+ approach: item.evaluationParameters && item.evaluationParameters.approach || 'exact',
205
+ threshold: item.evaluationParameters && item.evaluationParameters.threshold || 0.6
206
+ },
188
207
  isRunning: false
189
208
  }));
190
209
  this.testCases = importedTestCases;
@@ -221,7 +240,8 @@ export class LLMTestRunner {
221
240
  id: testCase.id,
222
241
  question: testCase.question,
223
242
  expectedKeywords: testCase.expectedKeywords,
224
- expectedSourceLinks: testCase.expectedSourceLinks
243
+ expectedSourceLinks: testCase.expectedSourceLinks,
244
+ evaluationParameters: testCase.evaluationParameters
225
245
  }));
226
246
  const jsonContent = JSON.stringify(exportData, null, 2);
227
247
  // Added a small delay to show the loading state
@@ -246,13 +266,17 @@ export class LLMTestRunner {
246
266
  'Expected Source Links',
247
267
  'Generated Source Links',
248
268
  'Source Links Match',
249
- 'Response Time (s)'
269
+ 'Response Time (s)',
270
+ 'Evaluation Approach',
271
+ 'Evaluation Score'
250
272
  ];
251
273
  csvRows.push(headers.join(','));
252
274
  // Add data rows
253
275
  this.testCases.forEach(testCase => {
254
276
  const expectedKeywords = testCase.expectedKeywords.join('; ');
255
277
  const expectedSourceLinks = testCase.expectedSourceLinks.join('; ');
278
+ const evaluationApproach = testCase.evaluationParameters.approach;
279
+ const evaluationScore = testCase.evaluationResult.evaluationApproachResult.score.toString();
256
280
  let generatedKeywords = '';
257
281
  let generatedSourceLinks = '';
258
282
  let keywordsMatch = '';
@@ -283,7 +307,9 @@ export class LLMTestRunner {
283
307
  this.escapeCsvField(expectedSourceLinks),
284
308
  this.escapeCsvField(generatedSourceLinks),
285
309
  sourceLinksMatch,
286
- responseTime
310
+ responseTime,
311
+ this.escapeCsvField(evaluationApproach),
312
+ this.escapeCsvField(evaluationScore)
287
313
  ];
288
314
  csvRows.push(row.join(','));
289
315
  });
@@ -303,7 +329,7 @@ export class LLMTestRunner {
303
329
  return field;
304
330
  }
305
331
  render() {
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, {
332
+ return (h("div", { key: 'a59114cb83a90bb07fa78afb28a18cb40d5624ef', class: "test-runner-container" }, h("header", { key: '8e1551c323d4a8d7bfdaa84bef13e9d034d4d065', class: "test-runner-header" }, h("div", { key: 'dfe283bf22f9df6ce3b14f638ef3ba45faff6536', class: "header-left" }, h("input", { key: '3f6ca4fb9eacc165ba5397bd49fa663efebb9508', class: "hidden", type: "file", ref: (el) => (this.fileInput = el), onChange: (e) => this.handleFileChange(e), accept: ".json,application/json" }), h("button", { key: '40c1a863ec7b85962becd622fd8cd7e2f0eb0440', class: "btn btn-secondary", onClick: () => this.handleFileSelect() }, h("span", { key: 'e819012901ba2202b0265ddef350e821914d5073', class: "icon" }, "\u2191"), "Import Test Suite"), h("button", { key: '0e9494d7b686e6d8da2202a04b5b511c09639904', class: "btn btn-secondary", onClick: () => this.handleExportTestSuite(), disabled: this.isExportingTestSuite }, h("span", { key: 'c77d0cb7ebf9199405c2a904b8a5937b2d46372f', class: "icon" }, this.isExportingTestSuite ? '⏳' : '↓'), this.isExportingTestSuite ? 'Exporting...' : 'Export Test Suite')), h("div", { key: '9c3118aaf41f8fac20e6d55c75e267aac5c0844d', class: "header-right" }, h("button", { key: '32477c9e22de69df13dc524f635c5862fd7c0647', class: "btn btn-secondary" }, h("span", { key: '63c4cfaf53ba37c32b81e83df6bf64e25d85039f', class: "icon" }, "\u2699\uFE0F"), "Prompt Editor"), h("button", { key: '2bc01b34151a9b5fdff5106d2425c0317cf7024d', class: "btn btn-secondary", onClick: () => this.handleExportTestResults(), disabled: this.isExportingTestResults }, h("span", { key: '92c3519359d6bad5698f0e8972eca495160e7667', class: "icon" }, this.isExportingTestResults ? '⏳' : '↓'), this.isExportingTestResults ? 'Exporting...' : 'Export Test Results'), h("button", { key: 'c65b94d6914eaa7d33e1bea2bb79c534366583b9', class: "btn btn-primary", onClick: () => this.runAllTests(), disabled: this.isRunningAll }, this.isRunningAll ? 'Running...' : 'Run All'))), h(ErrorMessage, { key: '1fb3988f1d7f247f9ef04c67002dff905f18e4a9', message: this.error, onClear: () => (this.error = '') }), h("div", { key: '90567bc83c6b0113109750462dd34cc0f3f8cb60', class: "test-runner-content" }, h("div", { key: '6999fdf60ea5a11c1e98605d487e9bb2d1d6f35b', class: "column-headers" }, h("div", { key: '5e065157361f979463e2e563a8c7172d15e54a16', class: "column-header" }, "Input"), h("div", { key: 'af914643821e6a06fa0659ed5cfd16bcff0d8bbd', class: "column-header" }, "Output"), h("div", { key: '9a9df10bdfa6db8f2e62236ef74ce19e8c052de7', class: "column-header" }, "Evaluation"), h("div", { key: 'abcdbe7d71d8f7cfd40bf604c57c558d2fd25723', class: "column-header" }, "Actions")), h("div", { key: 'b62f3673f6b78229b4febd555fbebdb804906dc3', 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, {
307
333
  question: e.target.value
308
334
  }), 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) => {
309
335
  if (e.key === 'Enter') {
@@ -315,7 +341,10 @@ export class LLMTestRunner {
315
341
  this.addSourceLink(testCase.id, e.target.value);
316
342
  e.target.value = '';
317
343
  }
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")))));
344
+ } }))), h("div", { class: "approach" }, h("label", null, "Evaluation"), h("div", { class: 'approach-select' }, h("select", { onInput: (e) => {
345
+ const target = e.target;
346
+ this.updateApproach(testCase, target.value);
347
+ } }, EvaluationApproachValues.map((approach) => (h("option", { value: approach, key: approach, selected: testCase.evaluationParameters?.approach === approach }, approach))))))), 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: '7d9e0a31b425cbe4d81038aafe7a912d45ccd11c', class: "add-test-case" }, h("button", { key: '1a42d72e7ffaf0f8943fe82d7d202267d78d47c6', class: "btn btn-outline", onClick: () => this.addNewTestCase() }, "+ Add Question")))));
319
348
  }
320
349
  static get is() { return "llm-test-runner"; }
321
350
  static get encapsulation() { return "shadow"; }
@@ -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, 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}"]}
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';\nimport { EvaluationParameters, EvaluationApproach, EvaluationApproachValues } from '../../types/evaluation';\n\nexport interface TestCase {\n id: string;\n question: string;\n expectedKeywords: string[];\n expectedSourceLinks: string[];\n evaluationParameters?: EvaluationParameters;\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: Error | unknown) => 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 evaluationParameters: {\n approach: 'exact',\n },\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 evaluationParameters: {\n approach: 'exact'\n },\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 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 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: Error | unknown) => {\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 updateApproach(testCase: TestCase, approach: EvaluationApproach) {\n if (testCase) {\n this.updateTestCase(testCase.id, {\n evaluationParameters: {\n ...testCase.evaluationParameters,\n approach: approach\n }\n });\n }\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 evaluationParameters: testCase.evaluationParameters\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 evaluationParameters: {\n approach: item.evaluationParameters && item.evaluationParameters.approach || 'exact',\n threshold: item.evaluationParameters && item.evaluationParameters.threshold || 0.6\n },\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 evaluationParameters: testCase.evaluationParameters\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 'Evaluation Approach',\n 'Evaluation Score'\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 const evaluationApproach = testCase.evaluationParameters.approach;\n const evaluationScore = testCase.evaluationResult.evaluationApproachResult.score.toString();\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 this.escapeCsvField(evaluationApproach),\n this.escapeCsvField(evaluationScore)\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\n <div class=\"approach\">\n <label>Evaluation</label>\n <div class='approach-select'>\n <select\n onInput={(e: Event) => {\n const target = e.target as HTMLSelectElement;\n this.updateApproach(testCase, target.value as EvaluationApproach);\n }}\n >\n {EvaluationApproachValues.map((approach) => (\n <option\n value={approach}\n key={approach}\n selected={testCase.evaluationParameters?.approach === approach}\n >\n {approach}\n </option>\n ))}\n </select>\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}\n"]}
@@ -0,0 +1,4 @@
1
+ export const DEFAULT_ROUGE_PASS_SCORE = 0.7;
2
+ export const DEFAULT_SEMANTIC_PASS_SCORE = 0.7;
3
+ export const ROUGE = 'rouge';
4
+ //# sourceMappingURL=constant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constant.js","sourceRoot":"","sources":["../../../src/lib/evaluation/constant.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAC5C,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAC/C,MAAM,CAAC,MAAM,KAAK,GAAG,OAAO,CAAC","sourcesContent":["export const DEFAULT_ROUGE_PASS_SCORE = 0.7;\nexport const DEFAULT_SEMANTIC_PASS_SCORE = 0.7;\nexport const ROUGE = 'rouge';"]}
@@ -0,0 +1,6 @@
1
+ export var EvaluationApproach;
2
+ (function (EvaluationApproach) {
3
+ EvaluationApproach["EXACT"] = "exact";
4
+ EvaluationApproach["SEMANTIC"] = "semantic";
5
+ })(EvaluationApproach || (EvaluationApproach = {}));
6
+ //# sourceMappingURL=evaluation-approach.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluation-approach.js","sourceRoot":"","sources":["../../../../src/lib/evaluation/constants/evaluation-approach.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,kBAGT;AAHH,WAAY,kBAAkB;IAC1B,qCAAe,CAAA;IACf,2CAAqB,CAAA;AACvB,CAAC,EAHS,kBAAkB,KAAlB,kBAAkB,QAG3B","sourcesContent":["export enum EvaluationApproach {\n EXACT = 'exact',\n SEMANTIC = 'semantic',\n }"]}
@@ -1,12 +1,28 @@
1
+ import { performEvaluation } from "./evaluators/exact/exact";
2
+ import { performRouge1Evaluation } from "./evaluators/rouge1-evaluator";
3
+ import { performSemanticEvaluation } from "./evaluators/semantic/index";
1
4
  export class LLMEvaluationEngine {
2
- constructor() { }
3
5
  async evaluateResponse(request, callback) {
4
6
  try {
5
- console.log('🔍 Starting evaluation for test case:', request.testCaseId);
6
- const result = await this.performEvaluation(request);
7
- console.log('Evaluation completed for test case:', request.testCaseId);
8
- console.log('Result:', result);
9
- callback(result);
7
+ const approach = request.evaluationParameters.approach;
8
+ switch (approach) {
9
+ case 'exact':
10
+ const exactResult = await performEvaluation(request);
11
+ callback(exactResult);
12
+ break;
13
+ case 'rouge':
14
+ const rougeResult = await performRouge1Evaluation(request);
15
+ callback(rougeResult);
16
+ break;
17
+ case 'semantic':
18
+ const semanticResult = await performSemanticEvaluation(request);
19
+ callback(semanticResult);
20
+ break;
21
+ default:
22
+ console.warn(`Unknown matching approach: ${request.evaluationParameters.approach}, falling back to exact matching`);
23
+ const fallbackResult = await performEvaluation(request);
24
+ callback(fallbackResult);
25
+ }
10
26
  }
11
27
  catch (error) {
12
28
  console.error('Evaluation failed:', error);
@@ -15,47 +31,15 @@ export class LLMEvaluationEngine {
15
31
  passed: false,
16
32
  keywordMatches: [],
17
33
  sourceLinkMatches: [],
18
- timestamp: new Date().toISOString()
34
+ timestamp: new Date().toISOString(),
35
+ evaluationParameters: request.evaluationParameters,
36
+ evaluationApproachResult: {
37
+ score: 0,
38
+ approachUsed: 'exact',
39
+ },
19
40
  };
20
41
  callback(errorResult);
21
42
  }
22
43
  }
23
- async performEvaluation(request) {
24
- const { testCaseId, expectedKeywords, expectedSourceLinks, actualResponse } = request;
25
- const keywordMatches = this.evaluateKeywords(expectedKeywords, actualResponse);
26
- const sourceLinkMatches = this.evaluateSourceLinks(expectedSourceLinks, actualResponse);
27
- // Test passes only if ALL expected keywords and source links are found
28
- const totalItems = keywordMatches.length + sourceLinkMatches.length;
29
- const foundItems = keywordMatches.filter(m => m.found).length + sourceLinkMatches.filter(m => m.found).length;
30
- const passed = foundItems === totalItems;
31
- return {
32
- testCaseId,
33
- passed,
34
- keywordMatches,
35
- sourceLinkMatches,
36
- timestamp: new Date().toISOString()
37
- };
38
- }
39
- evaluateKeywords(expectedKeywords, actualResponse) {
40
- // Case-insensitive keyword matching
41
- const response = actualResponse.toLowerCase();
42
- return expectedKeywords.map(keyword => {
43
- const keywordToMatch = keyword.toLowerCase();
44
- const found = response.includes(keywordToMatch);
45
- return {
46
- keyword,
47
- found
48
- };
49
- });
50
- }
51
- evaluateSourceLinks(expectedSourceLinks, actualResponse) {
52
- return expectedSourceLinks.map(link => {
53
- const found = actualResponse.includes(link);
54
- return {
55
- link,
56
- found
57
- };
58
- });
59
- }
60
44
  }
61
45
  //# sourceMappingURL=evaluation-engine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"evaluation-engine.js","sourceRoot":"","sources":["../../../src/lib/evaluation/evaluation-engine.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,mBAAmB;IAC9B,gBAAgB,CAAC;IAEjB,KAAK,CAAC,gBAAgB,CACpB,OAA0B,EAC1B,QAA4B;QAE5B,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,uCAAuC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAEzE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;YAErD,OAAO,CAAC,GAAG,CAAC,qCAAqC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YACvE,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAE/B,QAAQ,CAAC,MAAM,CAAC,CAAC;QAEnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;YAE3C,MAAM,WAAW,GAAqB;gBACpC,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,MAAM,EAAE,KAAK;gBACb,cAAc,EAAE,EAAE;gBAClB,iBAAiB,EAAE,EAAE;gBACrB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;YAEF,QAAQ,CAAC,WAAW,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,OAA0B;QACxD,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;QAEtF,MAAM,cAAc,GAAG,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;QAC/E,MAAM,iBAAiB,GAAG,IAAI,CAAC,mBAAmB,CAAC,mBAAmB,EAAE,cAAc,CAAC,CAAC;QAExF,uEAAuE;QACvE,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC;QACpE,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;QAC9G,MAAM,MAAM,GAAG,UAAU,KAAK,UAAU,CAAC;QAEzC,OAAO;YACL,UAAU;YACV,MAAM;YACN,cAAc;YACd,iBAAiB;YACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;IACJ,CAAC;IAEO,gBAAgB,CAAC,gBAA0B,EAAE,cAAsB;QACzE,oCAAoC;QACpC,MAAM,QAAQ,GAAG,cAAc,CAAC,WAAW,EAAE,CAAC;QAE9C,OAAO,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;YACpC,MAAM,cAAc,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;YAC7C,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;YAEhD,OAAO;gBACL,OAAO;gBACP,KAAK;aACN,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,mBAAmB,CAAC,mBAA6B,EAAE,cAAsB;QAC/E,OAAO,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;YACpC,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAE5C,OAAO;gBACL,IAAI;gBACJ,KAAK;aACN,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;CAIF","sourcesContent":["import {\n EvaluationRequest,\n EvaluationResult,\n KeywordMatch,\n SourceLinkMatch,\n EvaluationCallback\n} from './types';\n\nexport class LLMEvaluationEngine {\n constructor() { }\n\n async evaluateResponse(\n request: EvaluationRequest,\n callback: EvaluationCallback\n ): Promise<void> {\n try {\n console.log('🔍 Starting evaluation for test case:', request.testCaseId);\n\n const result = await this.performEvaluation(request);\n\n console.log('Evaluation completed for test case:', request.testCaseId);\n console.log('Result:', result);\n\n callback(result);\n\n } catch (error) {\n console.error('Evaluation failed:', error);\n\n const errorResult: EvaluationResult = {\n testCaseId: request.testCaseId,\n passed: false,\n keywordMatches: [],\n sourceLinkMatches: [],\n timestamp: new Date().toISOString()\n };\n\n callback(errorResult);\n }\n }\n\n private async performEvaluation(request: EvaluationRequest): Promise<EvaluationResult> {\n const { testCaseId, expectedKeywords, expectedSourceLinks, actualResponse } = request;\n\n const keywordMatches = this.evaluateKeywords(expectedKeywords, actualResponse);\n const sourceLinkMatches = this.evaluateSourceLinks(expectedSourceLinks, actualResponse);\n\n // Test passes only if ALL expected keywords and source links are found\n const totalItems = keywordMatches.length + sourceLinkMatches.length;\n const foundItems = keywordMatches.filter(m => m.found).length + sourceLinkMatches.filter(m => m.found).length;\n const passed = foundItems === totalItems;\n\n return {\n testCaseId,\n passed,\n keywordMatches,\n sourceLinkMatches,\n timestamp: new Date().toISOString()\n };\n }\n\n private evaluateKeywords(expectedKeywords: string[], actualResponse: string): KeywordMatch[] {\n // Case-insensitive keyword matching\n const response = actualResponse.toLowerCase();\n\n return expectedKeywords.map(keyword => {\n const keywordToMatch = keyword.toLowerCase();\n const found = response.includes(keywordToMatch);\n\n return {\n keyword,\n found\n };\n });\n }\n\n private evaluateSourceLinks(expectedSourceLinks: string[], actualResponse: string): SourceLinkMatch[] {\n return expectedSourceLinks.map(link => {\n const found = actualResponse.includes(link);\n\n return {\n link,\n found\n };\n });\n }\n\n\n\n}\n\n"]}
1
+ {"version":3,"file":"evaluation-engine.js","sourceRoot":"","sources":["../../../src/lib/evaluation/evaluation-engine.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAExE,MAAM,OAAO,mBAAmB;IAE9B,KAAK,CAAC,gBAAgB,CAAC,OAA0B,EAAE,QAA4B;QAC7E,IAAI,CAAC;YACH,MAAM,QAAQ,GAAuB,OAAO,CAAC,oBAAoB,CAAC,QAAQ,CAAC;YAC3E,QAAQ,QAAQ,EAAE,CAAC;gBACjB,KAAK,OAAO;oBACV,MAAM,WAAW,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,CAAC;oBACrD,QAAQ,CAAC,WAAW,CAAC,CAAC;oBACtB,MAAM;gBAER,KAAK,OAAO;oBACV,MAAM,WAAW,GAAG,MAAM,uBAAuB,CAAC,OAAO,CAAC,CAAC;oBAC3D,QAAQ,CAAC,WAAW,CAAC,CAAC;oBACtB,MAAM;gBAER,KAAK,UAAU;oBACb,MAAM,cAAc,GAAG,MAAM,yBAAyB,CAAC,OAAO,CAAC,CAAC;oBAChE,QAAQ,CAAC,cAAc,CAAC,CAAC;oBACzB,MAAM;gBAER;oBACE,OAAO,CAAC,IAAI,CAAC,8BAA8B,OAAO,CAAC,oBAAoB,CAAC,QAAQ,kCAAkC,CAAC,CAAC;oBACpH,MAAM,cAAc,GAAG,MAAM,iBAAiB,CAAC,OAAO,CAAC,CAAC;oBACxD,QAAQ,CAAC,cAAc,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,KAAK,CAAC,CAAC;YAE3C,MAAM,WAAW,GAAqB;gBACpC,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,MAAM,EAAE,KAAK;gBACb,cAAc,EAAE,EAAE;gBAClB,iBAAiB,EAAE,EAAE;gBACrB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,oBAAoB,EAAE,OAAO,CAAC,oBAAoB;gBAClD,wBAAwB,EAAE;oBACxB,KAAK,EAAE,CAAC;oBACR,YAAY,EAAE,OAAO;iBACtB;aACF,CAAC;YAEF,QAAQ,CAAC,WAAW,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;CACF","sourcesContent":["import { EvaluationRequest, EvaluationResult, EvaluationCallback } from './types';\nimport { performEvaluation } from './evaluators/exact/exact';\nimport { EvaluationApproach } from '../../types/evaluation';\nimport { performRouge1Evaluation } from './evaluators/rouge1-evaluator';\nimport { performSemanticEvaluation } from './evaluators/semantic/index';\n\nexport class LLMEvaluationEngine {\n\n async evaluateResponse(request: EvaluationRequest, callback: EvaluationCallback): Promise<void> {\n try {\n const approach: EvaluationApproach = request.evaluationParameters.approach;\n switch (approach) {\n case 'exact':\n const exactResult = await performEvaluation(request);\n callback(exactResult);\n break;\n\n case 'rouge':\n const rougeResult = await performRouge1Evaluation(request);\n callback(rougeResult);\n break;\n\n case 'semantic':\n const semanticResult = await performSemanticEvaluation(request);\n callback(semanticResult);\n break;\n\n default:\n console.warn(`Unknown matching approach: ${request.evaluationParameters.approach}, falling back to exact matching`);\n const fallbackResult = await performEvaluation(request);\n callback(fallbackResult);\n }\n } catch (error) {\n console.error('Evaluation failed:', error);\n\n const errorResult: EvaluationResult = {\n testCaseId: request.testCaseId,\n passed: false,\n keywordMatches: [],\n sourceLinkMatches: [],\n timestamp: new Date().toISOString(),\n evaluationParameters: request.evaluationParameters,\n evaluationApproachResult: {\n score: 0,\n approachUsed: 'exact',\n },\n };\n\n callback(errorResult);\n }\n }\n}\n"]}
@@ -0,0 +1,51 @@
1
+ export async function performEvaluation(request) {
2
+ const { testCaseId, expectedKeywords, expectedSourceLinks, actualResponse } = request;
3
+ const keywordMatches = evaluateKeywords(expectedKeywords, actualResponse);
4
+ const sourceLinkMatches = evaluateSourceLinks(expectedSourceLinks, actualResponse);
5
+ // Test passes only if ALL expected keywords and source links are found
6
+ const totalItems = keywordMatches.length + sourceLinkMatches.length;
7
+ const foundItems = keywordMatches.filter(m => m.found).length + sourceLinkMatches.filter(m => m.found).length;
8
+ const passed = foundItems === totalItems;
9
+ return {
10
+ testCaseId,
11
+ passed,
12
+ keywordMatches,
13
+ sourceLinkMatches,
14
+ timestamp: new Date().toISOString(),
15
+ evaluationParameters: request.evaluationParameters,
16
+ evaluationApproachResult: {
17
+ score: foundItems / totalItems,
18
+ approachUsed: 'exact'
19
+ }
20
+ };
21
+ }
22
+ function evaluateKeywords(expectedKeywords, actualResponse) {
23
+ // Case-insensitive keyword matching
24
+ const response = actualResponse.toLowerCase();
25
+ return expectedKeywords.map(keyword => {
26
+ const keywordToMatch = keyword.toLowerCase();
27
+ const found = response.includes(keywordToMatch);
28
+ return {
29
+ keyword,
30
+ found,
31
+ evaluationApproachResult: {
32
+ score: found ? 1.0 : 0.0,
33
+ approachUsed: 'exact'
34
+ }
35
+ };
36
+ });
37
+ }
38
+ export function evaluateSourceLinks(expectedSourceLinks, actualResponse) {
39
+ return expectedSourceLinks.map(link => {
40
+ const found = actualResponse.includes(link);
41
+ return {
42
+ link,
43
+ found,
44
+ evaluationApproachResult: {
45
+ score: found ? 1.0 : 0.0,
46
+ approachUsed: 'exact'
47
+ }
48
+ };
49
+ });
50
+ }
51
+ //# sourceMappingURL=exact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exact.js","sourceRoot":"","sources":["../../../../../src/lib/evaluation/evaluators/exact/exact.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAA0B;IAE1B,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;IAEtF,MAAM,cAAc,GAAG,gBAAgB,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;IAC1E,MAAM,iBAAiB,GAAG,mBAAmB,CAAC,mBAAmB,EAAE,cAAc,CAAC,CAAC;IAEnF,uEAAuE;IACvE,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC;IACpE,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC;IAC9G,MAAM,MAAM,GAAG,UAAU,KAAK,UAAU,CAAC;IAEzC,OAAO;QACL,UAAU;QACV,MAAM;QACN,cAAc;QACd,iBAAiB;QACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,oBAAoB,EAAE,OAAO,CAAC,oBAAoB;QAClD,wBAAwB,EAAE;YACxB,KAAK,EAAE,UAAU,GAAG,UAAU;YAC9B,YAAY,EAAE,OAAO;SACtB;KACF,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,gBAA0B,EAAE,cAAsB;IAC1E,oCAAoC;IACpC,MAAM,QAAQ,GAAG,cAAc,CAAC,WAAW,EAAE,CAAC;IAE9C,OAAO,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE;QACpC,MAAM,cAAc,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;QAC7C,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QAEhD,OAAO;YACL,OAAO;YACP,KAAK;YACL,wBAAwB,EAAE;gBACxB,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;gBACxB,YAAY,EAAE,OAAO;aACtB;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,mBAA6B,EAAE,cAAsB;IACvF,OAAO,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;QACpC,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAE5C,OAAO;YACL,IAAI;YACJ,KAAK;YACL,wBAAwB,EAAE;gBACxB,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;gBACxB,YAAY,EAAE,OAAO;aACtB;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import {\n EvaluationRequest,\n EvaluationResult,\n KeywordMatch,\n SourceLinkMatch,\n} from '../../types';\n\nexport async function performEvaluation(\n request: EvaluationRequest\n): Promise<EvaluationResult> {\n const { testCaseId, expectedKeywords, expectedSourceLinks, actualResponse } = request;\n\n const keywordMatches = evaluateKeywords(expectedKeywords, actualResponse);\n const sourceLinkMatches = evaluateSourceLinks(expectedSourceLinks, actualResponse);\n\n // Test passes only if ALL expected keywords and source links are found\n const totalItems = keywordMatches.length + sourceLinkMatches.length;\n const foundItems = keywordMatches.filter(m => m.found).length + sourceLinkMatches.filter(m => m.found).length;\n const passed = foundItems === totalItems;\n\n return {\n testCaseId,\n passed,\n keywordMatches,\n sourceLinkMatches,\n timestamp: new Date().toISOString(),\n evaluationParameters: request.evaluationParameters,\n evaluationApproachResult: {\n score: foundItems / totalItems,\n approachUsed: 'exact'\n }\n };\n}\n\nfunction evaluateKeywords(expectedKeywords: string[], actualResponse: string): KeywordMatch[] {\n // Case-insensitive keyword matching\n const response = actualResponse.toLowerCase();\n\n return expectedKeywords.map(keyword => {\n const keywordToMatch = keyword.toLowerCase();\n const found = response.includes(keywordToMatch);\n\n return {\n keyword,\n found,\n evaluationApproachResult: {\n score: found ? 1.0 : 0.0,\n approachUsed: 'exact'\n }\n };\n });\n}\n\nexport function evaluateSourceLinks(expectedSourceLinks: string[], actualResponse: string): SourceLinkMatch[] {\n return expectedSourceLinks.map(link => {\n const found = actualResponse.includes(link);\n\n return {\n link,\n found,\n evaluationApproachResult: {\n score: found ? 1.0 : 0.0,\n approachUsed: 'exact'\n }\n };\n });\n}"]}