Flask web app on GCP Cloud Run. Tap a symbol to hear its Hebrew name.
pip install -r requirements.txt
python app.py
# Open http://localhost:8080docker build -t touch-n-hear .
docker run -p 8080:8080 touch-n-hear
# Open http://localhost:8080gcloud auth login
gcloud config set project YOUR_PROJECT_ID
gcloud services enable run.googleapis.com cloudbuild.googleapis.comPROJECT_ID=$(gcloud config get-value project)
REGION=me-west1 # Tel Aviv
# 1. Build image and push to Container Registry
gcloud builds submit --tag gcr.io/$PROJECT_ID/touch-n-hear
# 2. Deploy to Cloud Run
gcloud run deploy touch-n-hear \
--image gcr.io/$PROJECT_ID/touch-n-hear \
--platform managed \
--region $REGION \
--allow-unauthenticated \
--port 8080 \
--memory 256Mi \
--cpu 1 \
--min-instances 0 \
--max-instances 10Cloud Run prints your live HTTPS URL when done.
gcloud builds submit --tag gcr.io/$(gcloud config get-value project)/touch-n-hear && \
gcloud run deploy touch-n-hear \
--image gcr.io/$(gcloud config get-value project)/touch-n-hear \
--region me-west1 --platform managedCloud Run free tier (per month, per account):
- 2,000,000 requests
- 360,000 GB-seconds memory
- 180,000 vCPU-seconds
Low personal traffic will comfortably stay within free limits.
With --min-instances 0 the container shuts down after ~15 min of inactivity and takes ~1-2 seconds to wake on the next request. Fine for personal use.
To keep one instance always warm: add --min-instances 1 to the deploy command. This costs roughly $3-5/month but eliminates cold starts.
browser -> Cloud Run HTTPS (me-west1 / Tel Aviv)
-> gunicorn (2 workers)
-> Flask app.py
-> templates/index.html (Jinja2)
-> static/symbols.json (edit to change content)
All symbols, labels and Hebrew pronunciation live in static/symbols.json. Edit that file and redeploy -- no code changes needed. The file is UTF-8 with BOM so Hebrew displays correctly in Windows editors.
Counters persist in gs://touch-n-hear-bucket/counters.json.
Run these once before deploying:
PROJECT_ID=$(gcloud config get-value project)
# 1. Create the bucket (skip if it already exists)
gcloud storage buckets create gs://touch-n-hear-bucket \
--location=me-west1 \
--uniform-bucket-level-access
# 2. Grant the Cloud Run service account read/write access to the bucket.
# Cloud Run uses PROJECT_NUMBER-compute@developer.gserviceaccount.com by default.
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
SERVICE_ACCOUNT="${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
gcloud storage buckets add-iam-policy-binding gs://touch-n-hear-bucket \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/storage.objectAdmin"
# 3. Create the initial counters file
echo '{"total":0,"years":{},"months":{}}' | \
gcloud storage cp - gs://touch-n-hear-bucket/counters.jsonThe app reads COUNTERS_BUCKET env var (defaults to touch-n-hear-bucket).
Falls back to local static/counters.json if GCS is unreachable (local dev).
View live counts at: https://your-app-url/counters.json