Jrine commited on
Commit
a35eca8
·
1 Parent(s): 1257299

Add Docker API files

Browse files
Files changed (3) hide show
  1. Dockerfile +27 -0
  2. app.py +185 -0
  3. requirements.txt +8 -0
Dockerfile ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # Install system dependencies
6
+ RUN apt-get update && apt-get install -y \
7
+ build-essential \
8
+ curl \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ # Copy requirements and install Python dependencies
12
+ COPY requirements.txt .
13
+ RUN pip install --no-cache-dir --upgrade pip
14
+ RUN pip install --no-cache-dir -r requirements.txt
15
+
16
+ # Copy application code
17
+ COPY app.py .
18
+
19
+ # Expose port 7860 (Hugging Face Spaces default)
20
+ EXPOSE 7860
21
+
22
+ # Health check
23
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
24
+ CMD curl -f http://localhost:7860/health || exit 1
25
+
26
+ # Run the application
27
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,185 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import List, Optional
2
+
3
+ import numpy as np
4
+ from fastapi import FastAPI, HTTPException
5
+ from fastapi.middleware.cors import CORSMiddleware
6
+ from pydantic import BaseModel
7
+ from sentence_transformers import SentenceTransformer
8
+ from transformers import pipeline
9
+
10
+ app = FastAPI(
11
+ title="Learning Objective Taxonomy API",
12
+ description="API for Bloom's, Dave's, and CO-PO analysis",
13
+ version="1.0.0",
14
+ )
15
+
16
+ # CORS middleware for Next.js
17
+ app.add_middleware(
18
+ CORSMiddleware,
19
+ allow_origins=["*"],
20
+ allow_credentials=True,
21
+ allow_methods=["*"],
22
+ allow_headers=["*"],
23
+ )
24
+
25
+ # Load your models at startup
26
+ print("Loading models...")
27
+ try:
28
+ blooms_model = pipeline("text-classification", model="Jrine/blooms")
29
+ dave_model = pipeline("text-classification", model="Jrine/dave")
30
+ coppo_model = SentenceTransformer("Jrine/co-po")
31
+ print("✅ All models loaded successfully!")
32
+ except Exception as e:
33
+ print(f"❌ Error loading models: {e}")
34
+ blooms_model = None
35
+ dave_model = None
36
+ coppo_model = None
37
+
38
+
39
+ # Pydantic models
40
+ class TextRequest(BaseModel):
41
+ text: str
42
+
43
+
44
+ class AnalyzeAllRequest(BaseModel):
45
+ text: str
46
+
47
+
48
+ @app.get("/")
49
+ async def root():
50
+ return {
51
+ "message": "Learning Objective Taxonomy API",
52
+ "version": "1.0.0",
53
+ "endpoints": {
54
+ "blooms": "/api/blooms",
55
+ "dave": "/api/dave",
56
+ "coppo": "/api/coppo",
57
+ "analyze": "/api/analyze",
58
+ },
59
+ "status": {
60
+ "blooms": blooms_model is not None,
61
+ "dave": dave_model is not None,
62
+ "coppo": coppo_model is not None,
63
+ },
64
+ }
65
+
66
+
67
+ @app.post("/api/blooms")
68
+ async def predict_blooms(request: TextRequest):
69
+ if blooms_model is None:
70
+ raise HTTPException(status_code=503, detail="Blooms model not loaded")
71
+
72
+ try:
73
+ results = blooms_model(request.text)
74
+
75
+ return {
76
+ "success": True,
77
+ "model": "blooms-taxonomy",
78
+ "text": request.text,
79
+ "prediction": {
80
+ "level": results[0]["label"],
81
+ "confidence": results[0]["score"],
82
+ "all_predictions": results,
83
+ },
84
+ "timestamp": None,
85
+ }
86
+ except Exception as e:
87
+ raise HTTPException(status_code=500, detail=str(e))
88
+
89
+
90
+ @app.post("/api/dave")
91
+ async def predict_dave(request: TextRequest):
92
+ if dave_model is None:
93
+ raise HTTPException(status_code=503, detail="Dave model not loaded")
94
+
95
+ try:
96
+ results = dave_model(request.text)
97
+
98
+ return {
99
+ "success": True,
100
+ "model": "dave-psychomotor",
101
+ "text": request.text,
102
+ "prediction": {
103
+ "level": results[0]["label"],
104
+ "confidence": results[0]["score"],
105
+ "all_predictions": results,
106
+ },
107
+ "timestamp": None,
108
+ }
109
+ except Exception as e:
110
+ raise HTTPException(status_code=500, detail=str(e))
111
+
112
+
113
+ @app.post("/api/coppo")
114
+ async def predict_coppo(request: TextRequest):
115
+ if coppo_model is None:
116
+ raise HTTPException(status_code=503, detail="CO-PO model not loaded")
117
+
118
+ try:
119
+ embeddings = coppo_model.encode(request.text)
120
+
121
+ return {
122
+ "success": True,
123
+ "model": "co-po",
124
+ "text": request.text,
125
+ "embeddings": embeddings.tolist(),
126
+ "timestamp": None,
127
+ }
128
+ except Exception as e:
129
+ raise HTTPException(status_code=500, detail=str(e))
130
+
131
+
132
+ @app.post("/api/analyze")
133
+ async def analyze_all(request: AnalyzeAllRequest):
134
+ if not all([blooms_model, dave_model, coppo_model]):
135
+ raise HTTPException(status_code=503, detail="Not all models loaded")
136
+
137
+ try:
138
+ # Run all models
139
+ blooms_results = blooms_model(request.text)
140
+ dave_results = dave_model(request.text)
141
+ coppo_embeddings = coppo_model.encode(request.text)
142
+
143
+ return {
144
+ "success": True,
145
+ "text": request.text,
146
+ "results": {
147
+ "blooms": {
148
+ "level": blooms_results[0]["label"],
149
+ "confidence": blooms_results[0]["score"],
150
+ "all_predictions": blooms_results,
151
+ "model": "Jrine/blooms",
152
+ },
153
+ "dave": {
154
+ "level": dave_results[0]["label"],
155
+ "confidence": dave_results[0]["score"],
156
+ "all_predictions": dave_results,
157
+ "model": "Jrine/dave",
158
+ },
159
+ "coppo": {
160
+ "embeddings": coppo_embeddings.tolist(),
161
+ "model": "Jrine/co-po",
162
+ },
163
+ },
164
+ "timestamp": None,
165
+ }
166
+ except Exception as e:
167
+ raise HTTPException(status_code=500, detail=str(e))
168
+
169
+
170
+ @app.get("/health")
171
+ async def health():
172
+ return {
173
+ "status": "healthy",
174
+ "models_loaded": {
175
+ "blooms": blooms_model is not None,
176
+ "dave": dave_model is not None,
177
+ "coppo": coppo_model is not None,
178
+ },
179
+ }
180
+
181
+
182
+ if __name__ == "__main__":
183
+ import uvicorn
184
+
185
+ uvicorn.run(app, host="0.0.0.0", port=7860)
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ fastapi==0.109.0
2
+ uvicorn[standard]==0.27.0
3
+ sentence-transformers==2.3.1
4
+ transformers==4.37.2
5
+ torch==2.1.2
6
+ pydantic==2.5.3
7
+ numpy==1.24.3
8
+ python-multipart==0.0.6