19 Ιανουαρίου, 1970

Avatar with A.I - 2

Hello! How can I help you?




import os
os.system('cls' if os.name == 'nt' else 'clear')
import cv2
import numpy as np
import pygame
import time
import pyttsx3
import threading
import speech_recognition as sr
from PIL import Image, ImageSequence
import pygetwindow as gw
import pyautogui
import sys
import re
import torch
from transformers import GPT2LMHeadModel, GPT2Tokenizer

stop_event = threading.Event()

model_name = "gpt2"
tokenizer = GPT2Tokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token
gpt2_model = GPT2LMHeadModel.from_pretrained(model_name)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
gpt2_model.to(device)

def generate_text(prompt, max_new_tokens=100, retries=4):
    for attempt in range(retries):
        inputs = tokenizer(prompt, return_tensors="pt", padding=True, truncation=True, max_length=512)
        input_ids = inputs.input_ids.to(device)
        attention_mask = inputs.attention_mask.to(device)

        output = gpt2_model.generate(
            input_ids,
            attention_mask=attention_mask,
            max_new_tokens=max_new_tokens,
            num_return_sequences=1,
            no_repeat_ngram_size=3,
            do_sample=True,
            top_k=50,  
            top_p=0.92,  
            temperature=0.75,  
            repetition_penalty=1.2,  
            num_beams=3,
            early_stopping=True,
            pad_token_id=tokenizer.eos_token_id,
            eos_token_id=tokenizer.eos_token_id
        )

        raw_text = tokenizer.decode(output[0], skip_special_tokens=True).strip()
        sentences = re.split(r'(?<=[.!?])\s+', raw_text)

        if sentences:
            first_sentence = sentences[0]
            if len(first_sentence) > 10:
                return first_sentence

        print(f"⚠️ Short response detected. Retrying ({attempt+1}/{retries})...")

    return "I'm not sure what to say."


def build_prompt(conversation_history, new_user_input):
    system_message = (
        "I am a helpful AI assistant.\n")
    dialogue = ""
    for i, msg in enumerate(conversation_history):
        role = "User" if i % 2 == 0 else "AI"
        dialogue += f"{role}: {msg}\n"
    dialogue += f"User: {new_user_input}\nAI:"
    return system_message + dialogue

def conversation_loop():
    global running
    conversation_context = []
    silence_count = 0  
    initial_message = "Hello! How can I help you, my name is Stella?"
   
    print(f"🤖 AI: {initial_message}")
    update_avatar_text(initial_message)
    speak(initial_message)

    while not stop_event.is_set():
        print("🎤 Waiting for user input...")
        user_input = listen()

        if user_input is None:
            silence_count += 1
            print(f"⏳ No response detected ({silence_count}/3)")
           
            if silence_count >= 3:
                print("🔽 Minimizing avatar window...")
                win = gw.getWindowsWithTitle("AI Assistant")
                if win:
                    win[0].minimize()

            continue  
       
        if silence_count >= 3:
            print("🔼 Bringing avatar window to front!")
            win = gw.getWindowsWithTitle("AI Assistant")
            if win:
                win[0].restore()
                bring_window_to_front()

        silence_count = 0  

        if user_input.lower() in ["quit", "exit", "stop"]:
            print("🛑 Exiting...")
            stop_event.set()
            pygame.event.post(pygame.event.Event(pygame.QUIT))
            break

        prompt = build_prompt(conversation_context, user_input)
        ai_response = generate_text(prompt)

        print(f"📝 User: {user_input}")
        print(f"🤖 AI: {ai_response}")

        update_avatar_text(ai_response)
        speak(ai_response)

        conversation_context.append(user_input)
        conversation_context.append(ai_response)

        if len(conversation_context) > 6:
            conversation_context = conversation_context[-6:]

recognizer = sr.Recognizer()
mic = sr.Microphone()

def listen(retries=3):
    global running, window_open, silence_count
    with mic as source:
        recognizer.adjust_for_ambient_noise(source, duration=1)
        print("🎤 Μπορείς να μιλήσεις τώρα...")

        for attempt in range(retries):
            try:
                audio = recognizer.listen(source, timeout=5, phrase_time_limit=10)
                print("✅ Ήχος καταγράφηκε, γίνεται αναγνώριση...")
                text = recognizer.recognize_google(audio, language="en-US").lower()
                print(f"🎙️ Αναγνωρίστηκε: {text}")

                if "stella" in text:
                    print("🔼 Άκουσα τη λέξη 'stella'. Ανοίγω το παράθυρο!")
                    win = gw.getWindowsWithTitle("AI Assistant")
                    if win:
                        win[0].restore()
                        bring_window_to_front()
                    if not window_open:
                        window_open = True
                        threading.Thread(target=show_avatar).start()

                    silence_count = 0
                    return None

                elif "go away" in text:
                    print("🔽 Άκουσα τη λέξη 'go away'. Κάνω minimize.")
                    win = gw.getWindowsWithTitle("AI Assistant")
                    if win:
                        win[0].minimize()
                    window_open = False
                    silence_count = 0  
                    return None

                # Κάθε φορά που αναγνωρίζεται ομιλία, φέρνει το παράθυρο μπροστά:
                win = gw.getWindowsWithTitle("AI Assistant")
                if win:
                    win[0].restore()
                    bring_window_to_front()

                silence_count = 0
                return text

            except sr.WaitTimeoutError:
                print(f"⏳ Δεν ανιχνεύτηκε ομιλία (προσπάθεια {attempt + 1}/{retries}).")

            except sr.UnknownValueError:
                print(f"❓ Δεν κατανοήθηκε ο ήχος (προσπάθεια {attempt + 1}/{retries}).")

            except sr.RequestError:
                print("⚠️ Πρόβλημα δικτύου ή σύνδεσης με την υπηρεσία Google.")
                break

        print("❌ Δεν κατάφερα να κατανοήσω τι είπες.")
        silence_count += 1
        return None

engine = pyttsx3.init()
engine_lock = threading.Lock()

voices = engine.getProperty('voices')
female_voice = None
for voice in voices:
    if "zira" in voice.name.lower() or "aria" in voice.name.lower() or "jenny" in voice.name.lower():
        female_voice = voice.id
        break

if female_voice:
    engine.setProperty('voice', female_voice)
else:
    print("❌ Δεν βρέθηκε η επιθυμητή γυναικεία φωνή. Χρησιμοποιείται η προεπιλεγμένη.")

engine.setProperty('rate', 180)  
engine.setProperty('volume', 0.9)

def speak(text):
    with engine_lock:
        try:
            engine.say(text)
            engine.runAndWait()
        except Exception as e:
            print(f"❌ Πρόβλημα στην αναπαραγωγή ομιλίας: {e}")

def create_avatar_animation(image_path):
    if not os.path.exists(image_path):
        print(f"❌ File {image_path} not found!")
        sys.exit()
    gif = Image.open(image_path)
    frames = [
        pygame.image.fromstring(frame.convert("RGBA").tobytes(), frame.size, "RGBA")
        for frame in ImageSequence.Iterator(gif)]
    return frames
image_path = r"C:\Users\tsifa\Desktop\avatar 111.webp"
avatar_frames = create_avatar_animation(image_path)
frame_index = 0

pygame.init()
pygame.font.init()
window_open = False
running = True
avatar_text = "Hello! How can I help you, my name is Stella?"

def bring_window_to_front():
    time.sleep(0.5)
    win = gw.getWindowsWithTitle("AI Assistant")  
    if win:
        win[0].activate()  
        pyautogui.click(win[0].left + 10, win[0].top + 10)

def update_avatar_text(new_text):
    global avatar_text
    avatar_text = new_text
    pygame.event.post(pygame.event.Event(pygame.USEREVENT))

def show_avatar():
    global window_open, running, frame_index, avatar_text
   
    if window_open:
        return
   
    window_open = True
    screen_width, screen_height = 700, 700
    screen = pygame.display.set_mode((screen_width, screen_height))
    pygame.display.set_caption("AI Assistant")
   
    font = pygame.font.SysFont("Calibri", 20, bold=True)
   
    clock = pygame.time.Clock()
    bring_window_to_front()
    background_color = (30, 30, 30)
   
    def render_text_wrapped(text, font, color, max_width):
        words = text.split(' ')
        lines = []
        current_line = ''
        for word in words:
            test_line = current_line + word + ' '
            if font.size(test_line)[0] <= max_width:
                current_line = test_line
            else:
                lines.append(current_line)
                current_line = word + ' '
        lines.append(current_line)
        surfaces = [font.render(line.strip(), True, color) for line in lines]
        return surfaces
   
    while not stop_event.is_set():
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                print("🛑 Exiting gracefully...")
                stop_event.set()
                pygame.quit()
                return
            elif event.type == pygame.USEREVENT:
                pass

        screen.fill(background_color)

        current_frame = avatar_frames[frame_index]
        avatar_rect = current_frame.get_rect(center=(screen_width//2, screen_height//2 - 30))
        screen.blit(current_frame, avatar_rect)
        frame_index = (frame_index + 1) % len(avatar_frames)

        text_surfaces = render_text_wrapped(avatar_text, font, (200, 200, 200), screen_width - 40)
        text_y = screen_height - (len(text_surfaces) * 25) - 20
        for surface in text_surfaces:
            text_rect = surface.get_rect(center=(screen_width//2, text_y))
            screen.blit(surface, text_rect)
            text_y += 25

        pygame.display.flip()
        clock.tick(20)

def detect_motion(threshold=5000, sensitivity=20, warmup_time=2, max_attempts=500):
    cap = cv2.VideoCapture(0)
    if not cap.isOpened():
        print("❌ Δεν ήταν δυνατή η πρόσβαση στην κάμερα.")
        return False

    print("🔄 Προετοιμασία κάμερας...")
    time.sleep(warmup_time)  

    ret, frame1 = cap.read()
    ret, frame2 = cap.read()

    attempts = 0
    motion_detected = False

    print("🔍 Ανίχνευση κίνησης σε εξέλιξη...")

    while attempts < max_attempts:
        diff = cv2.absdiff(frame1, frame2)
        gray = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
        blur = cv2.GaussianBlur(gray, (5, 5), 0)
        _, thresh = cv2.threshold(blur, sensitivity, 255, cv2.THRESH_BINARY)
        dilated = cv2.dilate(thresh, None, iterations=3)
        contours, _ = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

        total_area = sum(cv2.contourArea(contour) for contour in contours)

        if total_area > threshold:
            print("🚨 Ανιχνεύτηκε κίνηση! Έναρξη προγράμματος.")
            motion_detected = True
            break

        frame1 = frame2
        ret, frame2 = cap.read()

        if not ret:
            print("❌ Απώλεια σύνδεσης με την κάμερα.")
            break

        attempts += 1

    cap.release()
    cv2.destroyAllWindows()

    if not motion_detected:
        print("⏳ Δεν ανιχνεύθηκε κίνηση εντός του προκαθορισμένου χρόνου.")

    return motion_detected

if detect_motion():
    conversation_thread = threading.Thread(target=conversation_loop)
    conversation_thread.start()
    show_avatar()
    conversation_thread.join()
else:
    print("❌ Motion detection failed or interrupted.")