Local AI Assistant commited on
Commit
7b9724a
·
1 Parent(s): a016784

Split services: Remove Auth/DB/Image from main API, proxy image requests

Browse files
Files changed (2) hide show
  1. Dockerfile +25 -14
  2. api.py +27 -105
Dockerfile CHANGED
@@ -1,23 +1,34 @@
1
- # Use Python 3.10
2
- FROM python:3.10
 
 
 
 
 
3
 
4
  # Set working directory
5
  WORKDIR /app
6
 
7
- # Copy requirements and install dependencies
 
 
 
 
 
 
8
  COPY requirements.txt .
9
- RUN pip install --no-cache-dir -r requirements.txt
10
 
11
- # Copy the rest of the application
12
- COPY . .
 
 
 
13
 
14
- # Create a writable directory for cache (Hugging Face requirement)
15
- RUN mkdir -p /app/cache
16
- ENV XDG_CACHE_HOME=/app/cache
17
- RUN chmod -R 777 /app/cache
18
 
19
- # Expose port 7860 (Hugging Face default)
20
- EXPOSE 7860
21
 
22
- # Run the application
23
- CMD ["uvicorn", "api:app", "--host", "0.0.0.0", "--port", "7860"]
 
1
+ # Use a lightweight Python base image
2
+ FROM python:3.10-slim
3
+
4
+ # Set environment variables
5
+ ENV PYTHONDONTWRITEBYTECODE=1 \
6
+ PYTHONUNBUFFERED=1 \
7
+ PORT=8080
8
 
9
  # Set working directory
10
  WORKDIR /app
11
 
12
+ # Install system dependencies
13
+ RUN apt-get update && apt-get install -y --no-install-recommends \
14
+ build-essential \
15
+ git \
16
+ && rm -rf /var/lib/apt/lists/*
17
+
18
+ # Copy requirements file
19
  COPY requirements.txt .
 
20
 
21
+ # Install Python dependencies
22
+ # Note: We install torch CPU version to keep image size smaller if GPU is not used,
23
+ # but Cloud Run is CPU-only by default anyway.
24
+ RUN pip install --no-cache-dir --upgrade pip && \
25
+ pip install --no-cache-dir -r requirements.txt
26
 
27
+ # Copy application code
28
+ COPY . .
 
 
29
 
30
+ # Expose the port
31
+ EXPOSE 8080
32
 
33
+ # Command to run the application
34
+ CMD ["uvicorn", "api:app", "--host", "0.0.0.0", "--port", "8080"]
api.py CHANGED
@@ -14,13 +14,13 @@ import os
14
  import base64
15
 
16
  from chat_engine import ChatEngine
17
- from image_engine import ImageEngine
18
  from rag_engine import RAGEngine
19
  import models
20
  import shutil
21
  import schemas
22
  import firebase_admin
23
  from firebase_admin import credentials, firestore, auth
 
24
 
25
  # Initialize FastAPI
26
  app = FastAPI()
@@ -34,32 +34,15 @@ app.add_middleware(
34
  allow_headers=["*"],
35
  )
36
 
37
- # Initialize Firebase Admin
38
  if not firebase_admin._apps:
39
- if os.path.exists("serviceAccountKey.json"):
40
- cred = credentials.Certificate("serviceAccountKey.json")
41
- else:
42
- # Try getting from env var (for Hugging Face)
43
- key_json = os.environ.get("FIREBASE_SERVICE_ACCOUNT_KEY")
44
- if key_json:
45
- import json
46
- cred_dict = json.loads(key_json)
47
- cred = credentials.Certificate(cred_dict)
48
- else:
49
- print("Warning: No service account key found. Firebase features will fail.")
50
- cred = None
51
-
52
- if cred:
53
- firebase_admin.initialize_app(cred)
54
 
55
- if firebase_admin._apps:
56
- db = firestore.client()
57
- else:
58
- db = None
59
 
60
  # Global engine instances (Lazy loaded)
61
  chat_engine = None
62
- image_engine = None
63
  rag_engine = None
64
 
65
  def get_chat_engine():
@@ -69,13 +52,6 @@ def get_chat_engine():
69
  chat_engine = ChatEngine()
70
  return chat_engine
71
 
72
- def get_image_engine():
73
- global image_engine
74
- if image_engine is None:
75
- print("Lazy loading Image Engine...")
76
- image_engine = ImageEngine()
77
- return image_engine
78
-
79
  def get_rag_engine():
80
  global rag_engine
81
  if rag_engine is None:
@@ -237,60 +213,20 @@ def read_root():
237
  return {"status": "Backend is running", "message": "Go to /docs to see the API"}
238
 
239
  @app.post("/chat")
240
- async def chat(request: ChatRequest, current_user: dict = Depends(get_current_user)):
241
- # ... (Keep existing /chat for backward compatibility if needed, or redirect logic)
242
- # For now, let's keep /chat as blocking and add /chat/stream
243
  try:
244
  # Get engine (lazy load)
245
  engine = get_chat_engine()
246
  # Generate Response
247
  response = engine.generate_response(request.message, request.history)
248
-
249
- # Save to Firestore if conversation_id is present
250
- if request.conversation_id:
251
- conv_ref = db.collection('conversations').document(request.conversation_id)
252
- # User Msg
253
- conv_ref.collection('messages').add({
254
- "role": "user",
255
- "content": request.message,
256
- "timestamp": datetime.utcnow()
257
- })
258
- # AI Msg
259
- conv_ref.collection('messages').add({
260
- "role": "assistant",
261
- "content": response,
262
- "timestamp": datetime.utcnow()
263
- })
264
- conv_ref.update({"updated_at": datetime.utcnow()})
265
-
266
  return {"response": response}
267
  except Exception as e:
268
  import traceback
269
  traceback.print_exc()
270
  raise HTTPException(status_code=500, detail=str(e))
271
 
272
- # RAG Endpoints
273
- @app.post("/upload")
274
- async def upload_file(file: UploadFile = File(...), current_user: dict = Depends(get_current_user)):
275
- try:
276
- # Save file locally
277
- upload_dir = "uploads"
278
- os.makedirs(upload_dir, exist_ok=True)
279
- file_path = os.path.join(upload_dir, file.filename)
280
-
281
- with open(file_path, "wb") as buffer:
282
- shutil.copyfileobj(file.file, buffer)
283
-
284
- # Ingest into RAG
285
- rag = get_rag_engine()
286
- rag.ingest_file(file_path)
287
-
288
- return {"filename": file.filename, "status": "ingested"}
289
- except Exception as e:
290
- raise HTTPException(status_code=500, detail=str(e))
291
-
292
  @app.post("/chat/stream")
293
- async def chat_stream(request: ChatRequest, current_user: dict = Depends(get_current_user)):
294
  try:
295
  # Check for RAG context
296
  context = ""
@@ -300,36 +236,13 @@ async def chat_stream(request: ChatRequest, current_user: dict = Depends(get_cur
300
  context = "\n\nRelevant Context:\n" + "\n".join(rag_docs) + "\n\n"
301
  print(f"Found {len(rag_docs)} relevant documents.")
302
 
303
- # Save User Message
304
- if request.conversation_id:
305
- conv_ref = db.collection('conversations').document(request.conversation_id)
306
- conv_ref.collection('messages').add({
307
- "role": "user",
308
- "content": request.message,
309
- "timestamp": datetime.utcnow()
310
- })
311
- conv_ref.update({"updated_at": datetime.utcnow()})
312
-
313
  async def stream_generator():
314
- full_response = ""
315
- # Prepend context to the message sent to AI (but not saved in DB as user message)
316
  augmented_message = context + request.message if context else request.message
317
 
318
  engine = get_chat_engine()
319
  for token in engine.generate_stream(augmented_message, request.history, request.language):
320
- full_response += token
321
  yield token
322
-
323
- # Save AI Message after generation
324
- if request.conversation_id:
325
- conv_ref = db.collection('conversations').document(request.conversation_id)
326
- conv_ref.collection('messages').add({
327
- "role": "assistant",
328
- "content": full_response,
329
- "timestamp": datetime.utcnow()
330
- })
331
-
332
- print(f"Generated response for conv {request.conversation_id}")
333
 
334
  return StreamingResponse(stream_generator(), media_type="text/plain")
335
 
@@ -338,19 +251,28 @@ async def chat_stream(request: ChatRequest, current_user: dict = Depends(get_cur
338
  traceback.print_exc()
339
  raise HTTPException(status_code=500, detail=str(e))
340
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  @app.post("/generate-image")
342
- async def generate_image(request: ImageRequest, current_user: dict = Depends(get_current_user)):
343
  try:
344
- # Generate image to a temporary file
345
- filename = "temp_generated.png"
346
- engine = get_image_engine()
347
- engine.generate_image(request.prompt, output_path=filename)
348
-
349
- # Read and encode to base64 to send to frontend
350
- with open(filename, "rb") as image_file:
351
- encoded_string = base64.b64encode(image_file.read()).decode('utf-8')
352
 
353
- return {"image_base64": encoded_string}
354
  except Exception as e:
355
  raise HTTPException(status_code=500, detail=str(e))
356
 
 
14
  import base64
15
 
16
  from chat_engine import ChatEngine
 
17
  from rag_engine import RAGEngine
18
  import models
19
  import shutil
20
  import schemas
21
  import firebase_admin
22
  from firebase_admin import credentials, firestore, auth
23
+ import requests
24
 
25
  # Initialize FastAPI
26
  app = FastAPI()
 
34
  allow_headers=["*"],
35
  )
36
 
37
+ # Initialize Firebase Admin (Optional/Placeholder if needed later)
38
  if not firebase_admin._apps:
39
+ # ... (Keep existing logic or comment out if fully removing)
40
+ pass
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
+ db = None # Placeholder
 
 
 
43
 
44
  # Global engine instances (Lazy loaded)
45
  chat_engine = None
 
46
  rag_engine = None
47
 
48
  def get_chat_engine():
 
52
  chat_engine = ChatEngine()
53
  return chat_engine
54
 
 
 
 
 
 
 
 
55
  def get_rag_engine():
56
  global rag_engine
57
  if rag_engine is None:
 
213
  return {"status": "Backend is running", "message": "Go to /docs to see the API"}
214
 
215
  @app.post("/chat")
216
+ async def chat(request: ChatRequest):
 
 
217
  try:
218
  # Get engine (lazy load)
219
  engine = get_chat_engine()
220
  # Generate Response
221
  response = engine.generate_response(request.message, request.history)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222
  return {"response": response}
223
  except Exception as e:
224
  import traceback
225
  traceback.print_exc()
226
  raise HTTPException(status_code=500, detail=str(e))
227
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  @app.post("/chat/stream")
229
+ async def chat_stream(request: ChatRequest):
230
  try:
231
  # Check for RAG context
232
  context = ""
 
236
  context = "\n\nRelevant Context:\n" + "\n".join(rag_docs) + "\n\n"
237
  print(f"Found {len(rag_docs)} relevant documents.")
238
 
 
 
 
 
 
 
 
 
 
 
239
  async def stream_generator():
240
+ # Prepend context to the message sent to AI
 
241
  augmented_message = context + request.message if context else request.message
242
 
243
  engine = get_chat_engine()
244
  for token in engine.generate_stream(augmented_message, request.history, request.language):
 
245
  yield token
 
 
 
 
 
 
 
 
 
 
 
246
 
247
  return StreamingResponse(stream_generator(), media_type="text/plain")
248
 
 
251
  traceback.print_exc()
252
  raise HTTPException(status_code=500, detail=str(e))
253
 
254
+ except Exception as e:
255
+ import traceback
256
+ traceback.print_exc()
257
+ raise HTTPException(status_code=500, detail=str(e))
258
+
259
+ # ... (Imports)
260
+ import requests
261
+
262
+ # ... (Chat Engine setup)
263
+
264
+ # Image Service URL (Hardcoded for now, or env var)
265
+ IMAGE_SERVICE_URL = "https://professorceo-cool-shot-ai-imagine.hf.space/generate-image"
266
+
267
  @app.post("/generate-image")
268
+ async def generate_image(request: ImageRequest):
269
  try:
270
+ # Call external Image Service
271
+ response = requests.post(IMAGE_SERVICE_URL, json={"prompt": request.prompt})
272
+ if response.status_code != 200:
273
+ raise HTTPException(status_code=response.status_code, detail="Image Service Error")
 
 
 
 
274
 
275
+ return response.json()
276
  except Exception as e:
277
  raise HTTPException(status_code=500, detail=str(e))
278