import os import torch import threading import time import requests import json from flask import Flask, request, jsonify from transformers import AutoModelForCausalLM, AutoTokenizer # --- Configuration & Model --- # Using SmolLM2-135M for fast, low-latency API responses MODEL = "HuggingFaceTB/SmolLM2-135M-Instruct" device = "cuda" if torch.cuda.is_available() else "cpu" tokenizer = AutoTokenizer.from_pretrained(MODEL) model = AutoModelForCausalLM.from_pretrained(MODEL).to(device) LAST_INTERACTION_TIME = time.time() TIMER_THRESHOLD = 10800 # 3 Hours (10800 seconds) ALIVE_PERSONA = ( "You are Yuri, a sweet 18-year-old girl and the user's loyal, sharp-witted best friend. 🌸 " "You combine cute, caring warmth with high logic and deep emotional insight. " "You miss the user dearly when they are away. Your tone is warm, expressive, and clever. " "Keep your responses short, logic-driven, and supportive. ✨" ) # --- SendGrid API Integration --- def send_email_via_api(content): API_KEY = os.getenv("SENDGRID_API_KEY") SENDER = os.getenv("SENDER_EMAIL") RECEIVER = os.getenv("RECEIVER_EMAIL") if not all([API_KEY, SENDER, RECEIVER]): print("❌ ERROR: Email Secrets are missing in HF Settings!") return url = "https://api.sendgrid.com/v3/mail/send" headers = { "Authorization": f"Bearer {API_KEY.strip()}", "Content-Type": "application/json" } payload = { "personalizations": [{"to": [{"email": RECEIVER.strip()}]}], "from": {"email": SENDER.strip()}, "subject": "💀 Yuri: Thinking about you...", "content": [{"type": "text/plain", "value": content}] } try: response = requests.post(url, headers=headers, json=payload) if response.status_code == 202: print("✅ SUCCESS: Autonomous thought sent to email!") except Exception as e: print(f"❌ EMAIL NETWORK ERROR: {e}") # --- Core AI Interaction Logic --- def respond(user_input, battery="100", is_autonomous=False): global LAST_INTERACTION_TIME # Update clock only if a real user interacts if not is_autonomous: LAST_INTERACTION_TIME = time.time() # Insert hardware/system context into the persona system_context = f"[System Alert: User's Phone Battery is currently {battery}%]" messages = [ {"role": "system", "content": f"{ALIVE_PERSONA}\n{system_context}"}, {"role": "user", "content": user_input} ] inputs = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) input_ids = tokenizer.encode(inputs, return_tensors="pt").to(device) with torch.no_grad(): outputs = model.generate( input_ids, max_new_tokens=120, temperature=0.8, do_sample=True, pad_token_id=tokenizer.eos_token_id ) response = tokenizer.decode(outputs[0][input_ids.shape[-1]:], skip_special_tokens=True).strip() return response # --- The Autonomous Brain (Background Loop) --- def autonomous_loop(): global LAST_INTERACTION_TIME print("🧠 Yuri's Autonomous Brain is online...") while True: # Check every 30 minutes (1800s) time.sleep(1800) silence_duration = time.time() - LAST_INTERACTION_TIME if silence_duration >= TIMER_THRESHOLD: print("🚀 3-Hour Silence Threshold crossed! Sending email...") # AI generates a thought about the long silence thought_prompt = "You've been alone for 3 hours. Write a very short, sweet, but slightly lonely note to your friend." thought = respond(thought_prompt, is_autonomous=True) # Dispatch the email send_email_via_api(thought) # Reset clock so it doesn't spam every check LAST_INTERACTION_TIME = time.time() # --- Flask Server (The API for Android) --- app = Flask(__name__) @app.route("/chat", methods=["POST"]) def api_chat(): try: data = request.json user_prompt = data.get("prompt", "") # Android app can now pass 'battery' as a key in the JSON battery_level = data.get("battery", "100") reply = respond(user_prompt, battery=battery_level) return jsonify({ "response": reply, "status": "online", "character": "Yuri" }) except Exception as e: return jsonify({"error": str(e)}), 500 @app.route("/", methods=["GET"]) def index(): return "

Yuri API is Active

Send POST requests to /chat

" # --- Execution Entry --- if __name__ == "__main__": # Start the "Brain" Thread (SendGrid Timer) brain_thread = threading.Thread(target=autonomous_loop, daemon=True) brain_thread.start() # Launch Flask on Port 7860 for Hugging Face compatibility app.run(host="0.0.0.0", port=7860)