Fix Modal app FastAPI integration and successful deployment
Browse files- Replace
@modal
.fastapi_endpoint() with
@modal
.asgi_app() for proper FastAPI integration
- Use .local() calls instead of .remote.aio() to avoid recursion issues
- Fix circular reference errors in JSON serialization
- Update datetime.utcnow() to datetime.now(timezone.utc) for deprecation warning
- Simplify task status endpoint to avoid recursion
- Successfully deployed at: https://fazeelusmani18--knowledgebridge-main-fastapi-app.modal.run
- Verified endpoints working: /health, /docs, /vector-search with proper error responses
- modal_app/main.py +79 -39
modal_app/main.py
CHANGED
@@ -13,6 +13,7 @@ app = modal.App("knowledgebridge-main")
|
|
13 |
image = (
|
14 |
modal.Image.debian_slim(python_version="3.11")
|
15 |
.pip_install([
|
|
|
16 |
"numpy",
|
17 |
"faiss-cpu",
|
18 |
"PyPDF2",
|
@@ -334,56 +335,95 @@ def get_task_status(task_id: str) -> Dict[str, Any]:
|
|
334 |
'message': 'Task completed successfully'
|
335 |
}
|
336 |
|
337 |
-
# Web endpoints
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
347 |
|
348 |
-
|
349 |
-
@modal.web_endpoint(method="POST", label="extract-text")
|
350 |
-
def web_extract_text(request_data: Dict[str, Any]) -> Dict[str, Any]:
|
351 |
-
"""HTTP endpoint for text extraction"""
|
352 |
-
documents = request_data.get('documents', [])
|
353 |
-
return extract_text_from_documents.remote(documents)
|
354 |
|
355 |
-
@
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
|
363 |
-
@
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
|
|
|
|
368 |
|
369 |
-
@
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
|
|
|
|
374 |
|
375 |
-
@
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
380 |
return {
|
381 |
'status': 'healthy',
|
382 |
'service': 'KnowledgeBridge Modal App',
|
383 |
'version': '1.0.0',
|
384 |
-
'timestamp': datetime.datetime.
|
385 |
}
|
386 |
|
|
|
|
|
|
|
|
|
|
|
387 |
if __name__ == "__main__":
|
388 |
print("KnowledgeBridge Modal App")
|
389 |
print("Available functions:")
|
|
|
13 |
image = (
|
14 |
modal.Image.debian_slim(python_version="3.11")
|
15 |
.pip_install([
|
16 |
+
"fastapi[standard]",
|
17 |
"numpy",
|
18 |
"faiss-cpu",
|
19 |
"PyPDF2",
|
|
|
335 |
'message': 'Task completed successfully'
|
336 |
}
|
337 |
|
338 |
+
# Web endpoints using FastAPI
|
339 |
+
from fastapi import FastAPI, HTTPException
|
340 |
+
from fastapi.responses import JSONResponse
|
341 |
+
from pydantic import BaseModel
|
342 |
+
from typing import List, Dict, Any, Optional
|
343 |
+
import datetime
|
344 |
+
|
345 |
+
# Pydantic models
|
346 |
+
class VectorSearchRequest(BaseModel):
|
347 |
+
query: str
|
348 |
+
index_name: str = "main_index"
|
349 |
+
max_results: int = 10
|
350 |
+
|
351 |
+
class DocumentRequest(BaseModel):
|
352 |
+
documents: List[Dict[str, Any]]
|
353 |
+
|
354 |
+
class IndexRequest(BaseModel):
|
355 |
+
documents: List[Dict[str, Any]]
|
356 |
+
index_name: str = "main_index"
|
357 |
+
|
358 |
+
class BatchRequest(BaseModel):
|
359 |
+
documents: List[Dict[str, Any]]
|
360 |
+
operations: List[str] = ["extract_text"]
|
361 |
+
index_name: str = "batch_index"
|
362 |
|
363 |
+
web_app = FastAPI(title="KnowledgeBridge Modal API")
|
|
|
|
|
|
|
|
|
|
|
364 |
|
365 |
+
@web_app.post("/vector-search")
|
366 |
+
async def api_vector_search(request: VectorSearchRequest):
|
367 |
+
try:
|
368 |
+
result = vector_search.local(request.query, request.index_name, request.max_results)
|
369 |
+
return result
|
370 |
+
except Exception as e:
|
371 |
+
raise HTTPException(status_code=500, detail=str(e))
|
372 |
|
373 |
+
@web_app.post("/extract-text")
|
374 |
+
async def api_extract_text(request: DocumentRequest):
|
375 |
+
try:
|
376 |
+
result = extract_text_from_documents.local(request.documents)
|
377 |
+
return result
|
378 |
+
except Exception as e:
|
379 |
+
raise HTTPException(status_code=500, detail=str(e))
|
380 |
|
381 |
+
@web_app.post("/build-index")
|
382 |
+
async def api_build_index(request: IndexRequest):
|
383 |
+
try:
|
384 |
+
result = build_vector_index.local(request.documents, request.index_name)
|
385 |
+
return result
|
386 |
+
except Exception as e:
|
387 |
+
raise HTTPException(status_code=500, detail=str(e))
|
388 |
|
389 |
+
@web_app.post("/batch-process")
|
390 |
+
async def api_batch_process(request: BatchRequest):
|
391 |
+
try:
|
392 |
+
result = batch_process_documents.local({
|
393 |
+
"documents": request.documents,
|
394 |
+
"operations": request.operations,
|
395 |
+
"index_name": request.index_name
|
396 |
+
})
|
397 |
+
return result
|
398 |
+
except Exception as e:
|
399 |
+
raise HTTPException(status_code=500, detail=str(e))
|
400 |
+
|
401 |
+
@web_app.get("/task-status/{task_id}")
|
402 |
+
async def api_task_status(task_id: str):
|
403 |
+
try:
|
404 |
+
return {
|
405 |
+
'task_id': task_id,
|
406 |
+
'status': 'completed',
|
407 |
+
'progress': 100,
|
408 |
+
'message': 'Task completed successfully'
|
409 |
+
}
|
410 |
+
except Exception as e:
|
411 |
+
raise HTTPException(status_code=500, detail=str(e))
|
412 |
+
|
413 |
+
@web_app.get("/health")
|
414 |
+
async def api_health():
|
415 |
return {
|
416 |
'status': 'healthy',
|
417 |
'service': 'KnowledgeBridge Modal App',
|
418 |
'version': '1.0.0',
|
419 |
+
'timestamp': datetime.datetime.now(datetime.timezone.utc).isoformat()
|
420 |
}
|
421 |
|
422 |
+
@app.function(image=image)
|
423 |
+
@modal.asgi_app()
|
424 |
+
def fastapi_app():
|
425 |
+
return web_app
|
426 |
+
|
427 |
if __name__ == "__main__":
|
428 |
print("KnowledgeBridge Modal App")
|
429 |
print("Available functions:")
|