Spaces:
Running
Running
| # ============================================================================= | |
| # env.example (committed template — copy to .env and fill in real values) | |
| # Mirrors the keys used in production. See docs/ACCOUNTS_AND_SERVICES.md for | |
| # where to obtain each value, and DEPLOYMENT.md for the deploy steps. | |
| # ============================================================================= | |
| ## OpenAI (meme caption suggestions) -- REQUIRED | |
| OPENAI_API_KEY=your-openai-api-key | |
| ## Giphy (GIF search) -- REQUIRED | |
| GIPHY_API_KEY=your-giphy-api-key | |
| ## Tenor (GIF search) -- OPTIONAL (leave blank; Giphy covers search) | |
| TENOR_API_KEY= | |
| # auto = use GPT-4o vision when OPENAI_API_KEY is set, else fall back to local BLIP. | |
| # Options: auto | openai | huggingface | |
| GIF_SUGGESTION_ENGINE=auto | |
| # Local BLIP fallback model. Keep in sync with the checkpoint baked in the Dockerfile. | |
| BLIP_MODEL=Salesforce/blip-image-captioning-base | |
| ## Freemium limits -- OPTIONAL (sensible defaults applied if unset) | |
| # Master switch for monetization gates (daily meme cap + premium-only formats). | |
| # Keep false until the app's subscription UI is enabled, or free users get capped | |
| # with no way to upgrade. Abuse/cost rate limits below stay active regardless. | |
| FREEMIUM_ENABLED=false | |
| # Free users: max saved memes per day (premium = unlimited). | |
| FREE_DAILY_MEMES=10 | |
| # Hourly cap on AI suggestion/caption calls, per user, by tier. | |
| FREE_AI_PER_HOUR=30 | |
| PREMIUM_AI_PER_HOUR=200 | |
| # Per-minute cap on keyword GIF search / trending, per user. | |
| GIF_SEARCH_PER_MINUTE=60 | |
| # Output formats reserved for paying users (comma-separated). | |
| PREMIUM_ONLY_FORMATS=mp4 | |
| # Watermark free-tier exports (virality + upgrade incentive). Premium never watermarked. | |
| WATERMARK_ENABLED=false | |
| WATERMARK_TEXT=Meme Jockey | |
| ## GIF export performance -- OPTIONAL (tune if saves feel slow) | |
| # Cap/subsample frames of long GIFs (0 = unlimited). ~48 keeps saves snappy. | |
| MEME_MAX_FRAMES=0 | |
| # Cap the longest side in pixels before encoding (0 = no limit). e.g. 720. | |
| MEME_MAX_DIM=0 | |
| # Floyd-Steinberg dithering on GIF frames. 0 = off (faster, slight banding). | |
| MEME_GIF_DITHER=1 | |
| ## POSTGRESQL -- REQUIRED | |
| # Local dev (docker/podman compose): | |
| POSTGRES_HOST=localhost | |
| POSTGRES_PORT=5432 | |
| POSTGRES_DB=memes_dev | |
| POSTGRES_USER=postgres | |
| POSTGRES_PASSWORD=postgres | |
| DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB} | |
| # Managed Postgres (e.g. Neon) — use the asyncpg-compatible SSL param: | |
| # DATABASE_URL=postgresql://user:pass@host/dbname?ssl=require | |
| ## Guest Account Configuration | |
| GUEST_MODE_ENABLED=false | |
| GUEST_PHONE_NUMBER=+10000000000 | |
| GUEST_OTP_CODE=000000 | |
| GUEST_TOKEN_TTL_SECONDS=3600 | |
| GUEST_DATA_QUOTA_MB=200 | |
| GUEST_DATA_RETENTION_HOURS=24 | |
| ## Fast2SMS (OTP delivery via SMS) -- OPTIONAL | |
| # Leave blank: OTP is printed to logs ([DEV SMS] to=… otp=…) instead of texted, | |
| # so login still works in dev (read the code from the logs). If SET, the key must | |
| # be valid AND the Fast2SMS wallet funded / account KYC-complete, or sends fail | |
| # with HTTP 502 "Couldn't send the OTP" and login breaks. See auth/sms_provider.py. | |
| FAST2SMS_API_KEY= | |
| # Most Indian Fast2SMS accounts must use the DLT template route (the bare "otp" | |
| # route returns HTTP 400 unless explicitly enabled). Set BOTH from your approved | |
| # DLT template to send real OTP SMS; leave blank to try the plain otp route. | |
| # FAST2SMS_SENDER_ID = your approved 3-6 char DLT header/sender ID | |
| # FAST2SMS_DLT_TEMPLATE_ID = the numeric ID of your approved OTP template | |
| # The template must have one variable for the code, e.g. | |
| # "Your Meme Jockey OTP is {#var#}. Do not share it." | |
| FAST2SMS_SENDER_ID= | |
| FAST2SMS_DLT_TEMPLATE_ID= | |
| # Debug aid: when true, /auth/request-otp returns the raw Fast2SMS error to the | |
| # client (e.g. invalid key / no balance). Keep FALSE in production. | |
| OTP_DEBUG=false | |
| ## Object storage — MinIO (local) or any S3-compatible (e.g. Backblaze B2) -- REQUIRED | |
| MINIO_ENDPOINT=localhost:9000 | |
| MINIO_ACCESS_KEY=minioadmin | |
| MINIO_SECRET_KEY=minioadmin | |
| MINIO_SECURE=false | |
| MINIO_BUCKET=memes-dev | |
| # MinIO root creds (local dev only!) | |
| MINIO_ROOT_USER=minioadmin | |
| MINIO_ROOT_PASSWORD=minioadmin | |
| ## Auth / JWT -- REQUIRED (generate long random strings) | |
| JWT_SECRET=change-me-256-bit-secret | |
| JWT_REFRESH_SECRET=change-me-another-secret | |
| JWT_ISS=meme-be | |
| JWT_AUD=app | |
| ACCESS_TTL_SECONDS=900 | |
| REFRESH_TTL_SECONDS=2592000 | |
| ARGON2_PEPPER=optional-static-pepper | |
| ## Google Sign-In -- OPTIONAL (OAuth 2.0 Web client ID; token audience) | |
| GOOGLE_WEB_CLIENT_ID= | |
| ## Razorpay (subscriptions) -- REQUIRED for in-app purchases (optional otherwise) | |
| # Test-mode keys look like rzp_test_...; live keys rzp_live_... (live needs a | |
| # KYC-activated account). Both id + secret MUST come from the same key pair and | |
| # the same mode, or Razorpay rejects them with "Authentication failed". | |
| # Verify config without a full checkout: GET /subscriptions/config-check | |
| # curl -H "X-Admin-Secret: <ADMIN_SECRET>" https://<host>/subscriptions/config-check | |
| RAZORPAY_KEY_ID= | |
| RAZORPAY_KEY_SECRET= | |
| # Debug aid: when true, /subscriptions/order returns the raw Razorpay error to | |
| # the client so payment failures can be diagnosed from the app. Keep FALSE in | |
| # production (real users would see raw internals). | |
| PAYMENTS_DEBUG=false | |
| ## Environment | |
| APP_ENV=development | |
| ADMIN_SECRET=change-me-admin-secret | |
| # Set CONTAINER_ENV=true when running in Docker/HF Space if APP_ENV isn't | |
| # "production" — switches the DB engine to the asyncpg driver. Optional. | |
| CONTAINER_ENV=false | |
| ## API Configuration | |
| API_BASE_URL=http://localhost:8000 | |