gcharanteja commited on
Commit
3d4271b
·
1 Parent(s): f77e581

Implement SQLite server and FastAPI integration with updated Dockerfile and startup script

Browse files
Files changed (5) hide show
  1. Dockerfile +14 -11
  2. app.py +42 -4
  3. requirements.txt +2 -1
  4. sqlite_server.py +101 -0
  5. start.sh +23 -0
Dockerfile CHANGED
@@ -1,16 +1,19 @@
1
- #Read the doc: https://huggingface.co/docs/hub/spaces-sdks-docker
2
- # you will also find guides on how best to write your Dockerfile
3
 
4
- FROM python:3.9
5
 
6
- RUN useradd -m -u 1000 user
7
- USER user
8
- ENV PATH="/home/user/.local/bin:$PATH"
9
 
10
- WORKDIR /app
 
 
 
 
11
 
12
- COPY --chown=user ./requirements.txt requirements.txt
13
- RUN pip install --no-cache-dir --upgrade -r requirements.txt
14
 
15
- COPY --chown=user . /app
16
- CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
1
+ FROM python:3.9-slim
 
2
 
3
+ WORKDIR /app
4
 
5
+ # Install requirements
6
+ COPY requirements.txt .
7
+ RUN pip install --no-cache-dir -r requirements.txt
8
 
9
+ # Copy all files
10
+ COPY . .
11
+
12
+ # Make start.sh executable
13
+ RUN chmod +x start.sh
14
 
15
+ EXPOSE 8000
16
+ EXPOSE 7860
17
 
18
+ # Run the startup script which handles both SQLite server and FastAPI
19
+ CMD ["./start.sh"]
app.py CHANGED
@@ -1,7 +1,45 @@
 
 
1
  from fastapi import FastAPI
 
2
 
3
- app = FastAPI()
4
 
5
- @app.get("/")
6
- def greet_json():
7
- return {"Hello": "World!sql "}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
  from fastapi import FastAPI
4
+ from fastapi.responses import HTMLResponse
5
 
6
+ app = FastAPI(title="SQLite on HF Space")
7
 
8
+ SQLITE_URL = "http://localhost:8000"
9
+
10
+ @app.get("/", response_class=HTMLResponse)
11
+ def read_root():
12
+ return """
13
+ <html>
14
+ <head><title>SQLite HF Space</title></head>
15
+ <body>
16
+ <h1>✅ SQLite Server is Running!</h1>
17
+ <p>Persistent Storage: /data/sqlite.db</p>
18
+ <p>API Endpoint: <a href="/docs">Swagger UI</a></p>
19
+ <p>Direct SQLite API: <code>{}/api/v1/heartbeat</code></p>
20
+ <p><strong>Available Endpoints:</strong></p>
21
+ <ul>
22
+ <li>GET /api/v1/heartbeat - Health check</li>
23
+ <li>POST /api/v1/query - Execute SELECT queries</li>
24
+ <li>POST /api/v1/execute - Execute INSERT/UPDATE/DELETE</li>
25
+ <li>GET /api/v1/tables - List all tables</li>
26
+ <li>GET /api/v1/schema - Get database schema</li>
27
+ </ul>
28
+ </body>
29
+ </html>
30
+ """.format(SQLITE_URL)
31
+
32
+ @app.get("/health")
33
+ def health_check():
34
+ try:
35
+ response = requests.get(f"{SQLITE_URL}/api/v1/heartbeat")
36
+ if response.status_code == 200:
37
+ return {"status": "healthy", "sqlite": "up"}
38
+ else:
39
+ return {"status": "unhealthy", "sqlite": "error"}
40
+ except Exception as e:
41
+ return {"status": "error", "detail": str(e)}
42
+
43
+ if __name__ == "__main__":
44
+ import uvicorn
45
+ uvicorn.run(app, host="0.0.0.0", port=int(os.getenv("PORT", 7860)))
requirements.txt CHANGED
@@ -1,2 +1,3 @@
1
  fastapi
2
- uvicorn[standard]
 
 
1
  fastapi
2
+ uvicorn[standard]
3
+ requests
sqlite_server.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sqlite3
3
+ import json
4
+ from pathlib import Path
5
+ from fastapi import FastAPI, HTTPException
6
+ from pydantic import BaseModel
7
+ from typing import List, Dict, Any
8
+ import uvicorn
9
+
10
+ app = FastAPI(title="SQLite Server")
11
+
12
+ DB_PATH = "/data/sqlite.db"
13
+
14
+ def ensure_db_exists():
15
+ Path("/data").mkdir(parents=True, exist_ok=True)
16
+ if not os.path.exists(DB_PATH):
17
+ conn = sqlite3.connect(DB_PATH)
18
+ conn.close()
19
+
20
+ def get_connection():
21
+ ensure_db_exists()
22
+ conn = sqlite3.connect(DB_PATH)
23
+ conn.row_factory = sqlite3.Row
24
+ return conn
25
+
26
+ class QueryRequest(BaseModel):
27
+ sql: str
28
+
29
+ class ExecuteRequest(BaseModel):
30
+ sql: str
31
+
32
+ @app.get("/api/v1/heartbeat")
33
+ def heartbeat():
34
+ try:
35
+ conn = get_connection()
36
+ conn.execute("SELECT 1")
37
+ conn.close()
38
+ return {"status": "ok"}
39
+ except Exception as e:
40
+ raise HTTPException(status_code=500, detail=str(e))
41
+
42
+ @app.post("/api/v1/query")
43
+ def query(request: QueryRequest):
44
+ try:
45
+ conn = get_connection()
46
+ cursor = conn.execute(request.sql)
47
+ rows = cursor.fetchall()
48
+ conn.close()
49
+ return {"data": [dict(row) for row in rows]}
50
+ except Exception as e:
51
+ raise HTTPException(status_code=400, detail=str(e))
52
+
53
+ @app.post("/api/v1/execute")
54
+ def execute(request: ExecuteRequest):
55
+ try:
56
+ conn = get_connection()
57
+ cursor = conn.execute(request.sql)
58
+ conn.commit()
59
+ changes = conn.total_changes
60
+ conn.close()
61
+ return {"rows_affected": cursor.rowcount, "total_changes": changes}
62
+ except Exception as e:
63
+ raise HTTPException(status_code=400, detail=str(e))
64
+
65
+ @app.get("/api/v1/tables")
66
+ def list_tables():
67
+ try:
68
+ conn = get_connection()
69
+ cursor = conn.execute(
70
+ "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'"
71
+ )
72
+ tables = [row[0] for row in cursor.fetchall()]
73
+ conn.close()
74
+ return {"tables": tables}
75
+ except Exception as e:
76
+ raise HTTPException(status_code=500, detail=str(e))
77
+
78
+ @app.get("/api/v1/schema")
79
+ def get_schema():
80
+ try:
81
+ conn = get_connection()
82
+ cursor = conn.execute(
83
+ "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'"
84
+ )
85
+ tables = [row[0] for row in cursor.fetchall()]
86
+
87
+ schema = {}
88
+ for table in tables:
89
+ cursor = conn.execute(f"PRAGMA table_info({table})")
90
+ schema[table] = [
91
+ {"name": col[1], "type": col[2], "notnull": col[3], "pk": col[5]}
92
+ for col in cursor.fetchall()
93
+ ]
94
+ conn.close()
95
+ return schema
96
+ except Exception as e:
97
+ raise HTTPException(status_code=500, detail=str(e))
98
+
99
+ if __name__ == "__main__":
100
+ ensure_db_exists()
101
+ uvicorn.run(app, host="0.0.0.0", port=8000)
start.sh ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ echo "=== Starting SQLite and FastAPI ==="
4
+
5
+ # Define the persistent directory
6
+ PERSIST_DIR="/data"
7
+ mkdir -p $PERSIST_DIR
8
+
9
+ # Start SQLite server in background
10
+ echo "🚀 Starting SQLite server on port 8000..."
11
+ python3 sqlite_server.py &
12
+ SQLITE_PID=$!
13
+
14
+ # Wait for SQLite server to start
15
+ sleep 2
16
+
17
+ # Start FastAPI app
18
+ echo "🌐 Starting FastAPI app on port 7860..."
19
+ python3 app.py &
20
+ APP_PID=$!
21
+
22
+ # Keep both processes alive
23
+ wait $SQLITE_PID $APP_PID