parent
b615610e1d
commit
0f52c3dc03
10
.env.example
10
.env.example
|
|
@ -5,5 +5,15 @@ DB_USER=root
|
||||||
DB_PASSWORD=
|
DB_PASSWORD=
|
||||||
DB_NAME=deteksi_pmk
|
DB_NAME=deteksi_pmk
|
||||||
|
|
||||||
|
# Railway / hosted MySQL support
|
||||||
|
# Railway biasanya menyediakan variabel ini otomatis saat plugin database dipasang.
|
||||||
|
MYSQLHOST=
|
||||||
|
MYSQLPORT=
|
||||||
|
MYSQLUSER=
|
||||||
|
MYSQLPASSWORD=
|
||||||
|
MYSQLDATABASE=
|
||||||
|
DATABASE_URL=
|
||||||
|
|
||||||
# Flask Configuration
|
# Flask Configuration
|
||||||
FLASK_SECRET=your-secret-key-here
|
FLASK_SECRET=your-secret-key-here
|
||||||
|
FLASK_DEBUG=0
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,21 @@ python app.py
|
||||||
|
|
||||||
Buka browser ke: **http://localhost:5000**
|
Buka browser ke: **http://localhost:5000**
|
||||||
|
|
||||||
|
## Deploy ke Railway
|
||||||
|
|
||||||
|
Repository ini sudah disiapkan untuk Railway dengan entrypoint Flask di `app.py`.
|
||||||
|
|
||||||
|
1. Hubungkan repository ini ke Railway.
|
||||||
|
2. Tambahkan layanan database MySQL di Railway jika ingin penyimpanan riwayat berjalan.
|
||||||
|
3. Set environment variable berikut di Railway:
|
||||||
|
- `FLASK_SECRET`
|
||||||
|
- `DATABASE_URL` atau `MYSQLHOST`, `MYSQLPORT`, `MYSQLUSER`, `MYSQLPASSWORD`, `MYSQLDATABASE`
|
||||||
|
4. Railway akan menjalankan `gunicorn app:app --bind 0.0.0.0:$PORT`.
|
||||||
|
|
||||||
|
Catatan:
|
||||||
|
- `opencv-python-headless` dipakai supaya build Railway tidak bergantung pada library GUI.
|
||||||
|
- Jika model belum ada di folder `models/`, jalankan training dulu sebelum deploy.
|
||||||
|
|
||||||
## Langkah 3: Upload Gambar & Lihat Riwayat
|
## Langkah 3: Upload Gambar & Lihat Riwayat
|
||||||
|
|
||||||
1. **Upload**: Klik "Upload Gambar" → Pilih file → Upload
|
1. **Upload**: Klik "Upload Gambar" → Pilih file → Upload
|
||||||
|
|
@ -45,6 +60,8 @@ DB_HOST=localhost
|
||||||
DB_USER=root
|
DB_USER=root
|
||||||
DB_PASSWORD=
|
DB_PASSWORD=
|
||||||
DB_NAME=deteksi_pmk
|
DB_NAME=deteksi_pmk
|
||||||
|
|
||||||
|
Untuk Railway, lebih aman pakai variabel environment yang disediakan oleh plugin database atau `DATABASE_URL`.
|
||||||
```
|
```
|
||||||
|
|
||||||
## 🔗 Useful Routes
|
## 🔗 Useful Routes
|
||||||
|
|
|
||||||
4
app.py
4
app.py
|
|
@ -911,4 +911,6 @@ def export_excel():
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(host='0.0.0.0', port=5000, debug=True)
|
port = int(os.environ.get('PORT', 5000))
|
||||||
|
debug = os.environ.get('FLASK_DEBUG', '0') == '1'
|
||||||
|
app.run(host='0.0.0.0', port=port, debug=debug)
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit ce2e5771dd78cd0ade90b677c15668361743e345
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://railway.app/railway.schema.json",
|
||||||
|
"build": {
|
||||||
|
"builder": "NIXPACKS"
|
||||||
|
},
|
||||||
|
"deploy": {
|
||||||
|
"startCommand": "gunicorn app:app --bind 0.0.0.0:$PORT",
|
||||||
|
"restartPolicyType": "ON_FAILURE",
|
||||||
|
"restartPolicyMaxRetries": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
opencv-python==4.9.0.80
|
opencv-python-headless==4.9.0.80
|
||||||
numpy<2
|
numpy<2
|
||||||
pandas>=2.1.0
|
pandas>=2.1.0
|
||||||
scikit-learn>=1.3.2
|
scikit-learn>=1.3.2
|
||||||
|
|
@ -10,3 +10,4 @@ Flask>=2.3.3
|
||||||
SQLAlchemy>=2.0.0
|
SQLAlchemy>=2.0.0
|
||||||
PyMySQL>=1.1.0
|
PyMySQL>=1.1.0
|
||||||
python-dotenv>=1.0.0
|
python-dotenv>=1.0.0
|
||||||
|
gunicorn>=21.2.0
|
||||||
|
|
@ -8,6 +8,7 @@ import json
|
||||||
import datetime
|
import datetime
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime, Text, Boolean, ForeignKey, Table, inspect, text
|
from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime, Text, Boolean, ForeignKey, Table, inspect, text
|
||||||
|
from sqlalchemy.engine import make_url
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
from sqlalchemy.orm import sessionmaker, relationship
|
from sqlalchemy.orm import sessionmaker, relationship
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
|
|
@ -16,18 +17,30 @@ from sqlalchemy.exc import SQLAlchemyError
|
||||||
import pytz
|
import pytz
|
||||||
TZ_INDONESIA = pytz.timezone('Asia/Jakarta')
|
TZ_INDONESIA = pytz.timezone('Asia/Jakarta')
|
||||||
|
|
||||||
# Database configuration from environment variables
|
DATABASE_URL = os.environ.get('DATABASE_URL')
|
||||||
DB_HOST = os.environ.get('DB_HOST', 'localhost')
|
|
||||||
DB_PORT = os.environ.get('DB_PORT', '3306')
|
|
||||||
DB_USER = os.environ.get('DB_USER', 'root')
|
def _build_database_uri():
|
||||||
DB_PASSWORD = os.environ.get('DB_PASSWORD', '')
|
"""Build a SQLAlchemy database URI from Railway or local environment variables."""
|
||||||
DB_NAME = os.environ.get('DB_NAME', 'deteksi_pmk')
|
if DATABASE_URL:
|
||||||
|
url = make_url(DATABASE_URL)
|
||||||
|
if url.drivername == 'mysql':
|
||||||
|
url = url.set(drivername='mysql+pymysql')
|
||||||
|
return str(url)
|
||||||
|
|
||||||
|
db_host = os.environ.get('DB_HOST') or os.environ.get('MYSQLHOST', 'localhost')
|
||||||
|
db_port = os.environ.get('DB_PORT') or os.environ.get('MYSQLPORT', '3306')
|
||||||
|
db_user = os.environ.get('DB_USER') or os.environ.get('MYSQLUSER', 'root')
|
||||||
|
db_password = os.environ.get('DB_PASSWORD') or os.environ.get('MYSQLPASSWORD', '')
|
||||||
|
db_name = os.environ.get('DB_NAME') or os.environ.get('MYSQLDATABASE', 'deteksi_pmk')
|
||||||
|
|
||||||
|
if db_password:
|
||||||
|
return f"mysql+pymysql://{db_user}:{db_password}@{db_host}:{db_port}/{db_name}"
|
||||||
|
return f"mysql+pymysql://{db_user}@{db_host}:{db_port}/{db_name}"
|
||||||
|
|
||||||
|
|
||||||
# Create database URI
|
# Create database URI
|
||||||
if DB_PASSWORD:
|
DATABASE_URI = _build_database_uri()
|
||||||
DATABASE_URI = f"mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
|
|
||||||
else:
|
|
||||||
DATABASE_URI = f"mysql+pymysql://{DB_USER}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
|
|
||||||
|
|
||||||
# Create engine
|
# Create engine
|
||||||
engine = create_engine(DATABASE_URI, echo=False, pool_pre_ping=True)
|
engine = create_engine(DATABASE_URI, echo=False, pool_pre_ping=True)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue