codeBOKER commited on
Commit
cb9a5de
Β·
1 Parent(s): f66a389

Update Dockerfile, README, routes, main.py, add app.py and expose

Browse files
Files changed (5) hide show
  1. Dockerfile +4 -3
  2. README.md +21 -0
  3. app.py +10 -0
  4. app/api/routes.py +9 -1
  5. app/main.py +25 -3
Dockerfile CHANGED
@@ -1,7 +1,8 @@
1
  FROM python:3.12-slim
2
 
3
  ENV PYTHONDONTWRITEBYTECODE=1 \
4
- PYTHONUNBUFFERED=1
 
5
 
6
  WORKDIR /app
7
 
@@ -10,5 +11,5 @@ RUN pip install --no-cache-dir -r requirements.txt
10
 
11
  COPY . .
12
 
13
- EXPOSE 8000
14
- CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
 
1
  FROM python:3.12-slim
2
 
3
  ENV PYTHONDONTWRITEBYTECODE=1 \
4
+ PYTHONUNBUFFERED=1 \
5
+ PORT=7860
6
 
7
  WORKDIR /app
8
 
 
11
 
12
  COPY . .
13
 
14
+ EXPOSE 7860
15
+ CMD ["python", "app.py"]
README.md CHANGED
@@ -155,6 +155,27 @@ Mounts the current directory with hot-reload enabled.
155
 
156
  ---
157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  ## WhatsApp Baileys Bridge
159
 
160
  FALZH uses the official Meta Cloud API for production messages. During early stages β€” while waiting for commercial approval β€” a **Baileys-based bridge** acts as the WhatsApp gateway.
 
155
 
156
  ---
157
 
158
+ ## Hugging Face Spaces
159
+
160
+ This repository is prepared to run as a Hugging Face Space using the top-level `app.py` entrypoint.
161
+
162
+ ### What to do in Hugging Face
163
+
164
+ 1. Create a new Space with the Python template.
165
+ 2. Connect this repository to the Space.
166
+ 3. Configure the required secrets in the Space settings if you want the full backend features enabled.
167
+ 4. Deploy.
168
+
169
+ The Space will expose the FastAPI app on port `7860` and the app will respond at:
170
+
171
+ - `/` β€” simple service overview
172
+ - `/healthz` β€” health check
173
+ - `/docs` β€” interactive API documentation
174
+
175
+ If the external services are not configured yet, the app still starts in a lightweight demo mode and serves the health endpoint.
176
+
177
+ ---
178
+
179
  ## WhatsApp Baileys Bridge
180
 
181
  FALZH uses the official Meta Cloud API for production messages. During early stages β€” while waiting for commercial approval β€” a **Baileys-based bridge** acts as the WhatsApp gateway.
app.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ import uvicorn
4
+
5
+ from main import app as falzh_app
6
+
7
+
8
+ if __name__ == "__main__":
9
+ port = int(os.environ.get("PORT", "7860"))
10
+ uvicorn.run(falzh_app, host="0.0.0.0", port=port, log_level="info")
app/api/routes.py CHANGED
@@ -33,8 +33,16 @@ import json
33
  router = APIRouter()
34
 
35
 
 
 
 
 
 
36
  @router.get("/healthz", response_model=HealthResponse)
37
- async def healthz(container: Annotated[ServiceContainer, Depends(get_container)]) -> HealthResponse:
 
 
 
38
  return HealthResponse(service=container.settings.app_name)
39
 
40
 
 
33
  router = APIRouter()
34
 
35
 
36
+ @router.get("/", include_in_schema=False)
37
+ async def root() -> dict[str, str]:
38
+ return {"service": "FALZH", "status": "ready", "docs": "/docs"}
39
+
40
+
41
  @router.get("/healthz", response_model=HealthResponse)
42
+ async def healthz(request: Request) -> HealthResponse:
43
+ container = getattr(request.app.state, "container", None)
44
+ if container is None:
45
+ return HealthResponse(service="FALZH (demo mode)")
46
  return HealthResponse(service=container.settings.app_name)
47
 
48
 
app/main.py CHANGED
@@ -16,9 +16,31 @@ def create_app(
16
  ) -> FastAPI:
17
  @asynccontextmanager
18
  async def lifespan(app: FastAPI) -> AsyncIterator[None]:
19
- active_settings = settings or (container.settings if container else get_settings())
20
- configure_logging(active_settings.log_level)
21
- app.state.container = container or await ServiceContainer.from_settings(active_settings)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  yield
23
 
24
  app = FastAPI(title="FALZH API", version="0.1.0", lifespan=lifespan)
 
16
  ) -> FastAPI:
17
  @asynccontextmanager
18
  async def lifespan(app: FastAPI) -> AsyncIterator[None]:
19
+ app.state.container = None
20
+ app.state.container_init_error = None
21
+
22
+ if container is not None:
23
+ active_settings = container.settings
24
+ app.state.container = container
25
+ else:
26
+ try:
27
+ active_settings = settings or get_settings()
28
+ except Exception as exc: # pragma: no cover - defensive startup path
29
+ active_settings = None
30
+ app.state.container_init_error = str(exc)
31
+
32
+ if active_settings is not None:
33
+ configure_logging(active_settings.log_level)
34
+ else:
35
+ configure_logging("INFO")
36
+
37
+ if container is None and active_settings is not None:
38
+ try:
39
+ app.state.container = await ServiceContainer.from_settings(active_settings)
40
+ except Exception as exc: # pragma: no cover - defensive startup path
41
+ app.state.container = None
42
+ app.state.container_init_error = str(exc)
43
+
44
  yield
45
 
46
  app = FastAPI(title="FALZH API", version="0.1.0", lifespan=lifespan)