mutarisi commited on
Commit
10fc241
·
1 Parent(s): ae78832

path way edits

Browse files
Files changed (3) hide show
  1. apiRoutes.py +44 -16
  2. app.py +12 -142
  3. lettersControllerS.py +6 -6
apiRoutes.py CHANGED
@@ -1,13 +1,22 @@
1
  from fastapi import APIRouter, WebSocket, WebSocketDisconnect, UploadFile, File, HTTPException
2
  import json
3
  from fastapi.responses import JSONResponse
4
- from controllers.lettersControllerS import detectFromImageBytes as detectLetters
5
- from controllers.wordsControllerS import detectFromImageBytes as detectWords
6
  from typing import List
7
  from dotenv import load_dotenv
8
  import httpx
9
  import os
10
 
 
 
 
 
 
 
 
 
 
11
  router = APIRouter(prefix="/handsUPApi")
12
 
13
  class ConnectionManager:
@@ -204,35 +213,54 @@ async def sendToHF(url: str, frames: List[UploadFile]):
204
 
205
  @router.post("/processLetters")
206
  async def process_letters(frames: List[UploadFile] = File(...)):
 
207
  sequence_num = 20
208
  if len(frames) != sequence_num:
209
- raise HTTPException(status_code=400, detail=f"Exactly {sequence_num} frames required")
210
 
211
- url = f"{HUGGINGFACE_BASE_URL}/detect-letters"
212
-
213
- result = await sendToHF(url, frames)
214
- print(f"Received result: {result}")
 
 
 
 
 
 
 
 
 
 
215
  return JSONResponse(content=result)
216
 
217
-
218
  @router.post("/processWords")
219
  async def process_words(frames: List[UploadFile] = File(...)):
 
220
  sequence_num = 90
221
  if len(frames) != sequence_num:
222
- raise HTTPException(status_code=400, detail=f"Exactly {sequence_num} frames required")
223
-
224
- url = f"{HUGGINGFACE_BASE_URL}/detect-words"
225
 
226
- result = await sendToHF(url, frames)
 
 
 
 
 
 
 
 
 
 
227
  return JSONResponse(content=result)
228
 
229
-
230
  @router.post("/sentence")
231
  async def sign_sentence(data: dict):
 
232
  gloss_input = data.get("gloss")
233
  if not gloss_input:
234
  raise HTTPException(status_code=400, detail="No gloss provided")
235
 
236
- from controllers.glossController import translateGloss
237
- translation = translateGloss(gloss_input)
238
- return {"translation": translation}
 
1
  from fastapi import APIRouter, WebSocket, WebSocketDisconnect, UploadFile, File, HTTPException
2
  import json
3
  from fastapi.responses import JSONResponse
4
+ from lettersControllerS import detectFromImageBytes as detectLetters
5
+ from wordsControllerS import detectFromImageBytes as detectWords
6
  from typing import List
7
  from dotenv import load_dotenv
8
  import httpx
9
  import os
10
 
11
+ os.environ["HF_HOME"] = "/tmp"
12
+ os.environ["HUGGINGFACE_HUB_CACHE"] = "/tmp/huggingface_cache"
13
+ os.makedirs("/tmp/huggingface_cache", exist_ok=True)
14
+ # Ensure these imports are correct
15
+ from lettersController import detectFromImage
16
+ from wordsController import detectWords
17
+ from glossController import translateGloss
18
+
19
+
20
  router = APIRouter(prefix="/handsUPApi")
21
 
22
  class ConnectionManager:
 
213
 
214
  @router.post("/processLetters")
215
  async def process_letters(frames: List[UploadFile] = File(...)):
216
+ """Processes a sequence of frames to detect sign language letters."""
217
  sequence_num = 20
218
  if len(frames) != sequence_num:
219
+ raise HTTPException(status_code=400, detail=f"Exactly {sequence_num} frames are required")
220
 
221
+ # CRITICAL: Read the binary content of each file
222
+ # We will pass a list of image bytes (memory buffers), NOT UploadFile objects.
223
+ image_bytes_list = []
224
+ try:
225
+ for frame in frames:
226
+ # frame.file is an async context manager, read() returns bytes
227
+ contents = await frame.read()
228
+ image_bytes_list.append(contents)
229
+ except Exception as e:
230
+ # Handle potential file read errors
231
+ raise HTTPException(status_code=500, detail=f"Error reading uploaded file contents: {e}")
232
+
233
+ # Pass the list of image bytes to the controller
234
+ result = detectFromImage(image_bytes_list)
235
  return JSONResponse(content=result)
236
 
 
237
  @router.post("/processWords")
238
  async def process_words(frames: List[UploadFile] = File(...)):
239
+ """Processes a sequence of frames to detect sign language words."""
240
  sequence_num = 90
241
  if len(frames) != sequence_num:
242
+ raise HTTPException(status_code=400, detail=f"Exactly {sequence_num} frames are required")
 
 
243
 
244
+ # CRITICAL: Read the binary content of each file
245
+ image_bytes_list = []
246
+ try:
247
+ for frame in frames:
248
+ contents = await frame.read()
249
+ image_bytes_list.append(contents)
250
+ except Exception as e:
251
+ raise HTTPException(status_code=500, detail=f"Error reading uploaded file contents: {e}")
252
+
253
+ # Call the imported function directly
254
+ result = detectWords(image_bytes_list)
255
  return JSONResponse(content=result)
256
 
 
257
  @router.post("/sentence")
258
  async def sign_sentence(data: dict):
259
+ """Generates a signed sentence from a given gloss."""
260
  gloss_input = data.get("gloss")
261
  if not gloss_input:
262
  raise HTTPException(status_code=400, detail="No gloss provided")
263
 
264
+ # Call the imported function directly
265
+ result = translateGloss(gloss_input)
266
+ return JSONResponse(content={"translation": result})
app.py CHANGED
@@ -1,145 +1,15 @@
1
  import os
2
- import sys
3
- import uvicorn
4
- from fastapi import FastAPI, UploadFile, File, Form
5
- from typing import List
6
- from starlette.responses import JSONResponse
7
- import tempfile
8
 
9
- # Correct import statements for all controllers
10
- try:
11
- from lettersController import detectFromImage
12
- from wordsController import detectWords
13
- from glossController import translateGloss
14
- print("Successfully imported functions from controllers.")
15
- except ImportError as e:
16
- print(f"ERROR: Could not import from controllers: {e}")
17
- sys.exit(1)
18
-
19
- # --- FastAPI App Initialization ---
20
  app = FastAPI()
21
-
22
- # --- Load AI Model and Assets on Startup ---
23
- # The models are loaded when the controller modules are imported.
24
- # It's a good practice to print a message to confirm this.
25
- print("\n--- Hugging Face Space starting. Models are being loaded... ---")
26
- print("--- AI letter, words, and translation models loaded. Ready to serve predictions. ---\n")
27
-
28
- # --- FastAPI Route for Letter Detection ---
29
- @app.post("/detect-letters")
30
- async def process_letters(
31
- frames: List[UploadFile] = File(...)
32
- ):
33
- """
34
- Receives 20 image frames and processes them to detect a letter or number.
35
- """
36
- sequence_num = 20
37
- if len(frames) != sequence_num:
38
- return JSONResponse(
39
- status_code=400,
40
- content={"error": f"Exactly {sequence_num} frames are required for letter detection", "success": False}
41
- )
42
-
43
- temp_dir = tempfile.mkdtemp()
44
- paths = []
45
-
46
- try:
47
- # Save each frame to a temporary file
48
- for i, frame in enumerate(frames):
49
- path = os.path.join(temp_dir, f'frame_{i}.jpg')
50
- contents = await frame.read()
51
- with open(path, "wb") as f:
52
- f.write(contents)
53
- paths.append(path)
54
-
55
- # Call the letter detection function
56
- result = detectFromImage(paths)
57
-
58
- return JSONResponse(content=result)
59
-
60
- except Exception as e:
61
- return JSONResponse(
62
- status_code=500,
63
- content={
64
- "error": "Error processing image sequence for letter detection",
65
- "details": str(e),
66
- "success": False
67
- }
68
- )
69
- finally:
70
- # Clean up temporary files
71
- for path in paths:
72
- os.remove(path)
73
- os.rmdir(temp_dir)
74
-
75
- # --- FastAPI Route for Word Detection ---
76
- @app.post("/detect-words")
77
- async def process_words(
78
- frames: List[UploadFile] = File(...)
79
- ):
80
- """
81
- Receives 90 image frames and processes them to detect a word.
82
- """
83
- sequence_length = 90
84
- if len(frames) != sequence_length:
85
- return JSONResponse(
86
- status_code=400,
87
- content={"error": f"Exactly {sequence_length} frames are required for word detection", "success": False}
88
- )
89
-
90
- temp_dir = tempfile.mkdtemp()
91
- paths = []
92
-
93
- try:
94
- # Save each frame to a temporary file
95
- for i, frame in enumerate(frames):
96
- path = os.path.join(temp_dir, f'frame_{i}.jpg')
97
- contents = await frame.read()
98
- with open(path, "wb") as f:
99
- f.write(contents)
100
- paths.append(path)
101
-
102
- # Call the word detection function
103
- result = detectWords(paths)
104
-
105
- return JSONResponse(content=result)
106
-
107
- except Exception as e:
108
- return JSONResponse(
109
- status_code=500,
110
- content={
111
- "error": "Error processing image sequence for word detection",
112
- "details": str(e),
113
- "success": False
114
- }
115
- )
116
- finally:
117
- # Clean up temporary files
118
- for path in paths:
119
- os.remove(path)
120
- os.rmdir(temp_dir)
121
-
122
- # --- FastAPI Route for Sentence Translation ---
123
- @app.post("/sentence")
124
- async def process_sentence(
125
- gloss: str = Form(...)
126
- ):
127
- """
128
- Receives a string of gloss and translates it into a human-readable sentence.
129
- """
130
- try:
131
- result = translateGloss(gloss)
132
- return JSONResponse(content={"translation": result, "success": True})
133
- except Exception as e:
134
- return JSONResponse(
135
- status_code=500,
136
- content={
137
- "error": "Error translating gloss",
138
- "details": str(e),
139
- "success": False
140
- }
141
- )
142
-
143
- if __name__ == "__main__":
144
- # Hugging Face Spaces automatically sets the port to 7860
145
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
1
  import os
2
+ from fastapi import FastAPI
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ from apiRoutes import router as sign_router
 
 
 
5
 
 
 
 
 
 
 
 
 
 
 
 
6
  app = FastAPI()
7
+ app.include_router(sign_router)
8
+
9
+ app.add_middleware(
10
+ CORSMiddleware,
11
+ allow_origins=["https://handsup.onrender.com"],
12
+ allow_credentials=True,
13
+ allow_methods=["*"],
14
+ allow_headers=["*"],
15
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
lettersControllerS.py CHANGED
@@ -5,16 +5,16 @@ import tensorflow as tf
5
  import mediapipe as mp
6
  from fastapi import WebSocket
7
 
8
- lettersModel = tf.keras.models.load_model('../../ai_model/models/detectLettersModel.keras')
9
- with open('../../ai_model/models/labelEncoder.pickle', 'rb') as f:
10
  labelEncoder = pickle.load(f)
11
 
12
- lettersModel2 = tf.keras.models.load_model('../../ai_model/jz_model/JZModel.keras')
13
- with open('../../ai_model/jz_model/labelEncoder.pickle', 'rb') as f:
14
  labelEncoder2 = pickle.load(f)
15
 
16
- numbersModel = tf.keras.models.load_model('../../ai_model/models/detectNumbersModel.keras')
17
- with open('../../ai_model/models/numLabelEncoder.pickle', 'rb') as f:
18
  numLabelEncoder = pickle.load(f)
19
 
20
  hands = mp.solutions.hands.Hands(static_image_mode=True)
 
5
  import mediapipe as mp
6
  from fastapi import WebSocket
7
 
8
+ lettersModel = tf.keras.models.load_model('ai_model/models/detectLettersModel.keras')
9
+ with open('ai_model/models/labelEncoder.pickle', 'rb') as f:
10
  labelEncoder = pickle.load(f)
11
 
12
+ lettersModel2 = tf.keras.models.load_model('ai_model/jz_model/JZModel.keras')
13
+ with open('ai_model/jz_model/labelEncoder.pickle', 'rb') as f:
14
  labelEncoder2 = pickle.load(f)
15
 
16
+ numbersModel = tf.keras.models.load_model('ai_model/models/detectNumbersModel.keras')
17
+ with open('ai_model/models/numLabelEncoder.pickle', 'rb') as f:
18
  numLabelEncoder = pickle.load(f)
19
 
20
  hands = mp.solutions.hands.Hands(static_image_mode=True)