fix(web): запуск синхронизации почты с веб-кнопки (rw-монтирование mutt, MUTT_DIR env, поддержка split PDF)
This commit is contained in:
parent
99fd5ebe88
commit
8cb5ee7036
4 changed files with 29 additions and 47 deletions
|
|
@ -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'))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
65
web/app.py
65
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 = "🤖 <b>AI Синхронизация Успешна!</b>\n\n📄 Архив почты обновлен на Google Drive.\n👉 Не забудь нажать <b>'Sync'</b> в 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"
|
||||
|
|
@ -706,10 +682,6 @@ async def emails_page(request: Request, username: str = Depends(get_current_admi
|
|||
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:
|
||||
dates = [d.last_email_date for d in audit_data if d.last_email_date]
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -208,7 +208,6 @@
|
|||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h4>МКД ЛЕНКОМ 37</h4>
|
||||
<small>СИСТЕМА УПРАВЛЕНИЯ & ЯДЕРНЫЙ ЩИТ</small>
|
||||
</div>
|
||||
|
||||
<nav>
|
||||
|
|
@ -216,7 +215,7 @@
|
|||
<i class="bi bi-terminal"></i> Дашборд
|
||||
</a>
|
||||
|
||||
<div class="nav-section-title">Юридический щит</div>
|
||||
<div class="nav-section-title">Правовая база</div>
|
||||
<a class="nav-link {% block nav_legal %}{% endblock %}" href="/legal">
|
||||
<i class="bi bi-shield-check"></i> Законы РФ & ИИ-Юрист
|
||||
</a>
|
||||
|
|
|
|||
Loading…
Reference in a new issue