parent
b615610e1d
commit
0f52c3dc03
10
.env.example
10
.env.example
|
|
@ -5,5 +5,15 @@ DB_USER=root
|
|||
DB_PASSWORD=
|
||||
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_SECRET=your-secret-key-here
|
||||
FLASK_DEBUG=0
|
||||
|
|
|
|||
|
|
@ -22,6 +22,21 @@ python app.py
|
|||
|
||||
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
|
||||
|
||||
1. **Upload**: Klik "Upload Gambar" → Pilih file → Upload
|
||||
|
|
@ -45,6 +60,8 @@ DB_HOST=localhost
|
|||
DB_USER=root
|
||||
DB_PASSWORD=
|
||||
DB_NAME=deteksi_pmk
|
||||
|
||||
Untuk Railway, lebih aman pakai variabel environment yang disediakan oleh plugin database atau `DATABASE_URL`.
|
||||
```
|
||||
|
||||
## 🔗 Useful Routes
|
||||
|
|
|
|||
4
app.py
4
app.py
|
|
@ -911,4 +911,6 @@ def export_excel():
|
|||
|
||||
|
||||
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
|
||||
pandas>=2.1.0
|
||||
scikit-learn>=1.3.2
|
||||
|
|
@ -9,4 +9,5 @@ joblib>=1.3.2
|
|||
Flask>=2.3.3
|
||||
SQLAlchemy>=2.0.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
|
||||
from collections import OrderedDict
|
||||
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.orm import sessionmaker, relationship
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
|
|
@ -16,18 +17,30 @@ from sqlalchemy.exc import SQLAlchemyError
|
|||
import pytz
|
||||
TZ_INDONESIA = pytz.timezone('Asia/Jakarta')
|
||||
|
||||
# Database configuration from environment variables
|
||||
DB_HOST = os.environ.get('DB_HOST', 'localhost')
|
||||
DB_PORT = os.environ.get('DB_PORT', '3306')
|
||||
DB_USER = os.environ.get('DB_USER', 'root')
|
||||
DB_PASSWORD = os.environ.get('DB_PASSWORD', '')
|
||||
DB_NAME = os.environ.get('DB_NAME', 'deteksi_pmk')
|
||||
DATABASE_URL = os.environ.get('DATABASE_URL')
|
||||
|
||||
|
||||
def _build_database_uri():
|
||||
"""Build a SQLAlchemy database URI from Railway or local environment variables."""
|
||||
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
|
||||
if DB_PASSWORD:
|
||||
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}"
|
||||
DATABASE_URI = _build_database_uri()
|
||||
|
||||
# Create engine
|
||||
engine = create_engine(DATABASE_URI, echo=False, pool_pre_ping=True)
|
||||
|
|
|
|||
Loading…
Reference in New Issue