perf: improve AI prompt cache reuse
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
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');
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user