diff --git a/website/Dockerfile b/website/Dockerfile new file mode 100644 index 0000000..4f8fde2 --- /dev/null +++ b/website/Dockerfile @@ -0,0 +1,27 @@ +# === Сборка фронтенда === +FROM node:18 AS frontend +WORKDIR /frontend +COPY frontend/ . +RUN npm install && npm run build + +# === Backend (Flask + модель) === +FROM python:3.10-slim +WORKDIR /app + +# Установим зависимости системы (для psycopg2 и модели) +RUN apt-get update && apt-get install -y gcc libpq-dev && apt-get clean + +# Копируем backend +COPY backend/ . + +# Устанавливаем Python зависимости +RUN pip install --no-cache-dir -r requirements.txt + +# Копируем собранный фронтенд +COPY --from=frontend /frontend/dist /app/static + +# Объявляем порт +ENV PORT=8080 + +# Стартуем Flask, а не Vite! +CMD ["python", "app.py"] diff --git a/website/docker-compose.yaml b/website/docker-compose.yaml new file mode 100644 index 0000000..7e83131 --- /dev/null +++ b/website/docker-compose.yaml @@ -0,0 +1,33 @@ +version: "3.8" + +services: + frontend: + build: ./frontend + ports: + - "5174:5174" + depends_on: + - backend + restart: always + + backend: + build: ./backend + ports: + - "5000:5000" + depends_on: + - db + restart: always + environment: + - DATABASE_URL=postgresql://user:password@db:5432/mydb + + db: + image: postgres:15 + restart: always + environment: + POSTGRES_DB: mydb + POSTGRES_USER: user + POSTGRES_PASSWORD: password + volumes: + - db_data:/var/lib/postgresql/data + +volumes: + db_data: diff --git a/website/history.json b/website/history.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/website/history.json @@ -0,0 +1 @@ +[] diff --git a/website/package-lock.json b/website/package-lock.json new file mode 100644 index 0000000..92bebc4 --- /dev/null +++ b/website/package-lock.json @@ -0,0 +1,124 @@ +{ + "name": "zkt25", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.7.2", + "@fortawesome/free-brands-svg-icons": "^6.7.2", + "@fortawesome/react-fontawesome": "^0.2.2", + "react-icons": "^5.5.0" + } + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz", + "integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz", + "integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==", + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.7.2.tgz", + "integrity": "sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz", + "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/react": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", + "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-icons": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz", + "integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + } + } +} diff --git a/website/package.json b/website/package.json new file mode 100644 index 0000000..82f2a3b --- /dev/null +++ b/website/package.json @@ -0,0 +1,8 @@ +{ + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.7.2", + "@fortawesome/free-brands-svg-icons": "^6.7.2", + "@fortawesome/react-fontawesome": "^0.2.2", + "react-icons": "^5.5.0" + } +} diff --git a/website/prepare-app-cloud.sh b/website/prepare-app-cloud.sh new file mode 100644 index 0000000..1dbee72 --- /dev/null +++ b/website/prepare-app-cloud.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Nastavenia +REGION="europe-central2" +PROJECT_ID="hatespeechsite" +REPO_NAME="hatespeech-registry" +IMAGE_NAME="hate-detektor" +IMAGE_URI="$REGION-docker.pkg.dev/$PROJECT_ID/$REPO_NAME/$IMAGE_NAME" +INSTANCE_CONNECTION="hatespeechsite:europe-central2:hate-db" +DATABASE_URL="postgresql://user:password@/mydb?host=/cloudsql/$INSTANCE_CONNECTION" + +echo "Build" +gcloud builds submit --tag $IMAGE_URI + +echo "Deploy" +gcloud run deploy $IMAGE_NAME \ + --image $IMAGE_URI \ + --platform managed \ + --region $REGION \ + --allow-unauthenticated \ + --port 8080 \ + --memory=2Gi \ + --timeout=600s \ + --add-cloudsql-instances=$INSTANCE_CONNECTION \ + --set-env-vars=DATABASE_URL=$DATABASE_URL diff --git a/website/remove-app-cloud.sh b/website/remove-app-cloud.sh new file mode 100644 index 0000000..392bd10 --- /dev/null +++ b/website/remove-app-cloud.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +REGION="europe-central2" +SERVICE_NAME="hate-detektor" + +echo "Vymazanie servisa Cloud Run..." +gcloud run services delete $SERVICE_NAME \ + --platform managed \ + --region $REGION \ + --quiet