feat(ai): enhance AI trace warnings and reason codes system
- Added structured warning system with `AdminAiWarning` type in backend and Flutter - Implemented detailed reason descriptors with `FlyerReasonDescriptor` for parse and match operations - Added `legacyWarnings` field to maintain backward compatibility - Enhanced AI trace service to collect and format warnings with item-level context - Updated flyer import services to include detailed reason descriptions in responses - Added Swedish diacritic preservation for cheese variants (Prästost, Herrgårdsost, Grevéost) - Implemented UTF-8 content validation for AI responses - Added new reason code definitions in `reason-codes.ts` - Updated Flutter UI to display structured warnings with severity indicators - Added error report generation and copy functionality in admin panel - Added comprehensive test coverage for new warning system and cheese normalization BREAKING CHANGE: AI trace warnings are now structured objects instead of simple strings
This commit is contained in:
@@ -86,7 +86,28 @@ void main() {
|
||||
durationMs: 1880,
|
||||
retryCount: 1,
|
||||
chunkCount: 3,
|
||||
warnings: const ['parse:low_confidence', 'match:no_match'],
|
||||
warnings: const [
|
||||
AdminAiWarning(
|
||||
code: 'low_confidence',
|
||||
kind: 'parse',
|
||||
title: 'Låg parsningskvalitet',
|
||||
message: 'Modellens säkerhet är låg, granska raden manuellt.',
|
||||
severity: 'warning',
|
||||
location: 'Steg: AI-parser',
|
||||
itemIndex: 5,
|
||||
),
|
||||
AdminAiWarning(
|
||||
code: 'no_match',
|
||||
kind: 'match',
|
||||
title: 'Ingen produktmatchning',
|
||||
message:
|
||||
'Vi kunde inte hitta någon befintlig produkt som matchar texten på flyern.',
|
||||
severity: 'warning',
|
||||
location: 'Steg: matchning mot dina produkter',
|
||||
itemIndex: 7,
|
||||
),
|
||||
],
|
||||
legacyWarnings: const ['parse:low_confidence', 'match:no_match'],
|
||||
error: null,
|
||||
prompt: 'Prompttext exempel',
|
||||
rawOutput: veryLargeOutput,
|
||||
@@ -198,8 +219,8 @@ void main() {
|
||||
|
||||
expect(find.text('Sammanfattning'), findsOneWidget);
|
||||
expect(find.text('Varningar (2)'), findsOneWidget);
|
||||
expect(find.text('parse:low_confidence'), findsOneWidget);
|
||||
expect(find.text('match:no_match'), findsOneWidget);
|
||||
expect(find.text('Låg parsningskvalitet'), findsOneWidget);
|
||||
expect(find.text('Ingen produktmatchning'), findsOneWidget);
|
||||
final detailScroll = find.byType(Scrollable).last;
|
||||
await tester.scrollUntilVisible(
|
||||
find.text('Model Output'),
|
||||
@@ -219,9 +240,11 @@ void main() {
|
||||
final copyPrompt = find.byTooltip('Kopiera');
|
||||
final copyOutput = find.byTooltip('Kopiera JSON');
|
||||
final copyWarnings = find.byTooltip('Kopiera alla varningar');
|
||||
final copyErrorReport = find.text('Kopiera felrapport');
|
||||
expect(copyPrompt, findsOneWidget);
|
||||
expect(copyOutput, findsOneWidget);
|
||||
expect(copyWarnings, findsOneWidget);
|
||||
expect(copyErrorReport, findsOneWidget);
|
||||
|
||||
await tester.tap(copyPrompt);
|
||||
await tester.pumpAndSettle();
|
||||
@@ -235,6 +258,10 @@ void main() {
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.takeException(), isNull);
|
||||
|
||||
await tester.tap(copyErrorReport);
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.takeException(), isNull);
|
||||
|
||||
addTearDown(() => tester.binding.setSurfaceSize(null));
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user