diff --git a/config.py b/config.py index 7cff5fe..7131ae3 100644 --- a/config.py +++ b/config.py @@ -90,7 +90,7 @@ if not ADMIN_USER_ID: SAFETY_MODE = os.getenv('SAFETY_MODE', 'production').lower() # 'production' или 'safe' # ===== ДИНАМИЧЕСКИЕ ПУТИ (ПЕРЕНОСИМОСТЬ) ===== -MUTT_DIR = os.getenv('MUTT_DIR', '/app/mutt' if os.path.exists('/app/mutt') else str(BASE_DIR.parent.parent / 'mutt')) +MUTT_DIR = os.getenv('MUTT_DIR', '/home/matrixhasyou/mutt' if os.path.exists('/home/matrixhasyou/mutt') else ('/app/mutt' if os.path.exists('/app/mutt') else str(BASE_DIR.parent.parent / 'mutt'))) GOOGLE_CREDS_FILE = os.getenv('GOOGLE_CREDS_FILE', '/app/config/google_creds.json' if os.path.exists('/app/config/google_creds.json') else str(BASE_DIR.parent.parent / 'domovoy_google_creds.json')) diff --git a/docker-compose.yml b/docker-compose.yml index f84617a..0c4ba3c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,6 +13,7 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock - ./.env:/app/.env:ro + - ./config.py:/app/config.py:ro - ./main.py:/app/main.py - ./logs:/app/logs - ./exports:/app/exports @@ -39,10 +40,12 @@ services: - PYTHONPATH=/app:/app/services - GOOGLE_CREDS_FILE=/home/matrixhasyou/domovoy_google_creds.json - GOOGLE_API_KEY=AIzaSyAJMfQ_mRZ1picRXVFNaeFJ7fpAkZxUKyk + - MUTT_DIR=/home/matrixhasyou/mutt - TZ=Europe/Ulyanovsk volumes: - /var/run/docker.sock:/var/run/docker.sock - ./.env:/app/.env:ro + - ./config.py:/app/config.py:ro - ./web:/app/web - ./podcasts:/app/podcasts - ./logs:/app/logs @@ -50,7 +53,8 @@ services: - ./data:/app/data - ./handlers:/app/handlers - ./services:/app/services - - /home/matrixhasyou/mutt:/home/matrixhasyou/mutt:ro + - /home/matrixhasyou/mutt:/home/matrixhasyou/mutt:rw + - /home/matrixhasyou/domovoy_drive_sync.py:/home/matrixhasyou/domovoy_drive_sync.py:ro - ../libs/swarmlib:/app/swarmlib:ro - /home/matrixhasyou/domovoy_google_creds.json:/home/matrixhasyou/domovoy_google_creds.json:ro - /home/matrixhasyou/.notebooklm:/root/.notebooklm:rw diff --git a/web/app.py b/web/app.py index c5c771d..df4c04e 100644 --- a/web/app.py +++ b/web/app.py @@ -115,40 +115,7 @@ async def upload_to_tg(content, filename, content_type): file_id = msg["photo"][-1]["file_id"] if file_type == "photo" else msg["document"]["file_id"] return file_id, file_type -@app.post("/api/emails/sync_ai") -async def api_sync_emails_to_ai(username: str = Depends(get_current_admin)): - sync_script = "/app/domovoy_drive_sync.py" if os.path.exists("/app/domovoy_drive_sync.py") else str(Path(config.MUTT_DIR).parent / "domovoy_drive_sync.py") - python_path = sys.executable - try: - # Запуск синхронизации - process = subprocess.run( - [python_path, sync_script], - capture_output=True, text=True, timeout=300 - ) - - if process.returncode == 0: - # Уведомляем админа в ТГ - msg = "🤖 AI Синхронизация Успешна!\n\n📄 Архив почты обновлен на Google Drive.\n👉 Не забудь нажать 'Sync' в NotebookLM!" - - # Отправка через API Telegram (упрощенно) - async with aiohttp.ClientSession() as session: - url = f"https://api.telegram.org/bot{config.BOT_TOKEN}/sendMessage" - params = { - "chat_id": config.ADMIN_USER_ID, - "text": msg, - "parse_mode": "HTML" - } - # Используем прокси если нужно - proxy = f"http://{config.PROXY_HOST}:{config.PROXY_PORT}" if config.USE_PROXY else None - await session.get(url, params=params, proxy=proxy) - - return {"success": True, "message": "Синхронизация завершена, уведомление отправлено."} - else: - return {"success": False, "error": process.stderr or process.stdout} - - except Exception as e: - return JSONResponse(status_code=500, content={"success": False, "error": str(e)}) # ============================================================================ # ГЛАВНАЯ ПАНЕЛЬ (DASHBOARD) @@ -679,7 +646,16 @@ async def emails_page(request: Request, username: str = Depends(get_current_admi latest_emails.append({"date": "-", "domain": "other", "subject": f.stem}) master_pdf_path = Path(config.MUTT_DIR) / "ALL_EMAILS_CONSOLIDATED.pdf" - last_update = datetime.fromtimestamp(master_pdf_path.stat().st_mtime, tz=timezone.utc) if master_pdf_path.exists() else None + parts = list(Path(config.MUTT_DIR).glob("ALL_EMAILS_CONSOLIDATED_part*.pdf")) + has_master_pdf = master_pdf_path.exists() or bool(parts) + pdf_size_mb = 0.0 + last_update = None + if master_pdf_path.exists(): + pdf_size_mb = round(master_pdf_path.stat().st_size / (1024 * 1024), 2) + last_update = datetime.fromtimestamp(master_pdf_path.stat().st_mtime, tz=timezone.utc) + elif parts: + pdf_size_mb = round(sum(p.stat().st_size for p in parts) / (1024 * 1024), 2) + last_update = datetime.fromtimestamp(max(p.stat().st_mtime for p in parts), tz=timezone.utc) # Drive sync status sync_time_file = Path(config.MUTT_DIR) / "last_ai_sync.txt" @@ -705,10 +681,6 @@ async def emails_page(request: Request, username: str = Depends(get_current_admi total_attachments = sum(int(m) for m in matches) except Exception as e: pass - - pdf_size_mb = 0.0 - if master_pdf_path.exists(): - pdf_size_mb = round(master_pdf_path.stat().st_size / (1024 * 1024), 2) last_email_date = None if audit_data: @@ -735,15 +707,17 @@ async def api_emails_run_full_sync(username: str = Depends(get_current_admin)): return JSONResponse(status_code=404, content={"message": "Master sync script not found"}) try: - # Run master sync script in background - subprocess.Popen([python_path, master_script], start_new_session=True) + # Run master sync script in background with logging + log_path = Path(config.MUTT_DIR) / "master_sync.log" + log_file = open(log_path, "a") + subprocess.Popen([python_path, master_script], stdout=log_file, stderr=log_file, start_new_session=True) return JSONResponse(content={"message": "Полная синхронизация (Сбор -> PDF -> G-Drive) запущена в фоне. Следите за уведомлениями в Telegram."}) except Exception as e: return JSONResponse(status_code=500, content={"message": str(e)}) @app.post("/api/emails/sync_ai") async def api_emails_sync_ai(username: str = Depends(get_current_admin)): - sync_script = "/app/domovoy_drive_sync.py" if os.path.exists("/app/domovoy_drive_sync.py") else str(Path(config.MUTT_DIR).parent / "domovoy_drive_sync.py") + sync_script = "/home/matrixhasyou/domovoy_drive_sync.py" if os.path.exists("/home/matrixhasyou/domovoy_drive_sync.py") else "/app/domovoy_drive_sync.py" python_path = sys.executable master_pdf = str(Path(config.MUTT_DIR) / "TOTAL_ARCHIVE_2025-2026.pdf") @@ -751,8 +725,10 @@ async def api_emails_sync_ai(username: str = Depends(get_current_admin)): return JSONResponse(status_code=404, content={"message": "Sync script not found"}) try: - # Run sync script in background - subprocess.Popen([python_path, sync_script, master_pdf], start_new_session=True) + # Run sync script in background with logging + log_path = Path(config.MUTT_DIR) / "master_sync.log" + log_file = open(log_path, "a") + subprocess.Popen([python_path, sync_script, master_pdf], stdout=log_file, stderr=log_file, start_new_session=True) return JSONResponse(content={"message": "Синхронизация с Google Drive запущена в фоне. Это займет около минуты."}) except Exception as e: return JSONResponse(status_code=500, content={"message": str(e)}) @@ -762,11 +738,14 @@ async def api_emails_pipeline_status(username: str = Depends(get_current_admin)) import time status_file = Path(config.MUTT_DIR) / "pipeline_status.json" master_pdf_path = Path(config.MUTT_DIR) / "ALL_EMAILS_CONSOLIDATED.pdf" + parts = list(Path(config.MUTT_DIR).glob("ALL_EMAILS_CONSOLIDATED_part*.pdf")) # Calculate fallback values pdf_size_mb = 0.0 if master_pdf_path.exists(): pdf_size_mb = round(master_pdf_path.stat().st_size / (1024 * 1024), 2) + elif parts: + pdf_size_mb = round(sum(p.stat().st_size for p in parts) / (1024 * 1024), 2) total_emails = 0 total_inbound = 0 diff --git a/web/templates/base.html b/web/templates/base.html index 0618c36..dd3aae8 100644 --- a/web/templates/base.html +++ b/web/templates/base.html @@ -208,7 +208,6 @@