Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/adicadi_medipal.json
T

1 line
385 KiB
JSON
Raw 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.
{"repo": "adicadi/medipal", "files": {"lib/services/deepseek_service.dart": {"9826e51837ccf6c6d0836ac04569d6baec48e52d": {"t": 1785745923.8786604, "n": 35270, "h": "29098d035d75b8d9", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'dart:io';\nimport 'package:flutter/foundation.dart';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\nimport '../utils/app_state.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // RESTORED: Working timeout values from old version\n static const Duration _timeout = Duration(seconds: 30); // INCREASED from 20\n static const int _maxRetries = 2;\n// INCREASED from 3\n\n // RESTORED: Working retry delays with exponential backoff\n static const List<int> _retryDelays = [500, 1500]; // INCREASED from 300, 800\n\n // ENHANCED: Age-appropriate quick responses\n static const Map<String, Map<String, String>> _quickResponses = {\n 'hello': {\n 'minor':\n 'Hi there! 🌟 I\\'m here to help you learn about staying healthy! Remember to always ask a trusted adult if you have health questions!',\n 'adult':\n 'Hello! I\\'m MediPal, your health assistant. How can I help you today? 😊',\n },\n 'hi': {\n 'minor':\n 'Hi! 👋 I can teach you fun ways to stay healthy! Always talk to your parents or guardians about health stuff too!',\n 'adult':\n 'Hi there! I\\'m here to help with any health questions you might have! 🩺',\n },\n 'help': {\n 'minor':\n 'I can teach you about:\\n• Healthy foods and exercise 🥕\\n• Why sleep is important 😴\\n• When to tell adults you don\\'t feel well\\n• Fun ways to stay strong! 💪\\n\\nBut always ask trusted adults about health questions!',\n 'adult':\n 'I can help you with:\\n• Medical questions and symptoms\\n• Medication information\\n• Health guidance\\n• Emergency information\\n\\nWhat would you like to know?',\n },\n 'emergency': {\n 'minor':\n '🚨 **If there\\'s an emergency:**\\n\\n1. Find a trusted adult RIGHT AWAY\\n2. Call 911 if no adult is around\\n3. Stay calm and ask for help\\n\\nAlways tell adults when you don\\'t feel well!',\n 'adult':\n '🚨 **MEDICAL EMERGENCY?**\\n\\nCall 911 immediately if experiencing:\\n• Difficulty breathing\\n• Chest pain\\n• Severe bleeding\\n• Loss of consciousness',\n },\n 'thanks': {\n 'minor':\n 'You\\'re welcome! 🌟 Keep learning about staying healthy, and remember to always talk to trusted adults about health questions!',\n 'adult':\n 'You\\'re welcome! I\\'m always here to help with your health questions. Take care! 😊',\n },\n 'thank you': {\n 'minor':\n 'You\\'re so welcome! 🌟 Keep asking great questions and always talk to trusted adults about your health!',\n 'adult':\n 'You\\'re very welcome! Feel free to ask if you have more questions. Stay healthy! 💙',\n },\n };\n\n // NEW: Adult content keywords for filtering\n static const List<String> _adultContentKeywords = [\n 'sex',\n 'sexual',\n 'pregnancy',\n 'contraception',\n 'std',\n 'sti',\n 'reproductive',\n 'genital',\n 'abortion',\n 'breast',\n 'period',\n 'menstruation',\n 'testosterone',\n 'viagra',\n 'drug abuse',\n 'alcohol',\n 'addiction',\n 'overdose',\n 'suicide',\n 'self-harm',\n 'depression',\n 'anxiety disorder'\n ];\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n if (kDebugMode) {\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n }\n if (kDebugMode) {\n print(\"🌍 Base URL: $_baseUrl\");\n }\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n // ENHANCED: Age-appropriate quick responses with AppState\n String? getQuickResponse(String message, AppState appState) {\n final normalizedMessage = message.toLowerCase().trim();\n\n // Check for adult content if user is a minor\n if (appState.isMinor && _containsAdultContent(normalizedMessage)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n\n // Direct matches with age-appropriate responses\n if (_quickResponses.containsKey(normalizedMessage)) {\n final responses = _quickResponses[normalizedMessage]!;\n return appState.isMinor ? responses['minor'] : responses['adult'];\n }\n\n // Age-appropriate pattern matches\n return _getPatternBasedResponse(normalizedMessage, appState);\n }\n\n // NEW: Check for adult content\n bool _containsAdultContent(String message) {\n final lowerMessage = message.toLowerCase();\n return _adultContentKeywords\n .any((keyword) => lowerMessage.contains(keyword));\n }\n\n // NEW: Minor redirect response\n String _getMinorRedirectResponse(String userName) {\n return '''\nHi ${userName.isNotEmpty ? userName : 'there'}! 🌟\n\nI notice you're asking about something that might be better discussed with a trusted adult like a parent, guardian, or doctor.\n\n**What you can do:**\n- Talk to a parent or guardian about your question \n- Ask a school nurse or counselor\n- Visit a doctor with a trusted adult\n\nRemember: I'm here to help with general health information, but for anything serious or personal, it's always best to talk to a real person who can help you properly! 😊\n\nIs there something else I can help you with today?\n ''';\n }\n\n // ENHANCED: Pattern-based responses with age consideration\n String? _getPatternBasedResponse(String message, AppState appState) {\n if (message.contains('headache')) {\n return appState.isMinor\n ? '🤕 **If your head hurts:**\\n• Tell a trusted adult right away\\n• Rest in a quiet place\\n• Drink some water\\n• Ask an adult about what to do\\n\\n⚠️ Always let adults help you when you don\\'t feel well!'\n : '🩺 **Headache Relief:**\\n• Stay hydrated (drink water)\\n• Rest in a quiet, dark room\\n• Apply cold/warm compress\\n• Consider OTC pain relief\\n\\n⚠️ See a doctor if severe or persistent.';\n }\n\n if (message.contains('fever')) {\n return appState.isMinor\n ? '🌡️ **If you feel hot and sick:**\\n• Tell an adult immediately\\n• Rest and drink water\\n• Let adults check your temperature\\n• Ask for help from grown-ups\\n\\n⚠️ Adults know what to do when you have a fever!'\n : '🌡️ **Fever Management:**\\n• Stay hydrated\\n• Rest and monitor temperature\\n• Light clothing\\n• Seek medical attention if >101.5°F (38.6°C)\\n\\n⚠️ Contact healthcare provider if persistent.';\n }\n\n if (message.contains('medication') && message.contains('safe')) {\n return appState.isMinor\n ? '💊 **About Medicines:**\\n• Only adults should give you medicine\\n• Never take medicine by yourself\\n• Always ask trusted adults first\\n• Tell adults about any medicine questions\\n\\n⚠️ Medicine safety is super important - let adults handle it!'\n : '💊 **Medication Safety:**\\n• Always follow prescribed dosage\\n• Check for drug interactions\\n• Store properly\\n• Don\\'t share medications\\n\\n⚠️ Consult your pharmacist or doctor with questions.';\n }\n\n return null; // No quick response available\n }\n\n // OPTIMIZED: Dramatically simplified system prompts\n String _getAgeAppropriateSystemPrompt(AppState appState) {\n final basePrompt = '''\nYou are MediPal for ${appState.userName}, Age: ${appState.userAge}, Gender: ${appState.userGender}\n''';\n final wearablePrompt = appState.wearableSummaryPrompt;\n final wearableLine = wearablePrompt.isNotEmpty ? '\\n$wearablePrompt\\n' : '';\n final documentLine = appState.chatDocumentContext.isNotEmpty\n ? '\\nHealth document context (on-device, user-provided):\\n${appState.chatDocumentContext}\\nUse only if relevant, and do not request non-health documents.\\n'\n : '';\n\n if (appState.isMinor) {\n return '''\n$basePrompt\nMINOR (Under 18): Use simple language. Always direct to trusted adults. Focus on wellness and safety. \nAvoid: self-medication, detailed medical terms, sensitive topics. Keep under 250 words. End with reminder to talk to adults.\nUse lots of friendly emojis to make the response visually appealing.\nFollow the conversation context; if the user asks a short follow-up, connect it to the previous medical topic.\nOnly answer health-related questions. If asked about non-health topics (e.g., programming, tech, homework), politely refuse and redirect to health.\n$wearableLine$documentLine\n ''';\n } else if (appState.isYoungAdult) {\n return '''\n$basePrompt\nYOUNG ADULT (18-24): Clear educational language. Emphasize preventive care and professional consultation.\nKeep under 350 words with disclaimers.\nOnly answer health-related questions. If asked about non-health topics (e.g., programming, tech, homework), politely refuse and redirect to health.\nAnswer short questions with short responses (1-3 sentences). Provide detailed answers only when the user asks for detail.\nInclude medical disclaimers only for serious or emergency topics; omit for general questions.\n$wearableLine$documentLine\n ''';\n } else {\n return '''\n$basePrompt\nADULT (25+): Detailed medical-grade information with appropriate terminology. \nThorough analysis with disclaimers. Keep under 500 words.\nOnly answer health-related questions. If asked about non-health topics (e.g., programming, tech, homework), politely refuse and redirect to health.\nAnswer short questions with short responses (1-3 sentences). Provide detailed answers only when the user asks for detail.\nInclude medical disclaimers only for serious or emergency topics; omit for general questions.\n$wearableLine$documentLine\n ''';\n }\n }\n\n bool _isHealthRelated(String message) {\n final text = message.toLowerCase();\n const healthKeywords = [\n 'health',\n 'symptom',\n 'symptoms',\n 'pain',\n 'ache',\n 'fever',\n 'cough',\n 'cold',\n 'flu',\n 'allergy',\n 'asthma',\n 'blood',\n 'pressure',\n 'heart',\n 'pulse',\n 'sleep',\n 'insomnia',\n 'stress',\n 'anxiety',\n 'depression',\n 'mental',\n 'wellness',\n 'diet',\n 'nutrition',\n 'calorie',\n 'exercise',\n 'workout',\n 'steps',\n 'medicine',\n 'medication',\n 'drug',\n 'dosage',\n 'side effect',\n 'doctor',\n 'hospital',\n 'clinic',\n 'injury',\n 'wound',\n 'infection',\n 'virus',\n 'bacteria',\n 'headache',\n 'migraine',\n 'nausea',\n 'vomit',\n 'diarrhea',\n 'constipation',\n 'period',\n 'pregnancy',\n 'sex',\n 'sexual',\n 'skin',\n 'rash',\n 'itch',\n 'temperature',\n 'vaccin',\n 'immun',\n 'therapy',\n 'diagnos',\n 'treatment',\n 'surgery',\n 'cholesterol',\n 'glucose',\n 'diabetes',\n 'otc',\n 'relief',\n ];\n\n for (final keyword in healthKeywords) {\n if (text.contains(keyword)) {\n return true;\n }\n }\n return false;\n }\n\n bool _isHealthFollowUp(List<Map<String, String>> history, String lastText) {\n if (history.length < 2) return false;\n final prev = history[history.length - 2];\n if (prev['isUser'] == 'true') return false;\n final prevText = (prev['text'] ?? '').toLowerCase();\n if (prevText.isEmpty) return false;\n if (_isHealthRelated(prevText)) return true;\n final wordCount = lastText.trim().split(RegExp(r'\\s+')).length;\n return wordCount <= 4;\n }\n\n bool _isDetailRequest(String text) {\n final lower = text.toLowerCase();\n const detailMarkers = [\n 'detail',\n 'explain',\n 'why',\n 'how',\n 'cause',\n 'causes',\n 'treatment',\n 'plan',\n 'steps',\n 'step by step',\n 'tell me more',\n 'more info',\n 'in depth',\n ];\n return detailMarkers.any(lower.contains);\n }\n\n bool _isListRequest(String text) {\n final lower = text.toLowerCase();\n const listMarkers = [\n 'which',\n 'options',\n 'list',\n 'examples',\n 'types',\n 'kinds',\n 'what otc',\n 'otc',\n 'meds',\n 'medicine',\n ];\n return listMarkers.any(lower.contains);\n }\n\n bool _isShortQuery(String text) {\n final wordCount = text.trim().split(RegExp(r'\\s+')).length;\n return wordCount <= 5 && !_isDetailRequest(text);\n }\n\n int _maxTokensForQuery(AppState appState, String lastText) {\n if (_isDetailRequest(lastText)) {\n return appState.isMinor ? 220 : 380;\n }\n if (_isShortQuery(lastText)) {\n if (_isListRequest(lastText)) {\n return appState.isMinor ? 180 : 260;\n }\n return appState.isMinor ? 120 : 180;\n }\n return appState.isMinor ? 180 : 320;\n }\n\n bool _isSeriousMedicalTopic(String text) {\n final lower = text.toLowerCase();\n const seriousKeywords = [\n 'chest pain',\n 'shortness of breath',\n 'difficulty breathing',\n 'severe',\n 'sudden',\n 'faint',\n 'passed out',\n 'seizure',\n 'stroke',\n 'heart attack',\n 'overdose',\n 'bleeding',\n 'blood',\n 'suicidal',\n 'self-harm',\n 'pregnancy bleeding',\n 'high fever',\n 'persistent',\n 'worsening',\n 'emergency',\n ];\n return seriousKeywords.any(lower.contains);\n }\n\n // ENHANCED: Streaming with age restrictions and AppState\n Stream<String> streamChatResponse(\n List<Map<String, String>> conversationHistory, AppState appState) async* {\n // Check for quick response first\n String lastUserText = '';\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final lastText = lastMessage['text'] ?? '';\n lastUserText = lastText;\n if (lastText.trim().isNotEmpty &&\n !_isHealthRelated(lastText) &&\n !_isHealthFollowUp(conversationHistory, lastText)) {\n yield appState.isMinor\n ? 'I can only help with health questions. Please ask about your health, symptoms, medicines, or wellness, and I’ll do my best to help.'\n : 'I’m a health-only assistant, so I can’t help with that topic. Ask me about symptoms, medications, wellness, or other health questions.';\n return;\n }\n final hasPriorUserMessages =\n conversationHistory.where((m) => m['isUser'] == 'true').length > 1;\n if (!hasPriorUserMessages) {\n final quickResponse = getQuickResponse(lastText, appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 300));\n yield quickResponse;\n return;\n }\n }\n }\n }\n final maxTokens = _maxTokensForQuery(appState, lastUserText);\n\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Accept': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n };\n\n final messages = _buildMessageHistory(conversationHistory, appState);\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': maxTokens,\n 'temperature': 0.4, // SIMPLIFIED: Single value\n 'stream': true,\n 'top_p': 0.8,\n });\n\n http.Client? client;\n try {\n final request =\n http.Request('POST', Uri.parse('$_baseUrl/chat/completions'))\n ..headers.addAll(headers)\n ..body = body;\n\n client = http.Client();\n final streamedResponse = await client.send(request).timeout(_timeout);\n\n if (streamedResponse.statusCode != 200) {\n throw Exception(\n 'API request failed with status: ${streamedResponse.statusCode}');\n }\n\n String accumulatedText = '';\n\n await for (final line in streamedResponse.stream\n .transform(utf8.decoder)\n .transform(const LineSplitter())\n .where((line) => line.trim().isNotEmpty)) {\n if (line.startsWith('data: ')) {\n final data = line.substring(6).trim();\n\n if (data == '[DONE]') {\n break;\n }\n\n try {\n final json = jsonDecode(data);\n final content = json['choices']?[0]?['delta']?['content'];\n\n if (content != null && content.isNotEmpty) {\n accumulatedText += content;\n\n // Filter content for minors\n if (appState.isMinor && _containsAdultContent(accumulatedText)) {\n yield _getMinorRedirectResponse(appState.userName);\n break;\n }\n\n yield accumulatedText;\n }\n } catch (e) {\n continue;\n }\n }\n }\n\n // Add disclaimer only for serious topics\n if (accumulatedText.isNotEmpty &&\n _isSeriousMedicalTopic(lastUserText) &&\n !accumulatedText.contains(appState.ageAppropriateDisclaimer)) {\n final finalResponse =\n '$accumulatedText\\n\\n${appState.ageAppropriateDisclaimer}';\n yield finalResponse;\n }\n } catch (e) {\n if (kDebugMode) {\n print('❌ Streaming error: $e');\n }\n try {\n final response = await sendChatMessage(conversationHistory, appState);\n yield response;\n } catch (fallbackError) {\n yield appState.getAgeAppropriateErrorMessage();\n }\n } finally {\n client?.close();\n }\n }\n\n // ENHANCED: Chat with age restrictions and AppState\n Future<String> sendChatMessage(\n List<Map<String, dynamic>> conversationHistory, AppState appState) async {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final lastText = lastMessage['text'] ?? '';\n if (lastText.trim().isNotEmpty &&\n !_isHealthRelated(lastText) &&\n !_isHealthFollowUp(\n conversationHistory.cast<Map<String, String>>(), lastText)) {\n return appState.isMinor\n ? 'I can only help with health questions. Please ask about your health, symptoms, medicines, or wellness, and I’ll do my best to help.'\n : 'I’m a health-only assistant, so I can’t help with that topic. Ask me about symptoms, medications, wellness, or other health questions.';\n }\n final hasPriorUserMessages =\n conversationHistory.where((m) => m['isUser'] == 'true').length > 1;\n if (!hasPriorUserMessages) {\n final quickResponse = getQuickResponse(lastText, appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 500));\n return quickResponse;\n }\n }\n }\n }\n\n final prompt = _buildChatPrompt(conversationHistory, appState);\n final result = await _safeApiCall(prompt, 'Error in chat conversation',\n isChat: true, appState: appState);\n\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n final lastText = lastMessage['text'] ?? '';\n if (_isSeriousMedicalTopic(lastText) &&\n !result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n }\n return result;\n }\n\n // Helper method to build message history for streaming with age restrictions\n List<Map<String, String>> _buildMessageHistory(\n List<Map<String, String>> conversationHistory, AppState appState) {\n final messages = <Map<String, String>>[];\n\n // Add age-appropriate system message\n messages.add({\n 'role': 'system',\n 'content': _getAgeAppropriateSystemPrompt(appState),\n });\n\n // Convert conversation history\n for (final message in conversationHistory) {\n messages.add({\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n });\n }\n\n return messages;\n }\n\n // ENHANCED: Symptom analysis with age restrictions\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) async {\n // Check for adult content in symptoms for minors\n if (appState.isMinor) {\n final symptomsText = symptoms.join(' ').toLowerCase();\n if (_containsAdultContent(symptomsText)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n }\n\n final prompt = _buildSymptomAnalysisPrompt(\n symptoms, severity, additionalInfo, appState);\n final result = await _safeApiCall(prompt, 'Error analyzing symptoms',\n appState: appState);\n\n return result;\n }\n\n // ENHANCED: Medication interactions with age restrictions\n Future<String> checkMedicationInteractions(\n List<String> medications, AppState appState) async {\n if (appState.isMinor) {\n return '''\nHi ${appState.userName}! 🌟\n\nMedicine questions are really important! Here's what you should do:\n\n**For Medicine Safety:**\n- Always ask a trusted adult before taking any medicine\n- Never take medicine by yourself\n- Tell adults about all medicines you take\n- Ask parents or guardians about medicine questions\n\n**Important:** Only doctors, parents, or guardians should decide about your medicines!\n\nRemember: Adults are there to keep you safe and healthy! 💙\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n\n final prompt = _buildMedicationInteractionPrompt(medications, appState);\n final result = await _safeApiCall(\n prompt, 'Error checking medication interactions',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Health insights with comprehensive data analysis\n Future<String> getHealthInsights(\n Map<String, dynamic> healthData, AppState appState) async {\n // If healthData is a string, treat it as a single chat message\n if (healthData is String) {\n final conversationHistory = [\n {'isUser': 'true', 'text': healthData}\n ];\n return sendChatMessage(conversationHistory, appState);\n }\n\n // Check for quick insights first\n if (healthData.isEmpty) {\n return _getDefaultHealthInsights(appState);\n }\n\n final prompt = _buildHealthInsightsPrompt(healthData, appState);\n final result = await _safeApiCall(prompt, 'Error getting health insights',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // NEW: Default health insights based on age\n String _getDefaultHealthInsights(AppState appState) {\n if (appState.isMinor) {\n return '''\n🌟 **Health Tips Just for You, ${appState.userName}!**\n\n**Stay Strong and Healthy:**\n🏃‍♀️ Play and be active every day - it's fun and makes you strong!\n😴 Get lots of sleep (9-11 hours) to help your body grow\n🥕 Eat colorful foods like fruits and vegetables\n💧 Drink water to keep your body happy\n🧠 Always tell trusted adults when you don't feel well\n\n**Remember:**\n- Your parents and guardians are there to help you stay healthy\n- Ask questions! Adults love to help you learn\n- You're doing great by learning about health! \n ''';\n } else {\n return '''\n🌟 **Personalized Health Insights for ${appState.userName}**\n\n**General Wellness Tips:**\n• Stay hydrated - aim for 8 glasses of water daily\n• Get 7-9 hours of quality sleep\n• Take regular breaks from screen time\n• Practice deep breathing exercises\n\n**Healthy Habits:**\n• Walk for 30 minutes daily\n• Eat colorful fruits and vegetables\n• Maintain regular meal times\n• Stay connected with loved ones\n\n💡 **Tip:** Add your health data to get more personalized insights!\n\n ''';\n }\n }\n\n // ENHANCED: Fallback response with age consideration\n String _getFallbackResponse(String userMessage, AppState appState) {\n final quickResponse = getQuickResponse(userMessage, appState);\n if (quickResponse != null) return quickResponse;\n\n return appState.getAgeAppropriateErrorMessage();\n }\n\n Future<String> _safeApiCall(String prompt, String contextMessage,\n {bool isChat = false, AppState? appState}) async {\n try {\n if (isChat) {\n return await _makeChatApiCall(prompt, appState);\n } else {\n return await _makeApiCallWithRetry(prompt, appState);\n }\n } on TimeoutException {\n if (kDebugMode) {\n print(\n '⏳ $contextMessage: Request timed out after ${_timeout.inSeconds}s');\n }\n if (isChat && appState != null) {\n final messages = jsonDecode(prompt) as List<dynamic>;\n final lastUserMessage = messages.lastWhere(\n (m) => m['role'] == 'user',\n orElse: () => {'content': ''},\n )['content'] ??\n '';\n return _getFallbackResponse(lastUserMessage, appState);\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'The request took longer than expected. Please try again.';\n } on SocketException catch (e) {\n if (kDebugMode) {\n print('🌐 Network error: ${e.message}');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'Network connection issue. Please check your internet and try again.';\n } catch (e) {\n if (kDebugMode) {\n print('⚠️ $contextMessage: $e');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'I\\'m experiencing technical difficulties. Please try again in a moment.';\n }\n }\n\n Future<String> _makeChatApiCall(\n String conversationHistoryJson, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive',\n 'Accept': 'application/json',\n };\n\n final List<dynamic> messages = jsonDecode(conversationHistoryJson);\n\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are MediPal, a helpful medical AI. Keep responses concise and include medical disclaimers.'\n });\n }\n\n String lastUserText = '';\n for (int i = messages.length - 1; i >= 0; i--) {\n if (messages[i]['role'] == 'user') {\n lastUserText = messages[i]['content'] ?? '';\n break;\n }\n }\n final maxTokens =\n appState != null ? _maxTokensForQuery(appState, lastUserText) : 300;\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': maxTokens,\n 'temperature': 0.4, // SIMPLIFIED\n 'top_p': 0.8,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _buildChatPrompt(\n List<Map<String, dynamic>> conversationHistory, AppState appState) {\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n return jsonEncode(messages);\n }\n\n // RESTORED: Working retry logic with exponential backoff\n Future<String> _makeApiCallWithRetry(\n String prompt, AppState? appState) async {\n int attempts = 0;\n\n while (true) {\n try {\n if (kDebugMode) {\n print('🔄 API attempt ${attempts + 1}/${_maxRetries + 1}');\n }\n return await _makeApiCall(prompt, appState);\n } on TimeoutException {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('⏳ Max retries reached after $attempts attempts');\n }\n rethrow;\n }\n\n // Use working retry delays with jitter\n final delayMs = _retryDelays[attempts - 1];\n final jitter =\n (delayMs * 0.1 * (DateTime.now().millisecond % 100) / 100).round();\n final finalDelay = delayMs + jitter;\n\n if (kDebugMode) {\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${finalDelay}ms');\n }\n await Future.delayed(Duration(milliseconds: finalDelay));\n } on SocketException catch (e) {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('🌐 Network error after $attempts attempts: ${e.message}');\n }\n rethrow;\n }\n\n final delayMs = _retryDelays[attempts - 1];\n if (kDebugMode) {\n print('🌐 Network issue, retrying in ${delayMs}ms...');\n }\n await Future.delayed(Duration(milliseconds: delayMs));\n } catch (e) {\n if (kDebugMode) {\n print('❌ Non-retryable error: $e');\n }\n rethrow;\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive', // Important for long requests\n };\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are a medical AI assistant. Provide concise, informative responses. Include medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(\n _timeout,\n onTimeout: () {\n throw TimeoutException(\n 'Request to DeepSeek API exceeded ${_timeout.inSeconds}s timeout',\n _timeout,\n );\n },\n );\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from DeepSeek API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // OPTIMIZED: Dramatically simplified symptom analysis prompt\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) {\n final buffer = StringBuffer();\n\n if (appState.isMinor) {\n buffer.writeln(\"Help young person (age ${appState.userAge}):\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n buffer.writeln(\n \"Provide: Simple explanation, when to tell adults. Keep brief under 200 words.\");\n } else {\n buffer\n .writeln(\"Analyze for ${appState.userAge}yo ${appState.userGender}:\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n\n // Only include top 3 additional info items to keep prompt short\n if (additionalInfo.isNotEmpty) {\n int count = 0;\n buffer.writeln(\"Info:\");\n for (var entry in additionalInfo.entries) {\n if (entry.value.toString().isNotEmpty && count < 3) {\n buffer.writeln(\"- ${entry.key}: ${entry.value}\");\n count++;\n }\n }\n }\n\n buffer.writeln(\n \"\\nProvide: Causes, when to see doctor, self-care, disclaimer. Under 300 words.\");\n }\n\n return buffer.toString();\n }\n\n // OPTIMIZED: Simplified medication interaction prompt\n String _buildMedicationInteractionPrompt(\n List<String> medications, AppState appState) {\n if (appState.isMinor) {\n return \"Minor asking about medicines. Redirect to trusted adults briefly.\";\n }\n\n return \"\"\"\nAnalyze interactions: ${medications.join(', ')}\nFor ${appState.userAge}yo ${appState.userGender}. \nProvide: 1) Risk level 2) Key effects 3) When to consult doctor 4) Disclaimer\nKeep under 250 words.\n\"\"\";\n }\n\n // OPTIMIZED: Wearable-driven health insights prompt\n String _buildHealthInsightsPrompt(\n Map<String, dynamic> healthData, AppState appState) {\n final buffer = StringBuffer();\n buffer.writeln(\n \"AI health insights for ${appState.userName} (${appState.userAge}yo, ${appState.userGender}).\");\n buffer.writeln(\n \"Use wearable summary + trends to provide: 1) Key insights 2) Tips to improve metrics 3) Encouraging next steps.\");\n buffer.writeln(\n \"If data is missing, say what's missing and give general tips.\");\n\n if (appState.isMinor) {\n buffer.writeln(\n \"Use lots of friendly emojis, simple language, and remind to talk to trusted adults.\");\n buffer.writeln(\"Keep under 180 words. Do not add a medical disclaimer.\");\n } else {\n buffer.writeln(\n \"Keep under 250 words, concise bullets. Do not add a medical disclaimer.\");\n }\n\n buffer.writeln(\"\\nWearable data (aggregates only):\");\n buffer.writeln(healthData.toString());\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl\\nTimeout: ${_timeout.inSeconds}s';\n}\n"}, "bf8db78eaac4e0f5718ef3c69accdc629b326636": {"t": 1785757935.8626647, "n": 35270, "h": "29098d035d75b8d9", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'dart:io';\nimport 'package:flutter/foundation.dart';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\nimport '../utils/app_state.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // RESTORED: Working timeout values from old version\n static const Duration _timeout = Duration(seconds: 30); // INCREASED from 20\n static const int _maxRetries = 2;\n// INCREASED from 3\n\n // RESTORED: Working retry delays with exponential backoff\n static const List<int> _retryDelays = [500, 1500]; // INCREASED from 300, 800\n\n // ENHANCED: Age-appropriate quick responses\n static const Map<String, Map<String, String>> _quickResponses = {\n 'hello': {\n 'minor':\n 'Hi there! 🌟 I\\'m here to help you learn about staying healthy! Remember to always ask a trusted adult if you have health questions!',\n 'adult':\n 'Hello! I\\'m MediPal, your health assistant. How can I help you today? 😊',\n },\n 'hi': {\n 'minor':\n 'Hi! 👋 I can teach you fun ways to stay healthy! Always talk to your parents or guardians about health stuff too!',\n 'adult':\n 'Hi there! I\\'m here to help with any health questions you might have! 🩺',\n },\n 'help': {\n 'minor':\n 'I can teach you about:\\n• Healthy foods and exercise 🥕\\n• Why sleep is important 😴\\n• When to tell adults you don\\'t feel well\\n• Fun ways to stay strong! 💪\\n\\nBut always ask trusted adults about health questions!',\n 'adult':\n 'I can help you with:\\n• Medical questions and symptoms\\n• Medication information\\n• Health guidance\\n• Emergency information\\n\\nWhat would you like to know?',\n },\n 'emergency': {\n 'minor':\n '🚨 **If there\\'s an emergency:**\\n\\n1. Find a trusted adult RIGHT AWAY\\n2. Call 911 if no adult is around\\n3. Stay calm and ask for help\\n\\nAlways tell adults when you don\\'t feel well!',\n 'adult':\n '🚨 **MEDICAL EMERGENCY?**\\n\\nCall 911 immediately if experiencing:\\n• Difficulty breathing\\n• Chest pain\\n• Severe bleeding\\n• Loss of consciousness',\n },\n 'thanks': {\n 'minor':\n 'You\\'re welcome! 🌟 Keep learning about staying healthy, and remember to always talk to trusted adults about health questions!',\n 'adult':\n 'You\\'re welcome! I\\'m always here to help with your health questions. Take care! 😊',\n },\n 'thank you': {\n 'minor':\n 'You\\'re so welcome! 🌟 Keep asking great questions and always talk to trusted adults about your health!',\n 'adult':\n 'You\\'re very welcome! Feel free to ask if you have more questions. Stay healthy! 💙',\n },\n };\n\n // NEW: Adult content keywords for filtering\n static const List<String> _adultContentKeywords = [\n 'sex',\n 'sexual',\n 'pregnancy',\n 'contraception',\n 'std',\n 'sti',\n 'reproductive',\n 'genital',\n 'abortion',\n 'breast',\n 'period',\n 'menstruation',\n 'testosterone',\n 'viagra',\n 'drug abuse',\n 'alcohol',\n 'addiction',\n 'overdose',\n 'suicide',\n 'self-harm',\n 'depression',\n 'anxiety disorder'\n ];\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n if (kDebugMode) {\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n }\n if (kDebugMode) {\n print(\"🌍 Base URL: $_baseUrl\");\n }\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n // ENHANCED: Age-appropriate quick responses with AppState\n String? getQuickResponse(String message, AppState appState) {\n final normalizedMessage = message.toLowerCase().trim();\n\n // Check for adult content if user is a minor\n if (appState.isMinor && _containsAdultContent(normalizedMessage)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n\n // Direct matches with age-appropriate responses\n if (_quickResponses.containsKey(normalizedMessage)) {\n final responses = _quickResponses[normalizedMessage]!;\n return appState.isMinor ? responses['minor'] : responses['adult'];\n }\n\n // Age-appropriate pattern matches\n return _getPatternBasedResponse(normalizedMessage, appState);\n }\n\n // NEW: Check for adult content\n bool _containsAdultContent(String message) {\n final lowerMessage = message.toLowerCase();\n return _adultContentKeywords\n .any((keyword) => lowerMessage.contains(keyword));\n }\n\n // NEW: Minor redirect response\n String _getMinorRedirectResponse(String userName) {\n return '''\nHi ${userName.isNotEmpty ? userName : 'there'}! 🌟\n\nI notice you're asking about something that might be better discussed with a trusted adult like a parent, guardian, or doctor.\n\n**What you can do:**\n- Talk to a parent or guardian about your question \n- Ask a school nurse or counselor\n- Visit a doctor with a trusted adult\n\nRemember: I'm here to help with general health information, but for anything serious or personal, it's always best to talk to a real person who can help you properly! 😊\n\nIs there something else I can help you with today?\n ''';\n }\n\n // ENHANCED: Pattern-based responses with age consideration\n String? _getPatternBasedResponse(String message, AppState appState) {\n if (message.contains('headache')) {\n return appState.isMinor\n ? '🤕 **If your head hurts:**\\n• Tell a trusted adult right away\\n• Rest in a quiet place\\n• Drink some water\\n• Ask an adult about what to do\\n\\n⚠️ Always let adults help you when you don\\'t feel well!'\n : '🩺 **Headache Relief:**\\n• Stay hydrated (drink water)\\n• Rest in a quiet, dark room\\n• Apply cold/warm compress\\n• Consider OTC pain relief\\n\\n⚠️ See a doctor if severe or persistent.';\n }\n\n if (message.contains('fever')) {\n return appState.isMinor\n ? '🌡️ **If you feel hot and sick:**\\n• Tell an adult immediately\\n• Rest and drink water\\n• Let adults check your temperature\\n• Ask for help from grown-ups\\n\\n⚠️ Adults know what to do when you have a fever!'\n : '🌡️ **Fever Management:**\\n• Stay hydrated\\n• Rest and monitor temperature\\n• Light clothing\\n• Seek medical attention if >101.5°F (38.6°C)\\n\\n⚠️ Contact healthcare provider if persistent.';\n }\n\n if (message.contains('medication') && message.contains('safe')) {\n return appState.isMinor\n ? '💊 **About Medicines:**\\n• Only adults should give you medicine\\n• Never take medicine by yourself\\n• Always ask trusted adults first\\n• Tell adults about any medicine questions\\n\\n⚠️ Medicine safety is super important - let adults handle it!'\n : '💊 **Medication Safety:**\\n• Always follow prescribed dosage\\n• Check for drug interactions\\n• Store properly\\n• Don\\'t share medications\\n\\n⚠️ Consult your pharmacist or doctor with questions.';\n }\n\n return null; // No quick response available\n }\n\n // OPTIMIZED: Dramatically simplified system prompts\n String _getAgeAppropriateSystemPrompt(AppState appState) {\n final basePrompt = '''\nYou are MediPal for ${appState.userName}, Age: ${appState.userAge}, Gender: ${appState.userGender}\n''';\n final wearablePrompt = appState.wearableSummaryPrompt;\n final wearableLine = wearablePrompt.isNotEmpty ? '\\n$wearablePrompt\\n' : '';\n final documentLine = appState.chatDocumentContext.isNotEmpty\n ? '\\nHealth document context (on-device, user-provided):\\n${appState.chatDocumentContext}\\nUse only if relevant, and do not request non-health documents.\\n'\n : '';\n\n if (appState.isMinor) {\n return '''\n$basePrompt\nMINOR (Under 18): Use simple language. Always direct to trusted adults. Focus on wellness and safety. \nAvoid: self-medication, detailed medical terms, sensitive topics. Keep under 250 words. End with reminder to talk to adults.\nUse lots of friendly emojis to make the response visually appealing.\nFollow the conversation context; if the user asks a short follow-up, connect it to the previous medical topic.\nOnly answer health-related questions. If asked about non-health topics (e.g., programming, tech, homework), politely refuse and redirect to health.\n$wearableLine$documentLine\n ''';\n } else if (appState.isYoungAdult) {\n return '''\n$basePrompt\nYOUNG ADULT (18-24): Clear educational language. Emphasize preventive care and professional consultation.\nKeep under 350 words with disclaimers.\nOnly answer health-related questions. If asked about non-health topics (e.g., programming, tech, homework), politely refuse and redirect to health.\nAnswer short questions with short responses (1-3 sentences). Provide detailed answers only when the user asks for detail.\nInclude medical disclaimers only for serious or emergency topics; omit for general questions.\n$wearableLine$documentLine\n ''';\n } else {\n return '''\n$basePrompt\nADULT (25+): Detailed medical-grade information with appropriate terminology. \nThorough analysis with disclaimers. Keep under 500 words.\nOnly answer health-related questions. If asked about non-health topics (e.g., programming, tech, homework), politely refuse and redirect to health.\nAnswer short questions with short responses (1-3 sentences). Provide detailed answers only when the user asks for detail.\nInclude medical disclaimers only for serious or emergency topics; omit for general questions.\n$wearableLine$documentLine\n ''';\n }\n }\n\n bool _isHealthRelated(String message) {\n final text = message.toLowerCase();\n const healthKeywords = [\n 'health',\n 'symptom',\n 'symptoms',\n 'pain',\n 'ache',\n 'fever',\n 'cough',\n 'cold',\n 'flu',\n 'allergy',\n 'asthma',\n 'blood',\n 'pressure',\n 'heart',\n 'pulse',\n 'sleep',\n 'insomnia',\n 'stress',\n 'anxiety',\n 'depression',\n 'mental',\n 'wellness',\n 'diet',\n 'nutrition',\n 'calorie',\n 'exercise',\n 'workout',\n 'steps',\n 'medicine',\n 'medication',\n 'drug',\n 'dosage',\n 'side effect',\n 'doctor',\n 'hospital',\n 'clinic',\n 'injury',\n 'wound',\n 'infection',\n 'virus',\n 'bacteria',\n 'headache',\n 'migraine',\n 'nausea',\n 'vomit',\n 'diarrhea',\n 'constipation',\n 'period',\n 'pregnancy',\n 'sex',\n 'sexual',\n 'skin',\n 'rash',\n 'itch',\n 'temperature',\n 'vaccin',\n 'immun',\n 'therapy',\n 'diagnos',\n 'treatment',\n 'surgery',\n 'cholesterol',\n 'glucose',\n 'diabetes',\n 'otc',\n 'relief',\n ];\n\n for (final keyword in healthKeywords) {\n if (text.contains(keyword)) {\n return true;\n }\n }\n return false;\n }\n\n bool _isHealthFollowUp(List<Map<String, String>> history, String lastText) {\n if (history.length < 2) return false;\n final prev = history[history.length - 2];\n if (prev['isUser'] == 'true') return false;\n final prevText = (prev['text'] ?? '').toLowerCase();\n if (prevText.isEmpty) return false;\n if (_isHealthRelated(prevText)) return true;\n final wordCount = lastText.trim().split(RegExp(r'\\s+')).length;\n return wordCount <= 4;\n }\n\n bool _isDetailRequest(String text) {\n final lower = text.toLowerCase();\n const detailMarkers = [\n 'detail',\n 'explain',\n 'why',\n 'how',\n 'cause',\n 'causes',\n 'treatment',\n 'plan',\n 'steps',\n 'step by step',\n 'tell me more',\n 'more info',\n 'in depth',\n ];\n return detailMarkers.any(lower.contains);\n }\n\n bool _isListRequest(String text) {\n final lower = text.toLowerCase();\n const listMarkers = [\n 'which',\n 'options',\n 'list',\n 'examples',\n 'types',\n 'kinds',\n 'what otc',\n 'otc',\n 'meds',\n 'medicine',\n ];\n return listMarkers.any(lower.contains);\n }\n\n bool _isShortQuery(String text) {\n final wordCount = text.trim().split(RegExp(r'\\s+')).length;\n return wordCount <= 5 && !_isDetailRequest(text);\n }\n\n int _maxTokensForQuery(AppState appState, String lastText) {\n if (_isDetailRequest(lastText)) {\n return appState.isMinor ? 220 : 380;\n }\n if (_isShortQuery(lastText)) {\n if (_isListRequest(lastText)) {\n return appState.isMinor ? 180 : 260;\n }\n return appState.isMinor ? 120 : 180;\n }\n return appState.isMinor ? 180 : 320;\n }\n\n bool _isSeriousMedicalTopic(String text) {\n final lower = text.toLowerCase();\n const seriousKeywords = [\n 'chest pain',\n 'shortness of breath',\n 'difficulty breathing',\n 'severe',\n 'sudden',\n 'faint',\n 'passed out',\n 'seizure',\n 'stroke',\n 'heart attack',\n 'overdose',\n 'bleeding',\n 'blood',\n 'suicidal',\n 'self-harm',\n 'pregnancy bleeding',\n 'high fever',\n 'persistent',\n 'worsening',\n 'emergency',\n ];\n return seriousKeywords.any(lower.contains);\n }\n\n // ENHANCED: Streaming with age restrictions and AppState\n Stream<String> streamChatResponse(\n List<Map<String, String>> conversationHistory, AppState appState) async* {\n // Check for quick response first\n String lastUserText = '';\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final lastText = lastMessage['text'] ?? '';\n lastUserText = lastText;\n if (lastText.trim().isNotEmpty &&\n !_isHealthRelated(lastText) &&\n !_isHealthFollowUp(conversationHistory, lastText)) {\n yield appState.isMinor\n ? 'I can only help with health questions. Please ask about your health, symptoms, medicines, or wellness, and I’ll do my best to help.'\n : 'I’m a health-only assistant, so I can’t help with that topic. Ask me about symptoms, medications, wellness, or other health questions.';\n return;\n }\n final hasPriorUserMessages =\n conversationHistory.where((m) => m['isUser'] == 'true').length > 1;\n if (!hasPriorUserMessages) {\n final quickResponse = getQuickResponse(lastText, appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 300));\n yield quickResponse;\n return;\n }\n }\n }\n }\n final maxTokens = _maxTokensForQuery(appState, lastUserText);\n\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Accept': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n };\n\n final messages = _buildMessageHistory(conversationHistory, appState);\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': maxTokens,\n 'temperature': 0.4, // SIMPLIFIED: Single value\n 'stream': true,\n 'top_p': 0.8,\n });\n\n http.Client? client;\n try {\n final request =\n http.Request('POST', Uri.parse('$_baseUrl/chat/completions'))\n ..headers.addAll(headers)\n ..body = body;\n\n client = http.Client();\n final streamedResponse = await client.send(request).timeout(_timeout);\n\n if (streamedResponse.statusCode != 200) {\n throw Exception(\n 'API request failed with status: ${streamedResponse.statusCode}');\n }\n\n String accumulatedText = '';\n\n await for (final line in streamedResponse.stream\n .transform(utf8.decoder)\n .transform(const LineSplitter())\n .where((line) => line.trim().isNotEmpty)) {\n if (line.startsWith('data: ')) {\n final data = line.substring(6).trim();\n\n if (data == '[DONE]') {\n break;\n }\n\n try {\n final json = jsonDecode(data);\n final content = json['choices']?[0]?['delta']?['content'];\n\n if (content != null && content.isNotEmpty) {\n accumulatedText += content;\n\n // Filter content for minors\n if (appState.isMinor && _containsAdultContent(accumulatedText)) {\n yield _getMinorRedirectResponse(appState.userName);\n break;\n }\n\n yield accumulatedText;\n }\n } catch (e) {\n continue;\n }\n }\n }\n\n // Add disclaimer only for serious topics\n if (accumulatedText.isNotEmpty &&\n _isSeriousMedicalTopic(lastUserText) &&\n !accumulatedText.contains(appState.ageAppropriateDisclaimer)) {\n final finalResponse =\n '$accumulatedText\\n\\n${appState.ageAppropriateDisclaimer}';\n yield finalResponse;\n }\n } catch (e) {\n if (kDebugMode) {\n print('❌ Streaming error: $e');\n }\n try {\n final response = await sendChatMessage(conversationHistory, appState);\n yield response;\n } catch (fallbackError) {\n yield appState.getAgeAppropriateErrorMessage();\n }\n } finally {\n client?.close();\n }\n }\n\n // ENHANCED: Chat with age restrictions and AppState\n Future<String> sendChatMessage(\n List<Map<String, dynamic>> conversationHistory, AppState appState) async {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final lastText = lastMessage['text'] ?? '';\n if (lastText.trim().isNotEmpty &&\n !_isHealthRelated(lastText) &&\n !_isHealthFollowUp(\n conversationHistory.cast<Map<String, String>>(), lastText)) {\n return appState.isMinor\n ? 'I can only help with health questions. Please ask about your health, symptoms, medicines, or wellness, and I’ll do my best to help.'\n : 'I’m a health-only assistant, so I can’t help with that topic. Ask me about symptoms, medications, wellness, or other health questions.';\n }\n final hasPriorUserMessages =\n conversationHistory.where((m) => m['isUser'] == 'true').length > 1;\n if (!hasPriorUserMessages) {\n final quickResponse = getQuickResponse(lastText, appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 500));\n return quickResponse;\n }\n }\n }\n }\n\n final prompt = _buildChatPrompt(conversationHistory, appState);\n final result = await _safeApiCall(prompt, 'Error in chat conversation',\n isChat: true, appState: appState);\n\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n final lastText = lastMessage['text'] ?? '';\n if (_isSeriousMedicalTopic(lastText) &&\n !result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n }\n return result;\n }\n\n // Helper method to build message history for streaming with age restrictions\n List<Map<String, String>> _buildMessageHistory(\n List<Map<String, String>> conversationHistory, AppState appState) {\n final messages = <Map<String, String>>[];\n\n // Add age-appropriate system message\n messages.add({\n 'role': 'system',\n 'content': _getAgeAppropriateSystemPrompt(appState),\n });\n\n // Convert conversation history\n for (final message in conversationHistory) {\n messages.add({\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n });\n }\n\n return messages;\n }\n\n // ENHANCED: Symptom analysis with age restrictions\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) async {\n // Check for adult content in symptoms for minors\n if (appState.isMinor) {\n final symptomsText = symptoms.join(' ').toLowerCase();\n if (_containsAdultContent(symptomsText)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n }\n\n final prompt = _buildSymptomAnalysisPrompt(\n symptoms, severity, additionalInfo, appState);\n final result = await _safeApiCall(prompt, 'Error analyzing symptoms',\n appState: appState);\n\n return result;\n }\n\n // ENHANCED: Medication interactions with age restrictions\n Future<String> checkMedicationInteractions(\n List<String> medications, AppState appState) async {\n if (appState.isMinor) {\n return '''\nHi ${appState.userName}! 🌟\n\nMedicine questions are really important! Here's what you should do:\n\n**For Medicine Safety:**\n- Always ask a trusted adult before taking any medicine\n- Never take medicine by yourself\n- Tell adults about all medicines you take\n- Ask parents or guardians about medicine questions\n\n**Important:** Only doctors, parents, or guardians should decide about your medicines!\n\nRemember: Adults are there to keep you safe and healthy! 💙\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n\n final prompt = _buildMedicationInteractionPrompt(medications, appState);\n final result = await _safeApiCall(\n prompt, 'Error checking medication interactions',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Health insights with comprehensive data analysis\n Future<String> getHealthInsights(\n Map<String, dynamic> healthData, AppState appState) async {\n // If healthData is a string, treat it as a single chat message\n if (healthData is String) {\n final conversationHistory = [\n {'isUser': 'true', 'text': healthData}\n ];\n return sendChatMessage(conversationHistory, appState);\n }\n\n // Check for quick insights first\n if (healthData.isEmpty) {\n return _getDefaultHealthInsights(appState);\n }\n\n final prompt = _buildHealthInsightsPrompt(healthData, appState);\n final result = await _safeApiCall(prompt, 'Error getting health insights',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // NEW: Default health insights based on age\n String _getDefaultHealthInsights(AppState appState) {\n if (appState.isMinor) {\n return '''\n🌟 **Health Tips Just for You, ${appState.userName}!**\n\n**Stay Strong and Healthy:**\n🏃‍♀️ Play and be active every day - it's fun and makes you strong!\n😴 Get lots of sleep (9-11 hours) to help your body grow\n🥕 Eat colorful foods like fruits and vegetables\n💧 Drink water to keep your body happy\n🧠 Always tell trusted adults when you don't feel well\n\n**Remember:**\n- Your parents and guardians are there to help you stay healthy\n- Ask questions! Adults love to help you learn\n- You're doing great by learning about health! \n ''';\n } else {\n return '''\n🌟 **Personalized Health Insights for ${appState.userName}**\n\n**General Wellness Tips:**\n• Stay hydrated - aim for 8 glasses of water daily\n• Get 7-9 hours of quality sleep\n• Take regular breaks from screen time\n• Practice deep breathing exercises\n\n**Healthy Habits:**\n• Walk for 30 minutes daily\n• Eat colorful fruits and vegetables\n• Maintain regular meal times\n• Stay connected with loved ones\n\n💡 **Tip:** Add your health data to get more personalized insights!\n\n ''';\n }\n }\n\n // ENHANCED: Fallback response with age consideration\n String _getFallbackResponse(String userMessage, AppState appState) {\n final quickResponse = getQuickResponse(userMessage, appState);\n if (quickResponse != null) return quickResponse;\n\n return appState.getAgeAppropriateErrorMessage();\n }\n\n Future<String> _safeApiCall(String prompt, String contextMessage,\n {bool isChat = false, AppState? appState}) async {\n try {\n if (isChat) {\n return await _makeChatApiCall(prompt, appState);\n } else {\n return await _makeApiCallWithRetry(prompt, appState);\n }\n } on TimeoutException {\n if (kDebugMode) {\n print(\n '⏳ $contextMessage: Request timed out after ${_timeout.inSeconds}s');\n }\n if (isChat && appState != null) {\n final messages = jsonDecode(prompt) as List<dynamic>;\n final lastUserMessage = messages.lastWhere(\n (m) => m['role'] == 'user',\n orElse: () => {'content': ''},\n )['content'] ??\n '';\n return _getFallbackResponse(lastUserMessage, appState);\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'The request took longer than expected. Please try again.';\n } on SocketException catch (e) {\n if (kDebugMode) {\n print('🌐 Network error: ${e.message}');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'Network connection issue. Please check your internet and try again.';\n } catch (e) {\n if (kDebugMode) {\n print('⚠️ $contextMessage: $e');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'I\\'m experiencing technical difficulties. Please try again in a moment.';\n }\n }\n\n Future<String> _makeChatApiCall(\n String conversationHistoryJson, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive',\n 'Accept': 'application/json',\n };\n\n final List<dynamic> messages = jsonDecode(conversationHistoryJson);\n\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are MediPal, a helpful medical AI. Keep responses concise and include medical disclaimers.'\n });\n }\n\n String lastUserText = '';\n for (int i = messages.length - 1; i >= 0; i--) {\n if (messages[i]['role'] == 'user') {\n lastUserText = messages[i]['content'] ?? '';\n break;\n }\n }\n final maxTokens =\n appState != null ? _maxTokensForQuery(appState, lastUserText) : 300;\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': maxTokens,\n 'temperature': 0.4, // SIMPLIFIED\n 'top_p': 0.8,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _buildChatPrompt(\n List<Map<String, dynamic>> conversationHistory, AppState appState) {\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n return jsonEncode(messages);\n }\n\n // RESTORED: Working retry logic with exponential backoff\n Future<String> _makeApiCallWithRetry(\n String prompt, AppState? appState) async {\n int attempts = 0;\n\n while (true) {\n try {\n if (kDebugMode) {\n print('🔄 API attempt ${attempts + 1}/${_maxRetries + 1}');\n }\n return await _makeApiCall(prompt, appState);\n } on TimeoutException {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('⏳ Max retries reached after $attempts attempts');\n }\n rethrow;\n }\n\n // Use working retry delays with jitter\n final delayMs = _retryDelays[attempts - 1];\n final jitter =\n (delayMs * 0.1 * (DateTime.now().millisecond % 100) / 100).round();\n final finalDelay = delayMs + jitter;\n\n if (kDebugMode) {\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${finalDelay}ms');\n }\n await Future.delayed(Duration(milliseconds: finalDelay));\n } on SocketException catch (e) {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('🌐 Network error after $attempts attempts: ${e.message}');\n }\n rethrow;\n }\n\n final delayMs = _retryDelays[attempts - 1];\n if (kDebugMode) {\n print('🌐 Network issue, retrying in ${delayMs}ms...');\n }\n await Future.delayed(Duration(milliseconds: delayMs));\n } catch (e) {\n if (kDebugMode) {\n print('❌ Non-retryable error: $e');\n }\n rethrow;\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive', // Important for long requests\n };\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are a medical AI assistant. Provide concise, informative responses. Include medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(\n _timeout,\n onTimeout: () {\n throw TimeoutException(\n 'Request to DeepSeek API exceeded ${_timeout.inSeconds}s timeout',\n _timeout,\n );\n },\n );\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from DeepSeek API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // OPTIMIZED: Dramatically simplified symptom analysis prompt\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) {\n final buffer = StringBuffer();\n\n if (appState.isMinor) {\n buffer.writeln(\"Help young person (age ${appState.userAge}):\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n buffer.writeln(\n \"Provide: Simple explanation, when to tell adults. Keep brief under 200 words.\");\n } else {\n buffer\n .writeln(\"Analyze for ${appState.userAge}yo ${appState.userGender}:\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n\n // Only include top 3 additional info items to keep prompt short\n if (additionalInfo.isNotEmpty) {\n int count = 0;\n buffer.writeln(\"Info:\");\n for (var entry in additionalInfo.entries) {\n if (entry.value.toString().isNotEmpty && count < 3) {\n buffer.writeln(\"- ${entry.key}: ${entry.value}\");\n count++;\n }\n }\n }\n\n buffer.writeln(\n \"\\nProvide: Causes, when to see doctor, self-care, disclaimer. Under 300 words.\");\n }\n\n return buffer.toString();\n }\n\n // OPTIMIZED: Simplified medication interaction prompt\n String _buildMedicationInteractionPrompt(\n List<String> medications, AppState appState) {\n if (appState.isMinor) {\n return \"Minor asking about medicines. Redirect to trusted adults briefly.\";\n }\n\n return \"\"\"\nAnalyze interactions: ${medications.join(', ')}\nFor ${appState.userAge}yo ${appState.userGender}. \nProvide: 1) Risk level 2) Key effects 3) When to consult doctor 4) Disclaimer\nKeep under 250 words.\n\"\"\";\n }\n\n // OPTIMIZED: Wearable-driven health insights prompt\n String _buildHealthInsightsPrompt(\n Map<String, dynamic> healthData, AppState appState) {\n final buffer = StringBuffer();\n buffer.writeln(\n \"AI health insights for ${appState.userName} (${appState.userAge}yo, ${appState.userGender}).\");\n buffer.writeln(\n \"Use wearable summary + trends to provide: 1) Key insights 2) Tips to improve metrics 3) Encouraging next steps.\");\n buffer.writeln(\n \"If data is missing, say what's missing and give general tips.\");\n\n if (appState.isMinor) {\n buffer.writeln(\n \"Use lots of friendly emojis, simple language, and remind to talk to trusted adults.\");\n buffer.writeln(\"Keep under 180 words. Do not add a medical disclaimer.\");\n } else {\n buffer.writeln(\n \"Keep under 250 words, concise bullets. Do not add a medical disclaimer.\");\n }\n\n buffer.writeln(\"\\nWearable data (aggregates only):\");\n buffer.writeln(healthData.toString());\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl\\nTimeout: ${_timeout.inSeconds}s';\n}\n"}, "536d975b40b35e8cd09967fdbf159f1c616a56ac": {"t": 1785757937.6237805, "n": 35882, "h": "a4f410b69033c09d", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'dart:io';\nimport 'package:flutter/foundation.dart';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\nimport '../utils/app_state.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // RESTORED: Working timeout values from old version\n static const Duration _timeout = Duration(seconds: 30); // INCREASED from 20\n static const int _maxRetries = 2;\n// INCREASED from 3\n\n // RESTORED: Working retry delays with exponential backoff\n static const List<int> _retryDelays = [500, 1500]; // INCREASED from 300, 800\n\n // ENHANCED: Age-appropriate quick responses\n static const Map<String, Map<String, String>> _quickResponses = {\n 'hello': {\n 'minor':\n 'Hi there! 🌟 I\\'m here to help you learn about staying healthy! Remember to always ask a trusted adult if you have health questions!',\n 'adult':\n 'Hello! I\\'m MediPal, your health assistant. How can I help you today? 😊',\n },\n 'hi': {\n 'minor':\n 'Hi! 👋 I can teach you fun ways to stay healthy! Always talk to your parents or guardians about health stuff too!',\n 'adult':\n 'Hi there! I\\'m here to help with any health questions you might have! 🩺',\n },\n 'help': {\n 'minor':\n 'I can teach you about:\\n• Healthy foods and exercise 🥕\\n• Why sleep is important 😴\\n• When to tell adults you don\\'t feel well\\n• Fun ways to stay strong! 💪\\n\\nBut always ask trusted adults about health questions!',\n 'adult':\n 'I can help you with:\\n• Medical questions and symptoms\\n• Medication information\\n• Health guidance\\n• Emergency information\\n\\nWhat would you like to know?',\n },\n 'emergency': {\n 'minor':\n '🚨 **If there\\'s an emergency:**\\n\\n1. Find a trusted adult RIGHT AWAY\\n2. Call 911 if no adult is around\\n3. Stay calm and ask for help\\n\\nAlways tell adults when you don\\'t feel well!',\n 'adult':\n '🚨 **MEDICAL EMERGENCY?**\\n\\nCall 911 immediately if experiencing:\\n• Difficulty breathing\\n• Chest pain\\n• Severe bleeding\\n• Loss of consciousness',\n },\n 'thanks': {\n 'minor':\n 'You\\'re welcome! 🌟 Keep learning about staying healthy, and remember to always talk to trusted adults about health questions!',\n 'adult':\n 'You\\'re welcome! I\\'m always here to help with your health questions. Take care! 😊',\n },\n 'thank you': {\n 'minor':\n 'You\\'re so welcome! 🌟 Keep asking great questions and always talk to trusted adults about your health!',\n 'adult':\n 'You\\'re very welcome! Feel free to ask if you have more questions. Stay healthy! 💙',\n },\n };\n\n // NEW: Adult content keywords for filtering\n static const List<String> _adultContentKeywords = [\n 'sex',\n 'sexual',\n 'pregnancy',\n 'contraception',\n 'std',\n 'sti',\n 'reproductive',\n 'genital',\n 'abortion',\n 'breast',\n 'period',\n 'menstruation',\n 'testosterone',\n 'viagra',\n 'drug abuse',\n 'alcohol',\n 'addiction',\n 'overdose',\n 'suicide',\n 'self-harm',\n 'depression',\n 'anxiety disorder'\n ];\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n if (kDebugMode) {\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n }\n if (kDebugMode) {\n print(\"🌍 Base URL: $_baseUrl\");\n }\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n // ENHANCED: Age-appropriate quick responses with AppState\n String? getQuickResponse(String message, AppState appState) {\n final normalizedMessage = message.toLowerCase().trim();\n\n // Check for adult content if user is a minor\n if (appState.isMinor && _containsAdultContent(normalizedMessage)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n\n // Direct matches with age-appropriate responses\n if (_quickResponses.containsKey(normalizedMessage)) {\n final responses = _quickResponses[normalizedMessage]!;\n return appState.isMinor ? responses['minor'] : responses['adult'];\n }\n\n // Age-appropriate pattern matches\n return _getPatternBasedResponse(normalizedMessage, appState);\n }\n\n // NEW: Check for adult content\n bool _containsAdultContent(String message) {\n final lowerMessage = message.toLowerCase();\n return _adultContentKeywords\n .any((keyword) => lowerMessage.contains(keyword));\n }\n\n // NEW: Minor redirect response\n String _getMinorRedirectResponse(String userName) {\n return '''\nHi ${userName.isNotEmpty ? userName : 'there'}! 🌟\n\nI notice you're asking about something that might be better discussed with a trusted adult like a parent, guardian, or doctor.\n\n**What you can do:**\n- Talk to a parent or guardian about your question \n- Ask a school nurse or counselor\n- Visit a doctor with a trusted adult\n\nRemember: I'm here to help with general health information, but for anything serious or personal, it's always best to talk to a real person who can help you properly! 😊\n\nIs there something else I can help you with today?\n ''';\n }\n\n // ENHANCED: Pattern-based responses with age consideration\n String? _getPatternBasedResponse(String message, AppState appState) {\n if (message.contains('headache')) {\n return appState.isMinor\n ? '🤕 **If your head hurts:**\\n• Tell a trusted adult right away\\n• Rest in a quiet place\\n• Drink some water\\n• Ask an adult about what to do\\n\\n⚠️ Always let adults help you when you don\\'t feel well!'\n : '🩺 **Headache Relief:**\\n• Stay hydrated (drink water)\\n• Rest in a quiet, dark room\\n• Apply cold/warm compress\\n• Consider OTC pain relief\\n\\n⚠️ See a doctor if severe or persistent.';\n }\n\n if (message.contains('fever')) {\n return appState.isMinor\n ? '🌡️ **If you feel hot and sick:**\\n• Tell an adult immediately\\n• Rest and drink water\\n• Let adults check your temperature\\n• Ask for help from grown-ups\\n\\n⚠️ Adults know what to do when you have a fever!'\n : '🌡️ **Fever Management:**\\n• Stay hydrated\\n• Rest and monitor temperature\\n• Light clothing\\n• Seek medical attention if >101.5°F (38.6°C)\\n\\n⚠️ Contact healthcare provider if persistent.';\n }\n\n if (message.contains('medication') && message.contains('safe')) {\n return appState.isMinor\n ? '💊 **About Medicines:**\\n• Only adults should give you medicine\\n• Never take medicine by yourself\\n• Always ask trusted adults first\\n• Tell adults about any medicine questions\\n\\n⚠️ Medicine safety is super important - let adults handle it!'\n : '💊 **Medication Safety:**\\n• Always follow prescribed dosage\\n• Check for drug interactions\\n• Store properly\\n• Don\\'t share medications\\n\\n⚠️ Consult your pharmacist or doctor with questions.';\n }\n\n return null; // No quick response available\n }\n\n // OPTIMIZED: Dramatically simplified system prompts\n String _getAgeAppropriateSystemPrompt(AppState appState) {\n final basePrompt = '''\nYou are MediPal for ${appState.userName}, Age: ${appState.userAge}, Gender: ${appState.userGender}\n''';\n final wearablePrompt = appState.wearableSummaryPrompt;\n final wearableLine = wearablePrompt.isNotEmpty ? '\\n$wearablePrompt\\n' : '';\n final documentLine = appState.chatDocumentContext.isNotEmpty\n ? '\\nHealth document context (on-device, user-provided):\\n${appState.chatDocumentContext}\\nUse only if relevant, and do not request non-health documents.\\n'\n : '';\n\n if (appState.isMinor) {\n return '''\n$basePrompt\nMINOR (Under 18): Use simple language. Always direct to trusted adults. Focus on wellness and safety. \nAvoid: self-medication, detailed medical terms, sensitive topics. Keep under 250 words. End with reminder to talk to adults.\nUse lots of friendly emojis to make the response visually appealing.\nFollow the conversation context; if the user asks a short follow-up, connect it to the previous medical topic.\nOnly answer health-related questions. If asked about non-health topics (e.g., programming, tech, homework), politely refuse and redirect to health.\n$wearableLine$documentLine\n ''';\n } else if (appState.isYoungAdult) {\n return '''\n$basePrompt\nYOUNG ADULT (18-24): Clear educational language. Emphasize preventive care and professional consultation.\nKeep under 350 words with disclaimers.\nOnly answer health-related questions. If asked about non-health topics (e.g., programming, tech, homework), politely refuse and redirect to health.\nAnswer short questions with short responses (1-3 sentences). Provide detailed answers only when the user asks for detail.\nInclude medical disclaimers only for serious or emergency topics; omit for general questions.\n$wearableLine$documentLine\n ''';\n } else {\n return '''\n$basePrompt\nADULT (25+): Detailed medical-grade information with appropriate terminology. \nThorough analysis with disclaimers. Keep under 500 words.\nOnly answer health-related questions. If asked about non-health topics (e.g., programming, tech, homework), politely refuse and redirect to health.\nAnswer short questions with short responses (1-3 sentences). Provide detailed answers only when the user asks for detail.\nInclude medical disclaimers only for serious or emergency topics; omit for general questions.\n$wearableLine$documentLine\n ''';\n }\n }\n\n bool _isHealthRelated(String message) {\n final text = message.toLowerCase();\n const healthKeywords = [\n 'health',\n 'symptom',\n 'symptoms',\n 'pain',\n 'ache',\n 'fever',\n 'cough',\n 'cold',\n 'flu',\n 'allergy',\n 'asthma',\n 'blood',\n 'pressure',\n 'heart',\n 'pulse',\n 'sleep',\n 'insomnia',\n 'stress',\n 'anxiety',\n 'depression',\n 'mental',\n 'wellness',\n 'diet',\n 'nutrition',\n 'calorie',\n 'exercise',\n 'workout',\n 'steps',\n 'medicine',\n 'medication',\n 'drug',\n 'dosage',\n 'side effect',\n 'doctor',\n 'hospital',\n 'clinic',\n 'injury',\n 'wound',\n 'infection',\n 'virus',\n 'bacteria',\n 'headache',\n 'migraine',\n 'nausea',\n 'vomit',\n 'diarrhea',\n 'constipation',\n 'period',\n 'pregnancy',\n 'sex',\n 'sexual',\n 'skin',\n 'rash',\n 'itch',\n 'temperature',\n 'vaccin',\n 'immun',\n 'therapy',\n 'diagnos',\n 'treatment',\n 'surgery',\n 'cholesterol',\n 'glucose',\n 'diabetes',\n 'otc',\n 'relief',\n ];\n\n for (final keyword in healthKeywords) {\n if (text.contains(keyword)) {\n return true;\n }\n }\n return false;\n }\n\n bool _isHealthFollowUp(List<Map<String, String>> history, String lastText) {\n if (history.length < 2) return false;\n final prev = history[history.length - 2];\n if (prev['isUser'] == 'true') return false;\n final prevText = (prev['text'] ?? '').toLowerCase();\n if (prevText.isEmpty) return false;\n if (_isHealthRelated(prevText)) return true;\n final wordCount = lastText.trim().split(RegExp(r'\\s+')).length;\n return wordCount <= 4;\n }\n\n bool _isDetailRequest(String text) {\n final lower = text.toLowerCase();\n const detailMarkers = [\n 'detail',\n 'explain',\n 'why',\n 'how',\n 'cause',\n 'causes',\n 'treatment',\n 'plan',\n 'steps',\n 'step by step',\n 'tell me more',\n 'more info',\n 'in depth',\n ];\n return detailMarkers.any(lower.contains);\n }\n\n bool _isListRequest(String text) {\n final lower = text.toLowerCase();\n const listMarkers = [\n 'which',\n 'options',\n 'list',\n 'examples',\n 'types',\n 'kinds',\n 'what otc',\n 'otc',\n 'meds',\n 'medicine',\n ];\n return listMarkers.any(lower.contains);\n }\n\n bool _isShortQuery(String text) {\n final wordCount = text.trim().split(RegExp(r'\\s+')).length;\n return wordCount <= 5 && !_isDetailRequest(text);\n }\n\n int _maxTokensForQuery(AppState appState, String lastText) {\n if (_isDetailRequest(lastText)) {\n return appState.isMinor ? 220 : 380;\n }\n if (_isShortQuery(lastText)) {\n if (_isListRequest(lastText)) {\n return appState.isMinor ? 180 : 260;\n }\n return appState.isMinor ? 120 : 180;\n }\n return appState.isMinor ? 180 : 320;\n }\n\n bool _isSeriousMedicalTopic(String text) {\n final lower = text.toLowerCase();\n const seriousKeywords = [\n 'chest pain',\n 'shortness of breath',\n 'difficulty breathing',\n 'severe',\n 'sudden',\n 'faint',\n 'passed out',\n 'seizure',\n 'stroke',\n 'heart attack',\n 'overdose',\n 'bleeding',\n 'blood',\n 'suicidal',\n 'self-harm',\n 'pregnancy bleeding',\n 'high fever',\n 'persistent',\n 'worsening',\n 'emergency',\n ];\n return seriousKeywords.any(lower.contains);\n }\n\n // ENHANCED: Streaming with age restrictions and AppState\n Stream<String> streamChatResponse(\n List<Map<String, String>> conversationHistory, AppState appState) async* {\n // Check for quick response first\n String lastUserText = '';\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final lastText = lastMessage['text'] ?? '';\n lastUserText = lastText;\n if (lastText.trim().isNotEmpty &&\n !_isHealthRelated(lastText) &&\n !_isHealthFollowUp(conversationHistory, lastText)) {\n yield appState.isMinor\n ? 'I can only help with health questions. Please ask about your health, symptoms, medicines, or wellness, and I’ll do my best to help.'\n : 'I’m a health-only assistant, so I can’t help with that topic. Ask me about symptoms, medications, wellness, or other health questions.';\n return;\n }\n final hasPriorUserMessages =\n conversationHistory.where((m) => m['isUser'] == 'true').length > 1;\n if (!hasPriorUserMessages) {\n final quickResponse = getQuickResponse(lastText, appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 300));\n yield quickResponse;\n return;\n }\n }\n }\n }\n final maxTokens = _maxTokensForQuery(appState, lastUserText);\n\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Accept': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n };\n\n final messages = _buildMessageHistory(conversationHistory, appState);\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': maxTokens,\n 'temperature': 0.4, // SIMPLIFIED: Single value\n 'stream': true,\n 'top_p': 0.8,\n });\n\n http.Client? client;\n try {\n final request =\n http.Request('POST', Uri.parse('$_baseUrl/chat/completions'))\n ..headers.addAll(headers)\n ..body = body;\n\n client = http.Client();\n final streamedResponse = await client.send(request).timeout(_timeout);\n\n if (streamedResponse.statusCode != 200) {\n throw Exception(\n 'API request failed with status: ${streamedResponse.statusCode}');\n }\n\n String accumulatedText = '';\n\n await for (final line in streamedResponse.stream\n .transform(utf8.decoder)\n .transform(const LineSplitter())\n .where((line) => line.trim().isNotEmpty)) {\n if (line.startsWith('data: ')) {\n final data = line.substring(6).trim();\n\n if (data == '[DONE]') {\n break;\n }\n\n try {\n final json = jsonDecode(data);\n final content = json['choices']?[0]?['delta']?['content'];\n\n if (content != null && content.isNotEmpty) {\n accumulatedText += content;\n\n // Filter content for minors\n if (appState.isMinor && _containsAdultContent(accumulatedText)) {\n yield _getMinorRedirectResponse(appState.userName);\n break;\n }\n\n yield accumulatedText;\n }\n } catch (e) {\n continue;\n }\n }\n }\n\n // Add disclaimer only for serious topics\n if (accumulatedText.isNotEmpty &&\n _isSeriousMedicalTopic(lastUserText) &&\n !accumulatedText.contains(appState.ageAppropriateDisclaimer)) {\n final finalResponse =\n '$accumulatedText\\n\\n${appState.ageAppropriateDisclaimer}';\n yield finalResponse;\n }\n } catch (e) {\n if (kDebugMode) {\n print('❌ Streaming error: $e');\n }\n try {\n final response = await sendChatMessage(conversationHistory, appState);\n yield response;\n } catch (fallbackError) {\n yield appState.getAgeAppropriateErrorMessage();\n }\n } finally {\n client?.close();\n }\n }\n\n // ENHANCED: Chat with age restrictions and AppState\n Future<String> sendChatMessage(\n List<Map<String, dynamic>> conversationHistory, AppState appState) async {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final lastText = lastMessage['text'] ?? '';\n if (lastText.trim().isNotEmpty &&\n !_isHealthRelated(lastText) &&\n !_isHealthFollowUp(\n conversationHistory.cast<Map<String, String>>(), lastText)) {\n return appState.isMinor\n ? 'I can only help with health questions. Please ask about your health, symptoms, medicines, or wellness, and I’ll do my best to help.'\n : 'I’m a health-only assistant, so I can’t help with that topic. Ask me about symptoms, medications, wellness, or other health questions.';\n }\n final hasPriorUserMessages =\n conversationHistory.where((m) => m['isUser'] == 'true').length > 1;\n if (!hasPriorUserMessages) {\n final quickResponse = getQuickResponse(lastText, appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 500));\n return quickResponse;\n }\n }\n }\n }\n\n final prompt = _buildChatPrompt(conversationHistory, appState);\n final result = await _safeApiCall(prompt, 'Error in chat conversation',\n isChat: true, appState: appState);\n\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n final lastText = lastMessage['text'] ?? '';\n if (_isSeriousMedicalTopic(lastText) &&\n !result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n }\n return result;\n }\n\n // Helper method to build message history for streaming with age restrictions\n List<Map<String, String>> _buildMessageHistory(\n List<Map<String, String>> conversationHistory, AppState appState) {\n final messages = <Map<String, String>>[];\n\n // Add age-appropriate system message\n messages.add({\n 'role': 'system',\n 'content': _getAgeAppropriateSystemPrompt(appState),\n });\n\n // Convert conversation history\n for (final message in conversationHistory) {\n messages.add({\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n });\n }\n\n return messages;\n }\n\n // ENHANCED: Symptom analysis with age restrictions\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) async {\n // Check for adult content in symptoms for minors\n if (appState.isMinor) {\n final symptomsText = symptoms.join(' ').toLowerCase();\n if (_containsAdultContent(symptomsText)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n }\n\n final prompt = _buildSymptomAnalysisPrompt(\n symptoms, severity, additionalInfo, appState);\n final result = await _safeApiCall(prompt, 'Error analyzing symptoms',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Medication interactions with age restrictions\n Future<String> checkMedicationInteractions(\n List<String> medications, AppState appState) async {\n if (appState.isMinor) {\n return '''\nHi ${appState.userName}! 🌟\n\nMedicine questions are really important! Here's what you should do:\n\n**For Medicine Safety:**\n- Always ask a trusted adult before taking any medicine\n- Never take medicine by yourself\n- Tell adults about all medicines you take\n- Ask parents or guardians about medicine questions\n\n**Important:** Only doctors, parents, or guardians should decide about your medicines!\n\nRemember: Adults are there to keep you safe and healthy! 💙\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n\n final prompt = _buildMedicationInteractionPrompt(medications, appState);\n final result = await _safeApiCall(\n prompt, 'Error checking medication interactions',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Health insights with comprehensive data analysis\n Future<String> getHealthInsights(\n Map<String, dynamic> healthData, AppState appState) async {\n // If healthData is a string, treat it as a single chat message\n if (healthData is String) {\n final conversationHistory = [\n {'isUser': 'true', 'text': healthData}\n ];\n return sendChatMessage(conversationHistory, appState);\n }\n\n // Check for quick insights first\n if (healthData.isEmpty) {\n return _getDefaultHealthInsights(appState);\n }\n\n final prompt = _buildHealthInsightsPrompt(healthData, appState);\n final result = await _safeApiCall(prompt, 'Error getting health insights',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // NEW: Default health insights based on age\n String _getDefaultHealthInsights(AppState appState) {\n if (appState.isMinor) {\n return '''\n🌟 **Health Tips Just for You, ${appState.userName}!**\n\n**Stay Strong and Healthy:**\n🏃‍♀️ Play and be active every day - it's fun and makes you strong!\n😴 Get lots of sleep (9-11 hours) to help your body grow\n🥕 Eat colorful foods like fruits and vegetables\n💧 Drink water to keep your body happy\n🧠 Always tell trusted adults when you don't feel well\n\n**Remember:**\n- Your parents and guardians are there to help you stay healthy\n- Ask questions! Adults love to help you learn\n- You're doing great by learning about health! \n\n${appState.ageAppropriateDisclaimer}\n ''';\n } else {\n return '''\n🌟 **Personalized Health Insights for ${appState.userName}**\n\n**General Wellness Tips:**\n• Stay hydrated - aim for 8 glasses of water daily\n• Get 7-9 hours of quality sleep\n• Take regular breaks from screen time\n• Practice deep breathing exercises\n\n**Healthy Habits:**\n• Walk for 30 minutes daily\n• Eat colorful fruits and vegetables\n• Maintain regular meal times\n• Stay connected with loved ones\n\n💡 **Tip:** Add your health data to get more personalized insights!\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n }\n\n // ENHANCED: Fallback response with age consideration\n String _getFallbackResponse(String userMessage, AppState appState) {\n final quickResponse = getQuickResponse(userMessage, appState);\n if (quickResponse != null) return quickResponse;\n\n return appState.getAgeAppropriateErrorMessage();\n }\n\n Future<String> _safeApiCall(String prompt, String contextMessage,\n {bool isChat = false, AppState? appState}) async {\n try {\n if (isChat) {\n return await _makeChatApiCall(prompt, appState);\n } else {\n return await _makeApiCallWithRetry(prompt, appState);\n }\n } on TimeoutException {\n if (kDebugMode) {\n print(\n '⏳ $contextMessage: Request timed out after ${_timeout.inSeconds}s');\n }\n if (isChat && appState != null) {\n final messages = jsonDecode(prompt) as List<dynamic>;\n final lastUserMessage = messages.lastWhere(\n (m) => m['role'] == 'user',\n orElse: () => {'content': ''},\n )['content'] ??\n '';\n return _getFallbackResponse(lastUserMessage, appState);\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'The request took longer than expected. Please try again.';\n } on SocketException catch (e) {\n if (kDebugMode) {\n print('🌐 Network error: ${e.message}');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'Network connection issue. Please check your internet and try again.';\n } catch (e) {\n if (kDebugMode) {\n print('⚠️ $contextMessage: $e');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'I\\'m experiencing technical difficulties. Please try again in a moment.';\n }\n }\n\n Future<String> _makeChatApiCall(\n String conversationHistoryJson, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive',\n 'Accept': 'application/json',\n };\n\n final List<dynamic> messages = jsonDecode(conversationHistoryJson);\n\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are MediPal, a helpful medical AI. Keep responses concise and include medical disclaimers.'\n });\n }\n\n String lastUserText = '';\n for (int i = messages.length - 1; i >= 0; i--) {\n if (messages[i]['role'] == 'user') {\n lastUserText = messages[i]['content'] ?? '';\n break;\n }\n }\n final maxTokens =\n appState != null ? _maxTokensForQuery(appState, lastUserText) : 300;\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': maxTokens,\n 'temperature': 0.4, // SIMPLIFIED\n 'top_p': 0.8,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _buildChatPrompt(\n List<Map<String, dynamic>> conversationHistory, AppState appState) {\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n return jsonEncode(messages);\n }\n\n // RESTORED: Working retry logic with exponential backoff\n Future<String> _makeApiCallWithRetry(\n String prompt, AppState? appState) async {\n int attempts = 0;\n\n while (true) {\n try {\n if (kDebugMode) {\n print('🔄 API attempt ${attempts + 1}/${_maxRetries + 1}');\n }\n return await _makeApiCall(prompt, appState);\n } on TimeoutException {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('⏳ Max retries reached after $attempts attempts');\n }\n rethrow;\n }\n\n // Use working retry delays with jitter\n final delayMs = _retryDelays[attempts - 1];\n final jitter =\n (delayMs * 0.1 * (DateTime.now().millisecond % 100) / 100).round();\n final finalDelay = delayMs + jitter;\n\n if (kDebugMode) {\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${finalDelay}ms');\n }\n await Future.delayed(Duration(milliseconds: finalDelay));\n } on SocketException catch (e) {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('🌐 Network error after $attempts attempts: ${e.message}');\n }\n rethrow;\n }\n\n final delayMs = _retryDelays[attempts - 1];\n if (kDebugMode) {\n print('🌐 Network issue, retrying in ${delayMs}ms...');\n }\n await Future.delayed(Duration(milliseconds: delayMs));\n } catch (e) {\n if (kDebugMode) {\n print('❌ Non-retryable error: $e');\n }\n rethrow;\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive', // Important for long requests\n };\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are a medical AI assistant. Provide concise, informative responses. Include medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(\n _timeout,\n onTimeout: () {\n throw TimeoutException(\n 'Request to DeepSeek API exceeded ${_timeout.inSeconds}s timeout',\n _timeout,\n );\n },\n );\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from DeepSeek API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // OPTIMIZED: Dramatically simplified symptom analysis prompt\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) {\n final buffer = StringBuffer();\n\n if (appState.isMinor) {\n buffer.writeln(\"Help young person (age ${appState.userAge}):\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n buffer.writeln(\n \"Provide: Simple explanation, when to tell adults. Keep brief under 200 words.\");\n } else {\n buffer\n .writeln(\"Analyze for ${appState.userAge}yo ${appState.userGender}:\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n\n // Only include top 3 additional info items to keep prompt short\n if (additionalInfo.isNotEmpty) {\n int count = 0;\n buffer.writeln(\"Info:\");\n for (var entry in additionalInfo.entries) {\n if (entry.value.toString().isNotEmpty && count < 3) {\n buffer.writeln(\"- ${entry.key}: ${entry.value}\");\n count++;\n }\n }\n }\n\n buffer.writeln(\n \"\\nProvide: Causes, when to see doctor, self-care, disclaimer. Under 300 words.\");\n }\n\n return buffer.toString();\n }\n\n // OPTIMIZED: Simplified medication interaction prompt\n String _buildMedicationInteractionPrompt(\n List<String> medications, AppState appState) {\n if (appState.isMinor) {\n return \"Minor asking about medicines. Redirect to trusted adults briefly.\";\n }\n\n return \"\"\"\nAnalyze interactions: ${medications.join(', ')}\nFor ${appState.userAge}yo ${appState.userGender}. \nProvide: 1) Risk level 2) Key effects 3) When to consult doctor 4) Disclaimer\nKeep under 250 words.\n\"\"\";\n }\n\n // OPTIMIZED: Dramatically simplified health insights prompt\n String _buildHealthInsightsPrompt(\n Map<String, dynamic> healthData, AppState appState) {\n if (appState.isMinor) {\n return \"\"\"\nCreate health tips for ${appState.userName} (${appState.userAge}yo):\nFocus on: healthy habits, exercise, sleep, nutrition.\nUse simple, encouraging language. Mention trusted adults. Keep under 200 words.\n\"\"\";\n }\n\n // Extract only top 5 most relevant health data items\n final relevantData = <String, dynamic>{};\n final priorityKeys = [\n 'medications_count',\n 'health_score',\n 'sleep_hours',\n 'recent_symptoms',\n 'activity_level'\n ];\n\n for (final key in priorityKeys) {\n if (healthData.containsKey(key) &&\n healthData[key] != null &&\n healthData[key].toString().isNotEmpty) {\n relevantData[key] = healthData[key];\n }\n if (relevantData.length >= 5) break;\n }\n\n final buffer = StringBuffer();\n buffer.writeln(\n \"Health insights for ${appState.userName} (${appState.userAge}yo, ${appState.userGender}):\");\n\n if (relevantData.isNotEmpty) {\n relevantData.forEach((key, value) {\n buffer.writeln(\"- $key: $value\");\n });\n }\n\n buffer.writeln(\n \"\\nProvide: Assessment, lifestyle tips, improvements, encouragement. Under 350 words with disclaimer.\");\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl\\nTimeout: ${_timeout.inSeconds}s';\n}\n"}, "c50fead91e9e0eb2358a45077a519cf19f9e25b5": {"t": 1785757939.4013367, "n": 32588, "h": "208fbb37faf79da8", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'dart:io';\nimport 'package:flutter/foundation.dart';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\nimport '../utils/app_state.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // RESTORED: Working timeout values from old version\n static const Duration _timeout = Duration(seconds: 30); // INCREASED from 20\n static const int _maxRetries = 2;\n// INCREASED from 3\n\n // RESTORED: Working retry delays with exponential backoff\n static const List<int> _retryDelays = [500, 1500]; // INCREASED from 300, 800\n\n // ENHANCED: Age-appropriate quick responses\n static const Map<String, Map<String, String>> _quickResponses = {\n 'hello': {\n 'minor':\n 'Hi there! 🌟 I\\'m here to help you learn about staying healthy! Remember to always ask a trusted adult if you have health questions!',\n 'adult':\n 'Hello! I\\'m MediPal, your health assistant. How can I help you today? 😊',\n },\n 'hi': {\n 'minor':\n 'Hi! 👋 I can teach you fun ways to stay healthy! Always talk to your parents or guardians about health stuff too!',\n 'adult':\n 'Hi there! I\\'m here to help with any health questions you might have! 🩺',\n },\n 'help': {\n 'minor':\n 'I can teach you about:\\n• Healthy foods and exercise 🥕\\n• Why sleep is important 😴\\n• When to tell adults you don\\'t feel well\\n• Fun ways to stay strong! 💪\\n\\nBut always ask trusted adults about health questions!',\n 'adult':\n 'I can help you with:\\n• Medical questions and symptoms\\n• Medication information\\n• Health guidance\\n• Emergency information\\n\\nWhat would you like to know?',\n },\n 'emergency': {\n 'minor':\n '🚨 **If there\\'s an emergency:**\\n\\n1. Find a trusted adult RIGHT AWAY\\n2. Call 911 if no adult is around\\n3. Stay calm and ask for help\\n\\nAlways tell adults when you don\\'t feel well!',\n 'adult':\n '🚨 **MEDICAL EMERGENCY?**\\n\\nCall 911 immediately if experiencing:\\n• Difficulty breathing\\n• Chest pain\\n• Severe bleeding\\n• Loss of consciousness',\n },\n 'thanks': {\n 'minor':\n 'You\\'re welcome! 🌟 Keep learning about staying healthy, and remember to always talk to trusted adults about health questions!',\n 'adult':\n 'You\\'re welcome! I\\'m always here to help with your health questions. Take care! 😊',\n },\n 'thank you': {\n 'minor':\n 'You\\'re so welcome! 🌟 Keep asking great questions and always talk to trusted adults about your health!',\n 'adult':\n 'You\\'re very welcome! Feel free to ask if you have more questions. Stay healthy! 💙',\n },\n };\n\n // NEW: Adult content keywords for filtering\n static const List<String> _adultContentKeywords = [\n 'sex',\n 'sexual',\n 'pregnancy',\n 'contraception',\n 'std',\n 'sti',\n 'reproductive',\n 'genital',\n 'abortion',\n 'breast',\n 'period',\n 'menstruation',\n 'testosterone',\n 'viagra',\n 'drug abuse',\n 'alcohol',\n 'addiction',\n 'overdose',\n 'suicide',\n 'self-harm',\n 'depression',\n 'anxiety disorder'\n ];\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n if (kDebugMode) {\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n }\n if (kDebugMode) {\n print(\"🌍 Base URL: $_baseUrl\");\n }\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n // ENHANCED: Age-appropriate quick responses with AppState\n String? getQuickResponse(String message, AppState appState) {\n final normalizedMessage = message.toLowerCase().trim();\n\n // Check for adult content if user is a minor\n if (appState.isMinor && _containsAdultContent(normalizedMessage)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n\n // Direct matches with age-appropriate responses\n if (_quickResponses.containsKey(normalizedMessage)) {\n final responses = _quickResponses[normalizedMessage]!;\n return appState.isMinor ? responses['minor'] : responses['adult'];\n }\n\n // Age-appropriate pattern matches\n return _getPatternBasedResponse(normalizedMessage, appState);\n }\n\n // NEW: Check for adult content\n bool _containsAdultContent(String message) {\n final lowerMessage = message.toLowerCase();\n return _adultContentKeywords\n .any((keyword) => lowerMessage.contains(keyword));\n }\n\n // NEW: Minor redirect response\n String _getMinorRedirectResponse(String userName) {\n return '''\nHi ${userName.isNotEmpty ? userName : 'there'}! 🌟\n\nI notice you're asking about something that might be better discussed with a trusted adult like a parent, guardian, or doctor.\n\n**What you can do:**\n- Talk to a parent or guardian about your question \n- Ask a school nurse or counselor\n- Visit a doctor with a trusted adult\n\nRemember: I'm here to help with general health information, but for anything serious or personal, it's always best to talk to a real person who can help you properly! 😊\n\nIs there something else I can help you with today?\n ''';\n }\n\n // ENHANCED: Pattern-based responses with age consideration\n String? _getPatternBasedResponse(String message, AppState appState) {\n if (message.contains('headache')) {\n return appState.isMinor\n ? '🤕 **If your head hurts:**\\n• Tell a trusted adult right away\\n• Rest in a quiet place\\n• Drink some water\\n• Ask an adult about what to do\\n\\n⚠️ Always let adults help you when you don\\'t feel well!'\n : '🩺 **Headache Relief:**\\n• Stay hydrated (drink water)\\n• Rest in a quiet, dark room\\n• Apply cold/warm compress\\n• Consider OTC pain relief\\n\\n⚠️ See a doctor if severe or persistent.';\n }\n\n if (message.contains('fever')) {\n return appState.isMinor\n ? '🌡️ **If you feel hot and sick:**\\n• Tell an adult immediately\\n• Rest and drink water\\n• Let adults check your temperature\\n• Ask for help from grown-ups\\n\\n⚠️ Adults know what to do when you have a fever!'\n : '🌡️ **Fever Management:**\\n• Stay hydrated\\n• Rest and monitor temperature\\n• Light clothing\\n• Seek medical attention if >101.5°F (38.6°C)\\n\\n⚠️ Contact healthcare provider if persistent.';\n }\n\n if (message.contains('medication') && message.contains('safe')) {\n return appState.isMinor\n ? '💊 **About Medicines:**\\n• Only adults should give you medicine\\n• Never take medicine by yourself\\n• Always ask trusted adults first\\n• Tell adults about any medicine questions\\n\\n⚠️ Medicine safety is super important - let adults handle it!'\n : '💊 **Medication Safety:**\\n• Always follow prescribed dosage\\n• Check for drug interactions\\n• Store properly\\n• Don\\'t share medications\\n\\n⚠️ Consult your pharmacist or doctor with questions.';\n }\n\n return null; // No quick response available\n }\n\n // OPTIMIZED: Dramatically simplified system prompts\n String _getAgeAppropriateSystemPrompt(AppState appState) {\n final basePrompt = '''\nYou are MediPal for ${appState.userName}, Age: ${appState.userAge}, Gender: ${appState.userGender}\n''';\n final wearablePrompt = appState.wearableSummaryPrompt;\n final wearableLine = wearablePrompt.isNotEmpty ? '\\n$wearablePrompt\\n' : '';\n final documentLine = appState.chatDocumentContext.isNotEmpty\n ? '\\nHealth document context (on-device, user-provided):\\n${appState.chatDocumentContext}\\nUse only if relevant, and do not request non-health documents.\\n'\n : '';\n\n if (appState.isMinor) {\n return '''\n$basePrompt\nMINOR (Under 18): Use simple language. Always direct to trusted adults. Focus on wellness and safety. \nAvoid: self-medication, detailed medical terms, sensitive topics. Keep under 250 words. End with reminder to talk to adults.\nOnly answer health-related questions. If asked about non-health topics (e.g., programming, tech, homework), politely refuse and redirect to health.\n$wearableLine$documentLine\n ''';\n } else if (appState.isYoungAdult) {\n return '''\n$basePrompt\nYOUNG ADULT (18-24): Clear educational language. Emphasize preventive care and professional consultation.\nKeep under 350 words with disclaimers.\nOnly answer health-related questions. If asked about non-health topics (e.g., programming, tech, homework), politely refuse and redirect to health.\n$wearableLine$documentLine\n ''';\n } else {\n return '''\n$basePrompt\nADULT (25+): Detailed medical-grade information with appropriate terminology. \nThorough analysis with disclaimers. Keep under 500 words.\nOnly answer health-related questions. If asked about non-health topics (e.g., programming, tech, homework), politely refuse and redirect to health.\n$wearableLine$documentLine\n ''';\n }\n }\n\n bool _isHealthRelated(String message) {\n final text = message.toLowerCase();\n const healthKeywords = [\n 'health',\n 'symptom',\n 'symptoms',\n 'pain',\n 'ache',\n 'fever',\n 'cough',\n 'cold',\n 'flu',\n 'allergy',\n 'asthma',\n 'blood',\n 'pressure',\n 'heart',\n 'pulse',\n 'sleep',\n 'insomnia',\n 'stress',\n 'anxiety',\n 'depression',\n 'mental',\n 'wellness',\n 'diet',\n 'nutrition',\n 'calorie',\n 'exercise',\n 'workout',\n 'steps',\n 'medicine',\n 'medication',\n 'drug',\n 'dosage',\n 'side effect',\n 'doctor',\n 'hospital',\n 'clinic',\n 'injury',\n 'wound',\n 'infection',\n 'virus',\n 'bacteria',\n 'headache',\n 'migraine',\n 'nausea',\n 'vomit',\n 'diarrhea',\n 'constipation',\n 'period',\n 'pregnancy',\n 'sex',\n 'sexual',\n 'skin',\n 'rash',\n 'itch',\n 'temperature',\n 'vaccin',\n 'immun',\n 'therapy',\n 'diagnos',\n 'treatment',\n 'surgery',\n 'cholesterol',\n 'glucose',\n 'diabetes',\n 'otc',\n 'relief',\n ];\n\n for (final keyword in healthKeywords) {\n if (text.contains(keyword)) {\n return true;\n }\n }\n return false;\n }\n\n bool _isHealthFollowUp(List<Map<String, String>> history, String lastText) {\n if (history.length < 2) return false;\n final prev = history[history.length - 2];\n if (prev['isUser'] == 'true') return false;\n final prevText = (prev['text'] ?? '').toLowerCase();\n if (prevText.isEmpty) return false;\n if (_isHealthRelated(prevText)) return true;\n final wordCount = lastText.trim().split(RegExp(r'\\\\s+')).length;\n return wordCount <= 4;\n }\n\n // ENHANCED: Streaming with age restrictions and AppState\n Stream<String> streamChatResponse(\n List<Map<String, String>> conversationHistory, AppState appState) async* {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final lastText = lastMessage['text'] ?? '';\n if (lastText.trim().isNotEmpty &&\n !_isHealthRelated(lastText) &&\n !_isHealthFollowUp(conversationHistory, lastText)) {\n yield appState.isMinor\n ? 'I can only help with health questions. Please ask about your health, symptoms, medicines, or wellness, and I’ll do my best to help.'\n : 'I’m a health-only assistant, so I can’t help with that topic. Ask me about symptoms, medications, wellness, or other health questions.';\n return;\n }\n final quickResponse =\n getQuickResponse(lastText, appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 300));\n yield quickResponse;\n return;\n }\n }\n }\n\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Accept': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n };\n\n final messages = _buildMessageHistory(conversationHistory, appState);\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': appState.isMinor ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED: Single value\n 'stream': true,\n 'top_p': 0.8,\n });\n\n http.Client? client;\n try {\n final request =\n http.Request('POST', Uri.parse('$_baseUrl/chat/completions'))\n ..headers.addAll(headers)\n ..body = body;\n\n client = http.Client();\n final streamedResponse = await client.send(request).timeout(_timeout);\n\n if (streamedResponse.statusCode != 200) {\n throw Exception(\n 'API request failed with status: ${streamedResponse.statusCode}');\n }\n\n String accumulatedText = '';\n\n await for (final line in streamedResponse.stream\n .transform(utf8.decoder)\n .transform(const LineSplitter())\n .where((line) => line.trim().isNotEmpty)) {\n if (line.startsWith('data: ')) {\n final data = line.substring(6).trim();\n\n if (data == '[DONE]') {\n break;\n }\n\n try {\n final json = jsonDecode(data);\n final content = json['choices']?[0]?['delta']?['content'];\n\n if (content != null && content.isNotEmpty) {\n accumulatedText += content;\n\n // Filter content for minors\n if (appState.isMinor && _containsAdultContent(accumulatedText)) {\n yield _getMinorRedirectResponse(appState.userName);\n break;\n }\n\n yield accumulatedText;\n }\n } catch (e) {\n continue;\n }\n }\n }\n\n // Add age-appropriate disclaimer\n if (accumulatedText.isNotEmpty &&\n !accumulatedText.contains(appState.ageAppropriateDisclaimer)) {\n final finalResponse =\n '$accumulatedText\\n\\n${appState.ageAppropriateDisclaimer}';\n yield finalResponse;\n }\n } catch (e) {\n if (kDebugMode) {\n print('❌ Streaming error: $e');\n }\n try {\n final response = await sendChatMessage(conversationHistory, appState);\n yield response;\n } catch (fallbackError) {\n yield appState.getAgeAppropriateErrorMessage();\n }\n } finally {\n client?.close();\n }\n }\n\n // ENHANCED: Chat with age restrictions and AppState\n Future<String> sendChatMessage(\n List<Map<String, dynamic>> conversationHistory, AppState appState) async {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final lastText = lastMessage['text'] ?? '';\n if (lastText.trim().isNotEmpty &&\n !_isHealthRelated(lastText) &&\n !_isHealthFollowUp(\n conversationHistory.cast<Map<String, String>>(), lastText)) {\n return appState.isMinor\n ? 'I can only help with health questions. Please ask about your health, symptoms, medicines, or wellness, and I’ll do my best to help.'\n : 'I’m a health-only assistant, so I can’t help with that topic. Ask me about symptoms, medications, wellness, or other health questions.';\n }\n final quickResponse =\n getQuickResponse(lastText, appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 500));\n return quickResponse;\n }\n }\n }\n\n final prompt = _buildChatPrompt(conversationHistory, appState);\n final result = await _safeApiCall(prompt, 'Error in chat conversation',\n isChat: true, appState: appState);\n\n // Add age-appropriate disclaimer if not already present\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // Helper method to build message history for streaming with age restrictions\n List<Map<String, String>> _buildMessageHistory(\n List<Map<String, String>> conversationHistory, AppState appState) {\n final messages = <Map<String, String>>[];\n\n // Add age-appropriate system message\n messages.add({\n 'role': 'system',\n 'content': _getAgeAppropriateSystemPrompt(appState),\n });\n\n // Convert conversation history\n for (final message in conversationHistory) {\n messages.add({\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n });\n }\n\n return messages;\n }\n\n // ENHANCED: Symptom analysis with age restrictions\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) async {\n // Check for adult content in symptoms for minors\n if (appState.isMinor) {\n final symptomsText = symptoms.join(' ').toLowerCase();\n if (_containsAdultContent(symptomsText)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n }\n\n final prompt = _buildSymptomAnalysisPrompt(\n symptoms, severity, additionalInfo, appState);\n final result = await _safeApiCall(prompt, 'Error analyzing symptoms',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Medication interactions with age restrictions\n Future<String> checkMedicationInteractions(\n List<String> medications, AppState appState) async {\n if (appState.isMinor) {\n return '''\nHi ${appState.userName}! 🌟\n\nMedicine questions are really important! Here's what you should do:\n\n**For Medicine Safety:**\n- Always ask a trusted adult before taking any medicine\n- Never take medicine by yourself\n- Tell adults about all medicines you take\n- Ask parents or guardians about medicine questions\n\n**Important:** Only doctors, parents, or guardians should decide about your medicines!\n\nRemember: Adults are there to keep you safe and healthy! 💙\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n\n final prompt = _buildMedicationInteractionPrompt(medications, appState);\n final result = await _safeApiCall(\n prompt, 'Error checking medication interactions',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Health insights with comprehensive data analysis\n Future<String> getHealthInsights(\n Map<String, dynamic> healthData, AppState appState) async {\n // If healthData is a string, treat it as a single chat message\n if (healthData is String) {\n final conversationHistory = [\n {'isUser': 'true', 'text': healthData}\n ];\n return sendChatMessage(conversationHistory, appState);\n }\n\n // Check for quick insights first\n if (healthData.isEmpty) {\n return _getDefaultHealthInsights(appState);\n }\n\n final prompt = _buildHealthInsightsPrompt(healthData, appState);\n final result = await _safeApiCall(prompt, 'Error getting health insights',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // NEW: Default health insights based on age\n String _getDefaultHealthInsights(AppState appState) {\n if (appState.isMinor) {\n return '''\n🌟 **Health Tips Just for You, ${appState.userName}!**\n\n**Stay Strong and Healthy:**\n🏃‍♀️ Play and be active every day - it's fun and makes you strong!\n😴 Get lots of sleep (9-11 hours) to help your body grow\n🥕 Eat colorful foods like fruits and vegetables\n💧 Drink water to keep your body happy\n🧠 Always tell trusted adults when you don't feel well\n\n**Remember:**\n- Your parents and guardians are there to help you stay healthy\n- Ask questions! Adults love to help you learn\n- You're doing great by learning about health! \n\n${appState.ageAppropriateDisclaimer}\n ''';\n } else {\n return '''\n🌟 **Personalized Health Insights for ${appState.userName}**\n\n**General Wellness Tips:**\n• Stay hydrated - aim for 8 glasses of water daily\n• Get 7-9 hours of quality sleep\n• Take regular breaks from screen time\n• Practice deep breathing exercises\n\n**Healthy Habits:**\n• Walk for 30 minutes daily\n• Eat colorful fruits and vegetables\n• Maintain regular meal times\n• Stay connected with loved ones\n\n💡 **Tip:** Add your health data to get more personalized insights!\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n }\n\n // ENHANCED: Fallback response with age consideration\n String _getFallbackResponse(String userMessage, AppState appState) {\n final quickResponse = getQuickResponse(userMessage, appState);\n if (quickResponse != null) return quickResponse;\n\n return appState.getAgeAppropriateErrorMessage();\n }\n\n Future<String> _safeApiCall(String prompt, String contextMessage,\n {bool isChat = false, AppState? appState}) async {\n try {\n if (isChat) {\n return await _makeChatApiCall(prompt, appState);\n } else {\n return await _makeApiCallWithRetry(prompt, appState);\n }\n } on TimeoutException {\n if (kDebugMode) {\n print(\n '⏳ $contextMessage: Request timed out after ${_timeout.inSeconds}s');\n }\n if (isChat && appState != null) {\n final messages = jsonDecode(prompt) as List<dynamic>;\n final lastUserMessage = messages.lastWhere(\n (m) => m['role'] == 'user',\n orElse: () => {'content': ''},\n )['content'] ??\n '';\n return _getFallbackResponse(lastUserMessage, appState);\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'The request took longer than expected. Please try again.';\n } on SocketException catch (e) {\n if (kDebugMode) {\n print('🌐 Network error: ${e.message}');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'Network connection issue. Please check your internet and try again.';\n } catch (e) {\n if (kDebugMode) {\n print('⚠️ $contextMessage: $e');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'I\\'m experiencing technical difficulties. Please try again in a moment.';\n }\n }\n\n Future<String> _makeChatApiCall(\n String conversationHistoryJson, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive',\n 'Accept': 'application/json',\n };\n\n final List<dynamic> messages = jsonDecode(conversationHistoryJson);\n\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are MediPal, a helpful medical AI. Keep responses concise and include medical disclaimers.'\n });\n }\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n 'top_p': 0.8,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _buildChatPrompt(\n List<Map<String, dynamic>> conversationHistory, AppState appState) {\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n return jsonEncode(messages);\n }\n\n // RESTORED: Working retry logic with exponential backoff\n Future<String> _makeApiCallWithRetry(\n String prompt, AppState? appState) async {\n int attempts = 0;\n\n while (true) {\n try {\n if (kDebugMode) {\n print('🔄 API attempt ${attempts + 1}/${_maxRetries + 1}');\n }\n return await _makeApiCall(prompt, appState);\n } on TimeoutException {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('⏳ Max retries reached after $attempts attempts');\n }\n rethrow;\n }\n\n // Use working retry delays with jitter\n final delayMs = _retryDelays[attempts - 1];\n final jitter =\n (delayMs * 0.1 * (DateTime.now().millisecond % 100) / 100).round();\n final finalDelay = delayMs + jitter;\n\n if (kDebugMode) {\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${finalDelay}ms');\n }\n await Future.delayed(Duration(milliseconds: finalDelay));\n } on SocketException catch (e) {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('🌐 Network error after $attempts attempts: ${e.message}');\n }\n rethrow;\n }\n\n final delayMs = _retryDelays[attempts - 1];\n if (kDebugMode) {\n print('🌐 Network issue, retrying in ${delayMs}ms...');\n }\n await Future.delayed(Duration(milliseconds: delayMs));\n } catch (e) {\n if (kDebugMode) {\n print('❌ Non-retryable error: $e');\n }\n rethrow;\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive', // Important for long requests\n };\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are a medical AI assistant. Provide concise, informative responses. Include medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(\n _timeout,\n onTimeout: () {\n throw TimeoutException(\n 'Request to DeepSeek API exceeded ${_timeout.inSeconds}s timeout',\n _timeout,\n );\n },\n );\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from DeepSeek API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // OPTIMIZED: Dramatically simplified symptom analysis prompt\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) {\n final buffer = StringBuffer();\n\n if (appState.isMinor) {\n buffer.writeln(\"Help young person (age ${appState.userAge}):\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n buffer.writeln(\n \"Provide: Simple explanation, when to tell adults. Keep brief under 200 words.\");\n } else {\n buffer\n .writeln(\"Analyze for ${appState.userAge}yo ${appState.userGender}:\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n\n // Only include top 3 additional info items to keep prompt short\n if (additionalInfo.isNotEmpty) {\n int count = 0;\n buffer.writeln(\"Info:\");\n for (var entry in additionalInfo.entries) {\n if (entry.value.toString().isNotEmpty && count < 3) {\n buffer.writeln(\"- ${entry.key}: ${entry.value}\");\n count++;\n }\n }\n }\n\n buffer.writeln(\n \"\\nProvide: Causes, when to see doctor, self-care, disclaimer. Under 300 words.\");\n }\n\n return buffer.toString();\n }\n\n // OPTIMIZED: Simplified medication interaction prompt\n String _buildMedicationInteractionPrompt(\n List<String> medications, AppState appState) {\n if (appState.isMinor) {\n return \"Minor asking about medicines. Redirect to trusted adults briefly.\";\n }\n\n return \"\"\"\nAnalyze interactions: ${medications.join(', ')}\nFor ${appState.userAge}yo ${appState.userGender}. \nProvide: 1) Risk level 2) Key effects 3) When to consult doctor 4) Disclaimer\nKeep under 250 words.\n\"\"\";\n }\n\n // OPTIMIZED: Dramatically simplified health insights prompt\n String _buildHealthInsightsPrompt(\n Map<String, dynamic> healthData, AppState appState) {\n if (appState.isMinor) {\n return \"\"\"\nCreate health tips for ${appState.userName} (${appState.userAge}yo):\nFocus on: healthy habits, exercise, sleep, nutrition.\nUse simple, encouraging language. Mention trusted adults. Keep under 200 words.\n\"\"\";\n }\n\n // Extract only top 5 most relevant health data items\n final relevantData = <String, dynamic>{};\n final priorityKeys = [\n 'medications_count',\n 'health_score',\n 'sleep_hours',\n 'recent_symptoms',\n 'activity_level'\n ];\n\n for (final key in priorityKeys) {\n if (healthData.containsKey(key) &&\n healthData[key] != null &&\n healthData[key].toString().isNotEmpty) {\n relevantData[key] = healthData[key];\n }\n if (relevantData.length >= 5) break;\n }\n\n final buffer = StringBuffer();\n buffer.writeln(\n \"Health insights for ${appState.userName} (${appState.userAge}yo, ${appState.userGender}):\");\n\n if (relevantData.isNotEmpty) {\n relevantData.forEach((key, value) {\n buffer.writeln(\"- $key: $value\");\n });\n }\n\n buffer.writeln(\n \"\\nProvide: Assessment, lifestyle tips, improvements, encouragement. Under 350 words with disclaimer.\");\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl\\nTimeout: ${_timeout.inSeconds}s';\n}\n"}, "972b61d88f0af570ebe9c11945c5ac582cbd3b7c": {"t": 1785757941.0154414, "n": 29168, "h": "225848d5229b0ab0", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'dart:io';\nimport 'package:flutter/foundation.dart';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\nimport '../utils/app_state.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // RESTORED: Working timeout values from old version\n static const Duration _timeout = Duration(seconds: 30); // INCREASED from 20\n static const int _maxRetries = 2;\n// INCREASED from 3\n\n // RESTORED: Working retry delays with exponential backoff\n static const List<int> _retryDelays = [500, 1500]; // INCREASED from 300, 800\n\n // ENHANCED: Age-appropriate quick responses\n static const Map<String, Map<String, String>> _quickResponses = {\n 'hello': {\n 'minor':\n 'Hi there! 🌟 I\\'m here to help you learn about staying healthy! Remember to always ask a trusted adult if you have health questions!',\n 'adult':\n 'Hello! I\\'m MediPal, your health assistant. How can I help you today? 😊',\n },\n 'hi': {\n 'minor':\n 'Hi! 👋 I can teach you fun ways to stay healthy! Always talk to your parents or guardians about health stuff too!',\n 'adult':\n 'Hi there! I\\'m here to help with any health questions you might have! 🩺',\n },\n 'help': {\n 'minor':\n 'I can teach you about:\\n• Healthy foods and exercise 🥕\\n• Why sleep is important 😴\\n• When to tell adults you don\\'t feel well\\n• Fun ways to stay strong! 💪\\n\\nBut always ask trusted adults about health questions!',\n 'adult':\n 'I can help you with:\\n• Medical questions and symptoms\\n• Medication information\\n• Health guidance\\n• Emergency information\\n\\nWhat would you like to know?',\n },\n 'emergency': {\n 'minor':\n '🚨 **If there\\'s an emergency:**\\n\\n1. Find a trusted adult RIGHT AWAY\\n2. Call 911 if no adult is around\\n3. Stay calm and ask for help\\n\\nAlways tell adults when you don\\'t feel well!',\n 'adult':\n '🚨 **MEDICAL EMERGENCY?**\\n\\nCall 911 immediately if experiencing:\\n• Difficulty breathing\\n• Chest pain\\n• Severe bleeding\\n• Loss of consciousness',\n },\n 'thanks': {\n 'minor':\n 'You\\'re welcome! 🌟 Keep learning about staying healthy, and remember to always talk to trusted adults about health questions!',\n 'adult':\n 'You\\'re welcome! I\\'m always here to help with your health questions. Take care! 😊',\n },\n 'thank you': {\n 'minor':\n 'You\\'re so welcome! 🌟 Keep asking great questions and always talk to trusted adults about your health!',\n 'adult':\n 'You\\'re very welcome! Feel free to ask if you have more questions. Stay healthy! 💙',\n },\n };\n\n // NEW: Adult content keywords for filtering\n static const List<String> _adultContentKeywords = [\n 'sex',\n 'sexual',\n 'pregnancy',\n 'contraception',\n 'std',\n 'sti',\n 'reproductive',\n 'genital',\n 'abortion',\n 'breast',\n 'period',\n 'menstruation',\n 'testosterone',\n 'viagra',\n 'drug abuse',\n 'alcohol',\n 'addiction',\n 'overdose',\n 'suicide',\n 'self-harm',\n 'depression',\n 'anxiety disorder'\n ];\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n if (kDebugMode) {\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n }\n if (kDebugMode) {\n print(\"🌍 Base URL: $_baseUrl\");\n }\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n // ENHANCED: Age-appropriate quick responses with AppState\n String? getQuickResponse(String message, AppState appState) {\n final normalizedMessage = message.toLowerCase().trim();\n\n // Check for adult content if user is a minor\n if (appState.isMinor && _containsAdultContent(normalizedMessage)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n\n // Direct matches with age-appropriate responses\n if (_quickResponses.containsKey(normalizedMessage)) {\n final responses = _quickResponses[normalizedMessage]!;\n return appState.isMinor ? responses['minor'] : responses['adult'];\n }\n\n // Age-appropriate pattern matches\n return _getPatternBasedResponse(normalizedMessage, appState);\n }\n\n // NEW: Check for adult content\n bool _containsAdultContent(String message) {\n final lowerMessage = message.toLowerCase();\n return _adultContentKeywords\n .any((keyword) => lowerMessage.contains(keyword));\n }\n\n // NEW: Minor redirect response\n String _getMinorRedirectResponse(String userName) {\n return '''\nHi ${userName.isNotEmpty ? userName : 'there'}! 🌟\n\nI notice you're asking about something that might be better discussed with a trusted adult like a parent, guardian, or doctor.\n\n**What you can do:**\n- Talk to a parent or guardian about your question \n- Ask a school nurse or counselor\n- Visit a doctor with a trusted adult\n\nRemember: I'm here to help with general health information, but for anything serious or personal, it's always best to talk to a real person who can help you properly! 😊\n\nIs there something else I can help you with today?\n ''';\n }\n\n // ENHANCED: Pattern-based responses with age consideration\n String? _getPatternBasedResponse(String message, AppState appState) {\n if (message.contains('headache')) {\n return appState.isMinor\n ? '🤕 **If your head hurts:**\\n• Tell a trusted adult right away\\n• Rest in a quiet place\\n• Drink some water\\n• Ask an adult about what to do\\n\\n⚠️ Always let adults help you when you don\\'t feel well!'\n : '🩺 **Headache Relief:**\\n• Stay hydrated (drink water)\\n• Rest in a quiet, dark room\\n• Apply cold/warm compress\\n• Consider OTC pain relief\\n\\n⚠️ See a doctor if severe or persistent.';\n }\n\n if (message.contains('fever')) {\n return appState.isMinor\n ? '🌡️ **If you feel hot and sick:**\\n• Tell an adult immediately\\n• Rest and drink water\\n• Let adults check your temperature\\n• Ask for help from grown-ups\\n\\n⚠️ Adults know what to do when you have a fever!'\n : '🌡️ **Fever Management:**\\n• Stay hydrated\\n• Rest and monitor temperature\\n• Light clothing\\n• Seek medical attention if >101.5°F (38.6°C)\\n\\n⚠️ Contact healthcare provider if persistent.';\n }\n\n if (message.contains('medication') && message.contains('safe')) {\n return appState.isMinor\n ? '💊 **About Medicines:**\\n• Only adults should give you medicine\\n• Never take medicine by yourself\\n• Always ask trusted adults first\\n• Tell adults about any medicine questions\\n\\n⚠️ Medicine safety is super important - let adults handle it!'\n : '💊 **Medication Safety:**\\n• Always follow prescribed dosage\\n• Check for drug interactions\\n• Store properly\\n• Don\\'t share medications\\n\\n⚠️ Consult your pharmacist or doctor with questions.';\n }\n\n return null; // No quick response available\n }\n\n // OPTIMIZED: Dramatically simplified system prompts\n String _getAgeAppropriateSystemPrompt(AppState appState) {\n final basePrompt = '''\nYou are MediPal for ${appState.userName}, Age: ${appState.userAge}, Gender: ${appState.userGender}\n''';\n final wearablePrompt = appState.wearableSummaryPrompt;\n final wearableLine = wearablePrompt.isNotEmpty ? '\\n$wearablePrompt\\n' : '';\n final documentLine = appState.chatDocumentContext.isNotEmpty\n ? '\\nHealth document context (on-device, user-provided):\\n${appState.chatDocumentContext}\\nUse only if relevant, and do not request non-health documents.\\n'\n : '';\n\n if (appState.isMinor) {\n return '''\n$basePrompt\nMINOR (Under 18): Use simple language. Always direct to trusted adults. Focus on wellness and safety. \nAvoid: self-medication, detailed medical terms, sensitive topics. Keep under 250 words. End with reminder to talk to adults.\n$wearableLine$documentLine\n ''';\n } else if (appState.isYoungAdult) {\n return '''\n$basePrompt\nYOUNG ADULT (18-24): Clear educational language. Emphasize preventive care and professional consultation.\nKeep under 350 words with disclaimers.\n$wearableLine$documentLine\n ''';\n } else {\n return '''\n$basePrompt\nADULT (25+): Detailed medical-grade information with appropriate terminology. \nThorough analysis with disclaimers. Keep under 500 words.\n$wearableLine$documentLine\n ''';\n }\n }\n\n // ENHANCED: Streaming with age restrictions and AppState\n Stream<String> streamChatResponse(\n List<Map<String, String>> conversationHistory, AppState appState) async* {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final quickResponse =\n getQuickResponse(lastMessage['text'] ?? '', appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 300));\n yield quickResponse;\n return;\n }\n }\n }\n\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Accept': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n };\n\n final messages = _buildMessageHistory(conversationHistory, appState);\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': appState.isMinor ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED: Single value\n 'stream': true,\n 'top_p': 0.8,\n });\n\n try {\n final request =\n http.Request('POST', Uri.parse('$_baseUrl/chat/completions'))\n ..headers.addAll(headers)\n ..body = body;\n\n final client = http.Client();\n final streamedResponse = await client.send(request).timeout(_timeout);\n\n if (streamedResponse.statusCode != 200) {\n throw Exception(\n 'API request failed with status: ${streamedResponse.statusCode}');\n }\n\n String accumulatedText = '';\n\n await for (final line in streamedResponse.stream\n .transform(utf8.decoder)\n .transform(const LineSplitter())\n .where((line) => line.trim().isNotEmpty)) {\n if (line.startsWith('data: ')) {\n final data = line.substring(6).trim();\n\n if (data == '[DONE]') {\n break;\n }\n\n try {\n final json = jsonDecode(data);\n final content = json['choices']?[0]?['delta']?['content'];\n\n if (content != null && content.isNotEmpty) {\n accumulatedText += content;\n\n // Filter content for minors\n if (appState.isMinor && _containsAdultContent(accumulatedText)) {\n yield _getMinorRedirectResponse(appState.userName);\n break;\n }\n\n yield accumulatedText;\n }\n } catch (e) {\n continue;\n }\n }\n }\n\n client.close();\n\n // Add age-appropriate disclaimer\n if (accumulatedText.isNotEmpty &&\n !accumulatedText.contains(appState.ageAppropriateDisclaimer)) {\n final finalResponse =\n '$accumulatedText\\n\\n${appState.ageAppropriateDisclaimer}';\n yield finalResponse;\n }\n } catch (e) {\n if (kDebugMode) {\n print('❌ Streaming error: $e');\n }\n try {\n final response = await sendChatMessage(conversationHistory, appState);\n yield response;\n } catch (fallbackError) {\n yield appState.getAgeAppropriateErrorMessage();\n }\n }\n }\n\n // ENHANCED: Chat with age restrictions and AppState\n Future<String> sendChatMessage(\n List<Map<String, dynamic>> conversationHistory, AppState appState) async {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final quickResponse =\n getQuickResponse(lastMessage['text'] ?? '', appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 500));\n return quickResponse;\n }\n }\n }\n\n final prompt = _buildChatPrompt(conversationHistory, appState);\n final result = await _safeApiCall(prompt, 'Error in chat conversation',\n isChat: true, appState: appState);\n\n // Add age-appropriate disclaimer if not already present\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // Helper method to build message history for streaming with age restrictions\n List<Map<String, String>> _buildMessageHistory(\n List<Map<String, String>> conversationHistory, AppState appState) {\n final messages = <Map<String, String>>[];\n\n // Add age-appropriate system message\n messages.add({\n 'role': 'system',\n 'content': _getAgeAppropriateSystemPrompt(appState),\n });\n\n // Convert conversation history\n for (final message in conversationHistory) {\n messages.add({\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n });\n }\n\n return messages;\n }\n\n // ENHANCED: Symptom analysis with age restrictions\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) async {\n // Check for adult content in symptoms for minors\n if (appState.isMinor) {\n final symptomsText = symptoms.join(' ').toLowerCase();\n if (_containsAdultContent(symptomsText)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n }\n\n final prompt = _buildSymptomAnalysisPrompt(\n symptoms, severity, additionalInfo, appState);\n final result = await _safeApiCall(prompt, 'Error analyzing symptoms',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Medication interactions with age restrictions\n Future<String> checkMedicationInteractions(\n List<String> medications, AppState appState) async {\n if (appState.isMinor) {\n return '''\nHi ${appState.userName}! 🌟\n\nMedicine questions are really important! Here's what you should do:\n\n**For Medicine Safety:**\n- Always ask a trusted adult before taking any medicine\n- Never take medicine by yourself\n- Tell adults about all medicines you take\n- Ask parents or guardians about medicine questions\n\n**Important:** Only doctors, parents, or guardians should decide about your medicines!\n\nRemember: Adults are there to keep you safe and healthy! 💙\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n\n final prompt = _buildMedicationInteractionPrompt(medications, appState);\n final result = await _safeApiCall(\n prompt, 'Error checking medication interactions',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Health insights with comprehensive data analysis\n Future<String> getHealthInsights(\n Map<String, dynamic> healthData, AppState appState) async {\n // If healthData is a string, treat it as a single chat message\n if (healthData is String) {\n final conversationHistory = [\n {'isUser': 'true', 'text': healthData}\n ];\n return sendChatMessage(conversationHistory, appState);\n }\n\n // Check for quick insights first\n if (healthData.isEmpty) {\n return _getDefaultHealthInsights(appState);\n }\n\n final prompt = _buildHealthInsightsPrompt(healthData, appState);\n final result = await _safeApiCall(prompt, 'Error getting health insights',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // NEW: Default health insights based on age\n String _getDefaultHealthInsights(AppState appState) {\n if (appState.isMinor) {\n return '''\n🌟 **Health Tips Just for You, ${appState.userName}!**\n\n**Stay Strong and Healthy:**\n🏃‍♀️ Play and be active every day - it's fun and makes you strong!\n😴 Get lots of sleep (9-11 hours) to help your body grow\n🥕 Eat colorful foods like fruits and vegetables\n💧 Drink water to keep your body happy\n🧠 Always tell trusted adults when you don't feel well\n\n**Remember:**\n- Your parents and guardians are there to help you stay healthy\n- Ask questions! Adults love to help you learn\n- You're doing great by learning about health! \n\n${appState.ageAppropriateDisclaimer}\n ''';\n } else {\n return '''\n🌟 **Personalized Health Insights for ${appState.userName}**\n\n**General Wellness Tips:**\n• Stay hydrated - aim for 8 glasses of water daily\n• Get 7-9 hours of quality sleep\n• Take regular breaks from screen time\n• Practice deep breathing exercises\n\n**Healthy Habits:**\n• Walk for 30 minutes daily\n• Eat colorful fruits and vegetables\n• Maintain regular meal times\n• Stay connected with loved ones\n\n💡 **Tip:** Add your health data to get more personalized insights!\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n }\n\n // ENHANCED: Fallback response with age consideration\n String _getFallbackResponse(String userMessage, AppState appState) {\n final quickResponse = getQuickResponse(userMessage, appState);\n if (quickResponse != null) return quickResponse;\n\n return appState.getAgeAppropriateErrorMessage();\n }\n\n Future<String> _safeApiCall(String prompt, String contextMessage,\n {bool isChat = false, AppState? appState}) async {\n try {\n if (isChat) {\n return await _makeChatApiCall(prompt, appState);\n } else {\n return await _makeApiCallWithRetry(prompt, appState);\n }\n } on TimeoutException {\n if (kDebugMode) {\n print(\n '⏳ $contextMessage: Request timed out after ${_timeout.inSeconds}s');\n }\n if (isChat && appState != null) {\n final messages = jsonDecode(prompt) as List<dynamic>;\n final lastUserMessage = messages.lastWhere(\n (m) => m['role'] == 'user',\n orElse: () => {'content': ''},\n )['content'] ??\n '';\n return _getFallbackResponse(lastUserMessage, appState);\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'The request took longer than expected. Please try again.';\n } on SocketException catch (e) {\n if (kDebugMode) {\n print('🌐 Network error: ${e.message}');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'Network connection issue. Please check your internet and try again.';\n } catch (e) {\n if (kDebugMode) {\n print('⚠️ $contextMessage: $e');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'I\\'m experiencing technical difficulties. Please try again in a moment.';\n }\n }\n\n Future<String> _makeChatApiCall(\n String conversationHistoryJson, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive',\n 'Accept': 'application/json',\n };\n\n final List<dynamic> messages = jsonDecode(conversationHistoryJson);\n\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are MediPal, a helpful medical AI. Keep responses concise and include medical disclaimers.'\n });\n }\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n 'top_p': 0.8,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _buildChatPrompt(\n List<Map<String, dynamic>> conversationHistory, AppState appState) {\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n return jsonEncode(messages);\n }\n\n // RESTORED: Working retry logic with exponential backoff\n Future<String> _makeApiCallWithRetry(\n String prompt, AppState? appState) async {\n int attempts = 0;\n\n while (true) {\n try {\n if (kDebugMode) {\n print('🔄 API attempt ${attempts + 1}/${_maxRetries + 1}');\n }\n return await _makeApiCall(prompt, appState);\n } on TimeoutException {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('⏳ Max retries reached after $attempts attempts');\n }\n rethrow;\n }\n\n // Use working retry delays with jitter\n final delayMs = _retryDelays[attempts - 1];\n final jitter =\n (delayMs * 0.1 * (DateTime.now().millisecond % 100) / 100).round();\n final finalDelay = delayMs + jitter;\n\n if (kDebugMode) {\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${finalDelay}ms');\n }\n await Future.delayed(Duration(milliseconds: finalDelay));\n } on SocketException catch (e) {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('🌐 Network error after $attempts attempts: ${e.message}');\n }\n rethrow;\n }\n\n final delayMs = _retryDelays[attempts - 1];\n if (kDebugMode) {\n print('🌐 Network issue, retrying in ${delayMs}ms...');\n }\n await Future.delayed(Duration(milliseconds: delayMs));\n } catch (e) {\n if (kDebugMode) {\n print('❌ Non-retryable error: $e');\n }\n rethrow;\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive', // Important for long requests\n };\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are a medical AI assistant. Provide concise, informative responses. Include medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(\n _timeout,\n onTimeout: () {\n throw TimeoutException(\n 'Request to DeepSeek API exceeded ${_timeout.inSeconds}s timeout',\n _timeout,\n );\n },\n );\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from DeepSeek API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // OPTIMIZED: Dramatically simplified symptom analysis prompt\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) {\n final buffer = StringBuffer();\n\n if (appState.isMinor) {\n buffer.writeln(\"Help young person (age ${appState.userAge}):\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n buffer.writeln(\n \"Provide: Simple explanation, when to tell adults. Keep brief under 200 words.\");\n } else {\n buffer\n .writeln(\"Analyze for ${appState.userAge}yo ${appState.userGender}:\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n\n // Only include top 3 additional info items to keep prompt short\n if (additionalInfo.isNotEmpty) {\n int count = 0;\n buffer.writeln(\"Info:\");\n for (var entry in additionalInfo.entries) {\n if (entry.value.toString().isNotEmpty && count < 3) {\n buffer.writeln(\"- ${entry.key}: ${entry.value}\");\n count++;\n }\n }\n }\n\n buffer.writeln(\n \"\\nProvide: Causes, when to see doctor, self-care, disclaimer. Under 300 words.\");\n }\n\n return buffer.toString();\n }\n\n // OPTIMIZED: Simplified medication interaction prompt\n String _buildMedicationInteractionPrompt(\n List<String> medications, AppState appState) {\n if (appState.isMinor) {\n return \"Minor asking about medicines. Redirect to trusted adults briefly.\";\n }\n\n return \"\"\"\nAnalyze interactions: ${medications.join(', ')}\nFor ${appState.userAge}yo ${appState.userGender}. \nProvide: 1) Risk level 2) Key effects 3) When to consult doctor 4) Disclaimer\nKeep under 250 words.\n\"\"\";\n }\n\n // OPTIMIZED: Dramatically simplified health insights prompt\n String _buildHealthInsightsPrompt(\n Map<String, dynamic> healthData, AppState appState) {\n if (appState.isMinor) {\n return \"\"\"\nCreate health tips for ${appState.userName} (${appState.userAge}yo):\nFocus on: healthy habits, exercise, sleep, nutrition.\nUse simple, encouraging language. Mention trusted adults. Keep under 200 words.\n\"\"\";\n }\n\n // Extract only top 5 most relevant health data items\n final relevantData = <String, dynamic>{};\n final priorityKeys = [\n 'medications_count',\n 'health_score',\n 'sleep_hours',\n 'recent_symptoms',\n 'activity_level'\n ];\n\n for (final key in priorityKeys) {\n if (healthData.containsKey(key) &&\n healthData[key] != null &&\n healthData[key].toString().isNotEmpty) {\n relevantData[key] = healthData[key];\n }\n if (relevantData.length >= 5) break;\n }\n\n final buffer = StringBuffer();\n buffer.writeln(\n \"Health insights for ${appState.userName} (${appState.userAge}yo, ${appState.userGender}):\");\n\n if (relevantData.isNotEmpty) {\n relevantData.forEach((key, value) {\n buffer.writeln(\"- $key: $value\");\n });\n }\n\n buffer.writeln(\n \"\\nProvide: Assessment, lifestyle tips, improvements, encouragement. Under 350 words with disclaimer.\");\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl\\nTimeout: ${_timeout.inSeconds}s';\n}\n"}, "c0831e9c40ce16bdd0ee90c15c3f9d847eac97fa": {"t": 1785757943.0121386, "n": 28885, "h": "a60be160cd5e45ab", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'dart:io';\nimport 'package:flutter/foundation.dart';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\nimport '../utils/app_state.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // RESTORED: Working timeout values from old version\n static const Duration _timeout = Duration(seconds: 30); // INCREASED from 20\n static const int _maxRetries = 2;\n// INCREASED from 3\n\n // RESTORED: Working retry delays with exponential backoff\n static const List<int> _retryDelays = [500, 1500]; // INCREASED from 300, 800\n\n // ENHANCED: Age-appropriate quick responses\n static const Map<String, Map<String, String>> _quickResponses = {\n 'hello': {\n 'minor':\n 'Hi there! 🌟 I\\'m here to help you learn about staying healthy! Remember to always ask a trusted adult if you have health questions!',\n 'adult':\n 'Hello! I\\'m MediPal, your health assistant. How can I help you today? 😊',\n },\n 'hi': {\n 'minor':\n 'Hi! 👋 I can teach you fun ways to stay healthy! Always talk to your parents or guardians about health stuff too!',\n 'adult':\n 'Hi there! I\\'m here to help with any health questions you might have! 🩺',\n },\n 'help': {\n 'minor':\n 'I can teach you about:\\n• Healthy foods and exercise 🥕\\n• Why sleep is important 😴\\n• When to tell adults you don\\'t feel well\\n• Fun ways to stay strong! 💪\\n\\nBut always ask trusted adults about health questions!',\n 'adult':\n 'I can help you with:\\n• Medical questions and symptoms\\n• Medication information\\n• Health guidance\\n• Emergency information\\n\\nWhat would you like to know?',\n },\n 'emergency': {\n 'minor':\n '🚨 **If there\\'s an emergency:**\\n\\n1. Find a trusted adult RIGHT AWAY\\n2. Call 911 if no adult is around\\n3. Stay calm and ask for help\\n\\nAlways tell adults when you don\\'t feel well!',\n 'adult':\n '🚨 **MEDICAL EMERGENCY?**\\n\\nCall 911 immediately if experiencing:\\n• Difficulty breathing\\n• Chest pain\\n• Severe bleeding\\n• Loss of consciousness',\n },\n 'thanks': {\n 'minor':\n 'You\\'re welcome! 🌟 Keep learning about staying healthy, and remember to always talk to trusted adults about health questions!',\n 'adult':\n 'You\\'re welcome! I\\'m always here to help with your health questions. Take care! 😊',\n },\n 'thank you': {\n 'minor':\n 'You\\'re so welcome! 🌟 Keep asking great questions and always talk to trusted adults about your health!',\n 'adult':\n 'You\\'re very welcome! Feel free to ask if you have more questions. Stay healthy! 💙',\n },\n };\n\n // NEW: Adult content keywords for filtering\n static const List<String> _adultContentKeywords = [\n 'sex',\n 'sexual',\n 'pregnancy',\n 'contraception',\n 'std',\n 'sti',\n 'reproductive',\n 'genital',\n 'abortion',\n 'breast',\n 'period',\n 'menstruation',\n 'testosterone',\n 'viagra',\n 'drug abuse',\n 'alcohol',\n 'addiction',\n 'overdose',\n 'suicide',\n 'self-harm',\n 'depression',\n 'anxiety disorder'\n ];\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n if (kDebugMode) {\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n }\n if (kDebugMode) {\n print(\"🌍 Base URL: $_baseUrl\");\n }\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n // ENHANCED: Age-appropriate quick responses with AppState\n String? getQuickResponse(String message, AppState appState) {\n final normalizedMessage = message.toLowerCase().trim();\n\n // Check for adult content if user is a minor\n if (appState.isMinor && _containsAdultContent(normalizedMessage)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n\n // Direct matches with age-appropriate responses\n if (_quickResponses.containsKey(normalizedMessage)) {\n final responses = _quickResponses[normalizedMessage]!;\n return appState.isMinor ? responses['minor'] : responses['adult'];\n }\n\n // Age-appropriate pattern matches\n return _getPatternBasedResponse(normalizedMessage, appState);\n }\n\n // NEW: Check for adult content\n bool _containsAdultContent(String message) {\n final lowerMessage = message.toLowerCase();\n return _adultContentKeywords\n .any((keyword) => lowerMessage.contains(keyword));\n }\n\n // NEW: Minor redirect response\n String _getMinorRedirectResponse(String userName) {\n return '''\nHi ${userName.isNotEmpty ? userName : 'there'}! 🌟\n\nI notice you're asking about something that might be better discussed with a trusted adult like a parent, guardian, or doctor.\n\n**What you can do:**\n- Talk to a parent or guardian about your question \n- Ask a school nurse or counselor\n- Visit a doctor with a trusted adult\n\nRemember: I'm here to help with general health information, but for anything serious or personal, it's always best to talk to a real person who can help you properly! 😊\n\nIs there something else I can help you with today?\n ''';\n }\n\n // ENHANCED: Pattern-based responses with age consideration\n String? _getPatternBasedResponse(String message, AppState appState) {\n if (message.contains('headache')) {\n return appState.isMinor\n ? '🤕 **If your head hurts:**\\n• Tell a trusted adult right away\\n• Rest in a quiet place\\n• Drink some water\\n• Ask an adult about what to do\\n\\n⚠️ Always let adults help you when you don\\'t feel well!'\n : '🩺 **Headache Relief:**\\n• Stay hydrated (drink water)\\n• Rest in a quiet, dark room\\n• Apply cold/warm compress\\n• Consider OTC pain relief\\n\\n⚠️ See a doctor if severe or persistent.';\n }\n\n if (message.contains('fever')) {\n return appState.isMinor\n ? '🌡️ **If you feel hot and sick:**\\n• Tell an adult immediately\\n• Rest and drink water\\n• Let adults check your temperature\\n• Ask for help from grown-ups\\n\\n⚠️ Adults know what to do when you have a fever!'\n : '🌡️ **Fever Management:**\\n• Stay hydrated\\n• Rest and monitor temperature\\n• Light clothing\\n• Seek medical attention if >101.5°F (38.6°C)\\n\\n⚠️ Contact healthcare provider if persistent.';\n }\n\n if (message.contains('medication') && message.contains('safe')) {\n return appState.isMinor\n ? '💊 **About Medicines:**\\n• Only adults should give you medicine\\n• Never take medicine by yourself\\n• Always ask trusted adults first\\n• Tell adults about any medicine questions\\n\\n⚠️ Medicine safety is super important - let adults handle it!'\n : '💊 **Medication Safety:**\\n• Always follow prescribed dosage\\n• Check for drug interactions\\n• Store properly\\n• Don\\'t share medications\\n\\n⚠️ Consult your pharmacist or doctor with questions.';\n }\n\n return null; // No quick response available\n }\n\n // OPTIMIZED: Dramatically simplified system prompts\n String _getAgeAppropriateSystemPrompt(AppState appState) {\n final basePrompt = '''\nYou are MediPal for ${appState.userName}, Age: ${appState.userAge}, Gender: ${appState.userGender}\n''';\n final wearablePrompt = appState.wearableSummaryPrompt;\n final wearableLine = wearablePrompt.isNotEmpty ? '\\n$wearablePrompt\\n' : '';\n\n if (appState.isMinor) {\n return '''\n$basePrompt\nMINOR (Under 18): Use simple language. Always direct to trusted adults. Focus on wellness and safety. \nAvoid: self-medication, detailed medical terms, sensitive topics. Keep under 250 words. End with reminder to talk to adults.\n$wearableLine\n ''';\n } else if (appState.isYoungAdult) {\n return '''\n$basePrompt\nYOUNG ADULT (18-24): Clear educational language. Emphasize preventive care and professional consultation.\nKeep under 350 words with disclaimers.\n$wearableLine\n ''';\n } else {\n return '''\n$basePrompt\nADULT (25+): Detailed medical-grade information with appropriate terminology. \nThorough analysis with disclaimers. Keep under 500 words.\n$wearableLine\n ''';\n }\n }\n\n // ENHANCED: Streaming with age restrictions and AppState\n Stream<String> streamChatResponse(\n List<Map<String, String>> conversationHistory, AppState appState) async* {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final quickResponse =\n getQuickResponse(lastMessage['text'] ?? '', appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 300));\n yield quickResponse;\n return;\n }\n }\n }\n\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Accept': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n };\n\n final messages = _buildMessageHistory(conversationHistory, appState);\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': appState.isMinor ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED: Single value\n 'stream': true,\n 'top_p': 0.8,\n });\n\n try {\n final request =\n http.Request('POST', Uri.parse('$_baseUrl/chat/completions'))\n ..headers.addAll(headers)\n ..body = body;\n\n final client = http.Client();\n final streamedResponse = await client.send(request).timeout(_timeout);\n\n if (streamedResponse.statusCode != 200) {\n throw Exception(\n 'API request failed with status: ${streamedResponse.statusCode}');\n }\n\n String accumulatedText = '';\n\n await for (final line in streamedResponse.stream\n .transform(utf8.decoder)\n .transform(const LineSplitter())\n .where((line) => line.trim().isNotEmpty)) {\n if (line.startsWith('data: ')) {\n final data = line.substring(6).trim();\n\n if (data == '[DONE]') {\n break;\n }\n\n try {\n final json = jsonDecode(data);\n final content = json['choices']?[0]?['delta']?['content'];\n\n if (content != null && content.isNotEmpty) {\n accumulatedText += content;\n\n // Filter content for minors\n if (appState.isMinor && _containsAdultContent(accumulatedText)) {\n yield _getMinorRedirectResponse(appState.userName);\n break;\n }\n\n yield accumulatedText;\n }\n } catch (e) {\n continue;\n }\n }\n }\n\n client.close();\n\n // Add age-appropriate disclaimer\n if (accumulatedText.isNotEmpty &&\n !accumulatedText.contains(appState.ageAppropriateDisclaimer)) {\n final finalResponse =\n '$accumulatedText\\n\\n${appState.ageAppropriateDisclaimer}';\n yield finalResponse;\n }\n } catch (e) {\n if (kDebugMode) {\n print('❌ Streaming error: $e');\n }\n try {\n final response = await sendChatMessage(conversationHistory, appState);\n yield response;\n } catch (fallbackError) {\n yield appState.getAgeAppropriateErrorMessage();\n }\n }\n }\n\n // ENHANCED: Chat with age restrictions and AppState\n Future<String> sendChatMessage(\n List<Map<String, dynamic>> conversationHistory, AppState appState) async {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final quickResponse =\n getQuickResponse(lastMessage['text'] ?? '', appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 500));\n return quickResponse;\n }\n }\n }\n\n final prompt = _buildChatPrompt(conversationHistory, appState);\n final result = await _safeApiCall(prompt, 'Error in chat conversation',\n isChat: true, appState: appState);\n\n // Add age-appropriate disclaimer if not already present\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // Helper method to build message history for streaming with age restrictions\n List<Map<String, String>> _buildMessageHistory(\n List<Map<String, String>> conversationHistory, AppState appState) {\n final messages = <Map<String, String>>[];\n\n // Add age-appropriate system message\n messages.add({\n 'role': 'system',\n 'content': _getAgeAppropriateSystemPrompt(appState),\n });\n\n // Convert conversation history\n for (final message in conversationHistory) {\n messages.add({\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n });\n }\n\n return messages;\n }\n\n // ENHANCED: Symptom analysis with age restrictions\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) async {\n // Check for adult content in symptoms for minors\n if (appState.isMinor) {\n final symptomsText = symptoms.join(' ').toLowerCase();\n if (_containsAdultContent(symptomsText)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n }\n\n final prompt = _buildSymptomAnalysisPrompt(\n symptoms, severity, additionalInfo, appState);\n final result = await _safeApiCall(prompt, 'Error analyzing symptoms',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Medication interactions with age restrictions\n Future<String> checkMedicationInteractions(\n List<String> medications, AppState appState) async {\n if (appState.isMinor) {\n return '''\nHi ${appState.userName}! 🌟\n\nMedicine questions are really important! Here's what you should do:\n\n**For Medicine Safety:**\n- Always ask a trusted adult before taking any medicine\n- Never take medicine by yourself\n- Tell adults about all medicines you take\n- Ask parents or guardians about medicine questions\n\n**Important:** Only doctors, parents, or guardians should decide about your medicines!\n\nRemember: Adults are there to keep you safe and healthy! 💙\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n\n final prompt = _buildMedicationInteractionPrompt(medications, appState);\n final result = await _safeApiCall(\n prompt, 'Error checking medication interactions',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Health insights with comprehensive data analysis\n Future<String> getHealthInsights(\n Map<String, dynamic> healthData, AppState appState) async {\n // If healthData is a string, treat it as a single chat message\n if (healthData is String) {\n final conversationHistory = [\n {'isUser': 'true', 'text': healthData}\n ];\n return sendChatMessage(conversationHistory, appState);\n }\n\n // Check for quick insights first\n if (healthData.isEmpty) {\n return _getDefaultHealthInsights(appState);\n }\n\n final prompt = _buildHealthInsightsPrompt(healthData, appState);\n final result = await _safeApiCall(prompt, 'Error getting health insights',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // NEW: Default health insights based on age\n String _getDefaultHealthInsights(AppState appState) {\n if (appState.isMinor) {\n return '''\n🌟 **Health Tips Just for You, ${appState.userName}!**\n\n**Stay Strong and Healthy:**\n🏃‍♀️ Play and be active every day - it's fun and makes you strong!\n😴 Get lots of sleep (9-11 hours) to help your body grow\n🥕 Eat colorful foods like fruits and vegetables\n💧 Drink water to keep your body happy\n🧠 Always tell trusted adults when you don't feel well\n\n**Remember:**\n- Your parents and guardians are there to help you stay healthy\n- Ask questions! Adults love to help you learn\n- You're doing great by learning about health! \n\n${appState.ageAppropriateDisclaimer}\n ''';\n } else {\n return '''\n🌟 **Personalized Health Insights for ${appState.userName}**\n\n**General Wellness Tips:**\n• Stay hydrated - aim for 8 glasses of water daily\n• Get 7-9 hours of quality sleep\n• Take regular breaks from screen time\n• Practice deep breathing exercises\n\n**Healthy Habits:**\n• Walk for 30 minutes daily\n• Eat colorful fruits and vegetables\n• Maintain regular meal times\n• Stay connected with loved ones\n\n💡 **Tip:** Add your health data to get more personalized insights!\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n }\n\n // ENHANCED: Fallback response with age consideration\n String _getFallbackResponse(String userMessage, AppState appState) {\n final quickResponse = getQuickResponse(userMessage, appState);\n if (quickResponse != null) return quickResponse;\n\n return appState.getAgeAppropriateErrorMessage();\n }\n\n Future<String> _safeApiCall(String prompt, String contextMessage,\n {bool isChat = false, AppState? appState}) async {\n try {\n if (isChat) {\n return await _makeChatApiCall(prompt, appState);\n } else {\n return await _makeApiCallWithRetry(prompt, appState);\n }\n } on TimeoutException {\n if (kDebugMode) {\n print(\n '⏳ $contextMessage: Request timed out after ${_timeout.inSeconds}s');\n }\n if (isChat && appState != null) {\n final messages = jsonDecode(prompt) as List<dynamic>;\n final lastUserMessage = messages.lastWhere(\n (m) => m['role'] == 'user',\n orElse: () => {'content': ''},\n )['content'] ??\n '';\n return _getFallbackResponse(lastUserMessage, appState);\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'The request took longer than expected. Please try again.';\n } on SocketException catch (e) {\n if (kDebugMode) {\n print('🌐 Network error: ${e.message}');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'Network connection issue. Please check your internet and try again.';\n } catch (e) {\n if (kDebugMode) {\n print('⚠️ $contextMessage: $e');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'I\\'m experiencing technical difficulties. Please try again in a moment.';\n }\n }\n\n Future<String> _makeChatApiCall(\n String conversationHistoryJson, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive',\n 'Accept': 'application/json',\n };\n\n final List<dynamic> messages = jsonDecode(conversationHistoryJson);\n\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are MediPal, a helpful medical AI. Keep responses concise and include medical disclaimers.'\n });\n }\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n 'top_p': 0.8,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _buildChatPrompt(\n List<Map<String, dynamic>> conversationHistory, AppState appState) {\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n return jsonEncode(messages);\n }\n\n // RESTORED: Working retry logic with exponential backoff\n Future<String> _makeApiCallWithRetry(\n String prompt, AppState? appState) async {\n int attempts = 0;\n\n while (true) {\n try {\n if (kDebugMode) {\n print('🔄 API attempt ${attempts + 1}/${_maxRetries + 1}');\n }\n return await _makeApiCall(prompt, appState);\n } on TimeoutException {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('⏳ Max retries reached after $attempts attempts');\n }\n rethrow;\n }\n\n // Use working retry delays with jitter\n final delayMs = _retryDelays[attempts - 1];\n final jitter =\n (delayMs * 0.1 * (DateTime.now().millisecond % 100) / 100).round();\n final finalDelay = delayMs + jitter;\n\n if (kDebugMode) {\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${finalDelay}ms');\n }\n await Future.delayed(Duration(milliseconds: finalDelay));\n } on SocketException catch (e) {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('🌐 Network error after $attempts attempts: ${e.message}');\n }\n rethrow;\n }\n\n final delayMs = _retryDelays[attempts - 1];\n if (kDebugMode) {\n print('🌐 Network issue, retrying in ${delayMs}ms...');\n }\n await Future.delayed(Duration(milliseconds: delayMs));\n } catch (e) {\n if (kDebugMode) {\n print('❌ Non-retryable error: $e');\n }\n rethrow;\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive', // Important for long requests\n };\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are a medical AI assistant. Provide concise, informative responses. Include medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(\n _timeout,\n onTimeout: () {\n throw TimeoutException(\n 'Request to DeepSeek API exceeded ${_timeout.inSeconds}s timeout',\n _timeout,\n );\n },\n );\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from DeepSeek API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // OPTIMIZED: Dramatically simplified symptom analysis prompt\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) {\n final buffer = StringBuffer();\n\n if (appState.isMinor) {\n buffer.writeln(\"Help young person (age ${appState.userAge}):\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n buffer.writeln(\n \"Provide: Simple explanation, when to tell adults. Keep brief under 200 words.\");\n } else {\n buffer\n .writeln(\"Analyze for ${appState.userAge}yo ${appState.userGender}:\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n\n // Only include top 3 additional info items to keep prompt short\n if (additionalInfo.isNotEmpty) {\n int count = 0;\n buffer.writeln(\"Info:\");\n for (var entry in additionalInfo.entries) {\n if (entry.value.toString().isNotEmpty && count < 3) {\n buffer.writeln(\"- ${entry.key}: ${entry.value}\");\n count++;\n }\n }\n }\n\n buffer.writeln(\n \"\\nProvide: Causes, when to see doctor, self-care, disclaimer. Under 300 words.\");\n }\n\n return buffer.toString();\n }\n\n // OPTIMIZED: Simplified medication interaction prompt\n String _buildMedicationInteractionPrompt(\n List<String> medications, AppState appState) {\n if (appState.isMinor) {\n return \"Minor asking about medicines. Redirect to trusted adults briefly.\";\n }\n\n return \"\"\"\nAnalyze interactions: ${medications.join(', ')}\nFor ${appState.userAge}yo ${appState.userGender}. \nProvide: 1) Risk level 2) Key effects 3) When to consult doctor 4) Disclaimer\nKeep under 250 words.\n\"\"\";\n }\n\n // OPTIMIZED: Dramatically simplified health insights prompt\n String _buildHealthInsightsPrompt(\n Map<String, dynamic> healthData, AppState appState) {\n if (appState.isMinor) {\n return \"\"\"\nCreate health tips for ${appState.userName} (${appState.userAge}yo):\nFocus on: healthy habits, exercise, sleep, nutrition.\nUse simple, encouraging language. Mention trusted adults. Keep under 200 words.\n\"\"\";\n }\n\n // Extract only top 5 most relevant health data items\n final relevantData = <String, dynamic>{};\n final priorityKeys = [\n 'medications_count',\n 'health_score',\n 'sleep_hours',\n 'recent_symptoms',\n 'activity_level'\n ];\n\n for (final key in priorityKeys) {\n if (healthData.containsKey(key) &&\n healthData[key] != null &&\n healthData[key].toString().isNotEmpty) {\n relevantData[key] = healthData[key];\n }\n if (relevantData.length >= 5) break;\n }\n\n final buffer = StringBuffer();\n buffer.writeln(\n \"Health insights for ${appState.userName} (${appState.userAge}yo, ${appState.userGender}):\");\n\n if (relevantData.isNotEmpty) {\n relevantData.forEach((key, value) {\n buffer.writeln(\"- $key: $value\");\n });\n }\n\n buffer.writeln(\n \"\\nProvide: Assessment, lifestyle tips, improvements, encouragement. Under 350 words with disclaimer.\");\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl\\nTimeout: ${_timeout.inSeconds}s';\n}\n"}, "0d20218c04e909fc7fd54ebd4e4e4add23b0e90a": {"t": 1785757944.544765, "n": 28703, "h": "f2aa281f44b49899", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'dart:io';\nimport 'package:flutter/foundation.dart';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\nimport '../utils/app_state.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // RESTORED: Working timeout values from old version\n static const Duration _timeout = Duration(seconds: 30); // INCREASED from 20\n static const int _maxRetries = 2;\n// INCREASED from 3\n\n // RESTORED: Working retry delays with exponential backoff\n static const List<int> _retryDelays = [500, 1500]; // INCREASED from 300, 800\n\n // ENHANCED: Age-appropriate quick responses\n static const Map<String, Map<String, String>> _quickResponses = {\n 'hello': {\n 'minor':\n 'Hi there! 🌟 I\\'m here to help you learn about staying healthy! Remember to always ask a trusted adult if you have health questions!',\n 'adult':\n 'Hello! I\\'m MediPal, your health assistant. How can I help you today? 😊',\n },\n 'hi': {\n 'minor':\n 'Hi! 👋 I can teach you fun ways to stay healthy! Always talk to your parents or guardians about health stuff too!',\n 'adult':\n 'Hi there! I\\'m here to help with any health questions you might have! 🩺',\n },\n 'help': {\n 'minor':\n 'I can teach you about:\\n• Healthy foods and exercise 🥕\\n• Why sleep is important 😴\\n• When to tell adults you don\\'t feel well\\n• Fun ways to stay strong! 💪\\n\\nBut always ask trusted adults about health questions!',\n 'adult':\n 'I can help you with:\\n• Medical questions and symptoms\\n• Medication information\\n• Health guidance\\n• Emergency information\\n\\nWhat would you like to know?',\n },\n 'emergency': {\n 'minor':\n '🚨 **If there\\'s an emergency:**\\n\\n1. Find a trusted adult RIGHT AWAY\\n2. Call 911 if no adult is around\\n3. Stay calm and ask for help\\n\\nAlways tell adults when you don\\'t feel well!',\n 'adult':\n '🚨 **MEDICAL EMERGENCY?**\\n\\nCall 911 immediately if experiencing:\\n• Difficulty breathing\\n• Chest pain\\n• Severe bleeding\\n• Loss of consciousness',\n },\n 'thanks': {\n 'minor':\n 'You\\'re welcome! 🌟 Keep learning about staying healthy, and remember to always talk to trusted adults about health questions!',\n 'adult':\n 'You\\'re welcome! I\\'m always here to help with your health questions. Take care! 😊',\n },\n 'thank you': {\n 'minor':\n 'You\\'re so welcome! 🌟 Keep asking great questions and always talk to trusted adults about your health!',\n 'adult':\n 'You\\'re very welcome! Feel free to ask if you have more questions. Stay healthy! 💙',\n },\n };\n\n // NEW: Adult content keywords for filtering\n static const List<String> _adultContentKeywords = [\n 'sex',\n 'sexual',\n 'pregnancy',\n 'contraception',\n 'std',\n 'sti',\n 'reproductive',\n 'genital',\n 'abortion',\n 'breast',\n 'period',\n 'menstruation',\n 'testosterone',\n 'viagra',\n 'drug abuse',\n 'alcohol',\n 'addiction',\n 'overdose',\n 'suicide',\n 'self-harm',\n 'depression',\n 'anxiety disorder'\n ];\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n if (kDebugMode) {\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n }\n if (kDebugMode) {\n print(\"🌍 Base URL: $_baseUrl\");\n }\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n // ENHANCED: Age-appropriate quick responses with AppState\n String? getQuickResponse(String message, AppState appState) {\n final normalizedMessage = message.toLowerCase().trim();\n\n // Check for adult content if user is a minor\n if (appState.isMinor && _containsAdultContent(normalizedMessage)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n\n // Direct matches with age-appropriate responses\n if (_quickResponses.containsKey(normalizedMessage)) {\n final responses = _quickResponses[normalizedMessage]!;\n return appState.isMinor ? responses['minor'] : responses['adult'];\n }\n\n // Age-appropriate pattern matches\n return _getPatternBasedResponse(normalizedMessage, appState);\n }\n\n // NEW: Check for adult content\n bool _containsAdultContent(String message) {\n final lowerMessage = message.toLowerCase();\n return _adultContentKeywords\n .any((keyword) => lowerMessage.contains(keyword));\n }\n\n // NEW: Minor redirect response\n String _getMinorRedirectResponse(String userName) {\n return '''\nHi ${userName.isNotEmpty ? userName : 'there'}! 🌟\n\nI notice you're asking about something that might be better discussed with a trusted adult like a parent, guardian, or doctor.\n\n**What you can do:**\n- Talk to a parent or guardian about your question \n- Ask a school nurse or counselor\n- Visit a doctor with a trusted adult\n\nRemember: I'm here to help with general health information, but for anything serious or personal, it's always best to talk to a real person who can help you properly! 😊\n\nIs there something else I can help you with today?\n ''';\n }\n\n // ENHANCED: Pattern-based responses with age consideration\n String? _getPatternBasedResponse(String message, AppState appState) {\n if (message.contains('headache')) {\n return appState.isMinor\n ? '🤕 **If your head hurts:**\\n• Tell a trusted adult right away\\n• Rest in a quiet place\\n• Drink some water\\n• Ask an adult about what to do\\n\\n⚠️ Always let adults help you when you don\\'t feel well!'\n : '🩺 **Headache Relief:**\\n• Stay hydrated (drink water)\\n• Rest in a quiet, dark room\\n• Apply cold/warm compress\\n• Consider OTC pain relief\\n\\n⚠️ See a doctor if severe or persistent.';\n }\n\n if (message.contains('fever')) {\n return appState.isMinor\n ? '🌡️ **If you feel hot and sick:**\\n• Tell an adult immediately\\n• Rest and drink water\\n• Let adults check your temperature\\n• Ask for help from grown-ups\\n\\n⚠️ Adults know what to do when you have a fever!'\n : '🌡️ **Fever Management:**\\n• Stay hydrated\\n• Rest and monitor temperature\\n• Light clothing\\n• Seek medical attention if >101.5°F (38.6°C)\\n\\n⚠️ Contact healthcare provider if persistent.';\n }\n\n if (message.contains('medication') && message.contains('safe')) {\n return appState.isMinor\n ? '💊 **About Medicines:**\\n• Only adults should give you medicine\\n• Never take medicine by yourself\\n• Always ask trusted adults first\\n• Tell adults about any medicine questions\\n\\n⚠️ Medicine safety is super important - let adults handle it!'\n : '💊 **Medication Safety:**\\n• Always follow prescribed dosage\\n• Check for drug interactions\\n• Store properly\\n• Don\\'t share medications\\n\\n⚠️ Consult your pharmacist or doctor with questions.';\n }\n\n return null; // No quick response available\n }\n\n // OPTIMIZED: Dramatically simplified system prompts\n String _getAgeAppropriateSystemPrompt(AppState appState) {\n final basePrompt = '''\nYou are MediPal for ${appState.userName}, Age: ${appState.userAge}, Gender: ${appState.userGender}\n''';\n\n if (appState.isMinor) {\n return '''\n$basePrompt\nMINOR (Under 18): Use simple language. Always direct to trusted adults. Focus on wellness and safety. \nAvoid: self-medication, detailed medical terms, sensitive topics. Keep under 250 words. End with reminder to talk to adults.\n ''';\n } else if (appState.isYoungAdult) {\n return '''\n$basePrompt\nYOUNG ADULT (18-24): Clear educational language. Emphasize preventive care and professional consultation.\nKeep under 350 words with disclaimers.\n ''';\n } else {\n return '''\n$basePrompt\nADULT (25+): Detailed medical-grade information with appropriate terminology. \nThorough analysis with disclaimers. Keep under 500 words.\n ''';\n }\n }\n\n // ENHANCED: Streaming with age restrictions and AppState\n Stream<String> streamChatResponse(\n List<Map<String, String>> conversationHistory, AppState appState) async* {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final quickResponse =\n getQuickResponse(lastMessage['text'] ?? '', appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 300));\n yield quickResponse;\n return;\n }\n }\n }\n\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Accept': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n };\n\n final messages = _buildMessageHistory(conversationHistory, appState);\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': appState.isMinor ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED: Single value\n 'stream': true,\n 'top_p': 0.8,\n });\n\n try {\n final request =\n http.Request('POST', Uri.parse('$_baseUrl/chat/completions'))\n ..headers.addAll(headers)\n ..body = body;\n\n final client = http.Client();\n final streamedResponse = await client.send(request).timeout(_timeout);\n\n if (streamedResponse.statusCode != 200) {\n throw Exception(\n 'API request failed with status: ${streamedResponse.statusCode}');\n }\n\n String accumulatedText = '';\n\n await for (final line in streamedResponse.stream\n .transform(utf8.decoder)\n .transform(const LineSplitter())\n .where((line) => line.trim().isNotEmpty)) {\n if (line.startsWith('data: ')) {\n final data = line.substring(6).trim();\n\n if (data == '[DONE]') {\n break;\n }\n\n try {\n final json = jsonDecode(data);\n final content = json['choices']?[0]?['delta']?['content'];\n\n if (content != null && content.isNotEmpty) {\n accumulatedText += content;\n\n // Filter content for minors\n if (appState.isMinor && _containsAdultContent(accumulatedText)) {\n yield _getMinorRedirectResponse(appState.userName);\n break;\n }\n\n yield accumulatedText;\n }\n } catch (e) {\n continue;\n }\n }\n }\n\n client.close();\n\n // Add age-appropriate disclaimer\n if (accumulatedText.isNotEmpty &&\n !accumulatedText.contains(appState.ageAppropriateDisclaimer)) {\n final finalResponse =\n '$accumulatedText\\n\\n${appState.ageAppropriateDisclaimer}';\n yield finalResponse;\n }\n } catch (e) {\n if (kDebugMode) {\n print('❌ Streaming error: $e');\n }\n try {\n final response = await sendChatMessage(conversationHistory, appState);\n yield response;\n } catch (fallbackError) {\n yield appState.getAgeAppropriateErrorMessage();\n }\n }\n }\n\n // ENHANCED: Chat with age restrictions and AppState\n Future<String> sendChatMessage(\n List<Map<String, dynamic>> conversationHistory, AppState appState) async {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final quickResponse =\n getQuickResponse(lastMessage['text'] ?? '', appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 500));\n return quickResponse;\n }\n }\n }\n\n final prompt = _buildChatPrompt(conversationHistory, appState);\n final result = await _safeApiCall(prompt, 'Error in chat conversation',\n isChat: true, appState: appState);\n\n // Add age-appropriate disclaimer if not already present\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // Helper method to build message history for streaming with age restrictions\n List<Map<String, String>> _buildMessageHistory(\n List<Map<String, String>> conversationHistory, AppState appState) {\n final messages = <Map<String, String>>[];\n\n // Add age-appropriate system message\n messages.add({\n 'role': 'system',\n 'content': _getAgeAppropriateSystemPrompt(appState),\n });\n\n // Convert conversation history\n for (final message in conversationHistory) {\n messages.add({\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n });\n }\n\n return messages;\n }\n\n // ENHANCED: Symptom analysis with age restrictions\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) async {\n // Check for adult content in symptoms for minors\n if (appState.isMinor) {\n final symptomsText = symptoms.join(' ').toLowerCase();\n if (_containsAdultContent(symptomsText)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n }\n\n final prompt = _buildSymptomAnalysisPrompt(\n symptoms, severity, additionalInfo, appState);\n final result = await _safeApiCall(prompt, 'Error analyzing symptoms',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Medication interactions with age restrictions\n Future<String> checkMedicationInteractions(\n List<String> medications, AppState appState) async {\n if (appState.isMinor) {\n return '''\nHi ${appState.userName}! 🌟\n\nMedicine questions are really important! Here's what you should do:\n\n**For Medicine Safety:**\n- Always ask a trusted adult before taking any medicine\n- Never take medicine by yourself\n- Tell adults about all medicines you take\n- Ask parents or guardians about medicine questions\n\n**Important:** Only doctors, parents, or guardians should decide about your medicines!\n\nRemember: Adults are there to keep you safe and healthy! 💙\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n\n final prompt = _buildMedicationInteractionPrompt(medications, appState);\n final result = await _safeApiCall(\n prompt, 'Error checking medication interactions',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Health insights with comprehensive data analysis\n Future<String> getHealthInsights(\n Map<String, dynamic> healthData, AppState appState) async {\n // If healthData is a string, treat it as a single chat message\n if (healthData is String) {\n final conversationHistory = [\n {'isUser': 'true', 'text': healthData}\n ];\n return sendChatMessage(conversationHistory, appState);\n }\n\n // Check for quick insights first\n if (healthData.isEmpty) {\n return _getDefaultHealthInsights(appState);\n }\n\n final prompt = _buildHealthInsightsPrompt(healthData, appState);\n final result = await _safeApiCall(prompt, 'Error getting health insights',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // NEW: Default health insights based on age\n String _getDefaultHealthInsights(AppState appState) {\n if (appState.isMinor) {\n return '''\n🌟 **Health Tips Just for You, ${appState.userName}!**\n\n**Stay Strong and Healthy:**\n🏃‍♀️ Play and be active every day - it's fun and makes you strong!\n😴 Get lots of sleep (9-11 hours) to help your body grow\n🥕 Eat colorful foods like fruits and vegetables\n💧 Drink water to keep your body happy\n🧠 Always tell trusted adults when you don't feel well\n\n**Remember:**\n- Your parents and guardians are there to help you stay healthy\n- Ask questions! Adults love to help you learn\n- You're doing great by learning about health! \n\n${appState.ageAppropriateDisclaimer}\n ''';\n } else {\n return '''\n🌟 **Personalized Health Insights for ${appState.userName}**\n\n**General Wellness Tips:**\n• Stay hydrated - aim for 8 glasses of water daily\n• Get 7-9 hours of quality sleep\n• Take regular breaks from screen time\n• Practice deep breathing exercises\n\n**Healthy Habits:**\n• Walk for 30 minutes daily\n• Eat colorful fruits and vegetables\n• Maintain regular meal times\n• Stay connected with loved ones\n\n💡 **Tip:** Add your health data to get more personalized insights!\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n }\n\n // ENHANCED: Fallback response with age consideration\n String _getFallbackResponse(String userMessage, AppState appState) {\n final quickResponse = getQuickResponse(userMessage, appState);\n if (quickResponse != null) return quickResponse;\n\n return appState.getAgeAppropriateErrorMessage();\n }\n\n Future<String> _safeApiCall(String prompt, String contextMessage,\n {bool isChat = false, AppState? appState}) async {\n try {\n if (isChat) {\n return await _makeChatApiCall(prompt, appState);\n } else {\n return await _makeApiCallWithRetry(prompt, appState);\n }\n } on TimeoutException {\n if (kDebugMode) {\n print(\n '⏳ $contextMessage: Request timed out after ${_timeout.inSeconds}s');\n }\n if (isChat && appState != null) {\n final messages = jsonDecode(prompt) as List<dynamic>;\n final lastUserMessage = messages.lastWhere(\n (m) => m['role'] == 'user',\n orElse: () => {'content': ''},\n )['content'] ??\n '';\n return _getFallbackResponse(lastUserMessage, appState);\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'The request took longer than expected. Please try again.';\n } on SocketException catch (e) {\n if (kDebugMode) {\n print('🌐 Network error: ${e.message}');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'Network connection issue. Please check your internet and try again.';\n } catch (e) {\n if (kDebugMode) {\n print('⚠️ $contextMessage: $e');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'I\\'m experiencing technical difficulties. Please try again in a moment.';\n }\n }\n\n Future<String> _makeChatApiCall(\n String conversationHistoryJson, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive',\n 'Accept': 'application/json',\n };\n\n final List<dynamic> messages = jsonDecode(conversationHistoryJson);\n\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are MediPal, a helpful medical AI. Keep responses concise and include medical disclaimers.'\n });\n }\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n 'top_p': 0.8,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _buildChatPrompt(\n List<Map<String, dynamic>> conversationHistory, AppState appState) {\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n return jsonEncode(messages);\n }\n\n // RESTORED: Working retry logic with exponential backoff\n Future<String> _makeApiCallWithRetry(\n String prompt, AppState? appState) async {\n int attempts = 0;\n\n while (true) {\n try {\n if (kDebugMode) {\n print('🔄 API attempt ${attempts + 1}/${_maxRetries + 1}');\n }\n return await _makeApiCall(prompt, appState);\n } on TimeoutException {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('⏳ Max retries reached after $attempts attempts');\n }\n rethrow;\n }\n\n // Use working retry delays with jitter\n final delayMs = _retryDelays[attempts - 1];\n final jitter =\n (delayMs * 0.1 * (DateTime.now().millisecond % 100) / 100).round();\n final finalDelay = delayMs + jitter;\n\n if (kDebugMode) {\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${finalDelay}ms');\n }\n await Future.delayed(Duration(milliseconds: finalDelay));\n } on SocketException catch (e) {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('🌐 Network error after $attempts attempts: ${e.message}');\n }\n rethrow;\n }\n\n final delayMs = _retryDelays[attempts - 1];\n if (kDebugMode) {\n print('🌐 Network issue, retrying in ${delayMs}ms...');\n }\n await Future.delayed(Duration(milliseconds: delayMs));\n } catch (e) {\n if (kDebugMode) {\n print('❌ Non-retryable error: $e');\n }\n rethrow;\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive', // Important for long requests\n };\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are a medical AI assistant. Provide concise, informative responses. Include medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(\n _timeout,\n onTimeout: () {\n throw TimeoutException(\n 'Request to DeepSeek API exceeded ${_timeout.inSeconds}s timeout',\n _timeout,\n );\n },\n );\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from DeepSeek API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // OPTIMIZED: Dramatically simplified symptom analysis prompt\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) {\n final buffer = StringBuffer();\n\n if (appState.isMinor) {\n buffer.writeln(\"Help young person (age ${appState.userAge}):\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n buffer.writeln(\n \"Provide: Simple explanation, when to tell adults. Keep brief under 200 words.\");\n } else {\n buffer\n .writeln(\"Analyze for ${appState.userAge}yo ${appState.userGender}:\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n\n // Only include top 3 additional info items to keep prompt short\n if (additionalInfo.isNotEmpty) {\n int count = 0;\n buffer.writeln(\"Info:\");\n for (var entry in additionalInfo.entries) {\n if (entry.value.toString().isNotEmpty && count < 3) {\n buffer.writeln(\"- ${entry.key}: ${entry.value}\");\n count++;\n }\n }\n }\n\n buffer.writeln(\n \"\\nProvide: Causes, when to see doctor, self-care, disclaimer. Under 300 words.\");\n }\n\n return buffer.toString();\n }\n\n // OPTIMIZED: Simplified medication interaction prompt\n String _buildMedicationInteractionPrompt(\n List<String> medications, AppState appState) {\n if (appState.isMinor) {\n return \"Minor asking about medicines. Redirect to trusted adults briefly.\";\n }\n\n return \"\"\"\nAnalyze interactions: ${medications.join(', ')}\nFor ${appState.userAge}yo ${appState.userGender}. \nProvide: 1) Risk level 2) Key effects 3) When to consult doctor 4) Disclaimer\nKeep under 250 words.\n\"\"\";\n }\n\n // OPTIMIZED: Dramatically simplified health insights prompt\n String _buildHealthInsightsPrompt(\n Map<String, dynamic> healthData, AppState appState) {\n if (appState.isMinor) {\n return \"\"\"\nCreate health tips for ${appState.userName} (${appState.userAge}yo):\nFocus on: healthy habits, exercise, sleep, nutrition.\nUse simple, encouraging language. Mention trusted adults. Keep under 200 words.\n\"\"\";\n }\n\n // Extract only top 5 most relevant health data items\n final relevantData = <String, dynamic>{};\n final priorityKeys = [\n 'medications_count',\n 'health_score',\n 'sleep_hours',\n 'recent_symptoms',\n 'activity_level'\n ];\n\n for (final key in priorityKeys) {\n if (healthData.containsKey(key) &&\n healthData[key] != null &&\n healthData[key].toString().isNotEmpty) {\n relevantData[key] = healthData[key];\n }\n if (relevantData.length >= 5) break;\n }\n\n final buffer = StringBuffer();\n buffer.writeln(\n \"Health insights for ${appState.userName} (${appState.userAge}yo, ${appState.userGender}):\");\n\n if (relevantData.isNotEmpty) {\n relevantData.forEach((key, value) {\n buffer.writeln(\"- $key: $value\");\n });\n }\n\n buffer.writeln(\n \"\\nProvide: Assessment, lifestyle tips, improvements, encouragement. Under 350 words with disclaimer.\");\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl\\nTimeout: ${_timeout.inSeconds}s';\n}\n"}, "1e58ede035618787915fa7d3b412058e6203976a": {"t": 1785757946.042274, "n": 28721, "h": "719cf471e29438e8", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'dart:io';\nimport 'package:flutter/foundation.dart';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\nimport '../utils/app_state.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // RESTORED: Working timeout values from old version\n static const Duration _timeout = Duration(seconds: 30); // INCREASED from 20\n static const int _maxRetries = 2;\n// INCREASED from 3\n\n // RESTORED: Working retry delays with exponential backoff\n static const List<int> _retryDelays = [500, 1500]; // INCREASED from 300, 800\n\n // ENHANCED: Age-appropriate quick responses\n static const Map<String, Map<String, String>> _quickResponses = {\n 'hello': {\n 'minor':\n 'Hi there! 🌟 I\\'m here to help you learn about staying healthy! Remember to always ask a trusted adult if you have health questions!',\n 'adult':\n 'Hello! I\\'m PersonalMedAI, your health assistant. How can I help you today? 😊',\n },\n 'hi': {\n 'minor':\n 'Hi! 👋 I can teach you fun ways to stay healthy! Always talk to your parents or guardians about health stuff too!',\n 'adult':\n 'Hi there! I\\'m here to help with any health questions you might have! 🩺',\n },\n 'help': {\n 'minor':\n 'I can teach you about:\\n• Healthy foods and exercise 🥕\\n• Why sleep is important 😴\\n• When to tell adults you don\\'t feel well\\n• Fun ways to stay strong! 💪\\n\\nBut always ask trusted adults about health questions!',\n 'adult':\n 'I can help you with:\\n• Medical questions and symptoms\\n• Medication information\\n• Health guidance\\n• Emergency information\\n\\nWhat would you like to know?',\n },\n 'emergency': {\n 'minor':\n '🚨 **If there\\'s an emergency:**\\n\\n1. Find a trusted adult RIGHT AWAY\\n2. Call 911 if no adult is around\\n3. Stay calm and ask for help\\n\\nAlways tell adults when you don\\'t feel well!',\n 'adult':\n '🚨 **MEDICAL EMERGENCY?**\\n\\nCall 911 immediately if experiencing:\\n• Difficulty breathing\\n• Chest pain\\n• Severe bleeding\\n• Loss of consciousness',\n },\n 'thanks': {\n 'minor':\n 'You\\'re welcome! 🌟 Keep learning about staying healthy, and remember to always talk to trusted adults about health questions!',\n 'adult':\n 'You\\'re welcome! I\\'m always here to help with your health questions. Take care! 😊',\n },\n 'thank you': {\n 'minor':\n 'You\\'re so welcome! 🌟 Keep asking great questions and always talk to trusted adults about your health!',\n 'adult':\n 'You\\'re very welcome! Feel free to ask if you have more questions. Stay healthy! 💙',\n },\n };\n\n // NEW: Adult content keywords for filtering\n static const List<String> _adultContentKeywords = [\n 'sex',\n 'sexual',\n 'pregnancy',\n 'contraception',\n 'std',\n 'sti',\n 'reproductive',\n 'genital',\n 'abortion',\n 'breast',\n 'period',\n 'menstruation',\n 'testosterone',\n 'viagra',\n 'drug abuse',\n 'alcohol',\n 'addiction',\n 'overdose',\n 'suicide',\n 'self-harm',\n 'depression',\n 'anxiety disorder'\n ];\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n if (kDebugMode) {\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n }\n if (kDebugMode) {\n print(\"🌍 Base URL: $_baseUrl\");\n }\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n // ENHANCED: Age-appropriate quick responses with AppState\n String? getQuickResponse(String message, AppState appState) {\n final normalizedMessage = message.toLowerCase().trim();\n\n // Check for adult content if user is a minor\n if (appState.isMinor && _containsAdultContent(normalizedMessage)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n\n // Direct matches with age-appropriate responses\n if (_quickResponses.containsKey(normalizedMessage)) {\n final responses = _quickResponses[normalizedMessage]!;\n return appState.isMinor ? responses['minor'] : responses['adult'];\n }\n\n // Age-appropriate pattern matches\n return _getPatternBasedResponse(normalizedMessage, appState);\n }\n\n // NEW: Check for adult content\n bool _containsAdultContent(String message) {\n final lowerMessage = message.toLowerCase();\n return _adultContentKeywords\n .any((keyword) => lowerMessage.contains(keyword));\n }\n\n // NEW: Minor redirect response\n String _getMinorRedirectResponse(String userName) {\n return '''\nHi ${userName.isNotEmpty ? userName : 'there'}! 🌟\n\nI notice you're asking about something that might be better discussed with a trusted adult like a parent, guardian, or doctor.\n\n**What you can do:**\n- Talk to a parent or guardian about your question \n- Ask a school nurse or counselor\n- Visit a doctor with a trusted adult\n\nRemember: I'm here to help with general health information, but for anything serious or personal, it's always best to talk to a real person who can help you properly! 😊\n\nIs there something else I can help you with today?\n ''';\n }\n\n // ENHANCED: Pattern-based responses with age consideration\n String? _getPatternBasedResponse(String message, AppState appState) {\n if (message.contains('headache')) {\n return appState.isMinor\n ? '🤕 **If your head hurts:**\\n• Tell a trusted adult right away\\n• Rest in a quiet place\\n• Drink some water\\n• Ask an adult about what to do\\n\\n⚠️ Always let adults help you when you don\\'t feel well!'\n : '🩺 **Headache Relief:**\\n• Stay hydrated (drink water)\\n• Rest in a quiet, dark room\\n• Apply cold/warm compress\\n• Consider OTC pain relief\\n\\n⚠️ See a doctor if severe or persistent.';\n }\n\n if (message.contains('fever')) {\n return appState.isMinor\n ? '🌡️ **If you feel hot and sick:**\\n• Tell an adult immediately\\n• Rest and drink water\\n• Let adults check your temperature\\n• Ask for help from grown-ups\\n\\n⚠️ Adults know what to do when you have a fever!'\n : '🌡️ **Fever Management:**\\n• Stay hydrated\\n• Rest and monitor temperature\\n• Light clothing\\n• Seek medical attention if >101.5°F (38.6°C)\\n\\n⚠️ Contact healthcare provider if persistent.';\n }\n\n if (message.contains('medication') && message.contains('safe')) {\n return appState.isMinor\n ? '💊 **About Medicines:**\\n• Only adults should give you medicine\\n• Never take medicine by yourself\\n• Always ask trusted adults first\\n• Tell adults about any medicine questions\\n\\n⚠️ Medicine safety is super important - let adults handle it!'\n : '💊 **Medication Safety:**\\n• Always follow prescribed dosage\\n• Check for drug interactions\\n• Store properly\\n• Don\\'t share medications\\n\\n⚠️ Consult your pharmacist or doctor with questions.';\n }\n\n return null; // No quick response available\n }\n\n // OPTIMIZED: Dramatically simplified system prompts\n String _getAgeAppropriateSystemPrompt(AppState appState) {\n final basePrompt = '''\nYou are PersonalMedAI for ${appState.userName}, Age: ${appState.userAge}, Gender: ${appState.userGender}\n''';\n\n if (appState.isMinor) {\n return '''\n$basePrompt\nMINOR (Under 18): Use simple language. Always direct to trusted adults. Focus on wellness and safety. \nAvoid: self-medication, detailed medical terms, sensitive topics. Keep under 250 words. End with reminder to talk to adults.\n ''';\n } else if (appState.isYoungAdult) {\n return '''\n$basePrompt\nYOUNG ADULT (18-24): Clear educational language. Emphasize preventive care and professional consultation.\nKeep under 350 words with disclaimers.\n ''';\n } else {\n return '''\n$basePrompt\nADULT (25+): Detailed medical-grade information with appropriate terminology. \nThorough analysis with disclaimers. Keep under 500 words.\n ''';\n }\n }\n\n // ENHANCED: Streaming with age restrictions and AppState\n Stream<String> streamChatResponse(\n List<Map<String, String>> conversationHistory, AppState appState) async* {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final quickResponse =\n getQuickResponse(lastMessage['text'] ?? '', appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 300));\n yield quickResponse;\n return;\n }\n }\n }\n\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Accept': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n };\n\n final messages = _buildMessageHistory(conversationHistory, appState);\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': appState.isMinor ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED: Single value\n 'stream': true,\n 'top_p': 0.8,\n });\n\n try {\n final request =\n http.Request('POST', Uri.parse('$_baseUrl/chat/completions'))\n ..headers.addAll(headers)\n ..body = body;\n\n final client = http.Client();\n final streamedResponse = await client.send(request).timeout(_timeout);\n\n if (streamedResponse.statusCode != 200) {\n throw Exception(\n 'API request failed with status: ${streamedResponse.statusCode}');\n }\n\n String accumulatedText = '';\n\n await for (final line in streamedResponse.stream\n .transform(utf8.decoder)\n .transform(const LineSplitter())\n .where((line) => line.trim().isNotEmpty)) {\n if (line.startsWith('data: ')) {\n final data = line.substring(6).trim();\n\n if (data == '[DONE]') {\n break;\n }\n\n try {\n final json = jsonDecode(data);\n final content = json['choices']?[0]?['delta']?['content'];\n\n if (content != null && content.isNotEmpty) {\n accumulatedText += content;\n\n // Filter content for minors\n if (appState.isMinor && _containsAdultContent(accumulatedText)) {\n yield _getMinorRedirectResponse(appState.userName);\n break;\n }\n\n yield accumulatedText;\n }\n } catch (e) {\n continue;\n }\n }\n }\n\n client.close();\n\n // Add age-appropriate disclaimer\n if (accumulatedText.isNotEmpty &&\n !accumulatedText.contains(appState.ageAppropriateDisclaimer)) {\n final finalResponse =\n '$accumulatedText\\n\\n${appState.ageAppropriateDisclaimer}';\n yield finalResponse;\n }\n } catch (e) {\n if (kDebugMode) {\n print('❌ Streaming error: $e');\n }\n try {\n final response = await sendChatMessage(conversationHistory, appState);\n yield response;\n } catch (fallbackError) {\n yield appState.getAgeAppropriateErrorMessage();\n }\n }\n }\n\n // ENHANCED: Chat with age restrictions and AppState\n Future<String> sendChatMessage(\n List<Map<String, dynamic>> conversationHistory, AppState appState) async {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final quickResponse =\n getQuickResponse(lastMessage['text'] ?? '', appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 500));\n return quickResponse;\n }\n }\n }\n\n final prompt = _buildChatPrompt(conversationHistory, appState);\n final result = await _safeApiCall(prompt, 'Error in chat conversation',\n isChat: true, appState: appState);\n\n // Add age-appropriate disclaimer if not already present\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // Helper method to build message history for streaming with age restrictions\n List<Map<String, String>> _buildMessageHistory(\n List<Map<String, String>> conversationHistory, AppState appState) {\n final messages = <Map<String, String>>[];\n\n // Add age-appropriate system message\n messages.add({\n 'role': 'system',\n 'content': _getAgeAppropriateSystemPrompt(appState),\n });\n\n // Convert conversation history\n for (final message in conversationHistory) {\n messages.add({\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n });\n }\n\n return messages;\n }\n\n // ENHANCED: Symptom analysis with age restrictions\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) async {\n // Check for adult content in symptoms for minors\n if (appState.isMinor) {\n final symptomsText = symptoms.join(' ').toLowerCase();\n if (_containsAdultContent(symptomsText)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n }\n\n final prompt = _buildSymptomAnalysisPrompt(\n symptoms, severity, additionalInfo, appState);\n final result = await _safeApiCall(prompt, 'Error analyzing symptoms',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Medication interactions with age restrictions\n Future<String> checkMedicationInteractions(\n List<String> medications, AppState appState) async {\n if (appState.isMinor) {\n return '''\nHi ${appState.userName}! 🌟\n\nMedicine questions are really important! Here's what you should do:\n\n**For Medicine Safety:**\n- Always ask a trusted adult before taking any medicine\n- Never take medicine by yourself\n- Tell adults about all medicines you take\n- Ask parents or guardians about medicine questions\n\n**Important:** Only doctors, parents, or guardians should decide about your medicines!\n\nRemember: Adults are there to keep you safe and healthy! 💙\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n\n final prompt = _buildMedicationInteractionPrompt(medications, appState);\n final result = await _safeApiCall(\n prompt, 'Error checking medication interactions',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Health insights with comprehensive data analysis\n Future<String> getHealthInsights(\n Map<String, dynamic> healthData, AppState appState) async {\n // If healthData is a string, treat it as a single chat message\n if (healthData is String) {\n final conversationHistory = [\n {'isUser': 'true', 'text': healthData}\n ];\n return sendChatMessage(conversationHistory, appState);\n }\n\n // Check for quick insights first\n if (healthData.isEmpty) {\n return _getDefaultHealthInsights(appState);\n }\n\n final prompt = _buildHealthInsightsPrompt(healthData, appState);\n final result = await _safeApiCall(prompt, 'Error getting health insights',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return '$result\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // NEW: Default health insights based on age\n String _getDefaultHealthInsights(AppState appState) {\n if (appState.isMinor) {\n return '''\n🌟 **Health Tips Just for You, ${appState.userName}!**\n\n**Stay Strong and Healthy:**\n🏃‍♀️ Play and be active every day - it's fun and makes you strong!\n😴 Get lots of sleep (9-11 hours) to help your body grow\n🥕 Eat colorful foods like fruits and vegetables\n💧 Drink water to keep your body happy\n🧠 Always tell trusted adults when you don't feel well\n\n**Remember:**\n- Your parents and guardians are there to help you stay healthy\n- Ask questions! Adults love to help you learn\n- You're doing great by learning about health! \n\n${appState.ageAppropriateDisclaimer}\n ''';\n } else {\n return '''\n🌟 **Personalized Health Insights for ${appState.userName}**\n\n**General Wellness Tips:**\n• Stay hydrated - aim for 8 glasses of water daily\n• Get 7-9 hours of quality sleep\n• Take regular breaks from screen time\n• Practice deep breathing exercises\n\n**Healthy Habits:**\n• Walk for 30 minutes daily\n• Eat colorful fruits and vegetables\n• Maintain regular meal times\n• Stay connected with loved ones\n\n💡 **Tip:** Add your health data to get more personalized insights!\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n }\n\n // ENHANCED: Fallback response with age consideration\n String _getFallbackResponse(String userMessage, AppState appState) {\n final quickResponse = getQuickResponse(userMessage, appState);\n if (quickResponse != null) return quickResponse;\n\n return appState.getAgeAppropriateErrorMessage();\n }\n\n Future<String> _safeApiCall(String prompt, String contextMessage,\n {bool isChat = false, AppState? appState}) async {\n try {\n if (isChat) {\n return await _makeChatApiCall(prompt, appState);\n } else {\n return await _makeApiCallWithRetry(prompt, appState);\n }\n } on TimeoutException {\n if (kDebugMode) {\n print(\n '⏳ $contextMessage: Request timed out after ${_timeout.inSeconds}s');\n }\n if (isChat && appState != null) {\n final messages = jsonDecode(prompt) as List<dynamic>;\n final lastUserMessage = messages.lastWhere(\n (m) => m['role'] == 'user',\n orElse: () => {'content': ''},\n )['content'] ??\n '';\n return _getFallbackResponse(lastUserMessage, appState);\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'The request took longer than expected. Please try again.';\n } on SocketException catch (e) {\n if (kDebugMode) {\n print('🌐 Network error: ${e.message}');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'Network connection issue. Please check your internet and try again.';\n } catch (e) {\n if (kDebugMode) {\n print('⚠️ $contextMessage: $e');\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'I\\'m experiencing technical difficulties. Please try again in a moment.';\n }\n }\n\n Future<String> _makeChatApiCall(\n String conversationHistoryJson, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive',\n 'Accept': 'application/json',\n };\n\n final List<dynamic> messages = jsonDecode(conversationHistoryJson);\n\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are PersonalMedAI, a helpful medical AI. Keep responses concise and include medical disclaimers.'\n });\n }\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n 'top_p': 0.8,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _buildChatPrompt(\n List<Map<String, dynamic>> conversationHistory, AppState appState) {\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n return jsonEncode(messages);\n }\n\n // RESTORED: Working retry logic with exponential backoff\n Future<String> _makeApiCallWithRetry(\n String prompt, AppState? appState) async {\n int attempts = 0;\n\n while (true) {\n try {\n if (kDebugMode) {\n print('🔄 API attempt ${attempts + 1}/${_maxRetries + 1}');\n }\n return await _makeApiCall(prompt, appState);\n } on TimeoutException {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('⏳ Max retries reached after $attempts attempts');\n }\n rethrow;\n }\n\n // Use working retry delays with jitter\n final delayMs = _retryDelays[attempts - 1];\n final jitter =\n (delayMs * 0.1 * (DateTime.now().millisecond % 100) / 100).round();\n final finalDelay = delayMs + jitter;\n\n if (kDebugMode) {\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${finalDelay}ms');\n }\n await Future.delayed(Duration(milliseconds: finalDelay));\n } on SocketException catch (e) {\n attempts++;\n if (attempts > _maxRetries) {\n if (kDebugMode) {\n print('🌐 Network error after $attempts attempts: ${e.message}');\n }\n rethrow;\n }\n\n final delayMs = _retryDelays[attempts - 1];\n if (kDebugMode) {\n print('🌐 Network issue, retrying in ${delayMs}ms...');\n }\n await Future.delayed(Duration(milliseconds: delayMs));\n } catch (e) {\n if (kDebugMode) {\n print('❌ Non-retryable error: $e');\n }\n rethrow;\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive', // Important for long requests\n };\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are a medical AI assistant. Provide concise, informative responses. Include medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(\n _timeout,\n onTimeout: () {\n throw TimeoutException(\n 'Request to DeepSeek API exceeded ${_timeout.inSeconds}s timeout',\n _timeout,\n );\n },\n );\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from DeepSeek API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // OPTIMIZED: Dramatically simplified symptom analysis prompt\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) {\n final buffer = StringBuffer();\n\n if (appState.isMinor) {\n buffer.writeln(\"Help young person (age ${appState.userAge}):\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n buffer.writeln(\n \"Provide: Simple explanation, when to tell adults. Keep brief under 200 words.\");\n } else {\n buffer\n .writeln(\"Analyze for ${appState.userAge}yo ${appState.userGender}:\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n\n // Only include top 3 additional info items to keep prompt short\n if (additionalInfo.isNotEmpty) {\n int count = 0;\n buffer.writeln(\"Info:\");\n for (var entry in additionalInfo.entries) {\n if (entry.value.toString().isNotEmpty && count < 3) {\n buffer.writeln(\"- ${entry.key}: ${entry.value}\");\n count++;\n }\n }\n }\n\n buffer.writeln(\n \"\\nProvide: Causes, when to see doctor, self-care, disclaimer. Under 300 words.\");\n }\n\n return buffer.toString();\n }\n\n // OPTIMIZED: Simplified medication interaction prompt\n String _buildMedicationInteractionPrompt(\n List<String> medications, AppState appState) {\n if (appState.isMinor) {\n return \"Minor asking about medicines. Redirect to trusted adults briefly.\";\n }\n\n return \"\"\"\nAnalyze interactions: ${medications.join(', ')}\nFor ${appState.userAge}yo ${appState.userGender}. \nProvide: 1) Risk level 2) Key effects 3) When to consult doctor 4) Disclaimer\nKeep under 250 words.\n\"\"\";\n }\n\n // OPTIMIZED: Dramatically simplified health insights prompt\n String _buildHealthInsightsPrompt(\n Map<String, dynamic> healthData, AppState appState) {\n if (appState.isMinor) {\n return \"\"\"\nCreate health tips for ${appState.userName} (${appState.userAge}yo):\nFocus on: healthy habits, exercise, sleep, nutrition.\nUse simple, encouraging language. Mention trusted adults. Keep under 200 words.\n\"\"\";\n }\n\n // Extract only top 5 most relevant health data items\n final relevantData = <String, dynamic>{};\n final priorityKeys = [\n 'medications_count',\n 'health_score',\n 'sleep_hours',\n 'recent_symptoms',\n 'activity_level'\n ];\n\n for (final key in priorityKeys) {\n if (healthData.containsKey(key) &&\n healthData[key] != null &&\n healthData[key].toString().isNotEmpty) {\n relevantData[key] = healthData[key];\n }\n if (relevantData.length >= 5) break;\n }\n\n final buffer = StringBuffer();\n buffer.writeln(\n \"Health insights for ${appState.userName} (${appState.userAge}yo, ${appState.userGender}):\");\n\n if (relevantData.isNotEmpty) {\n relevantData.forEach((key, value) {\n buffer.writeln(\"- $key: $value\");\n });\n }\n\n buffer.writeln(\n \"\\nProvide: Assessment, lifestyle tips, improvements, encouragement. Under 350 words with disclaimer.\");\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl\\nTimeout: ${_timeout.inSeconds}s';\n}\n"}, "85fce1c2475b217cb60593da61aaf5f011339453": {"t": 1785757947.9624941, "n": 28412, "h": "f3c705e256537f88", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'dart:io';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\nimport '../utils/app_state.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // RESTORED: Working timeout values from old version\n static const Duration _timeout = Duration(seconds: 30); // INCREASED from 20\n static const int _maxRetries = 2;\n static const Duration _connectTimeout =\n Duration(seconds: 5); // INCREASED from 3\n static const Duration _receiveTimeout = Duration(seconds: 25);\n\n // RESTORED: Working retry delays with exponential backoff\n static const List<int> _retryDelays = [500, 1500]; // INCREASED from 300, 800\n\n // ENHANCED: Age-appropriate quick responses\n static const Map<String, Map<String, String>> _quickResponses = {\n 'hello': {\n 'minor':\n 'Hi there! 🌟 I\\'m here to help you learn about staying healthy! Remember to always ask a trusted adult if you have health questions!',\n 'adult':\n 'Hello! I\\'m PersonalMedAI, your health assistant. How can I help you today? 😊',\n },\n 'hi': {\n 'minor':\n 'Hi! 👋 I can teach you fun ways to stay healthy! Always talk to your parents or guardians about health stuff too!',\n 'adult':\n 'Hi there! I\\'m here to help with any health questions you might have! 🩺',\n },\n 'help': {\n 'minor':\n 'I can teach you about:\\n• Healthy foods and exercise 🥕\\n• Why sleep is important 😴\\n• When to tell adults you don\\'t feel well\\n• Fun ways to stay strong! 💪\\n\\nBut always ask trusted adults about health questions!',\n 'adult':\n 'I can help you with:\\n• Medical questions and symptoms\\n• Medication information\\n• Health guidance\\n• Emergency information\\n\\nWhat would you like to know?',\n },\n 'emergency': {\n 'minor':\n '🚨 **If there\\'s an emergency:**\\n\\n1. Find a trusted adult RIGHT AWAY\\n2. Call 911 if no adult is around\\n3. Stay calm and ask for help\\n\\nAlways tell adults when you don\\'t feel well!',\n 'adult':\n '🚨 **MEDICAL EMERGENCY?**\\n\\nCall 911 immediately if experiencing:\\n• Difficulty breathing\\n• Chest pain\\n• Severe bleeding\\n• Loss of consciousness',\n },\n 'thanks': {\n 'minor':\n 'You\\'re welcome! 🌟 Keep learning about staying healthy, and remember to always talk to trusted adults about health questions!',\n 'adult':\n 'You\\'re welcome! I\\'m always here to help with your health questions. Take care! 😊',\n },\n 'thank you': {\n 'minor':\n 'You\\'re so welcome! 🌟 Keep asking great questions and always talk to trusted adults about your health!',\n 'adult':\n 'You\\'re very welcome! Feel free to ask if you have more questions. Stay healthy! 💙',\n },\n };\n\n // NEW: Adult content keywords for filtering\n static const List<String> _adultContentKeywords = [\n 'sex',\n 'sexual',\n 'pregnancy',\n 'contraception',\n 'std',\n 'sti',\n 'reproductive',\n 'genital',\n 'abortion',\n 'breast',\n 'period',\n 'menstruation',\n 'testosterone',\n 'viagra',\n 'drug abuse',\n 'alcohol',\n 'addiction',\n 'overdose',\n 'suicide',\n 'self-harm',\n 'depression',\n 'anxiety disorder'\n ];\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n print(\"🌍 Base URL: $_baseUrl\");\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n // ENHANCED: Age-appropriate quick responses with AppState\n String? getQuickResponse(String message, AppState appState) {\n final normalizedMessage = message.toLowerCase().trim();\n\n // Check for adult content if user is a minor\n if (appState.isMinor && _containsAdultContent(normalizedMessage)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n\n // Direct matches with age-appropriate responses\n if (_quickResponses.containsKey(normalizedMessage)) {\n final responses = _quickResponses[normalizedMessage]!;\n return appState.isMinor ? responses['minor'] : responses['adult'];\n }\n\n // Age-appropriate pattern matches\n return _getPatternBasedResponse(normalizedMessage, appState);\n }\n\n // NEW: Check for adult content\n bool _containsAdultContent(String message) {\n final lowerMessage = message.toLowerCase();\n return _adultContentKeywords\n .any((keyword) => lowerMessage.contains(keyword));\n }\n\n // NEW: Minor redirect response\n String _getMinorRedirectResponse(String userName) {\n return '''\nHi ${userName.isNotEmpty ? userName : 'there'}! 🌟\n\nI notice you're asking about something that might be better discussed with a trusted adult like a parent, guardian, or doctor.\n\n**What you can do:**\n- Talk to a parent or guardian about your question \n- Ask a school nurse or counselor\n- Visit a doctor with a trusted adult\n\nRemember: I'm here to help with general health information, but for anything serious or personal, it's always best to talk to a real person who can help you properly! 😊\n\nIs there something else I can help you with today?\n ''';\n }\n\n // ENHANCED: Pattern-based responses with age consideration\n String? _getPatternBasedResponse(String message, AppState appState) {\n if (message.contains('headache')) {\n return appState.isMinor\n ? '🤕 **If your head hurts:**\\n• Tell a trusted adult right away\\n• Rest in a quiet place\\n• Drink some water\\n• Ask an adult about what to do\\n\\n⚠️ Always let adults help you when you don\\'t feel well!'\n : '🩺 **Headache Relief:**\\n• Stay hydrated (drink water)\\n• Rest in a quiet, dark room\\n• Apply cold/warm compress\\n• Consider OTC pain relief\\n\\n⚠️ See a doctor if severe or persistent.';\n }\n\n if (message.contains('fever')) {\n return appState.isMinor\n ? '🌡️ **If you feel hot and sick:**\\n• Tell an adult immediately\\n• Rest and drink water\\n• Let adults check your temperature\\n• Ask for help from grown-ups\\n\\n⚠️ Adults know what to do when you have a fever!'\n : '🌡️ **Fever Management:**\\n• Stay hydrated\\n• Rest and monitor temperature\\n• Light clothing\\n• Seek medical attention if >101.5°F (38.6°C)\\n\\n⚠️ Contact healthcare provider if persistent.';\n }\n\n if (message.contains('medication') && message.contains('safe')) {\n return appState.isMinor\n ? '💊 **About Medicines:**\\n• Only adults should give you medicine\\n• Never take medicine by yourself\\n• Always ask trusted adults first\\n• Tell adults about any medicine questions\\n\\n⚠️ Medicine safety is super important - let adults handle it!'\n : '💊 **Medication Safety:**\\n• Always follow prescribed dosage\\n• Check for drug interactions\\n• Store properly\\n• Don\\'t share medications\\n\\n⚠️ Consult your pharmacist or doctor with questions.';\n }\n\n return null; // No quick response available\n }\n\n // OPTIMIZED: Dramatically simplified system prompts\n String _getAgeAppropriateSystemPrompt(AppState appState) {\n final basePrompt = '''\nYou are PersonalMedAI for ${appState.userName}, Age: ${appState.userAge}, Gender: ${appState.userGender}\n''';\n\n if (appState.isMinor) {\n return '''\n$basePrompt\nMINOR (Under 18): Use simple language. Always direct to trusted adults. Focus on wellness and safety. \nAvoid: self-medication, detailed medical terms, sensitive topics. Keep under 250 words. End with reminder to talk to adults.\n ''';\n } else if (appState.isYoungAdult) {\n return '''\n$basePrompt\nYOUNG ADULT (18-24): Clear educational language. Emphasize preventive care and professional consultation.\nKeep under 350 words with disclaimers.\n ''';\n } else {\n return '''\n$basePrompt\nADULT (25+): Detailed medical-grade information with appropriate terminology. \nThorough analysis with disclaimers. Keep under 500 words.\n ''';\n }\n }\n\n // ENHANCED: Streaming with age restrictions and AppState\n Stream<String> streamChatResponse(\n List<Map<String, String>> conversationHistory, AppState appState) async* {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final quickResponse =\n getQuickResponse(lastMessage['text'] ?? '', appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 300));\n yield quickResponse;\n return;\n }\n }\n }\n\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Accept': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n };\n\n final messages = _buildMessageHistory(conversationHistory, appState);\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': appState.isMinor ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED: Single value\n 'stream': true,\n 'top_p': 0.8,\n });\n\n try {\n final request =\n http.Request('POST', Uri.parse('$_baseUrl/chat/completions'))\n ..headers.addAll(headers)\n ..body = body;\n\n final client = http.Client();\n final streamedResponse = await client.send(request).timeout(_timeout);\n\n if (streamedResponse.statusCode != 200) {\n throw Exception(\n 'API request failed with status: ${streamedResponse.statusCode}');\n }\n\n String accumulatedText = '';\n\n await for (final line in streamedResponse.stream\n .transform(utf8.decoder)\n .transform(const LineSplitter())\n .where((line) => line.trim().isNotEmpty)) {\n if (line.startsWith('data: ')) {\n final data = line.substring(6).trim();\n\n if (data == '[DONE]') {\n break;\n }\n\n try {\n final json = jsonDecode(data);\n final content = json['choices']?[0]?['delta']?['content'];\n\n if (content != null && content.isNotEmpty) {\n accumulatedText += content;\n\n // Filter content for minors\n if (appState.isMinor && _containsAdultContent(accumulatedText)) {\n yield _getMinorRedirectResponse(appState.userName);\n break;\n }\n\n yield accumulatedText;\n }\n } catch (e) {\n continue;\n }\n }\n }\n\n client.close();\n\n // Add age-appropriate disclaimer\n if (accumulatedText.isNotEmpty &&\n !accumulatedText.contains(appState.ageAppropriateDisclaimer)) {\n final finalResponse =\n accumulatedText + '\\n\\n${appState.ageAppropriateDisclaimer}';\n yield finalResponse;\n }\n } catch (e) {\n print('❌ Streaming error: $e');\n try {\n final response = await sendChatMessage(conversationHistory, appState);\n yield response;\n } catch (fallbackError) {\n yield appState.getAgeAppropriateErrorMessage();\n }\n }\n }\n\n // ENHANCED: Chat with age restrictions and AppState\n Future<String> sendChatMessage(\n List<Map<String, dynamic>> conversationHistory, AppState appState) async {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final quickResponse =\n getQuickResponse(lastMessage['text'] ?? '', appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 500));\n return quickResponse;\n }\n }\n }\n\n final prompt = _buildChatPrompt(conversationHistory, appState);\n final result = await _safeApiCall(prompt, 'Error in chat conversation',\n isChat: true, appState: appState);\n\n // Add age-appropriate disclaimer if not already present\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return result + '\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // Helper method to build message history for streaming with age restrictions\n List<Map<String, String>> _buildMessageHistory(\n List<Map<String, String>> conversationHistory, AppState appState) {\n final messages = <Map<String, String>>[];\n\n // Add age-appropriate system message\n messages.add({\n 'role': 'system',\n 'content': _getAgeAppropriateSystemPrompt(appState),\n });\n\n // Convert conversation history\n for (final message in conversationHistory) {\n messages.add({\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n });\n }\n\n return messages;\n }\n\n // ENHANCED: Symptom analysis with age restrictions\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) async {\n // Check for adult content in symptoms for minors\n if (appState.isMinor) {\n final symptomsText = symptoms.join(' ').toLowerCase();\n if (_containsAdultContent(symptomsText)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n }\n\n final prompt = _buildSymptomAnalysisPrompt(\n symptoms, severity, additionalInfo, appState);\n final result = await _safeApiCall(prompt, 'Error analyzing symptoms',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return result + '\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Medication interactions with age restrictions\n Future<String> checkMedicationInteractions(\n List<String> medications, AppState appState) async {\n if (appState.isMinor) {\n return '''\nHi ${appState.userName}! 🌟\n\nMedicine questions are really important! Here's what you should do:\n\n**For Medicine Safety:**\n- Always ask a trusted adult before taking any medicine\n- Never take medicine by yourself\n- Tell adults about all medicines you take\n- Ask parents or guardians about medicine questions\n\n**Important:** Only doctors, parents, or guardians should decide about your medicines!\n\nRemember: Adults are there to keep you safe and healthy! 💙\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n\n final prompt = _buildMedicationInteractionPrompt(medications, appState);\n final result = await _safeApiCall(\n prompt, 'Error checking medication interactions',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return result + '\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Health insights with comprehensive data analysis\n Future<String> getHealthInsights(\n Map<String, dynamic> healthData, AppState appState) async {\n // If healthData is a string, treat it as a single chat message\n if (healthData is String) {\n final conversationHistory = [\n {'isUser': 'true', 'text': healthData}\n ];\n return sendChatMessage(conversationHistory, appState);\n }\n\n // Check for quick insights first\n if (healthData.isEmpty) {\n return _getDefaultHealthInsights(appState);\n }\n\n final prompt = _buildHealthInsightsPrompt(healthData, appState);\n final result = await _safeApiCall(prompt, 'Error getting health insights',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return result + '\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // NEW: Default health insights based on age\n String _getDefaultHealthInsights(AppState appState) {\n if (appState.isMinor) {\n return '''\n🌟 **Health Tips Just for You, ${appState.userName}!**\n\n**Stay Strong and Healthy:**\n🏃‍♀️ Play and be active every day - it's fun and makes you strong!\n😴 Get lots of sleep (9-11 hours) to help your body grow\n🥕 Eat colorful foods like fruits and vegetables\n💧 Drink water to keep your body happy\n🧠 Always tell trusted adults when you don't feel well\n\n**Remember:**\n- Your parents and guardians are there to help you stay healthy\n- Ask questions! Adults love to help you learn\n- You're doing great by learning about health! \n\n${appState.ageAppropriateDisclaimer}\n ''';\n } else {\n return '''\n🌟 **Personalized Health Insights for ${appState.userName}**\n\n**General Wellness Tips:**\n• Stay hydrated - aim for 8 glasses of water daily\n• Get 7-9 hours of quality sleep\n• Take regular breaks from screen time\n• Practice deep breathing exercises\n\n**Healthy Habits:**\n• Walk for 30 minutes daily\n• Eat colorful fruits and vegetables\n• Maintain regular meal times\n• Stay connected with loved ones\n\n💡 **Tip:** Add your health data to get more personalized insights!\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n }\n\n // ENHANCED: Fallback response with age consideration\n String _getFallbackResponse(String userMessage, AppState appState) {\n final quickResponse = getQuickResponse(userMessage, appState);\n if (quickResponse != null) return quickResponse;\n\n return appState.getAgeAppropriateErrorMessage();\n }\n\n Future<String> _safeApiCall(String prompt, String contextMessage,\n {bool isChat = false, AppState? appState}) async {\n try {\n if (isChat) {\n return await _makeChatApiCall(prompt, appState);\n } else {\n return await _makeApiCallWithRetry(prompt, appState);\n }\n } on TimeoutException catch (e) {\n print(\n '⏳ $contextMessage: Request timed out after ${_timeout.inSeconds}s');\n if (isChat && appState != null) {\n final messages = jsonDecode(prompt) as List<dynamic>;\n final lastUserMessage = messages.lastWhere(\n (m) => m['role'] == 'user',\n orElse: () => {'content': ''},\n )['content'] ??\n '';\n return _getFallbackResponse(lastUserMessage, appState);\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'The request took longer than expected. Please try again.';\n } on SocketException catch (e) {\n print('🌐 Network error: ${e.message}');\n return appState?.getAgeAppropriateErrorMessage() ??\n 'Network connection issue. Please check your internet and try again.';\n } catch (e) {\n print('⚠️ $contextMessage: $e');\n return appState?.getAgeAppropriateErrorMessage() ??\n 'I\\'m experiencing technical difficulties. Please try again in a moment.';\n }\n }\n\n Future<String> _makeChatApiCall(\n String conversationHistoryJson, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive',\n 'Accept': 'application/json',\n };\n\n final List<dynamic> messages = jsonDecode(conversationHistoryJson);\n\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are PersonalMedAI, a helpful medical AI. Keep responses concise and include medical disclaimers.'\n });\n }\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n 'top_p': 0.8,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _buildChatPrompt(\n List<Map<String, dynamic>> conversationHistory, AppState appState) {\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n return jsonEncode(messages);\n }\n\n // RESTORED: Working retry logic with exponential backoff\n Future<String> _makeApiCallWithRetry(\n String prompt, AppState? appState) async {\n int attempts = 0;\n\n while (true) {\n try {\n print('🔄 API attempt ${attempts + 1}/${_maxRetries + 1}');\n return await _makeApiCall(prompt, appState);\n } on TimeoutException catch (e) {\n attempts++;\n if (attempts > _maxRetries) {\n print('⏳ Max retries reached after ${attempts} attempts');\n rethrow;\n }\n\n // Use working retry delays with jitter\n final delayMs = _retryDelays[attempts - 1];\n final jitter =\n (delayMs * 0.1 * (DateTime.now().millisecond % 100) / 100).round();\n final finalDelay = delayMs + jitter;\n\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${finalDelay}ms');\n await Future.delayed(Duration(milliseconds: finalDelay));\n } on SocketException catch (e) {\n attempts++;\n if (attempts > _maxRetries) {\n print('🌐 Network error after ${attempts} attempts: ${e.message}');\n rethrow;\n }\n\n final delayMs = _retryDelays[attempts - 1];\n print('🌐 Network issue, retrying in ${delayMs}ms...');\n await Future.delayed(Duration(milliseconds: delayMs));\n } catch (e) {\n print('❌ Non-retryable error: $e');\n rethrow;\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive', // Important for long requests\n };\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are a medical AI assistant. Provide concise, informative responses. Include medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': appState?.isMinor == true ? 200 : 400, // OPTIMIZED\n 'temperature': 0.4, // SIMPLIFIED\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(\n _timeout,\n onTimeout: () {\n throw TimeoutException(\n 'Request to DeepSeek API exceeded ${_timeout.inSeconds}s timeout',\n _timeout,\n );\n },\n );\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from DeepSeek API');\n }\n } else if (response.statusCode == 429) {\n throw Exception('Rate limit exceeded - DeepSeek API is under heavy load');\n } else if (response.statusCode >= 500) {\n throw Exception('DeepSeek API server error: ${response.statusCode}');\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // OPTIMIZED: Dramatically simplified symptom analysis prompt\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) {\n final buffer = StringBuffer();\n\n if (appState.isMinor) {\n buffer.writeln(\"Help young person (age ${appState.userAge}):\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n buffer.writeln(\n \"Provide: Simple explanation, when to tell adults. Keep brief under 200 words.\");\n } else {\n buffer\n .writeln(\"Analyze for ${appState.userAge}yo ${appState.userGender}:\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}, Severity: $severity\");\n\n // Only include top 3 additional info items to keep prompt short\n if (additionalInfo.isNotEmpty) {\n int count = 0;\n buffer.writeln(\"Info:\");\n for (var entry in additionalInfo.entries) {\n if (entry.value.toString().isNotEmpty && count < 3) {\n buffer.writeln(\"- ${entry.key}: ${entry.value}\");\n count++;\n }\n }\n }\n\n buffer.writeln(\n \"\\nProvide: Causes, when to see doctor, self-care, disclaimer. Under 300 words.\");\n }\n\n return buffer.toString();\n }\n\n // OPTIMIZED: Simplified medication interaction prompt\n String _buildMedicationInteractionPrompt(\n List<String> medications, AppState appState) {\n if (appState.isMinor) {\n return \"Minor asking about medicines. Redirect to trusted adults briefly.\";\n }\n\n return \"\"\"\nAnalyze interactions: ${medications.join(', ')}\nFor ${appState.userAge}yo ${appState.userGender}. \nProvide: 1) Risk level 2) Key effects 3) When to consult doctor 4) Disclaimer\nKeep under 250 words.\n\"\"\";\n }\n\n // OPTIMIZED: Dramatically simplified health insights prompt\n String _buildHealthInsightsPrompt(\n Map<String, dynamic> healthData, AppState appState) {\n if (appState.isMinor) {\n return \"\"\"\nCreate health tips for ${appState.userName} (${appState.userAge}yo):\nFocus on: healthy habits, exercise, sleep, nutrition.\nUse simple, encouraging language. Mention trusted adults. Keep under 200 words.\n\"\"\";\n }\n\n // Extract only top 5 most relevant health data items\n final relevantData = <String, dynamic>{};\n final priorityKeys = [\n 'medications_count',\n 'health_score',\n 'sleep_hours',\n 'recent_symptoms',\n 'activity_level'\n ];\n\n for (final key in priorityKeys) {\n if (healthData.containsKey(key) &&\n healthData[key] != null &&\n healthData[key].toString().isNotEmpty) {\n relevantData[key] = healthData[key];\n }\n if (relevantData.length >= 5) break;\n }\n\n final buffer = StringBuffer();\n buffer.writeln(\n \"Health insights for ${appState.userName} (${appState.userAge}yo, ${appState.userGender}):\");\n\n if (relevantData.isNotEmpty) {\n relevantData.forEach((key, value) {\n buffer.writeln(\"- $key: $value\");\n });\n }\n\n buffer.writeln(\n \"\\nProvide: Assessment, lifestyle tips, improvements, encouragement. Under 350 words with disclaimer.\");\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl\\nTimeout: ${_timeout.inSeconds}s';\n}\n"}, "c82ef520137a7e088d38bac35a099958e466880c": {"t": 1785757949.5105388, "n": 29263, "h": "c7fd1d895f364465", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'dart:io';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\nimport '../utils/app_state.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // OPTIMIZED: Reduced timeout for faster failure detection\n static const Duration _timeout = Duration(seconds: 20);\n static const int _maxRetries = 2;\n static const Duration _connectTimeout = Duration(seconds: 3);\n\n // ENHANCED: Age-appropriate quick responses\n static const Map<String, Map<String, String>> _quickResponses = {\n 'hello': {\n 'minor':\n 'Hi there! 🌟 I\\'m here to help you learn about staying healthy! Remember to always ask a trusted adult if you have health questions!',\n 'adult':\n 'Hello! I\\'m PersonalMedAI, your health assistant. How can I help you today? 😊',\n },\n 'hi': {\n 'minor':\n 'Hi! 👋 I can teach you fun ways to stay healthy! Always talk to your parents or guardians about health stuff too!',\n 'adult':\n 'Hi there! I\\'m here to help with any health questions you might have! 🩺',\n },\n 'help': {\n 'minor':\n 'I can teach you about:\\n• Healthy foods and exercise 🥕\\n• Why sleep is important 😴\\n• When to tell adults you don\\'t feel well\\n• Fun ways to stay strong! 💪\\n\\nBut always ask trusted adults about health questions!',\n 'adult':\n 'I can help you with:\\n• Medical questions and symptoms\\n• Medication information\\n• Health guidance\\n• Emergency information\\n\\nWhat would you like to know?',\n },\n 'emergency': {\n 'minor':\n '🚨 **If there\\'s an emergency:**\\n\\n1. Find a trusted adult RIGHT AWAY\\n2. Call 911 if no adult is around\\n3. Stay calm and ask for help\\n\\nAlways tell adults when you don\\'t feel well!',\n 'adult':\n '🚨 **MEDICAL EMERGENCY?**\\n\\nCall 911 immediately if experiencing:\\n• Difficulty breathing\\n• Chest pain\\n• Severe bleeding\\n• Loss of consciousness',\n },\n 'thanks': {\n 'minor':\n 'You\\'re welcome! 🌟 Keep learning about staying healthy, and remember to always talk to trusted adults about health questions!',\n 'adult':\n 'You\\'re welcome! I\\'m always here to help with your health questions. Take care! 😊',\n },\n 'thank you': {\n 'minor':\n 'You\\'re so welcome! 🌟 Keep asking great questions and always talk to trusted adults about your health!',\n 'adult':\n 'You\\'re very welcome! Feel free to ask if you have more questions. Stay healthy! 💙',\n },\n };\n\n // NEW: Adult content keywords for filtering\n static const List<String> _adultContentKeywords = [\n 'sex',\n 'sexual',\n 'pregnancy',\n 'contraception',\n 'std',\n 'sti',\n 'reproductive',\n 'genital',\n 'abortion',\n 'breast',\n 'period',\n 'menstruation',\n 'testosterone',\n 'viagra',\n 'drug abuse',\n 'alcohol',\n 'addiction',\n 'overdose',\n 'suicide',\n 'self-harm',\n 'depression',\n 'anxiety disorder'\n ];\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n print(\"🌍 Base URL: $_baseUrl\");\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n // ENHANCED: Age-appropriate quick responses with AppState\n String? getQuickResponse(String message, AppState appState) {\n final normalizedMessage = message.toLowerCase().trim();\n\n // Check for adult content if user is a minor\n if (appState.isMinor && _containsAdultContent(normalizedMessage)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n\n // Direct matches with age-appropriate responses\n if (_quickResponses.containsKey(normalizedMessage)) {\n final responses = _quickResponses[normalizedMessage]!;\n return appState.isMinor ? responses['minor'] : responses['adult'];\n }\n\n // Age-appropriate pattern matches\n return _getPatternBasedResponse(normalizedMessage, appState);\n }\n\n // NEW: Check for adult content\n bool _containsAdultContent(String message) {\n final lowerMessage = message.toLowerCase();\n return _adultContentKeywords\n .any((keyword) => lowerMessage.contains(keyword));\n }\n\n // NEW: Minor redirect response\n String _getMinorRedirectResponse(String userName) {\n return '''\nHi ${userName.isNotEmpty ? userName : 'there'}! 🌟\n\nI notice you're asking about something that might be better discussed with a trusted adult like a parent, guardian, or doctor.\n\n**What you can do:**\n- Talk to a parent or guardian about your question \n- Ask a school nurse or counselor\n- Visit a doctor with a trusted adult\n\nRemember: I'm here to help with general health information, but for anything serious or personal, it's always best to talk to a real person who can help you properly! 😊\n\nIs there something else I can help you with today?\n ''';\n }\n\n // ENHANCED: Pattern-based responses with age consideration\n String? _getPatternBasedResponse(String message, AppState appState) {\n if (message.contains('headache')) {\n return appState.isMinor\n ? '🤕 **If your head hurts:**\\n• Tell a trusted adult right away\\n• Rest in a quiet place\\n• Drink some water\\n• Ask an adult about what to do\\n\\n⚠️ Always let adults help you when you don\\'t feel well!'\n : '🩺 **Headache Relief:**\\n• Stay hydrated (drink water)\\n• Rest in a quiet, dark room\\n• Apply cold/warm compress\\n• Consider OTC pain relief\\n\\n⚠️ See a doctor if severe or persistent.';\n }\n\n if (message.contains('fever')) {\n return appState.isMinor\n ? '🌡️ **If you feel hot and sick:**\\n• Tell an adult immediately\\n• Rest and drink water\\n• Let adults check your temperature\\n• Ask for help from grown-ups\\n\\n⚠️ Adults know what to do when you have a fever!'\n : '🌡️ **Fever Management:**\\n• Stay hydrated\\n• Rest and monitor temperature\\n• Light clothing\\n• Seek medical attention if >101.5°F (38.6°C)\\n\\n⚠️ Contact healthcare provider if persistent.';\n }\n\n if (message.contains('medication') && message.contains('safe')) {\n return appState.isMinor\n ? '💊 **About Medicines:**\\n• Only adults should give you medicine\\n• Never take medicine by yourself\\n• Always ask trusted adults first\\n• Tell adults about any medicine questions\\n\\n⚠️ Medicine safety is super important - let adults handle it!'\n : '💊 **Medication Safety:**\\n• Always follow prescribed dosage\\n• Check for drug interactions\\n• Store properly\\n• Don\\'t share medications\\n\\n⚠️ Consult your pharmacist or doctor with questions.';\n }\n\n return null; // No quick response available\n }\n\n // ENHANCED: Age-appropriate system prompts\n String _getAgeAppropriateSystemPrompt(AppState appState) {\n final basePrompt = '''\nYou are PersonalMedAI, a helpful medical information assistant.\nUser Profile: ${appState.userName}, Age: ${appState.userAge}, Gender: ${appState.userGender}\n''';\n\n if (appState.isMinor) {\n return '''\n$basePrompt\n\nCRITICAL AGE RESTRICTIONS FOR MINOR (Under 18):\n- Use simple, age-appropriate language (elementary/middle school level)\n- Always emphasize talking to parents/guardians/trusted adults\n- Avoid detailed medical terminology - use simple words\n- Focus on general wellness, safety, and healthy habits\n- Never suggest self-medication or self-treatment\n- Always recommend adult supervision for any health concerns\n- Use encouraging, non-scary language\n- Include fun, engaging explanations when appropriate\n- Redirect sensitive topics to trusted adults\n- Keep responses short and easy to understand\n\nFORBIDDEN TOPICS: reproductive health, mental health disorders, adult medications, self-diagnosis\n\nRESPONSE STYLE: Friendly, educational, and always directing to trusted adults for real medical decisions.\nALWAYS end responses with reminders to talk to trusted adults.\n ''';\n } else if (appState.isYoungAdult) {\n return '''\n$basePrompt\n\nAGE-APPROPRIATE GUIDANCE FOR YOUNG ADULT (18-24):\n- Use clear, educational language\n- Focus on preventive care and healthy lifestyle\n- Emphasize the importance of establishing healthcare relationships\n- Provide comprehensive information while stressing professional consultation\n- Address common concerns for this age group (mental health, lifestyle, etc.)\n- Encourage taking responsibility for health decisions\n- Provide practical advice for independent living\n\nRESPONSE LENGTH: Up to 400 words\nTONE: Supportive and empowering while maintaining medical disclaimers\n ''';\n } else {\n return '''\n$basePrompt\n\nCOMPREHENSIVE MEDICAL INFORMATION FOR ADULT (25+):\n- Provide detailed, medical-grade information\n- Use appropriate medical terminology with explanations\n- Discuss complex health topics as appropriate\n- Address age-specific health concerns\n- Provide thorough analysis while maintaining professional disclaimers\n- Include detailed self-care instructions where appropriate\n\nRESPONSE LENGTH: Up to 600 words\nTONE: Professional and comprehensive while remaining accessible\n ''';\n }\n }\n\n // ENHANCED: Streaming with age restrictions and AppState\n Stream<String> streamChatResponse(\n List<Map<String, String>> conversationHistory, AppState appState) async* {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final quickResponse =\n getQuickResponse(lastMessage['text'] ?? '', appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 300));\n yield quickResponse;\n return;\n }\n }\n }\n\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Accept': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n };\n\n final messages = _buildMessageHistory(conversationHistory, appState);\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': appState.maxAIResponseLength,\n 'temperature': appState.isMinor ? 0.3 : 0.4, // More consistent for minors\n 'stream': true,\n 'top_p': 0.8,\n });\n\n try {\n final request =\n http.Request('POST', Uri.parse('$_baseUrl/chat/completions'))\n ..headers.addAll(headers)\n ..body = body;\n\n final client = http.Client();\n final streamedResponse = await client.send(request).timeout(_timeout);\n\n if (streamedResponse.statusCode != 200) {\n throw Exception(\n 'API request failed with status: ${streamedResponse.statusCode}');\n }\n\n String accumulatedText = '';\n\n await for (final line in streamedResponse.stream\n .transform(utf8.decoder)\n .transform(const LineSplitter())\n .where((line) => line.trim().isNotEmpty)) {\n if (line.startsWith('data: ')) {\n final data = line.substring(6).trim();\n\n if (data == '[DONE]') {\n break;\n }\n\n try {\n final json = jsonDecode(data);\n final content = json['choices']?[0]?['delta']?['content'];\n\n if (content != null && content.isNotEmpty) {\n accumulatedText += content;\n\n // Filter content for minors\n if (appState.isMinor && _containsAdultContent(accumulatedText)) {\n yield _getMinorRedirectResponse(appState.userName);\n break;\n }\n\n yield accumulatedText;\n }\n } catch (e) {\n continue;\n }\n }\n }\n\n client.close();\n\n // Add age-appropriate disclaimer\n if (accumulatedText.isNotEmpty &&\n !accumulatedText.contains(appState.ageAppropriateDisclaimer)) {\n final finalResponse =\n accumulatedText + '\\n\\n${appState.ageAppropriateDisclaimer}';\n yield finalResponse;\n }\n } catch (e) {\n print('Streaming error: $e');\n try {\n final response = await sendChatMessage(conversationHistory, appState);\n yield response;\n } catch (fallbackError) {\n yield appState.getAgeAppropriateErrorMessage();\n }\n }\n }\n\n // ENHANCED: Chat with age restrictions and AppState\n Future<String> sendChatMessage(\n List<Map<String, dynamic>> conversationHistory, AppState appState) async {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final quickResponse =\n getQuickResponse(lastMessage['text'] ?? '', appState);\n if (quickResponse != null) {\n await Future.delayed(const Duration(milliseconds: 500));\n return quickResponse;\n }\n }\n }\n\n final prompt = _buildChatPrompt(conversationHistory, appState);\n final result = await _safeApiCall(prompt, 'Error in chat conversation',\n isChat: true, appState: appState);\n\n // Add age-appropriate disclaimer if not already present\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return result + '\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // Helper method to build message history for streaming with age restrictions\n List<Map<String, String>> _buildMessageHistory(\n List<Map<String, String>> conversationHistory, AppState appState) {\n final messages = <Map<String, String>>[];\n\n // Add age-appropriate system message\n messages.add({\n 'role': 'system',\n 'content': _getAgeAppropriateSystemPrompt(appState),\n });\n\n // Convert conversation history\n for (final message in conversationHistory) {\n messages.add({\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n });\n }\n\n return messages;\n }\n\n // ENHANCED: Symptom analysis with age restrictions\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) async {\n // Check for adult content in symptoms for minors\n if (appState.isMinor) {\n final symptomsText = symptoms.join(' ').toLowerCase();\n if (_containsAdultContent(symptomsText)) {\n return _getMinorRedirectResponse(appState.userName);\n }\n }\n\n final prompt = _buildSymptomAnalysisPrompt(\n symptoms, severity, additionalInfo, appState);\n final result = await _safeApiCall(prompt, 'Error analyzing symptoms',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return result + '\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Medication interactions with age restrictions\n Future<String> checkMedicationInteractions(\n List<String> medications, AppState appState) async {\n if (appState.isMinor) {\n return '''\nHi ${appState.userName}! 🌟\n\nMedicine questions are really important! Here's what you should do:\n\n**For Medicine Safety:**\n- Always ask a trusted adult before taking any medicine\n- Never take medicine by yourself\n- Tell adults about all medicines you take\n- Ask parents or guardians about medicine questions\n\n**Important:** Only doctors, parents, or guardians should decide about your medicines!\n\nRemember: Adults are there to keep you safe and healthy! 💙\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n\n final prompt = _buildMedicationInteractionPrompt(medications, appState);\n final result = await _safeApiCall(\n prompt, 'Error checking medication interactions',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return result + '\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // ENHANCED: Health insights with comprehensive data analysis\n Future<String> getHealthInsights(\n Map<String, dynamic> healthData, AppState appState) async {\n // If healthData is a string, treat it as a single chat message\n if (healthData is String) {\n final conversationHistory = [\n {'isUser': 'true', 'text': healthData}\n ];\n return sendChatMessage(conversationHistory, appState);\n }\n\n // Check for quick insights first\n if (healthData.isEmpty) {\n return _getDefaultHealthInsights(appState);\n }\n\n final prompt = _buildHealthInsightsPrompt(healthData, appState);\n final result = await _safeApiCall(prompt, 'Error getting health insights',\n appState: appState);\n\n // Add age-appropriate disclaimer\n if (!result.contains(appState.ageAppropriateDisclaimer)) {\n return result + '\\n\\n${appState.ageAppropriateDisclaimer}';\n }\n return result;\n }\n\n // NEW: Default health insights based on age\n String _getDefaultHealthInsights(AppState appState) {\n if (appState.isMinor) {\n return '''\n🌟 **Health Tips Just for You, ${appState.userName}!**\n\n**Stay Strong and Healthy:**\n🏃‍♀️ Play and be active every day - it's fun and makes you strong!\n😴 Get lots of sleep (9-11 hours) to help your body grow\n🥕 Eat colorful foods like fruits and vegetables\n💧 Drink water to keep your body happy\n🧠 Always tell trusted adults when you don't feel well\n\n**Remember:**\n- Your parents and guardians are there to help you stay healthy\n- Ask questions! Adults love to help you learn\n- You're doing great by learning about health! \n\n${appState.ageAppropriateDisclaimer}\n ''';\n } else {\n return '''\n🌟 **Personalized Health Insights for ${appState.userName}**\n\n**General Wellness Tips:**\n• Stay hydrated - aim for 8 glasses of water daily\n• Get 7-9 hours of quality sleep\n• Take regular breaks from screen time\n• Practice deep breathing exercises\n\n**Healthy Habits:**\n• Walk for 30 minutes daily\n• Eat colorful fruits and vegetables\n• Maintain regular meal times\n• Stay connected with loved ones\n\n💡 **Tip:** Add your health data to get more personalized insights!\n\n${appState.ageAppropriateDisclaimer}\n ''';\n }\n }\n\n // ENHANCED: Fallback response with age consideration\n String _getFallbackResponse(String userMessage, AppState appState) {\n final quickResponse = getQuickResponse(userMessage, appState);\n if (quickResponse != null) return quickResponse;\n\n return appState.getAgeAppropriateErrorMessage();\n }\n\n Future<String> _safeApiCall(String prompt, String contextMessage,\n {bool isChat = false, AppState? appState}) async {\n try {\n if (isChat) {\n return await _makeChatApiCall(prompt, appState);\n } else {\n return await _makeApiCallWithRetry(prompt, appState);\n }\n } on TimeoutException {\n print('⏳ $contextMessage: Request timed out - using fallback');\n if (isChat && appState != null) {\n final messages = jsonDecode(prompt) as List<dynamic>;\n final lastUserMessage = messages.lastWhere(\n (m) => m['role'] == 'user',\n orElse: () => {'content': ''},\n )['content'] ??\n '';\n return _getFallbackResponse(lastUserMessage, appState);\n }\n return appState?.getAgeAppropriateErrorMessage() ??\n 'The request took longer than expected. Please try again.';\n } catch (e) {\n print('⚠️ $contextMessage: $e');\n return appState?.getAgeAppropriateErrorMessage() ??\n 'I\\'m experiencing technical difficulties. Please try again in a moment.';\n }\n }\n\n Future<String> _makeChatApiCall(\n String conversationHistoryJson, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive',\n 'Accept': 'application/json',\n };\n\n final List<dynamic> messages = jsonDecode(conversationHistoryJson);\n\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are PersonalMedAI, a helpful medical AI. Keep responses concise and include medical disclaimers.'\n });\n }\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': appState?.maxAIResponseLength ?? 250,\n 'temperature': appState?.isMinor == true ? 0.3 : 0.4,\n 'top_p': 0.8,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _buildChatPrompt(\n List<Map<String, dynamic>> conversationHistory, AppState appState) {\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n return jsonEncode(messages);\n }\n\n Future<String> _makeApiCallWithRetry(\n String prompt, AppState? appState) async {\n int attempts = 0;\n const retryDelays = [300, 800];\n\n while (true) {\n try {\n return await _makeApiCall(prompt, appState);\n } catch (e) {\n attempts++;\n if (attempts > _maxRetries) rethrow;\n\n final delayMs = retryDelays[attempts - 1];\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${delayMs}ms');\n await Future.delayed(Duration(milliseconds: delayMs));\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt, AppState? appState) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n };\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content': appState != null\n ? _getAgeAppropriateSystemPrompt(appState)\n : 'You are a medical AI assistant. Provide concise, informative responses. Include medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': appState?.maxAIResponseLength ?? 250,\n 'temperature': appState?.isMinor == true ? 0.3 : 0.4,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n\n // Filter content for minors\n if (appState?.isMinor == true && _containsAdultContent(content)) {\n return _getMinorRedirectResponse(appState!.userName);\n }\n\n return content;\n } else {\n throw Exception('Invalid response format');\n }\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // ENHANCED: Age-appropriate symptom analysis prompt\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo, AppState appState) {\n final buffer = StringBuffer();\n\n if (appState.isMinor) {\n buffer.writeln(\n \"Help a young person (age ${appState.userAge}) understand these symptoms:\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}\");\n buffer.writeln(\"How bad it feels: $severity\");\n buffer.writeln(\n \"\\nProvide: 1) Simple explanation 2) When to tell adults 3) What adults can do to help\");\n buffer.writeln(\n \"Use simple words and always direct to trusted adults for help.\");\n } else {\n buffer.writeln(\n \"Analyze these symptoms for ${appState.userAge}-year-old ${appState.userGender.toLowerCase()}:\");\n buffer.writeln(\"Symptoms: ${symptoms.join(', ')}\");\n buffer.writeln(\"Severity: $severity\");\n\n if (additionalInfo.isNotEmpty) {\n buffer.writeln(\"Additional info:\");\n additionalInfo.forEach((key, value) {\n if (value.toString().isNotEmpty) {\n buffer.writeln(\"- ${key.replaceAll('_', ' ')}: $value\");\n }\n });\n }\n\n buffer.writeln(\n \"\\nProvide: 1) Possible causes 2) When to see doctor 3) Self-care tips 4) Disclaimer. Keep under ${appState.maxAIResponseLength} words.\");\n }\n\n return buffer.toString();\n }\n\n // ENHANCED: Age-appropriate medication interaction prompt\n String _buildMedicationInteractionPrompt(\n List<String> medications, AppState appState) {\n if (appState.isMinor) {\n return \"A young person is asking about medicine safety. Redirect them to trusted adults and explain why medicine safety is important for young people.\";\n }\n\n return \"Analyze interactions between: ${medications.join(', ')}\\n\\nFor ${appState.userAge}-year-old ${appState.userGender.toLowerCase()}. Provide: 1) Risk level 2) Key effects 3) When to consult doctor 4) Disclaimer. Keep under ${appState.maxAIResponseLength} words.\";\n }\n\n // ENHANCED: Age-appropriate health insights prompt with comprehensive data analysis\n String _buildHealthInsightsPrompt(\n Map<String, dynamic> healthData, AppState appState) {\n final buffer = StringBuffer();\n\n if (appState.isMinor) {\n buffer.writeln(\n \"Create fun, educational health tips for a ${appState.userAge}-year-old named ${appState.userName}:\");\n buffer.writeln(\n \"Focus on: healthy habits, exercise, sleep, eating well, when to tell adults about health\");\n buffer.writeln(\n \"Use simple, encouraging language and always mention talking to trusted adults.\");\n } else {\n buffer.writeln(\n \"Analyze this comprehensive health data for ${appState.userName} (age ${appState.userAge}, ${appState.userGender}):\");\n\n // Process the health data systematically\n final processedData = <String, dynamic>{};\n healthData.forEach((key, value) {\n if (value != null &&\n value.toString().isNotEmpty &&\n value.toString() != 'null') {\n processedData[key] = value;\n }\n });\n\n // Group data by categories for better analysis\n final categories = {\n 'Demographics': ['user_name', 'user_age', 'user_gender', 'age_group'],\n 'Medications': [\n 'medications_count',\n 'medications',\n 'medication_details'\n ],\n 'Health Metrics': [\n 'health_score',\n 'sleep_hours',\n 'recommended_steps',\n 'activity_level'\n ],\n 'Symptoms & History': [\n 'last_symptom_check',\n 'recent_symptoms',\n 'symptom_severity'\n ],\n 'Engagement': ['chat_activity', 'app_usage_days', 'most_asked_topics'],\n };\n\n categories.forEach((category, keys) {\n final categoryData = <String, dynamic>{};\n for (final key in keys) {\n if (processedData.containsKey(key)) {\n categoryData[key] = processedData[key];\n }\n }\n\n if (categoryData.isNotEmpty) {\n buffer.writeln(\"\\n**${category}:**\");\n categoryData.forEach((key, value) {\n buffer.writeln(\"- ${key.replaceAll('_', ' ')}: $value\");\n });\n }\n });\n\n buffer.writeln(\"\"\"\n\nProvide comprehensive personalized health insights:\n1. Profile-based health assessment\n2. Medication analysis (if applicable)\n3. Lifestyle recommendations based on age/gender\n4. Specific improvement suggestions\n5. Motivational encouragement\n6. Risk factors to monitor\n\nKeep response under ${appState.maxAIResponseLength} words and include medical disclaimer.\n\"\"\");\n }\n\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl';\n}\n"}, "e02659b5ec3ae77fcdb2d1e2373cc52cc9cdbb93": {"t": 1785757951.9980533, "n": 16627, "h": "7149866e2b684ce6", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'dart:io';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // OPTIMIZED: Reduced timeout for faster failure detection\n static const Duration _timeout = Duration(seconds: 20);\n static const int _maxRetries = 2;\n static const Duration _connectTimeout = Duration(seconds: 3);\n\n // OPTIMIZED: Quick response cache for common queries\n static const Map<String, String> _quickResponses = {\n 'hello':\n 'Hello! I\\'m PersonalMedAI, your health assistant. How can I help you today? 😊',\n 'hi':\n 'Hi there! I\\'m here to help with any health questions you might have! 🩺',\n 'help':\n 'I can help you with:\\n• Medical questions and symptoms\\n• Medication information\\n• Health guidance\\n• Emergency information\\n\\nWhat would you like to know?',\n 'emergency':\n '🚨 **MEDICAL EMERGENCY?**\\n\\nCall 911 immediately if experiencing:\\n• Difficulty breathing\\n• Chest pain\\n• Severe bleeding\\n• Loss of consciousness',\n 'thanks':\n 'You\\'re welcome! I\\'m always here to help with your health questions. Take care! 😊',\n 'thank you':\n 'You\\'re very welcome! Feel free to ask if you have more questions. Stay healthy! 💙',\n };\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n print(\"🌍 Base URL: $_baseUrl\");\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n // OPTIMIZED: Check for quick responses first\n String? getQuickResponse(String message) {\n final normalizedMessage = message.toLowerCase().trim();\n\n // Direct matches\n if (_quickResponses.containsKey(normalizedMessage)) {\n return _quickResponses[normalizedMessage];\n }\n\n // Partial matches for common patterns\n if (normalizedMessage.contains('headache')) {\n return '🩺 **Headache Relief:**\\n• Stay hydrated (drink water)\\n• Rest in a quiet, dark room\\n• Apply cold/warm compress\\n• Consider OTC pain relief\\n\\n⚠️ See a doctor if severe or persistent.';\n }\n\n if (normalizedMessage.contains('fever')) {\n return '🌡️ **Fever Management:**\\n• Stay hydrated\\n• Rest and monitor temperature\\n• Light clothing\\n• Seek medical attention if >101.5°F (38.6°C)\\n\\n⚠️ Contact healthcare provider if persistent.';\n }\n\n if (normalizedMessage.contains('medication') &&\n normalizedMessage.contains('safe')) {\n return '💊 **Medication Safety:**\\n• Always follow prescribed dosage\\n• Check for drug interactions\\n• Store properly\\n• Don\\'t share medications\\n\\n⚠️ Consult your pharmacist or doctor with questions.';\n }\n\n return null; // No quick response available\n }\n\n // OPTIMIZED: Enhanced streaming with proper error handling\n Stream<String> streamChatResponse(\n List<Map<String, String>> conversationHistory) async* {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final quickResponse = getQuickResponse(lastMessage['text'] ?? '');\n if (quickResponse != null) {\n // Simulate typing delay for quick responses\n await Future.delayed(const Duration(milliseconds: 300));\n yield quickResponse;\n return;\n }\n }\n }\n\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Accept': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n };\n\n final messages = _buildMessageHistory(conversationHistory);\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': 250, // Reduced for faster responses\n 'temperature': 0.4, // Slightly reduced for more focused responses\n 'stream': true,\n 'top_p': 0.8, // Add for faster generation\n });\n\n try {\n final request =\n http.Request('POST', Uri.parse('$_baseUrl/chat/completions'))\n ..headers.addAll(headers)\n ..body = body;\n\n final client = http.Client();\n final streamedResponse = await client.send(request).timeout(_timeout);\n\n if (streamedResponse.statusCode != 200) {\n throw Exception(\n 'API request failed with status: ${streamedResponse.statusCode}');\n }\n\n String accumulatedText = '';\n\n await for (final line in streamedResponse.stream\n .transform(utf8.decoder)\n .transform(const LineSplitter())\n .where((line) => line.trim().isNotEmpty)) {\n if (line.startsWith('data: ')) {\n final data = line.substring(6).trim();\n\n if (data == '[DONE]') {\n break;\n }\n\n try {\n final json = jsonDecode(data);\n final content = json['choices']?[0]?['delta']?['content'];\n\n if (content != null && content.isNotEmpty) {\n accumulatedText += content;\n yield accumulatedText;\n }\n } catch (e) {\n // Skip malformed chunks\n continue;\n }\n }\n }\n\n client.close();\n } catch (e) {\n print('Streaming error: $e');\n // Fallback to regular API call\n try {\n final response = await sendChatMessage(conversationHistory);\n yield response;\n } catch (fallbackError) {\n yield 'I apologize, but I\\'m experiencing technical difficulties. Please try again in a moment.';\n }\n }\n }\n\n // OPTIMIZED: Enhanced regular chat with quick response check\n Future<String> sendChatMessage(\n List<Map<String, dynamic>> conversationHistory) async {\n // Check for quick response first\n if (conversationHistory.isNotEmpty) {\n final lastMessage = conversationHistory.last;\n if (lastMessage['isUser'] == 'true') {\n final quickResponse = getQuickResponse(lastMessage['text'] ?? '');\n if (quickResponse != null) {\n // Simulate a small delay to feel natural\n await Future.delayed(const Duration(milliseconds: 500));\n return quickResponse;\n }\n }\n }\n\n final prompt = _buildChatPrompt(conversationHistory);\n return _safeApiCall(prompt, 'Error in chat conversation', isChat: true);\n }\n\n // Helper method to build message history for streaming\n List<Map<String, String>> _buildMessageHistory(\n List<Map<String, String>> conversationHistory) {\n final messages = <Map<String, String>>[];\n\n // Add system message\n messages.add({\n 'role': 'system',\n 'content':\n '''You are PersonalMedAI, a warm and knowledgeable medical AI assistant.\n\nKey traits:\n- Friendly, empathetic, and supportive\n- Provide clear, concise medical information\n- Keep responses under 200 words\n- Use simple medical terminology\n- Always include appropriate disclaimers\n- Show genuine care for user wellbeing\n\nGuidelines:\n- Recommend healthcare professionals for serious concerns\n- Provide practical health advice\n- Be encouraging and reassuring\n- Use emojis sparingly (🩺 💊 ❤️ ⚠️)\n\nRemember: Inform and support, don't replace professional medical consultation.'''\n });\n\n // Convert conversation history\n for (final message in conversationHistory) {\n messages.add({\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n });\n }\n\n return messages;\n }\n\n // Keep existing methods but optimize them\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo) async {\n final prompt =\n _buildSymptomAnalysisPrompt(symptoms, severity, additionalInfo);\n return _safeApiCall(prompt, 'Error analyzing symptoms');\n }\n\n Future<String> checkMedicationInteractions(List<String> medications) async {\n final prompt = _buildMedicationInteractionPrompt(medications);\n return _safeApiCall(prompt, 'Error checking medication interactions');\n }\n\n // OPTIMIZED: Enhanced fallback responses\n String _getFallbackResponse(String userMessage) {\n final quickResponse = getQuickResponse(userMessage);\n if (quickResponse != null) return quickResponse;\n\n return '🩺 I\\'m here to help with your health questions. Due to high demand, I\\'m experiencing some delays. Please try again in a moment, or contact your healthcare provider for urgent concerns.';\n }\n\n Future<String> _safeApiCall(String prompt, String contextMessage,\n {bool isChat = false}) async {\n try {\n if (isChat) {\n return await _makeChatApiCall(prompt);\n } else {\n return await _makeApiCallWithRetry(prompt);\n }\n } on TimeoutException {\n print('⏳ $contextMessage: Request timed out - using fallback');\n if (isChat) {\n final messages = jsonDecode(prompt) as List<dynamic>;\n final lastUserMessage = messages.lastWhere(\n (m) => m['role'] == 'user',\n orElse: () => {'content': ''},\n )['content'] ??\n '';\n return _getFallbackResponse(lastUserMessage);\n }\n return 'The request took longer than expected. Please try again.';\n } catch (e) {\n print('⚠️ $contextMessage: $e');\n return 'I\\'m experiencing technical difficulties. Please try again in a moment.';\n }\n }\n\n Future<String> _makeChatApiCall(String conversationHistoryJson) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive',\n 'Accept': 'application/json',\n };\n\n final List<dynamic> messages = jsonDecode(conversationHistoryJson);\n\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content':\n 'You are PersonalMedAI, a helpful medical AI. Keep responses concise (under 200 words) and include medical disclaimers.'\n });\n }\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': 250, // Reduced for speed\n 'temperature': 0.4, // Reduced for consistency\n 'top_p': 0.8,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _buildChatPrompt(List<Map<String, dynamic>> conversationHistory) {\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n return jsonEncode(messages);\n }\n\n Future<String> _makeApiCallWithRetry(String prompt) async {\n int attempts = 0;\n const retryDelays = [300, 800]; // Reduced delays\n\n while (true) {\n try {\n return await _makeApiCall(prompt);\n } catch (e) {\n attempts++;\n if (attempts > _maxRetries) rethrow;\n\n final delayMs = retryDelays[attempts - 1];\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${delayMs}ms');\n await Future.delayed(Duration(milliseconds: delayMs));\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n };\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content':\n 'You are a medical AI assistant. Provide concise, informative responses. Keep under 200 words and include medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': 250,\n 'temperature': 0.4,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content =\n choices[0]['message']['content']?.trim() ?? 'No response received.';\n content = _removeWordCountAnnotations(content);\n return content;\n } else {\n throw Exception('Invalid response format');\n }\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // Existing prompt methods with optimizations\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo) {\n final buffer = StringBuffer()\n ..writeln(\"Analyze these symptoms concisely:\")\n ..writeln(\"Symptoms: ${symptoms.join(', ')}\")\n ..writeln(\"Severity: $severity\");\n\n if (additionalInfo.isNotEmpty) {\n buffer.writeln(\"Additional info:\");\n additionalInfo.forEach((key, value) {\n if (value.toString().isNotEmpty) {\n buffer.writeln(\"- ${key.replaceAll('_', ' ')}: $value\");\n }\n });\n }\n\n buffer.writeln(\n \"\\nProvide: 1) Possible causes 2) When to see doctor 3) Self-care tips 4) Disclaimer. Keep under 200 words.\");\n return buffer.toString();\n }\n\n String _buildMedicationInteractionPrompt(List<String> medications) {\n return \"Analyze interactions between: ${medications.join(', ')}\\n\\nProvide: 1) Risk level 2) Key effects 3) When to consult doctor 4) Disclaimer. Keep under 150 words.\";\n }\n\n// Add this method to your DeepSeekService class\n Future<String> getHealthInsights(Map<String, dynamic> healthData) async {\n // If healthData is a string, treat it as a single chat message\n if (healthData is String) {\n final conversationHistory = [\n {'isUser': 'true', 'text': healthData}\n ];\n return sendChatMessage(conversationHistory);\n }\n\n // Check for quick insights first\n if (healthData.isEmpty) {\n return '''🌟 **Personalized Health Insights**\n\n**General Wellness Tips:**\n• Stay hydrated - aim for 8 glasses of water daily\n• Get 7-9 hours of quality sleep\n• Take regular breaks from screen time\n• Practice deep breathing exercises\n\n**Healthy Habits:**\n• Walk for 30 minutes daily\n• Eat colorful fruits and vegetables\n• Maintain regular meal times\n• Stay connected with loved ones\n\n💡 **Tip:** Add your health data to get more personalized insights!\n\n⚠️ *These are general wellness suggestions. Consult healthcare providers for personalized medical advice.*''';\n }\n\n // Generate insights from health data\n final prompt = _buildHealthInsightsPrompt(healthData);\n return _safeApiCall(prompt, 'Error getting health insights');\n }\n\n// Also add this helper method if it's missing\n String _buildHealthInsightsPrompt(Map<String, dynamic> healthData) {\n final buffer = StringBuffer()..writeln(\"Analyze this health data:\");\n\n healthData.forEach((key, value) {\n if (value != null && value.toString().isNotEmpty) {\n buffer.writeln(\"- ${key.replaceAll('_', ' ')}: $value\");\n }\n });\n\n buffer.writeln(\"\"\"\nProvide personalized health insights:\n1. Key observations from the data\n2. Improvement suggestions\n3. Lifestyle recommendations\n4. Encouragement and motivation\n\nKeep response under 200 words and include medical disclaimer.\n\"\"\");\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl';\n}\n"}, "6ca04048d56ba9af855403ddffeb4fc0bd40d778": {"t": 1785757953.7577791, "n": 14536, "h": "2b93f089a76b920a", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'dart:io';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // OPTIMIZED: Reduced timeout from 30s to 15s for faster failure detection\n static const Duration _timeout = Duration(seconds: 30);\n\n // OPTIMIZED: Increased retries from 2 to 3 for better success rate\n static const int _maxRetries = 2;\n\n // Add connection-specific timeouts\n static const Duration _connectTimeout = Duration(seconds: 5);\n static const Duration _receiveTimeout = Duration(seconds: 25);\n\n // OPTIMIZED: Exponential backoff delays\n static const List<int> _retryDelays = [500, 1500]; // Reduced delays\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n print(\"🌍 Base URL: $_baseUrl\");\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo) async {\n final prompt =\n _buildSymptomAnalysisPrompt(symptoms, severity, additionalInfo);\n return _safeApiCall(prompt, 'Error analyzing symptoms');\n }\n\n Future<String> checkMedicationInteractions(List<String> medications) async {\n final prompt = _buildMedicationInteractionPrompt(medications);\n return _safeApiCall(prompt, 'Error checking medication interactions');\n }\n\n // Add this new method for chat conversations\n Future<String> sendChatMessage(\n List<Map<String, String>> conversationHistory) async {\n final prompt = _buildChatPrompt(conversationHistory);\n return _safeApiCall(prompt, 'Error in chat conversation', isChat: true);\n }\n\n String _getFallbackResponse(String userMessage) {\n final message = userMessage.toLowerCase();\n\n if (message.contains('headache')) {\n return '🩺 For headaches, try:\\n• Stay hydrated\\n• Rest in a quiet, dark room\\n• Apply cold/warm compress\\n• Consider over-the-counter pain relief\\n\\nConsult a doctor if severe or persistent.';\n }\n\n if (message.contains('fever')) {\n return '🌡️ For fever:\\n• Stay hydrated\\n• Rest\\n• Monitor temperature\\n• Light clothing\\n• Seek medical attention if >101.5°F (38.6°C) or persistent.';\n }\n\n return '🩺 I\\'m here to help with your health questions. For specific symptoms, I recommend consulting with a healthcare professional for proper evaluation and treatment.';\n }\n\n// Update the _safeApiCall method to handle chat context\n Future<String> _safeApiCall(String prompt, String contextMessage,\n {bool isChat = false}) async {\n try {\n if (isChat) {\n return await _makeChatApiCall(prompt);\n } else {\n return await _makeApiCallWithRetry(prompt);\n }\n } on TimeoutException {\n print('⏳ $contextMessage: Request timed out - using fallback');\n if (isChat) {\n final messages = jsonDecode(prompt) as List<dynamic>;\n final lastUserMessage = messages.lastWhere(\n (m) => m['role'] == 'user',\n orElse: () => {'content': ''},\n )['content'] ??\n '';\n return _getFallbackResponse(lastUserMessage);\n }\n return 'The request took too long. Please try again with a shorter question.';\n } catch (e) {\n print('⚠️ $contextMessage: $e');\n return 'Unable to complete this request right now. Please try again later.';\n }\n }\n\n// Add new method for chat API calls with conversation history\n // Update your _makeChatApiCall method with enhanced system message\n Future<String> _makeChatApiCall(String conversationHistoryJson) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Connection': 'keep-alive', // Reuse connections\n 'Accept': 'application/json',\n };\n\n // Parse the conversation history from JSON\n final List<dynamic> messages = jsonDecode(conversationHistoryJson);\n\n // Add enhanced system message at the beginning if not present\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content':\n '''You are PersonalMedAI, a warm, empathetic, and knowledgeable medical AI assistant. You have a caring personality and always strive to provide helpful, accurate health information.\n\nYour key characteristics:\n- Friendly and approachable tone\n- Empathetic and supportive responses \n- Professional medical knowledge\n- Always prioritize user safety\n- Encourage consulting healthcare professionals when needed\n\nGuidelines for responses:\n- Greet users warmly by name when possible\n- Provide clear, concise medical information\n- Use reassuring language while being honest about limitations\n- Include appropriate disclaimers about seeking professional medical care\n- Ask follow-up questions when helpful\n- Show genuine care for the user's wellbeing\n- Keep responses focused and under 300 words\n- Use emojis sparingly but appropriately (like 🩺 💊 ❤️)\n\nRemember: You are here to inform and support, not to replace professional medical consultation. Always recommend seeing a healthcare provider for serious concerns, diagnosis, or treatment decisions. and also Complete all recommendations and always finish with proper medical disclaimers.'''\n });\n }\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': 300,\n 'temperature': 0.3,\n 'top_p': 0.7, // Add top_p for faster generation\n\n 'stream': false,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content = choices[0]['message']['content']?.trim() ??\n 'No response received from AI service.';\n content = _removeWordCountAnnotations(content);\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n// Add helper method to build chat prompt from conversation history\n String _buildChatPrompt(List<Map<String, String>> conversationHistory) {\n // Convert conversation history to the format expected by the API\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n return jsonEncode(messages);\n }\n\n// Update the getHealthInsights method to handle both single queries and chat format\n Future<String> getHealthInsights(dynamic healthData) async {\n // If healthData is a string, treat it as a single chat message\n if (healthData is String) {\n final conversationHistory = [\n {'isUser': 'true', 'text': healthData}\n ];\n return sendChatMessage(conversationHistory);\n }\n\n // Otherwise, use the existing health insights logic\n if (healthData is Map<String, dynamic>) {\n final prompt = _buildHealthInsightsPrompt(healthData);\n return _safeApiCall(prompt, 'Error getting health insights');\n }\n\n throw ArgumentError('Invalid healthData format');\n }\n\n Future<String> _makeApiCallWithRetry(String prompt) async {\n int attempts = 0;\n\n while (true) {\n try {\n return await _makeApiCall(prompt);\n } catch (e) {\n attempts++;\n if (attempts > _maxRetries) rethrow;\n\n // OPTIMIZED: Exponential backoff with jitter\n final delayMs = _retryDelays[attempts - 1];\n final jitter =\n (delayMs * 0.1 * (DateTime.now().millisecond % 100) / 100).round();\n final finalDelay = delayMs + jitter;\n\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${finalDelay}ms');\n await Future.delayed(Duration(milliseconds: finalDelay));\n }\n }\n }\n\n // Add this method for streaming responses\n // Add this method for streaming responses\n Future<Stream<String>> getChatResponseStream(\n List<Map<String, String>> conversationHistory) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n 'Accept': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n };\n\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n // Add system message\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content':\n 'You are PersonalMedAI. Keep responses concise and under 150 words.'\n });\n }\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': 200,\n 'temperature': 0.3,\n 'stream': true, // Enable streaming\n });\n\n final request =\n http.Request('POST', Uri.parse('$_baseUrl/chat/completions'))\n ..headers.addAll(headers)\n ..body = body;\n\n final client = http.Client();\n\n try {\n final streamedResponse = await client.send(request).timeout(_timeout);\n\n // Return the stream properly wrapped\n final stream = streamedResponse.stream\n .transform(utf8.decoder)\n .transform(const LineSplitter())\n .where(\n (line) => line.startsWith('data: ') && !line.contains('[DONE]'))\n .map<String>((line) {\n // Explicitly cast to String\n final data = line.substring(6);\n try {\n final json = jsonDecode(data);\n final content = json['choices']?[0]?['delta']?['content'];\n return content?.toString() ?? '';\n } catch (e) {\n return '';\n }\n }).where((content) => content.isNotEmpty);\n\n return stream;\n } catch (e) {\n client.close();\n throw Exception('Streaming request failed: $e');\n }\n }\n\n Future<String> _makeApiCall(String prompt) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n };\n\n // OPTIMIZED: Reduced max_tokens from 800 to 400 for faster responses\n // OPTIMIZED: Reduced temperature from 0.7 to 0.5 for more focused responses\n // OPTIMIZED: Added stream: true for faster perceived response times\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content':\n 'You are a helpful medical AI assistant. Provide concise, informative responses about health topics. Always recommend consulting healthcare professionals for serious concerns. Keep responses brief and focused. Include appropriate medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': 400, // REDUCED from 800\n 'temperature': 0.5, // REDUCED from 0.7\n 'stream': false, // Keep false for now, but consider streaming for UI\n });\n\n // OPTIMIZED: Separate connect and read timeouts\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content = choices[0]['message']['content']?.trim() ??\n 'No response received from AI service.';\n content = _removeWordCountAnnotations(content);\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n // Remove patterns like \"(Word count: 98)\" or \"*Word count: 98*\"\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // OPTIMIZED: Shortened and more focused prompts to reduce processing time\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo) {\n final buffer = StringBuffer()\n ..writeln(\"Analyze these symptoms briefly:\")\n ..writeln(\"Symptoms: ${symptoms.join(', ')}\")\n ..writeln(\"Severity: $severity\");\n\n if (additionalInfo.isNotEmpty) {\n buffer.writeln(\"Additional info:\");\n additionalInfo.forEach((key, value) {\n if (value.toString().isNotEmpty) {\n buffer.writeln(\"- ${key.replaceAll('_', ' ')}: $value\");\n }\n });\n }\n\n buffer.writeln(\"\"\"\nProvide concise analysis:\n1. Possible causes (2-3 main ones)\n2. When to seek medical attention\n3. Basic self-care suggestions\n4. Medical disclaimer\n\nKeep response under 300 words.\n\"\"\");\n return buffer.toString();\n }\n\n String _buildMedicationInteractionPrompt(List<String> medications) {\n return \"\"\"\nAnalyze interactions between: ${medications.join(', ')}\n\nProvide brief summary:\n1. Interaction level (Minor/Moderate/Major)\n2. Key effects to watch for\n3. When to consult healthcare provider\n4. Medical disclaimer\n\nKeep response under 250 words.\n\"\"\";\n }\n\n String _buildHealthInsightsPrompt(Map<String, dynamic> healthData) {\n final buffer = StringBuffer()..writeln(\"Health metrics:\");\n\n healthData.forEach((key, value) {\n buffer.writeln(\"- ${key.replaceAll('_', ' ')}: $value\");\n });\n\n buffer.writeln(\"\"\"\nProvide brief insights:\n1. Key observations\n2. Improvement suggestions\n3. General lifestyle tips\n4. Encouragement\n\nKeep response under 200 words.\n\"\"\");\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl';\n}\n"}, "14ec23683447dec377c1f6db28a497cf3ba5b4a7": {"t": 1785757955.1127977, "n": 10908, "h": "d9bb76e79031c17b", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // OPTIMIZED: Reduced timeout from 30s to 15s for faster failure detection\n static const Duration _timeout = Duration(seconds: 15);\n\n // OPTIMIZED: Increased retries from 2 to 3 for better success rate\n static const int _maxRetries = 3;\n\n // OPTIMIZED: Exponential backoff delays\n static const List<int> _retryDelays = [1000, 2000, 4000]; // ms\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n print(\"🌍 Base URL: $_baseUrl\");\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo) async {\n final prompt =\n _buildSymptomAnalysisPrompt(symptoms, severity, additionalInfo);\n return _safeApiCall(prompt, 'Error analyzing symptoms');\n }\n\n Future<String> checkMedicationInteractions(List<String> medications) async {\n final prompt = _buildMedicationInteractionPrompt(medications);\n return _safeApiCall(prompt, 'Error checking medication interactions');\n }\n\n // Add this new method for chat conversations\n Future<String> sendChatMessage(\n List<Map<String, String>> conversationHistory) async {\n final prompt = _buildChatPrompt(conversationHistory);\n return _safeApiCall(prompt, 'Error in chat conversation', isChat: true);\n }\n\n// Update the _safeApiCall method to handle chat context\n Future<String> _safeApiCall(String prompt, String contextMessage,\n {bool isChat = false}) async {\n try {\n if (isChat) {\n return await _makeChatApiCall(prompt);\n } else {\n return await _makeApiCallWithRetry(prompt);\n }\n } on TimeoutException {\n print('⏳ $contextMessage: Request timed out.');\n return 'The request took too long. Please try again later.';\n } catch (e) {\n print('⚠️ $contextMessage: $e');\n return 'Unable to complete this request right now. Please try again later.';\n }\n }\n\n// Add new method for chat API calls with conversation history\n // Update your _makeChatApiCall method with enhanced system message\n Future<String> _makeChatApiCall(String conversationHistoryJson) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n };\n\n // Parse the conversation history from JSON\n final List<dynamic> messages = jsonDecode(conversationHistoryJson);\n\n // Add enhanced system message at the beginning if not present\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content':\n '''You are PersonalMedAI, a warm, empathetic, and knowledgeable medical AI assistant. You have a caring personality and always strive to provide helpful, accurate health information.\n\nYour key characteristics:\n- Friendly and approachable tone\n- Empathetic and supportive responses \n- Professional medical knowledge\n- Always prioritize user safety\n- Encourage consulting healthcare professionals when needed\n\nGuidelines for responses:\n- Greet users warmly by name when possible\n- Provide clear, concise medical information\n- Use reassuring language while being honest about limitations\n- Include appropriate disclaimers about seeking professional medical care\n- Ask follow-up questions when helpful\n- Show genuine care for the user's wellbeing\n- Keep responses focused and under 300 words\n- Use emojis sparingly but appropriately (like 🩺 💊 ❤️)\n\nRemember: You are here to inform and support, not to replace professional medical consultation. Always recommend seeing a healthcare provider for serious concerns, diagnosis, or treatment decisions.'''\n });\n }\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': 400,\n 'temperature': 0.5,\n 'stream': false,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content = choices[0]['message']['content']?.trim() ??\n 'No response received from AI service.';\n content = _removeWordCountAnnotations(content);\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n// Add helper method to build chat prompt from conversation history\n String _buildChatPrompt(List<Map<String, String>> conversationHistory) {\n // Convert conversation history to the format expected by the API\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n return jsonEncode(messages);\n }\n\n// Update the getHealthInsights method to handle both single queries and chat format\n Future<String> getHealthInsights(dynamic healthData) async {\n // If healthData is a string, treat it as a single chat message\n if (healthData is String) {\n final conversationHistory = [\n {'isUser': 'true', 'text': healthData}\n ];\n return sendChatMessage(conversationHistory);\n }\n\n // Otherwise, use the existing health insights logic\n if (healthData is Map<String, dynamic>) {\n final prompt = _buildHealthInsightsPrompt(healthData);\n return _safeApiCall(prompt, 'Error getting health insights');\n }\n\n throw ArgumentError('Invalid healthData format');\n }\n\n Future<String> _makeApiCallWithRetry(String prompt) async {\n int attempts = 0;\n\n while (true) {\n try {\n return await _makeApiCall(prompt);\n } catch (e) {\n attempts++;\n if (attempts > _maxRetries) rethrow;\n\n // OPTIMIZED: Exponential backoff with jitter\n final delayMs = _retryDelays[attempts - 1];\n final jitter =\n (delayMs * 0.1 * (DateTime.now().millisecond % 100) / 100).round();\n final finalDelay = delayMs + jitter;\n\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${finalDelay}ms');\n await Future.delayed(Duration(milliseconds: finalDelay));\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n };\n\n // OPTIMIZED: Reduced max_tokens from 800 to 400 for faster responses\n // OPTIMIZED: Reduced temperature from 0.7 to 0.5 for more focused responses\n // OPTIMIZED: Added stream: true for faster perceived response times\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content':\n 'You are a helpful medical AI assistant. Provide concise, informative responses about health topics. Always recommend consulting healthcare professionals for serious concerns. Keep responses brief and focused. Include appropriate medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': 400, // REDUCED from 800\n 'temperature': 0.5, // REDUCED from 0.7\n 'stream': false, // Keep false for now, but consider streaming for UI\n });\n\n // OPTIMIZED: Separate connect and read timeouts\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content = choices[0]['message']['content']?.trim() ??\n 'No response received from AI service.';\n content = _removeWordCountAnnotations(content);\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n // Remove patterns like \"(Word count: 98)\" or \"*Word count: 98*\"\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // OPTIMIZED: Shortened and more focused prompts to reduce processing time\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo) {\n final buffer = StringBuffer()\n ..writeln(\"Analyze these symptoms briefly:\")\n ..writeln(\"Symptoms: ${symptoms.join(', ')}\")\n ..writeln(\"Severity: $severity\");\n\n if (additionalInfo.isNotEmpty) {\n buffer.writeln(\"Additional info:\");\n additionalInfo.forEach((key, value) {\n if (value.toString().isNotEmpty) {\n buffer.writeln(\"- ${key.replaceAll('_', ' ')}: $value\");\n }\n });\n }\n\n buffer.writeln(\"\"\"\nProvide concise analysis:\n1. Possible causes (2-3 main ones)\n2. When to seek medical attention\n3. Basic self-care suggestions\n4. Medical disclaimer\n\nKeep response under 300 words.\n\"\"\");\n return buffer.toString();\n }\n\n String _buildMedicationInteractionPrompt(List<String> medications) {\n return \"\"\"\nAnalyze interactions between: ${medications.join(', ')}\n\nProvide brief summary:\n1. Interaction level (Minor/Moderate/Major)\n2. Key effects to watch for\n3. When to consult healthcare provider\n4. Medical disclaimer\n\nKeep response under 250 words.\n\"\"\";\n }\n\n String _buildHealthInsightsPrompt(Map<String, dynamic> healthData) {\n final buffer = StringBuffer()..writeln(\"Health metrics:\");\n\n healthData.forEach((key, value) {\n buffer.writeln(\"- ${key.replaceAll('_', ' ')}: $value\");\n });\n\n buffer.writeln(\"\"\"\nProvide brief insights:\n1. Key observations\n2. Improvement suggestions\n3. General lifestyle tips\n4. Encouragement\n\nKeep response under 200 words.\n\"\"\");\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl';\n}\n"}, "b0bbb4454e5558d36c8f21765a3255383d85efc5": {"t": 1785757956.7757237, "n": 10034, "h": "8ffd3e84f1a65a7b", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // OPTIMIZED: Reduced timeout from 30s to 15s for faster failure detection\n static const Duration _timeout = Duration(seconds: 15);\n\n // OPTIMIZED: Increased retries from 2 to 3 for better success rate\n static const int _maxRetries = 3;\n\n // OPTIMIZED: Exponential backoff delays\n static const List<int> _retryDelays = [1000, 2000, 4000]; // ms\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n print(\"🌍 Base URL: $_baseUrl\");\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo) async {\n final prompt =\n _buildSymptomAnalysisPrompt(symptoms, severity, additionalInfo);\n return _safeApiCall(prompt, 'Error analyzing symptoms');\n }\n\n Future<String> checkMedicationInteractions(List<String> medications) async {\n final prompt = _buildMedicationInteractionPrompt(medications);\n return _safeApiCall(prompt, 'Error checking medication interactions');\n }\n\n // Add this new method for chat conversations\n Future<String> sendChatMessage(\n List<Map<String, String>> conversationHistory) async {\n final prompt = _buildChatPrompt(conversationHistory);\n return _safeApiCall(prompt, 'Error in chat conversation', isChat: true);\n }\n\n// Update the _safeApiCall method to handle chat context\n Future<String> _safeApiCall(String prompt, String contextMessage,\n {bool isChat = false}) async {\n try {\n if (isChat) {\n return await _makeChatApiCall(prompt);\n } else {\n return await _makeApiCallWithRetry(prompt);\n }\n } on TimeoutException {\n print('⏳ $contextMessage: Request timed out.');\n return 'The request took too long. Please try again later.';\n } catch (e) {\n print('⚠️ $contextMessage: $e');\n return 'Unable to complete this request right now. Please try again later.';\n }\n }\n\n// Add new method for chat API calls with conversation history\n Future<String> _makeChatApiCall(String conversationHistoryJson) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n };\n\n // Parse the conversation history from JSON\n final List<dynamic> messages = jsonDecode(conversationHistoryJson);\n\n // Add system message at the beginning if not present\n if (messages.isEmpty || messages.first['role'] != 'system') {\n messages.insert(0, {\n 'role': 'system',\n 'content':\n 'You are a helpful medical AI assistant. Provide concise, informative responses about health topics. Always recommend consulting healthcare professionals for serious concerns. Keep responses brief and focused. Include appropriate medical disclaimers.'\n });\n }\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': messages,\n 'max_tokens': 400,\n 'temperature': 0.5,\n 'stream': false,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content = choices[0]['message']['content']?.trim() ??\n 'No response received from AI service.';\n content = _removeWordCountAnnotations(content);\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n// Add helper method to build chat prompt from conversation history\n String _buildChatPrompt(List<Map<String, String>> conversationHistory) {\n // Convert conversation history to the format expected by the API\n final messages = conversationHistory\n .map((message) => {\n 'role': message['isUser'] == 'true' ? 'user' : 'assistant',\n 'content': message['text'] ?? '',\n })\n .toList();\n\n return jsonEncode(messages);\n }\n\n// Update the getHealthInsights method to handle both single queries and chat format\n Future<String> getHealthInsights(dynamic healthData) async {\n // If healthData is a string, treat it as a single chat message\n if (healthData is String) {\n final conversationHistory = [\n {'isUser': 'true', 'text': healthData}\n ];\n return sendChatMessage(conversationHistory);\n }\n\n // Otherwise, use the existing health insights logic\n if (healthData is Map<String, dynamic>) {\n final prompt = _buildHealthInsightsPrompt(healthData);\n return _safeApiCall(prompt, 'Error getting health insights');\n }\n\n throw ArgumentError('Invalid healthData format');\n }\n\n Future<String> _makeApiCallWithRetry(String prompt) async {\n int attempts = 0;\n\n while (true) {\n try {\n return await _makeApiCall(prompt);\n } catch (e) {\n attempts++;\n if (attempts > _maxRetries) rethrow;\n\n // OPTIMIZED: Exponential backoff with jitter\n final delayMs = _retryDelays[attempts - 1];\n final jitter =\n (delayMs * 0.1 * (DateTime.now().millisecond % 100) / 100).round();\n final finalDelay = delayMs + jitter;\n\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${finalDelay}ms');\n await Future.delayed(Duration(milliseconds: finalDelay));\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n };\n\n // OPTIMIZED: Reduced max_tokens from 800 to 400 for faster responses\n // OPTIMIZED: Reduced temperature from 0.7 to 0.5 for more focused responses\n // OPTIMIZED: Added stream: true for faster perceived response times\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content':\n 'You are a helpful medical AI assistant. Provide concise, informative responses about health topics. Always recommend consulting healthcare professionals for serious concerns. Keep responses brief and focused. Include appropriate medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': 400, // REDUCED from 800\n 'temperature': 0.5, // REDUCED from 0.7\n 'stream': false, // Keep false for now, but consider streaming for UI\n });\n\n // OPTIMIZED: Separate connect and read timeouts\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content = choices[0]['message']['content']?.trim() ??\n 'No response received from AI service.';\n content = _removeWordCountAnnotations(content);\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n // Remove patterns like \"(Word count: 98)\" or \"*Word count: 98*\"\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // OPTIMIZED: Shortened and more focused prompts to reduce processing time\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo) {\n final buffer = StringBuffer()\n ..writeln(\"Analyze these symptoms briefly:\")\n ..writeln(\"Symptoms: ${symptoms.join(', ')}\")\n ..writeln(\"Severity: $severity\");\n\n if (additionalInfo.isNotEmpty) {\n buffer.writeln(\"Additional info:\");\n additionalInfo.forEach((key, value) {\n if (value.toString().isNotEmpty) {\n buffer.writeln(\"- ${key.replaceAll('_', ' ')}: $value\");\n }\n });\n }\n\n buffer.writeln(\"\"\"\nProvide concise analysis:\n1. Possible causes (2-3 main ones)\n2. When to seek medical attention\n3. Basic self-care suggestions\n4. Medical disclaimer\n\nKeep response under 300 words.\n\"\"\");\n return buffer.toString();\n }\n\n String _buildMedicationInteractionPrompt(List<String> medications) {\n return \"\"\"\nAnalyze interactions between: ${medications.join(', ')}\n\nProvide brief summary:\n1. Interaction level (Minor/Moderate/Major)\n2. Key effects to watch for\n3. When to consult healthcare provider\n4. Medical disclaimer\n\nKeep response under 250 words.\n\"\"\";\n }\n\n String _buildHealthInsightsPrompt(Map<String, dynamic> healthData) {\n final buffer = StringBuffer()..writeln(\"Health metrics:\");\n\n healthData.forEach((key, value) {\n buffer.writeln(\"- ${key.replaceAll('_', ' ')}: $value\");\n });\n\n buffer.writeln(\"\"\"\nProvide brief insights:\n1. Key observations\n2. Improvement suggestions\n3. General lifestyle tips\n4. Encouragement\n\nKeep response under 200 words.\n\"\"\");\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl';\n}\n"}, "6566845f7f0852a86c1334c463d3aaf0b4a54684": {"t": 1785757958.2584589, "n": 6861, "h": "ff5e42be41dc6f6d", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n // OPTIMIZED: Reduced timeout from 30s to 15s for faster failure detection\n static const Duration _timeout = Duration(seconds: 15);\n\n // OPTIMIZED: Increased retries from 2 to 3 for better success rate\n static const int _maxRetries = 3;\n\n // OPTIMIZED: Exponential backoff delays\n static const List<int> _retryDelays = [1000, 2000, 4000]; // ms\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n print(\"🌍 Base URL: $_baseUrl\");\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo) async {\n final prompt =\n _buildSymptomAnalysisPrompt(symptoms, severity, additionalInfo);\n return _safeApiCall(prompt, 'Error analyzing symptoms');\n }\n\n Future<String> checkMedicationInteractions(List<String> medications) async {\n final prompt = _buildMedicationInteractionPrompt(medications);\n return _safeApiCall(prompt, 'Error checking medication interactions');\n }\n\n Future<String> getHealthInsights(Map<String, dynamic> healthData) async {\n final prompt = _buildHealthInsightsPrompt(healthData);\n return _safeApiCall(prompt, 'Error getting health insights');\n }\n\n Future<String> _safeApiCall(String prompt, String contextMessage) async {\n try {\n return await _makeApiCallWithRetry(prompt);\n } on TimeoutException {\n print('⏳ $contextMessage: Request timed out.');\n return 'The request took too long. Please try again later.';\n } catch (e) {\n print('⚠️ $contextMessage: $e');\n return 'Unable to complete this request right now. Please try again later.';\n }\n }\n\n Future<String> _makeApiCallWithRetry(String prompt) async {\n int attempts = 0;\n\n while (true) {\n try {\n return await _makeApiCall(prompt);\n } catch (e) {\n attempts++;\n if (attempts > _maxRetries) rethrow;\n\n // OPTIMIZED: Exponential backoff with jitter\n final delayMs = _retryDelays[attempts - 1];\n final jitter =\n (delayMs * 0.1 * (DateTime.now().millisecond % 100) / 100).round();\n final finalDelay = delayMs + jitter;\n\n print(\n '🔄 Retrying API call... (Attempt $attempts/$_maxRetries) - waiting ${finalDelay}ms');\n await Future.delayed(Duration(milliseconds: finalDelay));\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n };\n\n // OPTIMIZED: Reduced max_tokens from 800 to 400 for faster responses\n // OPTIMIZED: Reduced temperature from 0.7 to 0.5 for more focused responses\n // OPTIMIZED: Added stream: true for faster perceived response times\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content':\n 'You are a helpful medical AI assistant. Provide concise, informative responses about health topics. Always recommend consulting healthcare professionals for serious concerns. Keep responses brief and focused. Include appropriate medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': 400, // REDUCED from 800\n 'temperature': 0.5, // REDUCED from 0.7\n 'stream': false, // Keep false for now, but consider streaming for UI\n });\n\n // OPTIMIZED: Separate connect and read timeouts\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n String content = choices[0]['message']['content']?.trim() ??\n 'No response received from AI service.';\n content = _removeWordCountAnnotations(content);\n return content;\n } else {\n throw Exception('Invalid response format from API');\n }\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _removeWordCountAnnotations(String text) {\n // Remove patterns like \"(Word count: 98)\" or \"*Word count: 98*\"\n return text\n .replaceAll(RegExp(r'\\*?\\(Word count: \\d+\\)\\*?'), '')\n .replaceAll(RegExp(r'\\*Word count: \\d+\\*'), '')\n .replaceAll(RegExp(r'\\(Word count: \\d+\\)'), '')\n .replaceAll(RegExp(r'Word count: \\d+'), '')\n .trim();\n }\n\n // OPTIMIZED: Shortened and more focused prompts to reduce processing time\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo) {\n final buffer = StringBuffer()\n ..writeln(\"Analyze these symptoms briefly:\")\n ..writeln(\"Symptoms: ${symptoms.join(', ')}\")\n ..writeln(\"Severity: $severity\");\n\n if (additionalInfo.isNotEmpty) {\n buffer.writeln(\"Additional info:\");\n additionalInfo.forEach((key, value) {\n if (value.toString().isNotEmpty) {\n buffer.writeln(\"- ${key.replaceAll('_', ' ')}: $value\");\n }\n });\n }\n\n buffer.writeln(\"\"\"\nProvide concise analysis:\n1. Possible causes (2-3 main ones)\n2. When to seek medical attention\n3. Basic self-care suggestions\n4. Medical disclaimer\n\nKeep response under 300 words.\n\"\"\");\n return buffer.toString();\n }\n\n String _buildMedicationInteractionPrompt(List<String> medications) {\n return \"\"\"\nAnalyze interactions between: ${medications.join(', ')}\n\nProvide brief summary:\n1. Interaction level (Minor/Moderate/Major)\n2. Key effects to watch for\n3. When to consult healthcare provider\n4. Medical disclaimer\n\nKeep response under 250 words.\n\"\"\";\n }\n\n String _buildHealthInsightsPrompt(Map<String, dynamic> healthData) {\n final buffer = StringBuffer()..writeln(\"Health metrics:\");\n\n healthData.forEach((key, value) {\n buffer.writeln(\"- ${key.replaceAll('_', ' ')}: $value\");\n });\n\n buffer.writeln(\"\"\"\nProvide brief insights:\n1. Key observations\n2. Improvement suggestions\n3. General lifestyle tips\n4. Encouragement\n\nKeep response under 200 words.\n\"\"\");\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl';\n}\n"}, "d2bbf3e0c47ddf7501ec50c8caa1dad26a2e4a5a": {"t": 1785757964.5135517, "n": 5869, "h": "f905cfe6a278cbcc", "c": "import 'dart:convert';\nimport 'dart:async';\nimport 'package:http/http.dart' as http;\nimport 'package:flutter_dotenv/flutter_dotenv.dart';\n\nclass DeepSeekService {\n late final String _apiKey;\n late final String _baseUrl;\n\n static const Duration _timeout = Duration(seconds: 30);\n static const int _maxRetries = 2;\n\n DeepSeekService() {\n _apiKey = dotenv.env['DEEPSEEK_API_KEY'] ?? '';\n _baseUrl = dotenv.env['DEEPSEEK_BASE_URL'] ?? 'https://api.deepseek.com/v1';\n print(\"🔑 API Key Loaded: ${_apiKey.isNotEmpty ? \"Yes\" : \"No\"}\");\n print(\"🌍 Base URL: $_baseUrl\");\n\n if (_apiKey.isEmpty) {\n throw Exception('❌ DeepSeek API key not found in environment variables');\n }\n }\n\n Future<String> analyzeSymptoms(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo) async {\n final prompt =\n _buildSymptomAnalysisPrompt(symptoms, severity, additionalInfo);\n return _safeApiCall(prompt, 'Error analyzing symptoms');\n }\n\n Future<String> checkMedicationInteractions(List<String> medications) async {\n final prompt = _buildMedicationInteractionPrompt(medications);\n return _safeApiCall(prompt, 'Error checking medication interactions');\n }\n\n Future<String> getHealthInsights(Map<String, dynamic> healthData) async {\n final prompt = _buildHealthInsightsPrompt(healthData);\n return _safeApiCall(prompt, 'Error getting health insights');\n }\n\n Future<String> _safeApiCall(String prompt, String contextMessage) async {\n try {\n return await _makeApiCallWithRetry(prompt);\n } on TimeoutException {\n print('⏳ $contextMessage: Request timed out.');\n return 'The request took too long. Please try again later.';\n } catch (e) {\n print('⚠️ $contextMessage: $e');\n return 'Unable to complete this request right now. Please try again later.';\n }\n }\n\n Future<String> _makeApiCallWithRetry(String prompt) async {\n int attempts = 0;\n while (true) {\n try {\n return await _makeApiCall(prompt);\n } catch (e) {\n attempts++;\n if (attempts > _maxRetries) rethrow;\n print('🔄 Retrying API call... (Attempt $attempts/$_maxRetries)');\n await Future.delayed(const Duration(milliseconds: 500));\n }\n }\n }\n\n Future<String> _makeApiCall(String prompt) async {\n final headers = {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer $_apiKey',\n };\n\n final body = jsonEncode({\n 'model': 'deepseek-chat',\n 'messages': [\n {\n 'role': 'system',\n 'content':\n 'You are a helpful medical AI assistant. Provide informative responses about health topics, but always recommend consulting healthcare professionals for serious concerns. Keep responses concise and user-friendly. Always include appropriate medical disclaimers.'\n },\n {'role': 'user', 'content': prompt}\n ],\n 'max_tokens': 800,\n 'temperature': 0.7,\n 'stream': false,\n });\n\n final response = await http\n .post(Uri.parse('$_baseUrl/chat/completions'),\n headers: headers, body: body)\n .timeout(_timeout);\n\n if (response.statusCode == 200) {\n final data = jsonDecode(response.body);\n final choices = data['choices'];\n if (choices != null && choices.isNotEmpty) {\n return choices[0]['message']['content']?.trim() ??\n 'No response received from AI service.';\n } else {\n throw Exception('Invalid response format from API');\n }\n } else {\n throw Exception('API request failed with status: ${response.statusCode}');\n }\n }\n\n String _buildSymptomAnalysisPrompt(List<String> symptoms, String severity,\n Map<String, dynamic> additionalInfo) {\n final buffer = StringBuffer()\n ..writeln(\n \"Please analyze these symptoms and provide helpful medical information:\\n\")\n ..writeln(\"**Symptoms:** ${symptoms.join(', ')}\")\n ..writeln(\"**Severity:** $severity\\n\");\n\n if (additionalInfo.isNotEmpty) {\n buffer.writeln(\"**Additional Information:**\");\n additionalInfo.forEach((key, value) {\n if (value.toString().isNotEmpty) {\n buffer.writeln(\"- ${key.replaceAll('_', ' ').toUpperCase()}: $value\");\n }\n });\n buffer.writeln();\n }\n\n buffer.writeln(\"\"\"\nPlease provide a comprehensive analysis including:\n\n1. **Possible Common Causes:** List potential common conditions\n2. **When to Seek Medical Attention:** Clear guidelines for urgent care\n3. **Self-Care Recommendations:** Safe, general suggestions\n4. **Important Considerations:** Any red flags\n5. **Medical Disclaimer:** Remind that this is informational only\n\"\"\");\n\n return buffer.toString();\n }\n\n String _buildMedicationInteractionPrompt(List<String> medications) {\n return \"\"\"\nPlease analyze potential interactions between these medications:\n\n**Current Medications:** ${medications.join(', ')}\n\nInclude:\n1. Interaction assessment (Minor/Moderate/Major)\n2. Clinical significance & potential effects\n3. Monitoring recommendations\n4. When to consult healthcare providers\n5. Overall safety summary\n\nAlways remind users this is not a substitute for professional medical advice.\n\"\"\";\n }\n\n String _buildHealthInsightsPrompt(Map<String, dynamic> healthData) {\n final buffer = StringBuffer()..writeln(\"**Current Health Metrics:**\");\n healthData.forEach((key, value) {\n buffer.writeln(\"- ${key.replaceAll('_', ' ').toUpperCase()}: $value\");\n });\n\n buffer.writeln(\"\"\"\nProvide insights including:\n1. Positive observations\n2. Health trends\n3. Improvement opportunities\n4. General lifestyle tips\n5. Motivational encouragement\n\"\"\");\n\n return buffer.toString();\n }\n\n bool get isConfigured => _apiKey.isNotEmpty;\n\n String get configurationStatus =>\n 'API Key: ${_apiKey.isNotEmpty ? \"✓ Configured\" : \"✗ Missing\"}\\nBase URL: $_baseUrl';\n}\n"}}}}