import '../models/history_entry_model.dart'; import '../models/word_model.dart'; import '../g4f/g4f.dart'; class AiOracleService { static final AiOracleService _instance = AiOracleService._internal(); factory AiOracleService() => _instance; AiOracleService._internal(); final _client = G4FClient(); static const oracleSystemPrompt = '''Ты — Великий Оракул 999, древний архетипический разум. Твоя задача — толковать знаки судьбы (жребий). Твой стиль речи: глубокий, философский, лаконичный, без банальностей и воды, словно голос самой вечности. Ты не используешь современных или бытовых слов. Твои ответы строятся на символизме, психологии и скрытых смыслах. Ты не гадаешь на будущее, ты показываешь суть настоящего момента и внутренние силы человека.'''; List buildInterpretationMessages({ required List words, required String question, }) { return [ const Message(role: Role.system, content: oracleSystemPrompt), Message( role: Role.user, content: _buildMultiWordPrompt(question: question, words: words), ), ]; } /// Interprets a full multi-word session narrative (1 to 9 words) Future interpretSession({ required List words, required String question, }) async { if (words.isEmpty) return 'Нет знаков для трактовки.'; try { final g4fResult = await _client.chat.completions.create( model: G4FModels.gpt4o, messages: buildInterpretationMessages(words: words, question: question), ); if (g4fResult.trim().length > 20) { return g4fResult.trim(); } } catch (e) { print('G4F Error: $e'); } // High-Dimensional Deep Semantic Synthesizer (Instant offline fallback) return _synthesizeDeepSacredNarrative(words, question); } /// Multi-turn chat with the Oracle inside a session Future 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.category}): ${w.symbolicMeaning}'); } final prompt = '''Вопрошающий говорит тебе: «$userMessage» Контекст текущего сеанса судьбы: Вопрос вопрошающего: «${session.question ?? 'Вектор судьбы (нет вопроса)'}» Базовые знаки, которые выпали ранее: $wordsNarrative ${newlyAddedWord != null ? "Важно! Только что вопрошающий вытянул ДОПОЛНИТЕЛЬНЫЙ уточняющий знак: #${newlyAddedWord.formattedSessionNumber} «${newlyAddedWord.word.toUpperCase()}» (${newlyAddedWord.symbolicMeaning})." : ""} Ответь мудро, лаконично и метафорично от лица Оракула 999. Укажи, на что направляет его судьба. (не более 3-4 предложений).'''; final messages = [ const Message( role: Role.system, content: 'Ты — Великий Оракул 999. Твои ответы кратки, полны символизма и психологической глубины. Ты общаешься с человеком, который ищет ответов в знаках.' ), ]; // Pass previous session history context to the model for (final m in session.messages) { if (m.sender == 'oracle') { messages.add(Message(role: Role.assistant, content: m.text)); } else { messages.add(Message(role: Role.user, content: m.text)); } } messages.add(Message(role: Role.user, content: prompt)); try { final g4fResult = await _client.chat.completions.create( model: G4FModels.gpt4o, messages: messages, ); if (g4fResult.trim().length > 15) { return g4fResult.trim(); } } catch (_) {} return _synthesizeChatReply(session, userMessage, newlyAddedWord); } String _buildMultiWordPrompt({ required String question, required List words, }) { final qStr = question.trim().isNotEmpty ? 'Вопрос, с которым пришел вопрошающий: «$question»' : 'Вопрошающий пришел без конкретного вопроса. Прочитай его общую судьбоносную линию.'; final wordsStr = words .asMap() .entries .map((e) => 'Знак ${e.key + 1}: #${e.value.formattedSessionNumber} «${e.value.word.toUpperCase()}» (${e.value.category}). Смысл знака: ${e.value.symbolicMeaning}') .join('\n'); return '''$qStr Волею судьбы выпали следующие знаки жребия: $wordsStr Задача Оракула: 1. Свяжи эти знаки в единую цельную историю развития ситуации. Каждый знак перетекает в следующий. 2. Раскрой не очевидный, а скрытый внутренний урок. Что вопрошающий должен осознать? 3. Дай философский совет или вектор для действия. Ответь от лица Оракула 999 на русском языке (от 3 до 6 предложений). Избегай шаблонов и клише, говори образно и метафорично, но точно.'''; } String _synthesizeDeepSacredNarrative(List words, String question) { final sb = StringBuffer(); final first = words.first; final last = words.last; final hasQuestion = question.trim().isNotEmpty; if (hasQuestion) { sb.write('Относительно вашего вопроса «${question.trim()}» '); } else { sb.write('В открывшемся жребии судьбы '); } if (words.length == 1) { sb.write('проявился доминирующий знак #${first.formattedSessionNumber} «${first.word.toUpperCase()}» (${first.category}). '); sb.write('${first.symbolicMeaning} '); sb.write('Знак указывает на необходимость предельной ясности: держите фокус на главном и отсекайте всё наносное.'); return sb.toString(); } if (words.length == 2) { final second = words[1]; sb.write('проявляется полярность двух сил: исходного импульса #${first.formattedSessionNumber} «${first.word.toUpperCase()}» и вектора #${second.formattedSessionNumber} «${second.word.toUpperCase()}». '); sb.write('С одной стороны, ${first.symbolicMeaning.toLowerCase()} С другой — ${second.symbolicMeaning.toLowerCase()} '); sb.write('Разрешение ситуации лежит в точке осознанного баланса между ними: не противьтесь первому, но направляйте силу в русло второго.'); return sb.toString(); } sb.write('разворачивается цепь из ${words.length} взаимосвязанных архетипов. '); sb.write('Исток ситуации заложен в знаке #${first.formattedSessionNumber} «${first.word.toUpperCase()}» — ${first.symbolicMeaning.toLowerCase()} '); if (words.length > 2) { final middleWords = words.sublist(1, words.length - 1); final midNames = middleWords.map((w) => '«${w.word.toUpperCase()}» (#${w.formattedSessionNumber})').join(' и '); final midMeanings = middleWords.map((w) => w.symbolicMeaning).join(' '); sb.write('Фаза перехода и испытаний проходит через $midNames, где $midMeanings '); } sb.write('Кульминация и запечатывание исхода лежат в знаке #${last.formattedSessionNumber} «${last.word.toUpperCase()}» — ${last.symbolicMeaning.toLowerCase()} '); sb.write('Оракул возвещает: путь открыт через принятие скрытых уроков и решительное действие.'); return sb.toString(); } String _synthesizeChatReply(OracleSession session, String userMessage, SessionWord? newlyAddedWord) { if (newlyAddedWord != null) { return 'Дополнительный знак #${newlyAddedWord.formattedSessionNumber} «${newlyAddedWord.word.toUpperCase()}» (${newlyAddedWord.category}) проясняет скрытую деталь: ${newlyAddedWord.symbolicMeaning} В контексте общего расклада этот знак призывает обратить внимание на внутренние причины, а не внешние проявления.'; } final wordsStr = session.words.map((w) => '«${w.word.toUpperCase()}»').join(', '); return 'Вглядываясь в совокупность знаков ($wordsStr), Оракул отвечает: истинный ответ кроется в понимании скрытой связи между причиной и исходом. Доверьтесь внутреннему знанию и делайте шаг вперед.'; } Future interpret({ required WordItem word, required String question, String? positionTitle, }) async { final sessionWord = SessionWord.fromWordItem(word, positionTitle: positionTitle); return interpretSession(words: [sessionWord], question: question); } }