Files
dailyou/lib/core/llm/prompt_builder.dart
stefwill ea412d6fe9 feat: implement background LLM pattern analysis on Insights screen
Adds a prompt builder that serialises 7-day mood/activity data, wires
InsightNotifier to call the on-device LLM directly (no user interaction),
caches results by prompt hash, and renders the analysis as a passive card.
Includes loading, empty (<2 entries), and error states with a force-refresh button.
2026-04-26 14:37:37 +10:00

57 lines
2.1 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import '../database/daos/mood_dao.dart';
abstract class PromptBuilder {
static String buildWeeklyPrompt(List<MoodEntryWithActivities> entries) {
final lines = entries.map(_entryLine).join('\n');
return '''
You are a personal wellbeing assistant analysing a private mood journal.
Analyse the following data and identify 23 patterns or correlations across mood, sleep, energy, positivity, and self-worth.
End with one specific, actionable suggestion. Be concise (46 sentences total). Do not greet the user.
$lines''';
}
static String _entryLine(MoodEntryWithActivities e) {
final dt = e.entry.timestamp;
final date =
'${dt.year}-${dt.month.toString().padLeft(2, '0')}-${dt.day.toString().padLeft(2, '0')}';
final time =
'${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}';
final parts = <String>[
'$date $time',
'Mood ${e.entry.moodLevel}/5',
];
if (e.entry.sleepMinutes != null) {
final h = e.entry.sleepMinutes! ~/ 60;
final m = (e.entry.sleepMinutes! % 60).toString().padLeft(2, '0');
parts.add('Sleep ${h}h$m');
}
if (e.entry.energyLevel != null) {
parts.add('Energy ${_scale(e.entry.energyLevel!, _energyLabels)}');
}
if (e.entry.positivityLevel != null) {
parts.add('Positivity ${_scale(e.entry.positivityLevel!, _positivityLabels)}');
}
if (e.entry.selfWorthLevel != null) {
parts.add('Self-worth ${_scale(e.entry.selfWorthLevel!, _selfWorthLabels)}');
}
if (e.activities.isNotEmpty) {
parts.add('Activities: ${e.activities.map((a) => a.name).join(', ')}');
}
if (e.entry.note != null && e.entry.note!.isNotEmpty) {
parts.add('Note: ${e.entry.note}');
}
return parts.join(' | ');
}
static String _scale(int level, List<String> labels) =>
labels[(level - 1).clamp(0, labels.length - 1)];
static const _energyLabels = ['very low', 'low', 'ok', 'high', 'very high'];
static const _positivityLabels = ['very negative', 'negative', 'neutral', 'positive', 'very positive'];
static const _selfWorthLabels = ['very low', 'low', 'moderate', 'high', 'very high'];
}