Files
2026-11-13 18:48:00 +03:00

85 lines
2.9 KiB
Python

import argparse
import hashlib
import os
from pathlib import Path
import shutil
import subprocess
import sys
ROOT = Path(__file__).resolve().parent
BACKEND = ROOT / "backend"
FRONTEND = ROOT / "frontend"
VENV = ROOT / ".venv"
def install_dependencies(
inputs: tuple[Path, ...], stamp: Path, command: list[str], cwd: Path
) -> None:
fingerprint = hashlib.sha256()
for path in inputs:
fingerprint.update(hashlib.sha256(path.read_bytes()).digest())
current = fingerprint.hexdigest()
if stamp.is_file() and stamp.read_text(encoding="ascii") == current:
return
stamp.unlink(missing_ok=True)
subprocess.run(command, cwd=cwd, check=True)
stamp.write_text(current, encoding="ascii")
def main() -> int:
parser = argparse.ArgumentParser(description="Локальный запуск AI-заметок.")
parser.add_argument("--port", type=int, default=8000, help="Порт приложения (по умолчанию 8000).")
args = parser.parse_args()
if not 1 <= args.port <= 65535:
parser.error("Порт должен быть от 1 до 65535.")
if sys.version_info < (3, 11):
parser.exit(1, "Установите Python 3.11 или новее.\n")
npm = shutil.which("npm.cmd" if os.name == "nt" else "npm")
if not npm or not shutil.which("node"):
parser.exit(1, "Установите Node.js с npm и заново откройте терминал.\n")
env_file = ROOT / ".env"
if not env_file.exists():
shutil.copyfile(ROOT / ".env.example", env_file)
print("Создан .env. Для генерации добавьте ключ Groq в этот файл.", flush=True)
python = VENV / ("Scripts/python.exe" if os.name == "nt" else "bin/python")
if not python.is_file():
subprocess.run([sys.executable, "-m", "venv", str(VENV)], check=True)
install_dependencies(
(BACKEND / "requirements.txt",),
VENV / ".notes-dependencies",
[str(python), "-m", "pip", "install", "-r", "requirements.txt"],
BACKEND,
)
install_dependencies(
(FRONTEND / "package.json", FRONTEND / "package-lock.json"),
FRONTEND / "node_modules" / ".notes-dependencies",
[npm, "ci"],
FRONTEND,
)
subprocess.run([npm, "run", "build"], cwd=FRONTEND, check=True)
return subprocess.call(
[
str(python), "-m", "uvicorn", "app.main:app",
"--env-file", str(env_file), "--host", "127.0.0.1", "--port", str(args.port),
],
cwd=BACKEND,
env={**os.environ, "NOTES_WEB_DIST": str(FRONTEND / "dist")},
)
if __name__ == "__main__":
try:
raise SystemExit(main())
except subprocess.CalledProcessError as error:
print("Запуск остановлен. Причина указана выше.", file=sys.stderr)
raise SystemExit(error.returncode) from None
except KeyboardInterrupt:
raise SystemExit(130) from None