Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
sachin
commited on
Commit
·
5754eb2
1
Parent(s):
8a99693
fix-issue
Browse files- Dockerfile +7 -17
- Dockerfile.app +24 -0
- Dockerfile.base +18 -0
- src/server/main.py +12 -2
- src/server/utils/auth.py +30 -17
Dockerfile
CHANGED
@@ -1,34 +1,24 @@
|
|
1 |
# Use official Python runtime as base image
|
2 |
-
FROM
|
3 |
|
4 |
WORKDIR /app
|
5 |
|
6 |
-
# Set environment variables
|
7 |
-
ENV PYTHONDONTWRITEBYTECODE=1
|
8 |
-
ENV PYTHONUNBUFFERED=1
|
9 |
-
|
10 |
-
# Install system dependencies
|
11 |
-
RUN apt-get update && apt-get install -y \
|
12 |
-
gcc \
|
13 |
-
&& rm -rf /var/lib/apt/lists/*
|
14 |
-
|
15 |
-
# Install Python dependencies
|
16 |
-
COPY requirements.txt .
|
17 |
-
RUN pip install --no-cache-dir -r requirements.txt
|
18 |
-
|
19 |
# Copy application code
|
20 |
COPY . .
|
21 |
|
|
|
22 |
RUN useradd -ms /bin/bash appuser \
|
23 |
-
&&
|
|
|
24 |
|
25 |
USER appuser
|
26 |
-
|
|
|
27 |
EXPOSE 7860
|
28 |
|
29 |
# Healthcheck
|
30 |
HEALTHCHECK --interval=30s --timeout=3s \
|
31 |
CMD curl -f http://localhost:7860/v1/health || exit 1
|
32 |
|
33 |
-
# Command to run the application
|
34 |
CMD ["python", "/app/src/server/main.py", "--host", "0.0.0.0", "--port", "7860"]
|
|
|
1 |
# Use official Python runtime as base image
|
2 |
+
FROM slabstech/dhwani-api-server-base
|
3 |
|
4 |
WORKDIR /app
|
5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
# Copy application code
|
7 |
COPY . .
|
8 |
|
9 |
+
# Create appuser and set permissions for /app and /data
|
10 |
RUN useradd -ms /bin/bash appuser \
|
11 |
+
&& mkdir -p /data \
|
12 |
+
&& chown -R appuser:appuser /app /data
|
13 |
|
14 |
USER appuser
|
15 |
+
|
16 |
+
# Expose port from settings
|
17 |
EXPOSE 7860
|
18 |
|
19 |
# Healthcheck
|
20 |
HEALTHCHECK --interval=30s --timeout=3s \
|
21 |
CMD curl -f http://localhost:7860/v1/health || exit 1
|
22 |
|
23 |
+
# Command to run the application
|
24 |
CMD ["python", "/app/src/server/main.py", "--host", "0.0.0.0", "--port", "7860"]
|
Dockerfile.app
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Use official Python runtime as base image
|
2 |
+
FROM slabstech/dhwani-api-server-base
|
3 |
+
|
4 |
+
WORKDIR /app
|
5 |
+
|
6 |
+
# Copy application code
|
7 |
+
COPY . .
|
8 |
+
|
9 |
+
# Create appuser and set permissions for /app and /data
|
10 |
+
RUN useradd -ms /bin/bash appuser \
|
11 |
+
&& mkdir -p /data \
|
12 |
+
&& chown -R appuser:appuser /app /data
|
13 |
+
|
14 |
+
USER appuser
|
15 |
+
|
16 |
+
# Expose port from settings
|
17 |
+
EXPOSE 7860
|
18 |
+
|
19 |
+
# Healthcheck
|
20 |
+
HEALTHCHECK --interval=30s --timeout=3s \
|
21 |
+
CMD curl -f http://localhost:7860/v1/health || exit 1
|
22 |
+
|
23 |
+
# Command to run the application
|
24 |
+
CMD ["python", "/app/src/server/main.py", "--host", "0.0.0.0", "--port", "7860"]
|
Dockerfile.base
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Use official Python runtime as base image
|
2 |
+
FROM python:3.10-slim
|
3 |
+
|
4 |
+
WORKDIR /app
|
5 |
+
|
6 |
+
# Set environment variables
|
7 |
+
ENV PYTHONDONTWRITEBYTECODE=1
|
8 |
+
ENV PYTHONUNBUFFERED=1
|
9 |
+
|
10 |
+
# Install system dependencies
|
11 |
+
RUN apt-get update && apt-get install -y \
|
12 |
+
gcc \
|
13 |
+
curl \
|
14 |
+
&& rm -rf /var/lib/apt/lists/*
|
15 |
+
|
16 |
+
# Install Python dependencies
|
17 |
+
COPY requirements.txt .
|
18 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
src/server/main.py
CHANGED
@@ -51,8 +51,16 @@ app.add_middleware(
|
|
51 |
allow_headers=["*"],
|
52 |
)
|
53 |
|
54 |
-
# Rate limiting based on user_id
|
55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
|
57 |
# Request/Response Models
|
58 |
class SpeechRequest(BaseModel):
|
@@ -398,11 +406,13 @@ async def transcribe_audio(
|
|
398 |
response.raise_for_status()
|
399 |
|
400 |
transcription = response.json().get("text", "")
|
|
|
401 |
return TranscriptionResponse(text=transcription)
|
402 |
|
403 |
except requests.Timeout:
|
404 |
raise HTTPException(status_code=504, detail="Transcription service timeout")
|
405 |
except requests.RequestException as e:
|
|
|
406 |
raise HTTPException(status_code=500, detail=f"Transcription failed: {str(e)}")
|
407 |
|
408 |
@app.post("/v1/chat_v2",
|
|
|
51 |
allow_headers=["*"],
|
52 |
)
|
53 |
|
54 |
+
# Rate limiting based on user_id with fallback to IP
|
55 |
+
async def get_user_id_for_rate_limit(request: Request):
|
56 |
+
try:
|
57 |
+
credentials = bearer_scheme(request)
|
58 |
+
user_id = await get_current_user(credentials)
|
59 |
+
return user_id
|
60 |
+
except Exception:
|
61 |
+
return get_remote_address(request) # Fallback to IP if unauthenticated
|
62 |
+
|
63 |
+
limiter = Limiter(key_func=get_user_id_for_rate_limit)
|
64 |
|
65 |
# Request/Response Models
|
66 |
class SpeechRequest(BaseModel):
|
|
|
406 |
response.raise_for_status()
|
407 |
|
408 |
transcription = response.json().get("text", "")
|
409 |
+
logger.info(f"Transcription completed in {time() - start_time:.2f} seconds")
|
410 |
return TranscriptionResponse(text=transcription)
|
411 |
|
412 |
except requests.Timeout:
|
413 |
raise HTTPException(status_code=504, detail="Transcription service timeout")
|
414 |
except requests.RequestException as e:
|
415 |
+
logger.error(f"Transcription request failed: {str(e)}")
|
416 |
raise HTTPException(status_code=500, detail=f"Transcription failed: {str(e)}")
|
417 |
|
418 |
@app.post("/v1/chat_v2",
|
src/server/utils/auth.py
CHANGED
@@ -9,9 +9,11 @@ from sqlalchemy import create_engine, Column, String, Boolean
|
|
9 |
from sqlalchemy.ext.declarative import declarative_base
|
10 |
from sqlalchemy.orm import sessionmaker
|
11 |
from passlib.context import CryptContext
|
|
|
12 |
|
13 |
-
# SQLite database setup
|
14 |
-
|
|
|
15 |
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
|
16 |
Base = declarative_base()
|
17 |
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
@@ -22,6 +24,10 @@ class User(Base):
|
|
22 |
password = Column(String) # Stores hashed passwords
|
23 |
is_admin = Column(Boolean, default=False) # New admin flag
|
24 |
|
|
|
|
|
|
|
|
|
25 |
Base.metadata.create_all(bind=engine)
|
26 |
|
27 |
# Password hashing
|
@@ -43,6 +49,7 @@ class Settings(BaseSettings):
|
|
43 |
external_audio_proc_url: str = Field(..., env="EXTERNAL_AUDIO_PROC_URL")
|
44 |
default_admin_username: str = Field("admin", env="DEFAULT_ADMIN_USERNAME")
|
45 |
default_admin_password: str = Field("admin54321", env="DEFAULT_ADMIN_PASSWORD")
|
|
|
46 |
|
47 |
class Config:
|
48 |
env_file = ".env"
|
@@ -50,24 +57,30 @@ class Settings(BaseSettings):
|
|
50 |
|
51 |
settings = Settings()
|
52 |
|
53 |
-
# Seed initial data
|
54 |
def seed_initial_data():
|
55 |
db = SessionLocal()
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
|
|
|
|
|
|
|
|
|
|
70 |
|
|
|
71 |
seed_initial_data()
|
72 |
|
73 |
# Use HTTPBearer
|
|
|
9 |
from sqlalchemy.ext.declarative import declarative_base
|
10 |
from sqlalchemy.orm import sessionmaker
|
11 |
from passlib.context import CryptContext
|
12 |
+
import os
|
13 |
|
14 |
+
# SQLite database setup with Hugging Face persistent storage
|
15 |
+
DATABASE_PATH = "/data/users.db"
|
16 |
+
DATABASE_URL = f"sqlite:///{DATABASE_PATH}"
|
17 |
engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})
|
18 |
Base = declarative_base()
|
19 |
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
|
|
24 |
password = Column(String) # Stores hashed passwords
|
25 |
is_admin = Column(Boolean, default=False) # New admin flag
|
26 |
|
27 |
+
# Ensure the /data directory exists
|
28 |
+
os.makedirs(os.path.dirname(DATABASE_PATH), exist_ok=True)
|
29 |
+
|
30 |
+
# Create database tables
|
31 |
Base.metadata.create_all(bind=engine)
|
32 |
|
33 |
# Password hashing
|
|
|
49 |
external_audio_proc_url: str = Field(..., env="EXTERNAL_AUDIO_PROC_URL")
|
50 |
default_admin_username: str = Field("admin", env="DEFAULT_ADMIN_USERNAME")
|
51 |
default_admin_password: str = Field("admin54321", env="DEFAULT_ADMIN_PASSWORD")
|
52 |
+
database_path: str = DATABASE_PATH # Add for reference if needed elsewhere
|
53 |
|
54 |
class Config:
|
55 |
env_file = ".env"
|
|
|
57 |
|
58 |
settings = Settings()
|
59 |
|
60 |
+
# Seed initial data
|
61 |
def seed_initial_data():
|
62 |
db = SessionLocal()
|
63 |
+
try:
|
64 |
+
# Seed test user (non-admin)
|
65 |
+
if not db.query(User).filter_by(username="testuser").first():
|
66 |
+
hashed_password = pwd_context.hash("password123")
|
67 |
+
db.add(User(username="testuser", password=hashed_password, is_admin=False))
|
68 |
+
db.commit()
|
69 |
+
# Seed admin user using environment variables
|
70 |
+
admin_username = settings.default_admin_username
|
71 |
+
admin_password = settings.default_admin_password
|
72 |
+
if not db.query(User).filter_by(username=admin_username).first():
|
73 |
+
hashed_password = pwd_context.hash(admin_password)
|
74 |
+
db.add(User(username=admin_username, password=hashed_password, is_admin=True))
|
75 |
+
db.commit()
|
76 |
+
logger.info(f"Seeded initial data: admin user '{admin_username}'")
|
77 |
+
except Exception as e:
|
78 |
+
logger.error(f"Error seeding initial data: {str(e)}")
|
79 |
+
db.rollback()
|
80 |
+
finally:
|
81 |
+
db.close()
|
82 |
|
83 |
+
# Initialize database with seed data
|
84 |
seed_initial_data()
|
85 |
|
86 |
# Use HTTPBearer
|