Use json_serializable and const to improve AI data model

This commit is contained in:
Théo Poizat
2025-12-08 14:59:42 +01:00
committed by Dat H. Pham
parent 8b17fcdc54
commit f19993bb30
5 changed files with 49 additions and 37 deletions
@@ -1,6 +1,8 @@
import 'ai_message.dart'; import 'ai_message.dart';
class AIAPIRequest { class AIAPIRequest {
static const String _defaultModel = 'gpt-oss-120b';
final List<AIMessage> messages; final List<AIMessage> messages;
const AIAPIRequest({ const AIAPIRequest({
@@ -9,7 +11,7 @@ class AIAPIRequest {
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return { return {
'model': 'gpt-oss-120b', 'model': _defaultModel,
'messages': messages.map((m) => m.toJson()).toList(), 'messages': messages.map((m) => m.toJson()).toList(),
}; };
} }
@@ -1,31 +1,44 @@
import 'package:json_annotation/json_annotation.dart';
part 'ai_api_response.g.dart';
@JsonSerializable()
class AIApiResponse { class AIApiResponse {
final String content; final List<Choice> choices;
const AIApiResponse({ const AIApiResponse({
required this.choices
});
factory AIApiResponse.fromJson(Map<String, dynamic> json) => _$AIApiResponseFromJson(json);
Map<String, dynamic> toJson() => _$AIApiResponseToJson(this);
String? get content => choices.isNotEmpty ? choices[0].message.content : null;
}
@JsonSerializable()
class Choice {
final Message message;
const Choice({
required this.message
});
factory Choice.fromJson(Map<String, dynamic> json) => _$ChoiceFromJson(json);
Map<String, dynamic> toJson() => _$ChoiceToJson(this);
}
@JsonSerializable()
class Message {
final String content;
const Message({
required this.content required this.content
}); });
static AIApiResponse? parse(Map<String, dynamic> json) { factory Message.fromJson(Map<String, dynamic> json) => _$MessageFromJson(json);
final choices = json['choices'] as List<dynamic>?;
if (choices == null || choices.isEmpty) {
return null;
}
final firstChoice = choices[0] as Map<String, dynamic>?; Map<String, dynamic> toJson() => _$MessageToJson(this);
if (firstChoice == null) {
return null;
}
final message = firstChoice['message'] as Map<String, dynamic>?;
if (message == null) {
return null;
}
final content = message['content'] as String?;
if (content == null || content.isEmpty) {
return null;
}
return AIApiResponse(content: content);
}
} }
@@ -1,3 +1,8 @@
import 'package:json_annotation/json_annotation.dart';
part 'ai_message.g.dart';
@JsonSerializable()
class AIMessage { class AIMessage {
final String role; final String role;
final String content; final String content;
@@ -7,10 +12,7 @@ class AIMessage {
required this.content, required this.content,
}); });
Map<String, dynamic> toJson() { factory AIMessage.fromJson(Map<String, dynamic> json) => _$AIMessageFromJson(json);
return {
'role': role, Map<String, dynamic> toJson() => _$AIMessageToJson(this);
'content': content,
};
}
} }
@@ -28,12 +28,7 @@ class AIApi {
); );
if (response.statusCode == 200) { if (response.statusCode == 200) {
final parsedResponse = AIApiResponse.parse(response.data); return AIApiResponse.fromJson(response.data);
if (parsedResponse != null) {
return parsedResponse;
} else {
throw Exception('Empty response from AI service');
}
} else { } else {
throw Exception('AI API returned status code: ${response.statusCode}'); throw Exception('AI API returned status code: ${response.statusCode}');
} }
@@ -1,5 +1,5 @@
class AIResponse { class AIResponse {
final String result; final String? result;
const AIResponse({required this.result}); const AIResponse({required this.result});