import os from datetime import datetime from flask import Flask, render_template, request, jsonify, escape from dotenv import load_dotenv from chatbot import get_krishna_response from image_api import generate_krishna_image, generate_comic_strip from countdown import get_countdown from messages import daily_blessings, auto_generate_birthday_message from ayush_messages import ayush_surprises import logging import requests import random import backoff from functools import lru_cache # Configure logging logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) # Initialize Firebase if available try: from firebase_config import save_chat_message, get_chat_history firebase_enabled = True logger.debug("Firebase integration enabled") except ImportError: firebase_enabled = False logger.debug("Firebase disabled: firebase_config.py not found") # Load environment variables load_dotenv() HUGGINGFACE_API_TOKEN = os.getenv("HUGGINGFACE_API_TOKEN") if not HUGGINGFACE_API_TOKEN: logger.error("HUGGINGFACE_API_TOKEN not found in environment variables") raise ValueError("HUGGINGFACE_API_TOKEN is required") app = Flask(__name__) app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True # Daily messages with Bhagavad Gita verses DAILY_MESSAGES = { 0: {"message": "On Sundays, shine like the sun for all!", "verse": "Bhagavad Gita 9.29"}, 1: {"message": "Monday: Do your duty without attachment.", "verse": "Bhagavad Gita 2.47"}, 2: {"message": "Tuesday: The soul is eternal, beyond death.", "verse": "Bhagavad Gita 2.20"}, 3: {"message": "Wednesday: Krishna brings victory!", "verse": "Bhagavad Gita 18.78"}, 4: {"message": "Thursday: Surrender to the divine will.", "verse": "Bhagavad Gita 18.66"}, 5: {"message": "Friday: Cultivate compassion.", "verse": "Bhagavad Gita 16.1-3"}, 6: {"message": "Saturday: Find joy in spiritual practice.", "verse": "Bhagavad Gita 6.17"} } # Festival messages FESTIVAL_MESSAGES = { (1, 26): {"message": "Happy Republic Day! Let Dharma guide our nation.", "verse": "Bhagavad Gita 4.7", "special": True}, (8, 19): {"message": "Happy Krishna Janmashtami! Celebrate the divine birth.", "verse": "Bhagavad Gita 4.9", "special": True}, (4, 19): {"message": ayush_surprises["birthday"], "verse": "Bhagavad Gita 2.22", "special": True} } def parse_huggingface_response(response): """Parse Hugging Face API response.""" try: result = response.json() if isinstance(result, list) and result and "generated_text" in result[0]: return result[0]["generated_text"].strip() elif isinstance(result, dict) and "generated_text" in result: return result["generated_text"].strip() elif isinstance(result, str): return result.strip() logger.error("Unexpected API response format") return None except Exception as e: logger.error(f"Error parsing API response: {str(e)}") return None def get_daily_message_and_blessing(): """Retrieve daily message and blessing.""" try: today = datetime.now() day_of_week = (today.weekday() + 1) % 7 month_day = (today.month, today.day) if month_day in FESTIVAL_MESSAGES: daily_message = FESTIVAL_MESSAGES[month_day] else: daily_message = DAILY_MESSAGES.get(day_of_week, {"message": "Seek the divine today.", "verse": "Bhagavad Gita 6.30"}) daily_message['special'] = False daily_blessing_index = (today.day - 1) % len(daily_blessings) daily_blessing = daily_blessings[daily_blessing_index] return { "message": daily_message["message"], "verse": daily_message["verse"], "is_special": daily_message.get("special", False), "blessing": daily_blessing } except Exception as e: logger.error(f"Error in get_daily_message_and_blessing: {str(e)}") return { "message": "Seek the divine today.", "verse": "Bhagavad Gita 6.30", "is_special": False, "blessing": "Hare Manavi! May Vrindavan’s joy fill your heart!" } @backoff.on_exception(backoff.expo, (requests.exceptions.RequestException, requests.exceptions.HTTPError), max_tries=2, max_time=60) def make_api_request(url, headers, payload, timeout=30): """Make API requests with exponential backoff.""" try: response = requests.post(url, headers=headers, json=payload, timeout=timeout) if response.status_code == 200: return response logger.error(f"API error: {response.status_code} - {response.text}") raise requests.exceptions.HTTPError(f"API returned status {response.status_code}") except requests.exceptions.RequestException as e: logger.error(f"API request failed: {str(e)}") raise @lru_cache(maxsize=10) def generate_birthday_message(): """Generate a birthday message for Manavi.""" try: today = datetime.now() if today.month == 4 and today.day == 19: return ayush_surprises["birthday"] headers = { "Authorization": f"Bearer {HUGGINGFACE_API_TOKEN}", "Content-Type": "application/json" } prompt = ( "You are Little Krishna, speaking to Manavi on her birthday, April 19, 2025. " "Ayush created this chatbot as a surprise. Write a short, heartfelt birthday message (1-2 sentences) starting with 'Happy Birthday, Manavi!', using Vrindavan imagery. " "Example: 'Happy Birthday, Manavi! I’ve brought Vrindavan’s sweetest butter and a flute melody to make your heart dance!'" ) payload = { "inputs": prompt, "parameters": { "max_length": 60, "temperature": 0.9, "top_p": 0.9, "top_k": 50 } } response = make_api_request( "https://api-inference.huggingface.co/models/mistralai/Mixtral-8x7B-Instruct-v0.1", headers=headers, payload=payload ) result = parse_huggingface_response(response) if result and result.startswith("Happy Birthday, Manavi!"): return result logger.warning("Invalid API response; using fallback") return auto_generate_birthday_message(include_tease=True) except Exception as e: logger.error(f"Error in generate_birthday_message: {str(e)}") return auto_generate_birthday_message(include_tease=True) @lru_cache(maxsize=10) def generate_gift_suggestions(): """Generate personalized gift suggestions for Manavi.""" try: headers = { "Authorization": f"Bearer {HUGGINGFACE_API_TOKEN}", "Content-Type": "application/json" } prompt = ( "You are Little Krishna, speaking to Manavi on her birthday, April 19, 2025. " "Suggest three gifts reflecting her interests in art, nature, and spirituality, in a playful Krishna tone. " "Return as a numbered list (1., 2., 3.). Example: '1. A peacock feather paintbrush for vibrant art!\n2. A lotus journal for serene thoughts!\n3. A flute pendant for spiritual melodies!'" ) payload = { "inputs": prompt, "parameters": { "max_length": 100, "temperature": 0.9, "top_p": 0.9, "top_k": 50 } } response = make_api_request( "https://api-inference.huggingface.co/models/mistralai/Mixtral-8x7B-Instruct-v0.1", headers=headers, payload=payload ) result = parse_huggingface_response(response) if result: suggestions = result.strip().split('\n') return [s.strip() for s in suggestions if s.strip()] logger.warning("Using fallback gift suggestions") return [ "Hare Manavi! A peacock feather paintbrush for vibrant art!", "Hare Manavi! A lotus journal for serene thoughts!", "Hare Manavi! A flute pendant for spiritual melodies!" ] except Exception as e: logger.error(f"Error in generate_gift_suggestions: {str(e)}") return [ "Hare Manavi! A peacock feather paintbrush for vibrant art!", "Hare Manavi! A lotus journal for serene thoughts!", "Hare Manavi! A flute pendant for spiritual melodies!" ] @lru_cache(maxsize=10) def generate_horoscope(): """Generate a daily horoscope for Manavi.""" try: today = datetime.now().strftime("%B %d, %Y") headers = { "Authorization": f"Bearer {HUGGINGFACE_API_TOKEN}", "Content-Type": "application/json" } prompt = ( f"You are Little Krishna, speaking to Manavi on {today}. " "Generate a short daily horoscope (1-2 sentences) for Manavi, reflecting her interests in art, nature, and spirituality, in a playful tone with Vrindavan imagery. " "Example: 'Hare Manavi! Today, the Yamuna inspires your art—paint with Vrindavan’s colors and let your spirit dance!'" ) payload = { "inputs": prompt, "parameters": { "max_length": 60, "temperature": 0.9, "top_p": 0.9, "top_k": 50 } } response = make_api_request( "https://api-inference.huggingface.co/models/mistralai/Mixtral-8x7B-Instruct-v0.1", headers=headers, payload=payload ) result = parse_huggingface_response(response) if result: return result logger.warning("Using fallback horoscope") return "Hare Manavi! Today, the Yamuna inspires your art—paint with Vrindavan’s colors and let your spirit dance!" except Exception as e: logger.error(f"Error in generate_horoscope: {str(e)}") return "Hare Manavi! Today, the Yamuna inspires your art—paint with Vrindavan’s colors and let your spirit dance!" @app.route('/') def home(): """Render the home page.""" try: daily_data = get_daily_message_and_blessing() countdown_days = get_countdown() daily_horoscope = generate_horoscope() return render_template('home.html', daily_message=daily_data['message'], verse_reference=daily_data['verse'], is_special=daily_data['is_special'], daily_blessing=daily_data['blessing'], daily_horoscope=daily_horoscope, countdown=countdown_days) except Exception as e: logger.error(f"Error in / route: {str(e)}") return render_template('error.html', error_message='Failed to load homepage. Please try again.'), 500 @app.route('/chat', methods=['GET', 'POST']) def chat(): """Handle chat interactions.""" try: if request.method == 'POST': if 'message' not in request.form: logger.error("Missing 'message' in POST request") return jsonify({'error': 'Missing message parameter'}), 400 user_input = escape(request.form['message'].strip()) if not user_input: logger.error("Empty message received") return jsonify({'error': 'Message cannot be empty'}), 400 if len(user_input) > 500: logger.error("Message too long") return jsonify({'error': 'Message too long (max 500 characters)'}), 400 logger.info(f"Received chat input: {user_input}") reply = get_krishna_response(user_input) logger.info(f"Generated reply: {reply}") if firebase_enabled: try: save_chat_message(user_input, reply) logger.debug("Saved chat message to Firebase") except Exception as e: logger.error(f"Failed to save chat message: {str(e)}") return jsonify({'reply': reply}) try: chat_history = get_chat_history() if firebase_enabled else [] logger.debug(f"Retrieved chat history: {len(chat_history)} messages") except Exception as e: logger.error(f"Failed to retrieve chat history: {str(e)}") chat_history = [] return render_template('chat.html', chat_history=chat_history) except Exception as e: logger.error(f"Error in /chat route: {str(e)}") return render_template('error.html', error_message='Failed to load chat page. Please try again.'), 500 @app.route('/adventure', methods=['GET', 'POST']) def adventure(): """Handle the interactive Vrindavan adventure game.""" try: if request.method == 'POST': choice = request.form.get('choice', '') current_scene = request.form.get('current_scene', 'start') logger.info(f"Adventure POST: current_scene={current_scene}, choice={choice}") scenes = { 'start': { 'prompt': ( "You are Little Krishna, guiding Manavi on a Vrindavan adventure. " "Start with a short scene (2-3 sentences) and offer two choices. " "Example: 'Hare Manavi! By the Yamuna’s sparkling waters, shall we chase peacocks or sneak butter? (Choices: Chase peacocks, Sneak butter)'" ), 'next_scenes': {'Chase peacocks': 'peacocks', 'Sneak butter': 'butter'} }, 'peacocks': { 'prompt': ( "Manavi chose to chase peacocks. Describe a short scene (2-3 sentences) and offer two new choices. " "Example: 'Hare Manavi! We chased peacocks, their feathers shimmering—shall we climb a kadamba tree or play a flute tune? (Choices: Climb tree, Play flute)'" ), 'next_scenes': {'Climb tree': 'tree', 'Play flute': 'flute'} }, 'butter': { 'prompt': ( "Manavi chose to sneak butter. Describe a short scene (2-3 sentences) and offer two new choices. " "Example: 'Hare Manavi! We sneaked butter, giggling—shall we hide by the Yamuna or share with calves? (Choices: Hide by Yamuna, Share with calves)'" ), 'next_scenes': {'Hide by Yamuna': 'yamuna', 'Share with calves': 'calves'} }, 'tree': { 'prompt': ( "Manavi chose to climb the kadamba tree. Describe a short scene (2-3 sentences) and end the story. " "Example: 'Hare Manavi! We climbed the kadamba tree, watching peacocks—what a magical Vrindavan day!'" ), 'next_scenes': {} }, 'flute': { 'prompt': ( "Manavi chose to play the flute. Describe a short scene (2-3 sentences) and end the story. " "Example: 'Hare Manavi! I played a flute tune, and peacocks danced—what a joyful Vrindavan memory!'" ), 'next_scenes': {} }, 'yamuna': { 'prompt': ( "Manavi chose to hide by the Yamuna. Describe a short scene (2-3 sentences) and end the story. " "Example: 'Hare Manavi! We hid by the Yamuna, sharing butter—what a mischievous adventure!'" ), 'next_scenes': {} }, 'calves': { 'prompt': ( "Manavi chose to share butter with calves. Describe a short scene (2-3 sentences) and end the story. " "Example: 'Hare Manavi! We shared butter with calves, who mooed happily—what a sweet moment!'" ), 'next_scenes': {} } } scene = scenes.get(current_scene, scenes['start']) headers = { "Authorization": f"Bearer {HUGGINGFACE_API_TOKEN}", "Content-Type": "application/json" } payload = { "inputs": scene['prompt'], "parameters": { "max_length": 80, "temperature": 0.9, "top_p": 0.9, "top_k": 50 } } response = make_api_request( "https://api-inference.huggingface.co/models/mistralai/Mixtral-8x7B-Instruct-v0.1", headers=headers, payload=payload ) if response and response.status_code == 200: result = parse_huggingface_response(response) story_text = result or scene['prompt'].split('Example: ')[1] else: logger.error("Failed to generate adventure scene") story_text = scene['prompt'].split('Example: ')[1] next_scene = scene['next_scenes'].get(choice) if next_scene: return jsonify({'scene': story_text, 'current_scene': next_scene, 'choices': list(scene['next_scenes'].keys())}) return jsonify({'scene': story_text, 'current_scene': None, 'choices': []}) return render_template('adventure.html') except Exception as e: logger.error(f"Error in /adventure route: {str(e)}") return render_template('error.html', error_message='Failed to load adventure page. Please try again.'), 500 @app.route('/message') def message(): """Render the birthday message page.""" try: birthday_message = generate_birthday_message() gift_suggestions = generate_gift_suggestions() birthday_image_url = "/static/assets/krishna.png" today = datetime.now() is_birthday = today.month == 4 and today.day == 19 return render_template('message.html', birthday_message=birthday_message, birthday_image_url=birthday_image_url, gift_suggestions=gift_suggestions, is_birthday=is_birthday) except Exception as e: logger.error(f"Error in /message route: {str(e)}") return render_template('error.html', error_message='Failed to load birthday message page. Please try again.'), 500 @app.route('/image', methods=['POST']) def image(): """Generate a Krishna-themed image.""" try: prompt = request.json.get('prompt', '') if not prompt: return jsonify({'error': 'Missing prompt parameter'}), 400 image_url = generate_krishna_image(prompt) if image_url: return jsonify({'image_url': image_url}) return jsonify({'error': 'Failed to generate image'}), 500 except Exception as e: logger.error(f"Error in /image route: {str(e)}") return jsonify({'error': 'Internal Server Error. Please try again.'}), 500 @app.route('/comic', methods=['GET']) def comic(): """Generate a Krishna-themed comic strip.""" try: comic_images = generate_comic_strip() return jsonify({'comic_images': comic_images}) except Exception as e: logger.error(f"Error in /comic route: {str(e)}") return jsonify({'error': 'Internal Server Error. Please try again.'}), 500 @app.route('/story', methods=['POST']) def story(): """Generate a Krishna story.""" try: theme = request.json.get('theme', 'Vrindavan') prompt = ( f"You are Little Krishna, telling a short story (2-3 sentences) to Manavi with the theme '{theme}'. " f"Keep it fun and Krishna-like. Example: 'Hare Manavi! I hid the gopis’ butter in a peacock’s nest—what a Vrindavan adventure!'" ) headers = { "Authorization": f"Bearer {HUGGINGFACE_API_TOKEN}", "Content-Type": "application/json" } payload = { "inputs": prompt, "parameters": { "max_length": 80, "temperature": 0.9, "top_p": 0.9, "top_k": 50 } } response = make_api_request( "https://api-inference.huggingface.co/models/mistralai/Mixtral-8x7B-Instruct-v0.1", headers=headers, payload=payload ) result = parse_huggingface_response(response) if result: return jsonify({'story': result}) logger.error("Failed to generate story") return jsonify({'story': f"Hare Manavi! I hid the gopis’ {theme} in a peacock’s nest—what a Vrindavan adventure!'"}) except Exception as e: logger.error(f"Error in /story route: {str(e)}") return jsonify({'error': 'Internal Server Error. Please try again.'}), 500 @app.route('/story_audio', methods=['POST']) def story_audio(): """Generate audio narration for a story.""" try: story_text = request.json.get('story_text', '') if not story_text: return jsonify({'error': 'Missing story_text parameter'}), 400 headers = { "Authorization": f"Bearer {HUGGINGFACE_API_TOKEN}", "Content-Type": "application/json" } payload = {"inputs": story_text} response = make_api_request( "https://api-inference.huggingface.co/models/facebook/tts-transformer-en-ljspeech", headers=headers, payload=payload ) if response and response.status_code == 200: audio_path = "static/audio/story_audio.mp3" os.makedirs(os.path.dirname(audio_path), exist_ok=True) with open(audio_path, "wb") as f: f.write(response.content) return jsonify({'audio_url': f"/{audio_path}"}) logger.error("Failed to generate story audio") return jsonify({'error': 'Failed to generate audio'}), 500 except Exception as e: logger.error(f"Error in /story_audio route: {str(e)}") return jsonify({'error': 'Internal Server Error. Please try again.'}), 500 @app.route('/riddle', methods=['GET']) def riddle(): """Generate a Krishna-themed riddle.""" try: headers = { "Authorization": f"Bearer {HUGGINGFACE_API_TOKEN}", "Content-Type": "application/json" } prompt = ( "You are Little Krishna, speaking to Manavi. Generate a short, Krishna-themed riddle (1-2 sentences) with a playful tone, using Vrindavan imagery. " "Include the answer in parentheses. Example: 'Hare Manavi! I play a tune that makes gopis dance, but I’m not a drum—what am I? (Answer: Flute)'" ) payload = { "inputs": prompt, "parameters": { "max_length": 60, "temperature": 0.9, "top_p": 0.9, "top_k": 50 } } response = make_api_request( "https://api-inference.huggingface.co/models/mistralai/Mixtral-8x7B-Instruct-v0.1", headers=headers, payload=payload ) result = parse_huggingface_response(response) if result: return jsonify({'riddle': result}) logger.error("Failed to generate riddle") return jsonify({'riddle': "Hare Manavi! I play a tune that makes gopis dance—what am I? (Answer: Flute)"}) except Exception as e: logger.error(f"Error in /riddle route: {str(e)}") return jsonify({'error': 'Internal Server Error. Please try again.'}), 500 @app.route('/countdown') def countdown(): """Return days until Manavi's birthday.""" try: days_left = get_countdown() return jsonify({'days': days_left}) except Exception as e: logger.error(f"Error in /countdown route: {str(e)}") return jsonify({'error': 'Internal Server Error. Please try again.'}), 500 if __name__ == '__main__': port = int(os.environ.get('PORT', 7860)) app.run(host='0.0.0.0', port=port, debug=False)