Загрузка данных


import json
import os
import shutil
import webbrowser
import datetime
import subprocess
import speech_recognition as sr
from gtts import gTTS
import pygame
from google import genai
import pyautogui
import psutil
import time

# Ваш API-ключ Google AI Studio
client = genai.Client(api_key="AQ.Ab8RN6I6Y9j9sE5GH8dPNYMtp13I4DGqzthmFvvjJ17UIVZ6fA")

# Файлы для постоянного хранения памяти и настроек
MEMORY_FILE = "nova_memory.json"
SETTINGS_FILE = "nova_settings.json"

def load_settings():
    """Загружает настройки (имя пользователя и язык)"""
    if os.path.exists(SETTINGS_FILE):
        try:
            with open(SETTINGS_FILE, "r", encoding="utf-8") as f:
                return json.load(f)
        except Exception:
            return {"user_name": "друг", "lang": "ru"}
    return {"user_name": "друг", "lang": "ru"}

def save_settings(settings):
    """Сохраняет настройки"""
    try:
        with open(SETTINGS_FILE, "w", encoding="utf-8") as f:
            json.dump(settings, f, ensure_ascii=False, indent=2)
    except Exception as e:
        print(f"Ошибка сохранения настроек: {e}")

def load_memory():
    """Загружает историю диалога из файла при запуске"""
    if os.path.exists(MEMORY_FILE):
        try:
            with open(MEMORY_FILE, "r", encoding="utf-8") as f:
                return json.load(f)
        except Exception:
            return []
    return []

def save_memory():
    """Сохраняет текущую историю диалога в файл"""
    try:
        with open(MEMORY_FILE, "w", encoding="utf-8") as f:
            json.dump(chat_history, f, ensure_ascii=False, indent=2)
    except Exception as e:
        print(f"Ошибка сохранения памяти: {e}")

# Инициализация состояния
chat_history = load_memory()
app_settings = load_settings()
user_name = app_settings.get("user_name", "друг")
current_lang = app_settings.get("lang", "ru")

def speak(text, lang=None):
    use_lang = lang if lang else current_lang
    print(f"Нова [{use_lang}]: {text}")
    try:
        tts = gTTS(text=text, lang=use_lang)
        audio_file = "temp_voice.mp3"
        tts.save(audio_file)
        
        pygame.mixer.init()
        pygame.mixer.music.load(audio_file)
        pygame.mixer.music.play()
        while pygame.mixer.music.get_busy():
            pygame.time.Clock().tick(10)
        pygame.mixer.quit()
        
        if os.path.exists(audio_file):
            os.remove(audio_file)
    except Exception as e:
        print(f"Ошибка озвучки: {e}")

def listen():
    r = sr.Recognizer()
    with sr.Microphone() as source:
        print("\nСлушаю...")
        r.adjust_for_ambient_noise(source, duration=0.5)
        try:
            audio = r.listen(source, timeout=5, phrase_time_limit=10)
        except sr.WaitTimeoutError:
            return ""
            
    try:
        rec_lang = "ru-RU" if current_lang == "ru" else "en-US"
        command = r.recognize_google(audio, language=rec_lang)
        print(f"Вы сказали: {command}")
        return command
    except sr.UnknownValueError:
        return ""
    except sr.RequestError:
        print("Ошибка соединения с сервисом распознавания речи.")
        return ""

def parse_intent_with_ai(user_speech):
    global chat_history, user_name, current_lang
    chat_history.append(f"{user_name}: {user_speech}")
    
    context_slice = chat_history[-10:]
    context_str = "\n".join(context_slice)

    prompt = f"""
    Ты — Нова, элитный голосовой ассистент на ПК. Пользователя зовут "{user_name}". Текущий язык: "{current_lang}".
    Проанализируй фразу и верни СТРОГО JSON без markdown-оформления (без ```json):
    {{
      "action": одно из значений: 
        "open_chat", "change_language", "set_name", "open_youtube", "google_search", "open_app", 
        "open_folder", "empty_recycle_bin", "shutdown_pc", "cancel_shutdown", "sleep_pc", 
        "time_info", "battery_info", "take_screenshot", "create_note", "copy_files", "exit", "chat",
      "messenger": "название мессенджера (telegram, discord, whatsapp)",
      "chat_target": "имя контакта или чата, который нужно найти",
      "new_lang": "код языка (ru, en, de и т.д., иначе пусто)",
      "new_name": "имя пользователя, если просит изменить (иначе пусто)",
      "query": "поисковый запрос для ютуба или гугла",
      "app_name": "название программы",
      "folder_name": "название папки",
      "minutes": число,
      "note_text": "текст заметки",
      "source_path": "путь откуда",
      "dest_path": "путь куда",
      "text": "развернутый ответ пользователю"
    }}

    История разговора:
    {context_str}
    
    Текущая фраза: "{user_speech}"
    """
    try:
        response = client.models.generate_content(model='gemini-2.5-flash', contents=prompt)
        clean_text = response.text.replace("```json", "").replace("```", "").strip()
        result = json.loads(clean_text)
        
        if result.get("action") == "change_language":
            n_lang = result.get("new_lang")
            if n_lang:
                current_lang = n_lang.lower()
                app_settings["lang"] = current_lang
                save_settings(app_settings)
                
        if result.get("action") == "set_name":
            new_n = result.get("new_name")
            if new_n:
                user_name = new_n
                app_settings["user_name"] = user_name
                save_settings(app_settings)
                
        if result.get("action") in ["chat", "set_name", "change_language", "open_chat"]:
            chat_history.append(f"Нова: {result.get('text')}")
            
        save_memory()
        return result
    except Exception as e:
        print(f"Ошибка ИИ: {e}")
        return {"action": "chat", "text": "Я не совсем поняла команду, повторите пожалуйста."}

def execute_action(intent):
    action = intent.get("action")
    
    if action == "open_chat":
        messenger = intent.get("messenger", "").lower()
        target = intent.get("chat_target", "")
        speak(f"Открываю чат с пользователем {target} в приложении {messenger}.")
        
        if "telegram" in messenger:
            os.system("start telegram")
            time.sleep(2)
            pyautogui.hotkey('ctrl', 'k')
            time.sleep(0.5)
            pyautogui.write(target, interval=0.1)
            time.sleep(1)
            pyautogui.press('enter')
        elif "discord" in messenger or "дискорд" in messenger:
            os.system("start discord")
            time.sleep(2)
            pyautogui.hotkey('ctrl', 'k')
            time.sleep(0.5)
            pyautogui.write(target, interval=0.1)
            time.sleep(1)
            pyautogui.press('enter')
        else:
            speak("Не удалось определить мессенджер для открытия чата.")

    elif action == "change_language":
        speak(intent.get("text", "Я сменила язык."))
        
    elif action == "open_youtube":
        q = intent.get("query", "")
        webbrowser.open(f"[https://www.youtube.com/results?search_query=](https://www.youtube.com/results?search_query=){q}")
        speak(f"Ищу на ютубе: {q}")
        
    elif action == "google_search":
        q = intent.get("query", "")
        webbrowser.open(f"[https://www.google.com/search?q=](https://www.google.com/search?q=){q}")
        speak("Ищу в интернете.")
        
    elif action == "open_app":
        app = intent.get("app_name", "").lower()
        if "steam" in app: os.system("start steam://")
        elif "calc" in app or "калькулятор" in app: os.system("calc")
        elif "discord" in app: os.system("start discord")
        elif "telegram" in app: os.system("start telegram")
        elif "chrome" in app or "браузер" in app: os.system("start chrome")
        elif "notepad" in app or "блокнот" in app: os.system("notepad")
        elif "code" in app or "vs code" in app: os.system("code")
        speak("Запускаю приложение.")
        
    elif action == "open_folder":
        folder = intent.get("folder_name", "").lower()
        userprofile = os.environ.get("USERPROFILE", "C:\\Users\\Default")
        path_to_open = ""
        if "загруз" in folder or "downloads" in folder:
            path_to_open = os.path.join(userprofile, "Downloads")
        elif "документ" in folder or "documents" in folder:
            path_to_open = os.path.join(userprofile, "Documents")
        elif "рабочий стол" in folder or "desktop" in folder:
            path_to_open = os.path.join(userprofile, "Desktop")
        else:
            path_to_open = folder
            
        if path_to_open and os.path.exists(path_to_open):
            os.startfile(path_to_open)
            speak("Открываю папку.")
        else:
            speak("Не удалось найти указанную папку.")
            
    elif action == "empty_recycle_bin":
        try:
            os.system("PowerShell -Command \"Clear-RecycleBin -Force -ErrorAction SilentlyContinue\"")
            speak("Корзина успешно очищена.")
        except Exception as e:
            speak(f"Не удалось очистить корзину: {e}")
            
    elif action == "shutdown_pc":
        minutes = int(intent.get("minutes", 0))
        if minutes > 0:
            os.system(f"shutdown /s /t {minutes * 60}")
            speak(f"Компьютер выключится через {minutes} минут.")
        else:
            os.system("shutdown /s /t 60")
            speak("Компьютер выключится через минуту.")
            
    elif action == "cancel_shutdown":
        os.system("shutdown /a")
        speak("Отменила выключение компьютера.")
        
    elif action == "sleep_pc":
        speak("Перевожу компьютер в спящий режим.")
        os.system("rundll32.exe powrprof.dll,SetSuspendState 0,1,0")
        
    elif action == "time_info":
        now = datetime.datetime.now().strftime("%H:%M")
        speak(f"Текущее время: {now}")
        
    elif action == "battery_info":
        battery = psutil.sensors_battery()
        if battery:
            plugged = "подключен к зарядке" if battery.power_plugged else "работает от батареи"
            speak(f"Заряд батареи {battery.percent} процентов, компьютер {plugged}.")
        else:
            speak("Не удалось определить состояние батареи.")
            
    elif action == "take_screenshot":
        try:
            os.makedirs("screenshots", exist_ok=True)
            filename = f"screenshots/shot_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.png"
            pyautogui.screenshot().save(filename)
            speak("Скриншот успешно сохранен.")
        except Exception as e:
            speak(f"Не удалось сделать скриншот: {e}")
            
    elif action == "create_note":
        text = intent.get("note_text", "Пустая заметка")
        with open("nova_notes.txt", "a", encoding="utf-8") as f:
            f.write(f"[{datetime.datetime.now().strftime('%Y-%m-%d %H:%M')}] {text}\n")
        speak("Записала в блокнот.")
        
    elif action == "copy_files":
        src = intent.get("source_path")
        dst = intent.get("dest_path")
        try:
            if src and dst and os.path.exists(src):
                if os.path.isdir(src):
                    shutil.copytree(src, dst, dirs_exist_ok=True)
                else:
                    shutil.copy(src, dst)
                speak("Файлы успешно скопированы.")
            else:
                speak("Не найден указанный путь.")
        except Exception as e:
            speak(f"Ошибка копирования: {e}")
            
    elif action == "set_name":
        speak(intent.get("text", "Готово."))
        
    elif action == "exit":
        speak(f"До свидания, {user_name}!")
        exit()
        
    elif action == "chat":
        speak(intent.get("text", "Слушаю вас."))

if __name__ == "__main__":
    speak(f"Нова активирована. Рада вас слышать, {user_name}!")
    while True:
        cmd = listen()
        if cmd:
            intent_data = parse_intent_with_ai(cmd)
            execute_action(intent_data)