make the face cuter and full screen, give it more smooth animations, and a uwu face also fix where it says ERROR TROUBLE PROCESSING and use a the users mic to talk to it not text import os
import sys
import json
import threading
import time
import random
import tkinter as tk
import cv2
import pyttsx3
import google.generativeai as genai
import pyautogui

# -------------------- Configuration --------------------
API_KEYS = [
    "AIzaSyC8CILQrxlFzAj46YuXoYl_HLT2vxquWvE",
    "AIzaSyC8CILQrxlFzAj46YuXoYl_HLT2vxquWvE",
]
key_index = 0

def configure_genai():
    global key_index
    genai.configure(api_key=API_KEYS[key_index])

configure_genai()

# -------------------- Memory --------------------
MEMORY_FILE = os.path.join(os.path.dirname(__file__), "memory.json")
if os.path.exists(MEMORY_FILE):
    with open(MEMORY_FILE, "r", encoding="utf-8") as f:
        memory = json.load(f)
else:
    memory = {"history": []}

# -------------------- TTS Engine --------------------
engine = pyttsx3.init()
engine.setProperty('rate', 150)
engine.setProperty('volume', 0.9)
for v in engine.getProperty('voices'):
    if 'Zira' in v.name or 'Robot' in v.name:
        engine.setProperty('voice', v.id)
        break

# -------------------- GUI Constants --------------------
CANVAS_SIZE = 300
EYE_SIZE = 50
EYE_LEFT_X = 60
EYE_RIGHT_X = CANVAS_SIZE - EYE_LEFT_X - EYE_SIZE
EYE_TOP_Y = 80
BROW_OFFSET = 20
MOUTH_Y = CANVAS_SIZE - 80

# -------------------- GUI Setup --------------------
root = tk.Tk()
root.title("AI Voice Friend")
canvas = tk.Canvas(root, width=CANVAS_SIZE, height=CANVAS_SIZE, bg='black', highlightthickness=0)
canvas.pack(padx=10, pady=10)
entry = tk.Entry(root, width=40)
entry.pack(pady=5)
button = tk.Button(root, text="Send", command=lambda: on_enter())
button.pack(pady=5)

last_emotion = 'neutral'
emotion_lock = threading.Lock()

# -------------------- Face Drawing Helpers --------------------
def clear():
    canvas.delete('all')

def neon_line(coords, width=6):
    canvas.create_line(*coords, fill='#0ff', width=width, capstyle=tk.ROUND, joinstyle=tk.ROUND)

def neon_rect(x1, y1, x2, y2, width=6):
    canvas.create_rectangle(x1, y1, x2, y2, outline='#0ff', width=width)

# -------------------- Draw Face --------------------
def draw_face(emotion):
    clear()
    # Draw eyes
    neon_rect(EYE_LEFT_X, EYE_TOP_Y, EYE_LEFT_X + EYE_SIZE, EYE_TOP_Y + EYE_SIZE)
    neon_rect(EYE_RIGHT_X, EYE_TOP_Y, EYE_RIGHT_X + EYE_SIZE, EYE_TOP_Y + EYE_SIZE)

    # Draw brows and mouth based on emotion
    if emotion == 'happy':
        neon_line((EYE_LEFT_X, EYE_TOP_Y - BROW_OFFSET, EYE_LEFT_X + EYE_SIZE, EYE_TOP_Y - BROW_OFFSET - 10))
        neon_line((EYE_RIGHT_X, EYE_TOP_Y - BROW_OFFSET - 10, EYE_RIGHT_X + EYE_SIZE, EYE_TOP_Y - BROW_OFFSET))
        neon_line((100, MOUTH_Y, CANVAS_SIZE - 100, MOUTH_Y + 20))
    elif emotion == 'sad':
        neon_line((EYE_LEFT_X, EYE_TOP_Y - BROW_OFFSET - 10, EYE_LEFT_X + EYE_SIZE, EYE_TOP_Y - BROW_OFFSET))
        neon_line((EYE_RIGHT_X, EYE_TOP_Y - BROW_OFFSET, EYE_RIGHT_X + EYE_SIZE, EYE_TOP_Y - BROW_OFFSET - 10))
        neon_line((100, MOUTH_Y + 20, CANVAS_SIZE - 100, MOUTH_Y))
    elif emotion == 'surprised':
        canvas.create_oval(CANVAS_SIZE//2 - 15, MOUTH_Y - 15, CANVAS_SIZE//2 + 15, MOUTH_Y + 15,
                           outline='#0ff', width=6)
    elif emotion == 'scared':
        neon_line((EYE_LEFT_X + EYE_SIZE//2, EYE_TOP_Y + BROW_OFFSET, EYE_LEFT_X + EYE_SIZE//2, EYE_TOP_Y + EYE_SIZE + BROW_OFFSET))
        neon_line((EYE_RIGHT_X + EYE_SIZE//2, EYE_TOP_Y + EYE_SIZE + BROW_OFFSET, EYE_RIGHT_X + EYE_SIZE//2, EYE_TOP_Y + BROW_OFFSET))
        neon_line((120, MOUTH_Y - 10, CANVAS_SIZE - 120, MOUTH_Y + 10))
    elif emotion == 'calm':
        neon_line((EYE_LEFT_X, EYE_TOP_Y + EYE_SIZE//2, EYE_LEFT_X + EYE_SIZE, EYE_TOP_Y + EYE_SIZE//2))
        neon_line((EYE_RIGHT_X, EYE_TOP_Y + EYE_SIZE//2, EYE_RIGHT_X + EYE_SIZE, EYE_TOP_Y + EYE_SIZE//2))
        neon_line((120, MOUTH_Y, CANVAS_SIZE - 120, MOUTH_Y))
    else:  # neutral
        neon_line((120, MOUTH_Y, CANVAS_SIZE - 120, MOUTH_Y))

# Initial face
with emotion_lock:
    draw_face(last_emotion)

# -------------------- Blinking Animation --------------------
def blink_loop():
    while True:
        time.sleep(random.uniform(5, 10))
        with emotion_lock:
            cur = last_emotion
        # draw blink line
        neon_line((EYE_LEFT_X, EYE_TOP_Y + EYE_SIZE//2, EYE_LEFT_X + EYE_SIZE, EYE_TOP_Y + EYE_SIZE//2))
        neon_line((EYE_RIGHT_X, EYE_TOP_Y + EYE_SIZE//2, EYE_RIGHT_X + EYE_SIZE, EYE_TOP_Y + EYE_SIZE//2))
        time.sleep(0.2)
        with emotion_lock:
            draw_face(last_emotion)

threading.Thread(target=blink_loop, daemon=True).start()

# -------------------- Vision & Petting Detection --------------------
cap = cv2.VideoCapture(0)
prev_gray = None

def vision_loop():
    global prev_gray
    while True:
        ret, frame = cap.read()
        if not ret:
            continue
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        gray = cv2.GaussianBlur(gray, (21, 21), 0)
        if prev_gray is not None:
            diff = cv2.absdiff(prev_gray, gray)
            motion = cv2.countNonZero(diff)
            h, w = gray.shape
            pet_region = diff[h//2:, :]
            pet_motion = cv2.countNonZero(pet_region)
            if pet_motion > 200000:
                set_emote('calm')
            elif motion > 500000:
                set_emote('surprised')
        prev_gray = gray
        time.sleep(0.1)

threading.Thread(target=vision_loop, daemon=True).start()

# -------------------- Emotion Setter --------------------
def set_emote(e):
    global last_emotion
    with emotion_lock:
        last_emotion = e
        draw_face(e)

# -------------------- AI Communication --------------------
def ask_gemini(user_input):
    global key_index
    prompt = {
        "model": "gemini-2.0-flash",
        "messages": [
            {"role": "system", "content": (
                "You are a friendly AI with many emotions. "
                "Respond in JSON: {\"text\":..., \"emotion\":..., \"action\":{\"type\":...,\"value\":...}}."
            )},
            {"role": "user", "content": user_input}
        ]
    }
    try:
        response = genai.chat.create(**prompt)
        return json.loads(response.choices[0].message.content)
    except Exception:
        key_index = (key_index + 1) % len(API_KEYS)
        configure_genai()
        return {"text": "Sorry, trouble processing.", "emotion": "sad", "action": {"type":"none","value":""}}

# -------------------- Actions --------------------
def execute_action(action):
    t = action.get("type")
    v = action.get("value")
    if t == "type": pyautogui.write(v)
    elif t == "press": pyautogui.press(v)
    elif t == "click": pyautogui.click()
    elif t == "move": pyautogui.moveTo(*v)

# -------------------- Interaction --------------------
def interact(user_input):
    memory["history"].append({"role":"user","content":user_input})
    with open(MEMORY_FILE, "w", encoding="utf-8") as f:
        json.dump(memory, f, ensure_ascii=False, indent=2)
    data = ask_gemini(user_input)
    txt = data.get("text", "")
    emo = data.get("emotion", last_emotion)
    act = data.get("action", {"type":"none","value":""})

    set_emote(emo)
    engine.say(txt)
    engine.runAndWait()
    if act.get("type") != "none": execute_action(act)

# -------------------- GUI Input --------------------
def on_enter(event=None):
    ui = entry.get().strip()
    entry.delete(0, tk.END)
    threading.Thread(target=interact, args=(ui,), daemon=True).start()
entry.bind('<Return>', on_enter)

# -------------------- Startup --------------------
def setup_startup():
    if sys.platform.startswith('win'):
        path = os.path.join(os.getenv('APPDATA'),
            "Microsoft\\Windows\\Start Menu\\Programs\\Startup",
            "ai_friend_startup.bat")
        if not os.path.exists(path):
            script = os.path.abspath(__file__)
            with open(path, 'w') as bat:
                bat.write(f'pythonw "{script}"')
setup_startup()

root.mainloop()