Get and build prompt from local JSON file

Here we map our AI actions to the prompt from the JSON file
to be able to use them.
This commit is contained in:
Théo Poizat
2026-01-29 16:27:37 +01:00
committed by Dat H. Pham
parent 11fd808080
commit 04696eecd7
9 changed files with 449 additions and 75 deletions
+30
View File
@@ -0,0 +1,30 @@
{
"prompts": [
{
"name": "test-prompt",
"messages": [
{
"role": "system",
"content": "You are a test assistant."
},
{
"role": "user",
"content": "INSTRUCTION:\nTest instruction.\n\nTEXT:\n{{input}}"
}
]
},
{
"name": "test-prompt-with-task",
"messages": [
{
"role": "system",
"content": "You are a test assistant with task."
},
{
"role": "user",
"content": "INSTRUCTION:\n{{task}}\n\nTEXT:\n{{input}}"
}
]
}
]
}
@@ -0,0 +1,167 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:scribe/scribe/ai/domain/model/prompt_data.dart';
import 'package:scribe/scribe/ai/data/model/ai_message.dart';
void main() {
group('PromptData', () {
test('fromJson should parse prompts correctly', () {
// Arrange
final jsonData = {
"prompts": [
{
"name": "test-prompt-1",
"messages": [
{
"role": "system",
"content": "System message 1"
},
{
"role": "user",
"content": "User message 1"
}
]
},
{
"name": "test-prompt-2",
"messages": [
{
"role": "system",
"content": "System message 2"
},
{
"role": "user",
"content": "User message 2"
}
]
}
]
};
// Act
final promptData = PromptData.fromJson(jsonData);
// Assert
expect(promptData.prompts.length, 2);
expect(promptData.prompts.first.name, 'test-prompt-1');
expect(promptData.prompts.last.name, 'test-prompt-2');
expect(promptData.prompts.first.messages.length, 2);
expect(promptData.prompts.last.messages.length, 2);
});
test('fromJson should handle empty prompts list', () {
// Arrange
final jsonData = {
"prompts": []
};
// Act
final promptData = PromptData.fromJson(jsonData);
// Assert
expect(promptData.prompts.length, 0);
});
});
group('Prompt', () {
test('fromJson should parse prompt correctly', () {
// Arrange
final jsonData = {
"name": "test-prompt",
"messages": [
{
"role": "system",
"content": "System message"
},
{
"role": "user",
"content": "User message with {{input}} placeholder"
}
]
};
// Act
final prompt = Prompt.fromJson(jsonData);
// Assert
expect(prompt.name, 'test-prompt');
expect(prompt.messages.length, 2);
expect(prompt.messages.first.role, 'system');
expect(prompt.messages.first.content, 'System message');
expect(prompt.messages.last.role, 'user');
expect(prompt.messages.last.content, 'User message with {{input}} placeholder');
});
test('buildPrompt should replace input placeholder correctly', () {
// Arrange
final messages = [
const AIMessage(role: 'system', content: 'System message'),
const AIMessage(role: 'user', content: 'User message with {{input}} placeholder')
];
final prompt = Prompt(name: 'test-prompt', messages: messages);
// Act
final result = prompt.buildPrompt('test input value');
// Assert
expect(result.length, 2);
expect(result.first.role, 'system');
expect(result.first.content, 'System message');
expect(result.last.role, 'user');
expect(result.last.content, 'User message with test input value placeholder');
});
test('buildPrompt should replace task placeholder when provided', () {
// Arrange
final messages = [
const AIMessage(role: 'system', content: 'System message'),
const AIMessage(role: 'user', content: 'Task: {{task}}, Input: {{input}}')
];
final prompt = Prompt(name: 'test-prompt', messages: messages);
// Act
final result = prompt.buildPrompt('test input value', task: 'test task value');
// Assert
expect(result.length, 2);
expect(result.first.role, 'system');
expect(result.first.content, 'System message');
expect(result.last.role, 'user');
expect(result.last.content, 'Task: test task value, Input: test input value');
});
test('buildPrompt should not replace task placeholder when not provided', () {
// Arrange
final messages = [
const AIMessage(role: 'system', content: 'System message'),
const AIMessage(role: 'user', content: 'Task: {{task}}, Input: {{input}}')
];
final prompt = Prompt(name: 'test-prompt', messages: messages);
// Act
final result = prompt.buildPrompt('test input value');
// Assert
expect(result.length, 2);
expect(result.first.role, 'system');
expect(result.first.content, 'System message');
expect(result.last.role, 'user');
expect(result.last.content, 'Task: {{task}}, Input: test input value');
});
test('buildPrompt should handle messages without placeholders', () {
// Arrange
final messages = [
const AIMessage(role: 'system', content: 'System message'),
const AIMessage(role: 'user', content: 'User message without placeholders')
];
final prompt = Prompt(name: 'test-prompt', messages: messages);
// Act
final result = prompt.buildPrompt('test input', task: 'test task');
// Assert
expect(result.length, 2);
expect(result.last.content, 'User message without placeholders');
});
});
}
@@ -0,0 +1,101 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:scribe/scribe/ai/domain/service/prompt_service.dart';
import 'package:scribe/scribe/ai/domain/model/prompt_data.dart';
import 'package:scribe/scribe/ai/data/model/ai_message.dart';
void main() {
setUpAll(() {
TestWidgetsFlutterBinding.ensureInitialized();
});
group('PromptService', () {
test('PromptService should be singleton', () {
// Act
final service1 = PromptService();
final service2 = PromptService();
// Assert
expect(service1, same(service2));
});
test('buildPromptByName should build prompt with input text', () async {
// Arrange
final service = PromptService();
// Act - this will use the real prompts.json file
final messages = await service.buildPromptByName('change-tone-casual', 'Hello, how are you?');
// Assert
expect(messages.length, 2);
expect(messages.first.role, 'system');
expect(messages.last.role, 'user');
expect(messages.last.content, contains('Hello, how are you?'));
});
test('buildPromptByName should build prompt with input text and task', () async {
// Arrange
final service = PromptService();
// Act - this will use the real prompts.json file
final messages = await service.buildPromptByName('custom-prompt-mail', 'Hello, how are you?', task: 'Make it more casual');
// Assert
expect(messages.length, 2);
expect(messages.first.role, 'system');
expect(messages.last.role, 'user');
expect(messages.last.content, contains('Hello, how are you?'));
expect(messages.last.content, contains('Make it more casual'));
});
});
group('PromptService getPromptByName', () {
test('getPromptByName should return correct prompt from data', () async {
// Arrange
final promptData = PromptData(
prompts: [
Prompt(
name: 'test-prompt',
messages: [
const AIMessage(role: 'system', content: 'System message'),
const AIMessage(role: 'user', content: 'User message with {{input}}')
]
)
]
);
// Act
final prompt = promptData.prompts.firstWhere(
(prompt) => prompt.name == 'test-prompt',
orElse: () => throw Exception('Prompt not found: test-prompt'),
);
// Assert
expect(prompt.name, 'test-prompt');
expect(prompt.messages.length, 2);
});
test('getPromptByName should throw exception for non-existent prompt', () async {
// Arrange
final promptData = PromptData(
prompts: [
Prompt(
name: 'test-prompt',
messages: [
const AIMessage(role: 'system', content: 'System message'),
const AIMessage(role: 'user', content: 'User message')
]
)
]
);
// Act & Assert
expect(
() => promptData.prompts.firstWhere(
(prompt) => prompt.name == 'non-existent-prompt',
orElse: () => throw Exception('Prompt not found: non-existent-prompt'),
),
throwsException,
);
});
});
}