128 lines
4.3 KiB
Dart
128 lines
4.3 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:http/http.dart' as http;
|
|
import 'package:http/testing.dart';
|
|
import 'package:kouyu_english/core/ai_service.dart';
|
|
import 'package:kouyu_english/core/models.dart';
|
|
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
test(
|
|
'lexicon requests keep a stable system prefix and dynamic JSON last',
|
|
() async {
|
|
AiService.instance.setFallbackApiKey('test-key');
|
|
final captured = <List<dynamic>>[];
|
|
|
|
Future<void> request(String text) async {
|
|
await http.runWithClient(
|
|
() => AiService.instance.temporaryDefinition(
|
|
provider: AiProviderType.compatible,
|
|
endpoint: 'https://api.deepseek.com',
|
|
model: 'deepseek-flash',
|
|
text: text,
|
|
),
|
|
() => MockClient((request) async {
|
|
final body = jsonDecode(request.body) as Map<String, dynamic>;
|
|
captured.add(body['messages'] as List<dynamic>);
|
|
return http.Response(
|
|
jsonEncode({
|
|
'choices': [
|
|
{
|
|
'message': {'content': '{"definition":"测试"}'},
|
|
},
|
|
],
|
|
}),
|
|
200,
|
|
headers: {'content-type': 'application/json; charset=utf-8'},
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
|
|
await request('apple');
|
|
await request('airport');
|
|
|
|
expect(captured, hasLength(2));
|
|
expect(captured[0], hasLength(2));
|
|
expect(captured[0][0]['role'], 'system');
|
|
expect(captured[0][0]['content'], captured[1][0]['content']);
|
|
expect(captured[0][0]['content'], isNot(contains('apple')));
|
|
expect(jsonDecode(captured[0][1]['content'] as String), {
|
|
'text': 'apple',
|
|
});
|
|
expect(jsonDecode(captured[1][1]['content'] as String), {
|
|
'text': 'airport',
|
|
});
|
|
},
|
|
);
|
|
|
|
test(
|
|
'dialogue evaluation keeps learner data out of the cached prefix',
|
|
() async {
|
|
AiService.instance.setFallbackApiKey('test-key');
|
|
final captured = <List<dynamic>>[];
|
|
|
|
Future<void> request({
|
|
required String learnerText,
|
|
required String turnId,
|
|
}) async {
|
|
await http.runWithClient(
|
|
() => AiService.instance.checkDialogueIntervention(
|
|
provider: AiProviderType.compatible,
|
|
endpoint: 'https://api.deepseek.com',
|
|
model: 'deepseek-flash',
|
|
partnerLine: 'How are you?',
|
|
taskLabel: 'Say how you feel.',
|
|
learnerText: learnerText,
|
|
turnId: turnId,
|
|
),
|
|
() => MockClient((request) async {
|
|
final body = jsonDecode(request.body) as Map<String, dynamic>;
|
|
captured.add(body['messages'] as List<dynamic>);
|
|
return http.Response(
|
|
jsonEncode({
|
|
'choices': [
|
|
{
|
|
'message': {
|
|
'content': jsonEncode({
|
|
'schemaVersion': 'dialogue-intervention-2',
|
|
'turnId': turnId,
|
|
'accepted': true,
|
|
'goalSatisfied': true,
|
|
'verdict': 'accepted',
|
|
'reasonCode': 'goal-met',
|
|
'suggestion': null,
|
|
'explanation': '表达自然。',
|
|
}),
|
|
},
|
|
},
|
|
],
|
|
}),
|
|
200,
|
|
headers: {'content-type': 'application/json; charset=utf-8'},
|
|
);
|
|
}),
|
|
);
|
|
}
|
|
|
|
await request(learnerText: 'I am fine.', turnId: 'turn-1');
|
|
await request(learnerText: 'I feel tired.', turnId: 'turn-2');
|
|
|
|
final firstSystem = captured[0][0]['content'] as String;
|
|
final secondSystem = captured[1][0]['content'] as String;
|
|
expect(firstSystem, secondSystem);
|
|
expect(firstSystem, isNot(contains('I am fine.')));
|
|
expect(firstSystem, isNot(contains('turn-1')));
|
|
|
|
final firstInput = jsonDecode(captured[0][1]['content'] as String);
|
|
final secondInput = jsonDecode(captured[1][1]['content'] as String);
|
|
expect(firstInput['learnerText'], 'I am fine.');
|
|
expect(firstInput['turnId'], 'turn-1');
|
|
expect(secondInput['learnerText'], 'I feel tired.');
|
|
expect(secondInput['turnId'], 'turn-2');
|
|
},
|
|
);
|
|
}
|