ca1eed5061
- Added `productName` field to `AdminAiWarning` to include product context in warnings - Updated `collectWarnings` to extract and include `rawName` as `productName` in AI trace warnings - Added `signals` field to `FlyerParseItem` type for detailed product signals - Enhanced Flutter admin panel to display product names in AI trace warnings - Added new `AdminAiTraceResponse` DTO for AI trace data structure
139 lines
4.4 KiB
Dart
139 lines
4.4 KiB
Dart
import 'admin_ai_trace.dart';
|
|
|
|
class AdminAiWarning {
|
|
final String code;
|
|
final String kind;
|
|
final String title;
|
|
final String message;
|
|
final String severity;
|
|
final String? location;
|
|
final int? itemIndex;
|
|
final String? productName;
|
|
|
|
const AdminAiWarning({
|
|
required this.code,
|
|
required this.kind,
|
|
required this.title,
|
|
required this.message,
|
|
required this.severity,
|
|
required this.location,
|
|
required this.itemIndex,
|
|
required this.productName,
|
|
});
|
|
|
|
factory AdminAiWarning.fromJson(Map<String, dynamic> json) {
|
|
return AdminAiWarning(
|
|
code: (json['code'] ?? '').toString(),
|
|
kind: (json['kind'] ?? '').toString(),
|
|
title: (json['title'] ?? '').toString(),
|
|
message: (json['message'] ?? '').toString(),
|
|
severity: (json['severity'] ?? '').toString(),
|
|
location: json['location']?.toString(),
|
|
itemIndex: (json['itemIndex'] as num?)?.toInt(),
|
|
productName: json['productName']?.toString(),
|
|
);
|
|
}
|
|
|
|
factory AdminAiWarning.fromLegacy(String value) {
|
|
final trimmed = value.trim();
|
|
final parts = trimmed.split(':');
|
|
final kind = parts.isNotEmpty ? parts.first : 'parse';
|
|
final code = parts.length > 1 ? parts.sublist(1).join(':') : trimmed;
|
|
return AdminAiWarning(
|
|
code: code,
|
|
kind: kind,
|
|
title: trimmed,
|
|
message: trimmed,
|
|
severity: 'warning',
|
|
location: null,
|
|
itemIndex: null,
|
|
productName: null,
|
|
);
|
|
}
|
|
}
|
|
|
|
class AdminAiTraceDetail {
|
|
final String id;
|
|
final AdminAiTraceSource source;
|
|
final AdminAiTraceStatus status;
|
|
final DateTime createdAt;
|
|
final int userId;
|
|
final String userLabel;
|
|
final int? sessionId;
|
|
final String? fileName;
|
|
final String? model;
|
|
final int? durationMs;
|
|
final int? retryCount;
|
|
final int? chunkCount;
|
|
final List<AdminAiWarning> warnings;
|
|
final List<String> legacyWarnings;
|
|
final String? error;
|
|
final String? prompt;
|
|
final String? rawOutput;
|
|
final Map<String, dynamic>? normalizedOutput;
|
|
final Map<String, dynamic> summary;
|
|
|
|
const AdminAiTraceDetail({
|
|
required this.id,
|
|
required this.source,
|
|
required this.status,
|
|
required this.createdAt,
|
|
required this.userId,
|
|
required this.userLabel,
|
|
required this.sessionId,
|
|
required this.fileName,
|
|
required this.model,
|
|
required this.durationMs,
|
|
required this.retryCount,
|
|
required this.chunkCount,
|
|
required this.warnings,
|
|
required this.legacyWarnings,
|
|
required this.error,
|
|
required this.prompt,
|
|
required this.rawOutput,
|
|
required this.normalizedOutput,
|
|
required this.summary,
|
|
});
|
|
|
|
factory AdminAiTraceDetail.fromJson(Map<String, dynamic> json) {
|
|
final warningsRaw = (json['warnings'] as List<dynamic>?) ?? const [];
|
|
final legacyWarningsRaw = (json['legacyWarnings'] as List<dynamic>?) ?? const [];
|
|
final normalizedOutputMap = json['normalizedOutput'] is Map
|
|
? Map<String, dynamic>.from(json['normalizedOutput'] as Map)
|
|
: null;
|
|
final summaryMap = json['summary'] is Map
|
|
? Map<String, dynamic>.from(json['summary'] as Map)
|
|
: const <String, dynamic>{};
|
|
|
|
return AdminAiTraceDetail(
|
|
id: (json['id'] ?? '').toString(),
|
|
source: AdminAiTraceSourceX.fromApi(json['source']?.toString()),
|
|
status: AdminAiTraceStatusX.fromApi(json['status']?.toString()),
|
|
createdAt: DateTime.tryParse((json['createdAt'] ?? '').toString()) ??
|
|
DateTime.fromMillisecondsSinceEpoch(0),
|
|
userId: (json['userId'] as num?)?.toInt() ?? 0,
|
|
userLabel: (json['userLabel'] ?? '').toString(),
|
|
sessionId: (json['sessionId'] as num?)?.toInt(),
|
|
fileName: json['fileName']?.toString(),
|
|
model: json['model']?.toString(),
|
|
durationMs: (json['durationMs'] as num?)?.toInt(),
|
|
retryCount: (json['retryCount'] as num?)?.toInt(),
|
|
chunkCount: (json['chunkCount'] as num?)?.toInt(),
|
|
warnings: warningsRaw
|
|
.map((entry) {
|
|
if (entry is Map) {
|
|
return AdminAiWarning.fromJson(Map<String, dynamic>.from(entry));
|
|
}
|
|
return AdminAiWarning.fromLegacy(entry.toString());
|
|
})
|
|
.toList(),
|
|
legacyWarnings: legacyWarningsRaw.map((entry) => entry.toString()).toList(),
|
|
error: json['error']?.toString(),
|
|
prompt: json['prompt']?.toString(),
|
|
rawOutput: json['rawOutput']?.toString(),
|
|
normalizedOutput: normalizedOutputMap,
|
|
summary: summaryMap,
|
|
);
|
|
}
|
|
}
|