feat: interactive oracle session chat and dynamic draw additional d10 cards for context refinement

This commit is contained in:
Alma Alexyz
2026-08-31 15:31:51 +05:00
parent 95c64ce1cd
commit 10c3fee083
3 changed files with 734 additions and 224 deletions
+55
View File
@@ -52,6 +52,61 @@ class AiOracleService {
return _generateOfflineSessionInterpretation(words, question);
}
/// Multi-turn chat with the Oracle inside a session, supporting context refinement and additional words
Future<String> chatWithOracle({
required OracleSession session,
required String userMessage,
SessionWord? newlyAddedWord,
}) async {
final wordsNarrative = StringBuffer();
for (int i = 0; i < session.words.length; i++) {
final w = session.words[i];
wordsNarrative.writeln('${i + 1}. Знак #${w.formattedSessionNumber} «${w.word.toUpperCase()}» (${w.partOfSpeech}): ${w.symbolicMeaning}');
}
final chatHistoryBuf = StringBuffer();
for (final msg in session.messages.take(8)) {
if (msg.sender == 'user') {
chatHistoryBuf.writeln('Вопрошающий: ${msg.text}');
} else if (msg.sender == 'oracle') {
chatHistoryBuf.writeln('Оракул: ${msg.text}');
}
}
final addedWordContext = newlyAddedWord != null
? '\n[ВАЖНО: Вопрошающий только что вытянул ДОПОЛНИТЕЛЬНЫЙ ЗНАК для уточнения деталей: #${newlyAddedWord.formattedSessionNumber} «${newlyAddedWord.word.toUpperCase()}» (${newlyAddedWord.symbolicMeaning}). Обязательно вплети этот новый знак в ответ!]\n'
: '';
final prompt = '''Ты — Священный Оракул Клеромантии 999. Ты ведешь глубокий диалог с вопрошающим в рамках текущей сессии гадания.
Контекст сессии:
Вопрос: «${session.question ?? 'Общий расклад'}»
Выпавшие знаки жребия:
$wordsNarrative
$addedWordContext
Предыдущий диалог:
$chatHistoryBuf
Новая реплика/вопрос вопрошающего:
«$userMessage»
Инструкция:
Ответь на реплику вопрошающего прямо, мудро и ёмко (2-4 предложения).
Опирайся на символизм выпавших знаков (особенно дополнительных, если они появились). Раскрой скрытые детали и дай практичный духовный совет.''';
try {
final res = await _callPollinationsOpenAi(prompt);
if (res != null && res.trim().isNotEmpty) return res.trim();
} catch (_) {}
try {
final res = await _callPollinationsDirect(prompt);
if (res != null && res.trim().isNotEmpty) return res.trim();
} catch (_) {}
return 'Оракул внимает вашим словам. ${newlyAddedWord != null ? "Дополнительный знак «${newlyAddedWord.word}» уточняет скрытые детали: ${newlyAddedWord.symbolicMeaning}. " : ""}Слушайте голос интуиции и действуйте в согласии с открывшейся истиной.';
}
/// Single word legacy interpretation helper
Future<String> interpret({
required WordItem word,