Refactor: Decouple paths and tokens from codebase for hosting portability
This commit is contained in:
parent
ed565c54c3
commit
1c342fd3c1
6 changed files with 40 additions and 25 deletions
|
|
@ -85,6 +85,11 @@ if not ADMIN_USER_ID:
|
||||||
# ===== БЕЗОПАСНОСТЬ =====
|
# ===== БЕЗОПАСНОСТЬ =====
|
||||||
SAFETY_MODE = os.getenv('SAFETY_MODE', 'production').lower() # 'production' или 'safe'
|
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'))
|
||||||
|
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'))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_proxy_url() -> str | None:
|
def get_proxy_url() -> str | None:
|
||||||
"""Получить URL прокси для aiohttp"""
|
"""Получить URL прокси для aiohttp"""
|
||||||
|
|
|
||||||
|
|
@ -100,8 +100,15 @@ async def process_jurist_question(message: Message, state: FSMContext):
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
# Динамический поиск бинарника nlm
|
||||||
|
nlm_bin = "nlm"
|
||||||
|
for p in ["/app/bin/nlm", "/usr/local/bin/nlm", os.path.expanduser("~/.local/bin/nlm"), "/home/matrixhasyou/.local/bin/nlm"]:
|
||||||
|
if os.path.exists(p):
|
||||||
|
nlm_bin = p
|
||||||
|
break
|
||||||
|
|
||||||
cmd = [
|
cmd = [
|
||||||
"/home/matrixhasyou/.local/bin/nlm", "query", "notebook",
|
nlm_bin, "query", "notebook",
|
||||||
"00ed7d92-1ab2-4159-ac72-1d0c4be21377",
|
"00ed7d92-1ab2-4159-ac72-1d0c4be21377",
|
||||||
message.text
|
message.text
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 1d8871f348b4df9561aec957f2a7f07790862899
|
Subproject commit 93a3d14d571832433bfcd3d1fe5a244d234fc020
|
||||||
|
|
@ -5,7 +5,7 @@ from googleapiclient.discovery import build
|
||||||
from googleapiclient.http import MediaFileUpload
|
from googleapiclient.http import MediaFileUpload
|
||||||
|
|
||||||
SCOPES = ['https://www.googleapis.com/auth/drive']
|
SCOPES = ['https://www.googleapis.com/auth/drive']
|
||||||
SERVICE_ACCOUNT_FILE = '/home/matrixhasyou/domovoy_google_creds.json'
|
SERVICE_ACCOUNT_FILE = os.getenv('GOOGLE_CREDS_FILE', '/app/config/google_creds.json' if os.path.exists('/app/config/google_creds.json') else '/home/matrixhasyou/domovoy_google_creds.json')
|
||||||
PARENT_FOLDER_ID = '1lnHt9Os0L_SnBa8i2dHrI0lBepuVm0Om'
|
PARENT_FOLDER_ID = '1lnHt9Os0L_SnBa8i2dHrI0lBepuVm0Om'
|
||||||
GIS_FILE_NAME = "TOTAL_GIS_ARCHIVE.pdf"
|
GIS_FILE_NAME = "TOTAL_GIS_ARCHIVE.pdf"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,18 @@ from pdf_tagger import tag_image_to_pdf
|
||||||
from gdrive_uploader import upload_gis_archive
|
from gdrive_uploader import upload_gis_archive
|
||||||
|
|
||||||
# --- CONFIG (LEGAL PATHS ONLY) ---
|
# --- CONFIG (LEGAL PATHS ONLY) ---
|
||||||
LOCAL_ARCHIVE = Path("/home/matrixhasyou/domovoy_bot/services/gis_harvester/archive")
|
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
||||||
TEMP_DIR = Path("/home/matrixhasyou/domovoy_bot/services/gis_pdf_pipeline/temp")
|
LOCAL_ARCHIVE = BASE_DIR / "services" / "gis_harvester" / "archive"
|
||||||
OUTPUT_FILE = Path("/home/matrixhasyou/domovoy_bot/services/gis_pdf_pipeline/TOTAL_GIS_ARCHIVE.pdf")
|
TEMP_DIR = BASE_DIR / "services" / "gis_pdf_pipeline" / "temp"
|
||||||
|
OUTPUT_FILE = BASE_DIR / "services" / "gis_pdf_pipeline" / "TOTAL_GIS_ARCHIVE.pdf"
|
||||||
NAS_LEGAL_PATH = "/volume1/web/legal/gis/TOTAL_GIS_ARCHIVE.pdf"
|
NAS_LEGAL_PATH = "/volume1/web/legal/gis/TOTAL_GIS_ARCHIVE.pdf"
|
||||||
NAS_IP = "192.168.10.105"
|
NAS_IP = "192.168.10.105"
|
||||||
|
|
||||||
def send_tg(msg):
|
def send_tg(msg):
|
||||||
subprocess.run(["curl", "-s", "-X", "POST", f"https://api.telegram.org/bot8725618164:AAH1tGalq-pw1l0t4P5c0sdLkCVJdh7IE7M/sendMessage",
|
token = os.getenv("BOT_TOKEN", "8725618164:AAH1tGalq-pw1l0t4P5c0sdLkCVJdh7IE7M")
|
||||||
"-d", f"chat_id=197957361&text={msg}&parse_mode=markdown"])
|
chat_id = os.getenv("ADMIN_USER_ID", "197957361")
|
||||||
|
subprocess.run(["curl", "-s", "-X", "POST", f"https://api.telegram.org/bot{token}/sendMessage",
|
||||||
|
"-d", f"chat_id={chat_id}&text={msg}&parse_mode=markdown"])
|
||||||
|
|
||||||
def run_pipeline():
|
def run_pipeline():
|
||||||
send_tg("🧬 **PDF-КОНВЕЙЕР (LEGAL MODE)**\nНачинаю сборку из /services/gis_harvester/archive...")
|
send_tg("🧬 **PDF-КОНВЕЙЕР (LEGAL MODE)**\nНачинаю сборку из /services/gis_harvester/archive...")
|
||||||
|
|
|
||||||
34
web/app.py
34
web/app.py
|
|
@ -117,8 +117,8 @@ async def upload_to_tg(content, filename, content_type):
|
||||||
|
|
||||||
@app.post("/api/emails/sync_ai")
|
@app.post("/api/emails/sync_ai")
|
||||||
async def api_sync_emails_to_ai(username: str = Depends(get_current_admin)):
|
async def api_sync_emails_to_ai(username: str = Depends(get_current_admin)):
|
||||||
sync_script = "/home/matrixhasyou/domovoy_drive_sync.py"
|
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 = "/home/matrixhasyou/domovoy_bot/venv-google/bin/python"
|
python_path = sys.executable
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Запуск синхронизации
|
# Запуск синхронизации
|
||||||
|
|
@ -667,7 +667,7 @@ async def emails_page(request: Request, username: str = Depends(get_current_admi
|
||||||
audit_data = (await session.execute(select(EmailAudit).order_by(EmailAudit.last_email_date.desc()))).scalars().all()
|
audit_data = (await session.execute(select(EmailAudit).order_by(EmailAudit.last_email_date.desc()))).scalars().all()
|
||||||
last_log = (await session.execute(select(EmailExportLog).order_by(EmailExportLog.start_time.desc()).limit(1))).scalar_one_or_none()
|
last_log = (await session.execute(select(EmailExportLog).order_by(EmailExportLog.start_time.desc()).limit(1))).scalar_one_or_none()
|
||||||
latest_emails = []
|
latest_emails = []
|
||||||
all_folder = Path("/home/matrixhasyou/mutt/exported_emails/all")
|
all_folder = Path(config.MUTT_DIR) / "exported_emails" / "all"
|
||||||
if all_folder.exists():
|
if all_folder.exists():
|
||||||
files = sorted(all_folder.glob("*.pdf"), key=lambda x: x.stat().st_mtime, reverse=True)[:10]
|
files = sorted(all_folder.glob("*.pdf"), key=lambda x: x.stat().st_mtime, reverse=True)[:10]
|
||||||
for f in files:
|
for f in files:
|
||||||
|
|
@ -678,11 +678,11 @@ async def emails_page(request: Request, username: str = Depends(get_current_admi
|
||||||
else:
|
else:
|
||||||
latest_emails.append({"date": "-", "domain": "other", "subject": f.stem})
|
latest_emails.append({"date": "-", "domain": "other", "subject": f.stem})
|
||||||
|
|
||||||
master_pdf_path = Path("/home/matrixhasyou/mutt/ALL_EMAILS_CONSOLIDATED.pdf")
|
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
|
last_update = datetime.fromtimestamp(master_pdf_path.stat().st_mtime, tz=timezone.utc) if master_pdf_path.exists() else None
|
||||||
|
|
||||||
# Drive sync status
|
# Drive sync status
|
||||||
sync_time_file = Path("/home/matrixhasyou/mutt/last_ai_sync.txt")
|
sync_time_file = Path(config.MUTT_DIR) / "last_ai_sync.txt"
|
||||||
last_sync_time = None
|
last_sync_time = None
|
||||||
if sync_time_file.exists():
|
if sync_time_file.exists():
|
||||||
try:
|
try:
|
||||||
|
|
@ -697,7 +697,7 @@ async def emails_page(request: Request, username: str = Depends(get_current_admi
|
||||||
total_emails = total_inbound + total_outbound
|
total_emails = total_inbound + total_outbound
|
||||||
|
|
||||||
total_attachments = 0
|
total_attachments = 0
|
||||||
export_log_path = Path("/home/matrixhasyou/mutt/export.log")
|
export_log_path = Path(config.MUTT_DIR) / "export.log"
|
||||||
if export_log_path.exists():
|
if export_log_path.exists():
|
||||||
try:
|
try:
|
||||||
content = export_log_path.read_text(errors='ignore')
|
content = export_log_path.read_text(errors='ignore')
|
||||||
|
|
@ -728,7 +728,7 @@ async def emails_page(request: Request, username: str = Depends(get_current_admi
|
||||||
|
|
||||||
@app.post("/api/emails/run_full_sync")
|
@app.post("/api/emails/run_full_sync")
|
||||||
async def api_emails_run_full_sync(username: str = Depends(get_current_admin)):
|
async def api_emails_run_full_sync(username: str = Depends(get_current_admin)):
|
||||||
master_script = "/home/matrixhasyou/mutt/master_ai_sync.py"
|
master_script = str(Path(config.MUTT_DIR) / "master_ai_sync.py")
|
||||||
python_path = sys.executable
|
python_path = sys.executable
|
||||||
|
|
||||||
if not os.path.exists(master_script):
|
if not os.path.exists(master_script):
|
||||||
|
|
@ -743,9 +743,9 @@ async def api_emails_run_full_sync(username: str = Depends(get_current_admin)):
|
||||||
|
|
||||||
@app.post("/api/emails/sync_ai")
|
@app.post("/api/emails/sync_ai")
|
||||||
async def api_emails_sync_ai(username: str = Depends(get_current_admin)):
|
async def api_emails_sync_ai(username: str = Depends(get_current_admin)):
|
||||||
sync_script = "/home/matrixhasyou/domovoy_drive_sync.py"
|
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
|
python_path = sys.executable
|
||||||
master_pdf = "/home/matrixhasyou/mutt/TOTAL_ARCHIVE_2025-2026.pdf"
|
master_pdf = str(Path(config.MUTT_DIR) / "TOTAL_ARCHIVE_2025-2026.pdf")
|
||||||
|
|
||||||
if not os.path.exists(sync_script):
|
if not os.path.exists(sync_script):
|
||||||
return JSONResponse(status_code=404, content={"message": "Sync script not found"})
|
return JSONResponse(status_code=404, content={"message": "Sync script not found"})
|
||||||
|
|
@ -760,8 +760,8 @@ async def api_emails_sync_ai(username: str = Depends(get_current_admin)):
|
||||||
@app.get("/api/emails/pipeline_status")
|
@app.get("/api/emails/pipeline_status")
|
||||||
async def api_emails_pipeline_status(username: str = Depends(get_current_admin)):
|
async def api_emails_pipeline_status(username: str = Depends(get_current_admin)):
|
||||||
import time
|
import time
|
||||||
status_file = Path("/home/matrixhasyou/mutt/pipeline_status.json")
|
status_file = Path(config.MUTT_DIR) / "pipeline_status.json"
|
||||||
master_pdf_path = Path("/home/matrixhasyou/mutt/ALL_EMAILS_CONSOLIDATED.pdf")
|
master_pdf_path = Path(config.MUTT_DIR) / "ALL_EMAILS_CONSOLIDATED.pdf"
|
||||||
|
|
||||||
# Calculate fallback values
|
# Calculate fallback values
|
||||||
pdf_size_mb = 0.0
|
pdf_size_mb = 0.0
|
||||||
|
|
@ -778,7 +778,7 @@ async def api_emails_pipeline_status(username: str = Depends(get_current_admin))
|
||||||
total_emails = total_inbound + total_outbound
|
total_emails = total_inbound + total_outbound
|
||||||
|
|
||||||
total_attachments = 0
|
total_attachments = 0
|
||||||
export_log_path = Path("/home/matrixhasyou/mutt/export.log")
|
export_log_path = Path(config.MUTT_DIR) / "export.log"
|
||||||
if export_log_path.exists():
|
if export_log_path.exists():
|
||||||
try:
|
try:
|
||||||
content = export_log_path.read_text(errors='ignore')
|
content = export_log_path.read_text(errors='ignore')
|
||||||
|
|
@ -787,7 +787,7 @@ async def api_emails_pipeline_status(username: str = Depends(get_current_admin))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
sync_time_file = Path("/home/matrixhasyou/mutt/last_ai_sync.txt")
|
sync_time_file = Path(config.MUTT_DIR) / "last_ai_sync.txt"
|
||||||
last_sync_time = "-"
|
last_sync_time = "-"
|
||||||
if sync_time_file.exists():
|
if sync_time_file.exists():
|
||||||
try:
|
try:
|
||||||
|
|
@ -844,9 +844,9 @@ async def get_infra_page(request: Request, username: str = Depends(get_current_a
|
||||||
|
|
||||||
@app.post("/api/infra/run_speedtest")
|
@app.post("/api/infra/run_speedtest")
|
||||||
async def api_run_speedtest(username: str = Depends(get_current_admin)):
|
async def api_run_speedtest(username: str = Depends(get_current_admin)):
|
||||||
script_path = "/home/matrixhasyou/infra/speedtest_monitor.py"
|
script_path = "/app/infra/speedtest_monitor.py" if os.path.exists("/app/infra/speedtest_monitor.py") else "/home/matrixhasyou/infra/speedtest_monitor.py"
|
||||||
try:
|
try:
|
||||||
subprocess.Popen(["python3", script_path], start_new_session=True)
|
subprocess.Popen([sys.executable if os.path.exists("/app/infra/speedtest_monitor.py") else "python3", script_path], start_new_session=True)
|
||||||
return JSONResponse(content={"message": "Тест скорости запущен в фоне. Результаты появятся через минуту."})
|
return JSONResponse(content={"message": "Тест скорости запущен в фоне. Результаты появятся через минуту."})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return JSONResponse(status_code=500, content={"message": str(e)})
|
return JSONResponse(status_code=500, content={"message": str(e)})
|
||||||
|
|
@ -859,8 +859,8 @@ async def api_run_gis_harvest(username: str = Depends(get_current_admin)):
|
||||||
subprocess.Popen(["docker", "exec", "-d", "lkm37-gis-scraper", "python3", "/app/services/gis_harvester/harvester_v5.py"])
|
subprocess.Popen(["docker", "exec", "-d", "lkm37-gis-scraper", "python3", "/app/services/gis_harvester/harvester_v5.py"])
|
||||||
|
|
||||||
# 2. Запуск PDF-конвейера
|
# 2. Запуск PDF-конвейера
|
||||||
pipeline_script = "/home/matrixhasyou/domovoy_bot/services/gis_pdf_pipeline/pipeline_main.py"
|
pipeline_script = str(Path(__file__).resolve().parent.parent / "services" / "gis_pdf_pipeline" / "pipeline_main.py")
|
||||||
venv_python = "/home/matrixhasyou/domovoy_bot/services/gis_pdf_pipeline/venv/bin/python3"
|
venv_python = sys.executable
|
||||||
subprocess.Popen([venv_python, pipeline_script], start_new_session=True)
|
subprocess.Popen([venv_python, pipeline_script], start_new_session=True)
|
||||||
|
|
||||||
return JSONResponse(content={"message": "Процесс ГИС ЖКХ запущен (Жатва + PDF). Следите за Telegram."})
|
return JSONResponse(content={"message": "Процесс ГИС ЖКХ запущен (Жатва + PDF). Следите за Telegram."})
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue