arnavam commited on
Commit
988f34d
·
1 Parent(s): 8cffbfe

updated dockerfile & api

Browse files
Files changed (4) hide show
  1. .DS_Store +0 -0
  2. API_DOCS.md +98 -0
  3. Dockerfile +3 -0
  4. server.py +123 -0
.DS_Store CHANGED
Binary files a/.DS_Store and b/.DS_Store differ
 
API_DOCS.md CHANGED
@@ -179,6 +179,80 @@ or
179
  }
180
  ```
181
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  ## File Storage
183
 
184
  All uploaded files and processed data are stored in the `/Model/` directory:
@@ -240,4 +314,28 @@ async def stream_audio():
240
  await websocket.send(json.dumps({"command": "stop"}))
241
 
242
  asyncio.run(stream_audio())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
  ```
 
179
  }
180
  ```
181
 
182
+ ### 5. Get Angle Metadata for Session
183
+ **Endpoint:** `GET /api/audio/angles/{session_id}`
184
+
185
+ **Description:** Retrieve angle data collected during an audio streaming session.
186
+
187
+ **Authentication:** Required (JWT token)
188
+
189
+ **Parameters:**
190
+ - `session_id` (path parameter): The UUID of the audio session
191
+
192
+ **Response:**
193
+ ```json
194
+ {
195
+ "ok": true,
196
+ "session_id": "uuid-here",
197
+ "angles": [
198
+ {"timestamp": 0.000, "angle": 45.50},
199
+ {"timestamp": 0.064, "angle": 46.20},
200
+ {"timestamp": 0.128, "angle": 47.00}
201
+ ],
202
+ "count": 3
203
+ }
204
+ ```
205
+
206
+ ### 6. Download Audio File
207
+ **Endpoint:** `GET /api/audio/download/{session_id}`
208
+
209
+ **Description:** Download the recorded audio file (.wav) for a specific session.
210
+
211
+ **Authentication:** Required (JWT token)
212
+
213
+ **Parameters:**
214
+ - `session_id` (path parameter): The UUID of the audio session
215
+
216
+ **Response:**
217
+ - Binary WAV file with `Content-Type: audio/wav`
218
+ - File download with appropriate filename header
219
+
220
+ ### 7. Set Desired Angle
221
+ **Endpoint:** `POST /api/audio/set-angle/{session_id}`
222
+
223
+ **Description:** Send a desired/target angle to the audio processing backend for a session.
224
+
225
+ **Authentication:** Required (JWT token)
226
+
227
+ **Parameters:**
228
+ - `session_id` (path parameter): The UUID of the audio session
229
+ - `angle` (form parameter, required): Desired angle in degrees (0-360)
230
+
231
+ **Request:**
232
+ ```
233
+ POST /api/audio/set-angle/session-uuid-here
234
+ Content-Type: multipart/form-data
235
+
236
+ angle=45.5
237
+ ```
238
+
239
+ **Response:**
240
+ ```json
241
+ {
242
+ "ok": true,
243
+ "message": "Desired angle set to 45.5°",
244
+ "session_id": "uuid-here",
245
+ "angle": 45.5
246
+ }
247
+ ```
248
+
249
+ **Error Response (Invalid Angle):**
250
+ ```json
251
+ {
252
+ "detail": "Angle must be between 0 and 360 degrees"
253
+ }
254
+ ```
255
+
256
  ## File Storage
257
 
258
  All uploaded files and processed data are stored in the `/Model/` directory:
 
314
  await websocket.send(json.dumps({"command": "stop"}))
315
 
316
  asyncio.run(stream_audio())
317
+
318
+ # 4. Get angle data for a session
319
+ response = requests.get(
320
+ f"http://localhost:8000/api/audio/angles/{session_id}",
321
+ headers={"Authorization": f"Bearer {token}"}
322
+ )
323
+ angles = response.json()["angles"]
324
+ print(f"Recorded {len(angles)} angle measurements")
325
+
326
+ # 5. Download recorded audio
327
+ response = requests.get(
328
+ f"http://localhost:8000/api/audio/download/{session_id}",
329
+ headers={"Authorization": f"Bearer {token}"}
330
+ )
331
+ with open("downloaded_audio.wav", "wb") as f:
332
+ f.write(response.content)
333
+
334
+ # 6. Send desired angle to backend
335
+ response = requests.post(
336
+ f"http://localhost:8000/api/audio/set-angle/{session_id}",
337
+ data={"angle": 90.0},
338
+ headers={"Authorization": f"Bearer {token}"}
339
+ )
340
+ print(response.json())
341
  ```
Dockerfile CHANGED
@@ -3,6 +3,9 @@ FROM python:3.11-slim
3
  WORKDIR /app
4
 
5
  RUN apt-get update && apt-get install -y \
 
 
 
6
  libgl1-mesa-glx \
7
  libglib2.0-0 \
8
  libsm6 \
 
3
  WORKDIR /app
4
 
5
  RUN apt-get update && apt-get install -y \
6
+ gcc \
7
+ gfortran \
8
+ libopenblas-dev \
9
  libgl1-mesa-glx \
10
  libglib2.0-0 \
11
  libsm6 \
server.py CHANGED
@@ -710,5 +710,128 @@ async def list_audio_recordings(current_user: UserPublic = Depends(get_current_u
710
  logger.error(f"Error listing recordings: {e}")
711
  raise HTTPException(status_code=500, detail=str(e))
712
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
713
  if __name__ == "__main__":
714
  uvicorn.run("server:app", host="0.0.0.0", port=8000, reload=True)
 
710
  logger.error(f"Error listing recordings: {e}")
711
  raise HTTPException(status_code=500, detail=str(e))
712
 
713
+ @app.get("/api/audio/angles/{session_id}")
714
+ async def get_audio_angles(
715
+ session_id: str
716
+ ):
717
+ """Get angle metadata for a specific audio session."""
718
+ try:
719
+ metadata_file = MODEL_DIR / "audio_recordings" / f"audio_{session_id}_metadata.txt"
720
+
721
+ if not metadata_file.exists():
722
+ raise HTTPException(
723
+ status_code=404,
724
+ detail=f"No metadata found for session {session_id}"
725
+ )
726
+
727
+ angles_data = []
728
+ with open(metadata_file, 'r') as f:
729
+ lines = f.readlines()
730
+ # Skip header if present
731
+ start_idx = 1 if lines and 'timestamp' in lines[0] else 0
732
+ for line in lines[start_idx:]:
733
+ if line.strip():
734
+ parts = line.strip().split(',')
735
+ if len(parts) >= 2:
736
+ try:
737
+ timestamp = float(parts[0])
738
+ angle = float(parts[1])
739
+ angles_data.append({"timestamp": timestamp, "angle": angle})
740
+ except ValueError:
741
+ continue
742
+
743
+ return {
744
+ "ok": True,
745
+ "session_id": session_id,
746
+ "angles": angles_data,
747
+ "count": len(angles_data)
748
+ }
749
+ except HTTPException:
750
+ raise
751
+ except Exception as e:
752
+ logger.error(f"Error retrieving angles for session {session_id}: {e}")
753
+ raise HTTPException(status_code=500, detail=str(e))
754
+
755
+ @app.get("/api/audio/download/{session_id}")
756
+ async def download_audio_file(
757
+ session_id: str
758
+ ):
759
+ """Download recorded audio file for a specific session."""
760
+ try:
761
+ # Find the audio file matching this session_id
762
+ audio_dir = MODEL_DIR / "audio_recordings"
763
+
764
+ if not audio_dir.exists():
765
+ raise HTTPException(status_code=404, detail="No audio recordings found")
766
+
767
+ # Search for the file with this session_id
768
+ audio_file = None
769
+ for file in audio_dir.glob(f"audio_{session_id}_*.wav"):
770
+ # Skip metadata files
771
+ if not str(file).endswith("_metadata.txt"):
772
+ audio_file = file
773
+ break
774
+
775
+ if not audio_file or not audio_file.exists():
776
+ raise HTTPException(
777
+ status_code=404,
778
+ detail=f"Audio file not found for session {session_id}"
779
+ )
780
+
781
+ return StreamingResponse(
782
+ iter([await asyncio.get_event_loop().run_in_executor(None, audio_file.read_bytes)]),
783
+ media_type="audio/wav",
784
+ headers={
785
+ "Content-Disposition": f"attachment; filename={audio_file.name}"
786
+ }
787
+ )
788
+ except HTTPException:
789
+ raise
790
+ except Exception as e:
791
+ logger.error(f"Error downloading audio for session {session_id}: {e}")
792
+ raise HTTPException(status_code=500, detail=str(e))
793
+
794
+ @app.post("/api/audio/set-angle/{session_id}")
795
+ async def set_desired_angle(
796
+ session_id: str,
797
+ angle: float = Form(...)
798
+ ):
799
+ """Send a desired angle to the audio processing system."""
800
+ try:
801
+ if not (0 <= angle <= 360):
802
+ raise HTTPException(
803
+ status_code=400,
804
+ detail="Angle must be between 0 and 360 degrees"
805
+ )
806
+
807
+ # Check if session exists
808
+ audio_dir = MODEL_DIR / "audio_recordings"
809
+ session_exists = any(audio_dir.glob(f"audio_{session_id}_*.wav"))
810
+
811
+ if not session_exists:
812
+ raise HTTPException(
813
+ status_code=404,
814
+ detail=f"Session {session_id} not found"
815
+ )
816
+
817
+ # Store desired angle (append to metadata or create angle request file)
818
+ desired_angle_file = audio_dir / f"audio_{session_id}_desired_angle.txt"
819
+ with open(desired_angle_file, 'w') as f:
820
+ f.write(f"{angle}\n")
821
+
822
+ logger.info(f"Set desired angle {angle}° for session {session_id}")
823
+
824
+ return {
825
+ "ok": True,
826
+ "message": f"Desired angle set to {angle}°",
827
+ "session_id": session_id,
828
+ "angle": angle
829
+ }
830
+ except HTTPException:
831
+ raise
832
+ except Exception as e:
833
+ logger.error(f"Error setting angle for session {session_id}: {e}")
834
+ raise HTTPException(status_code=500, detail=str(e))
835
+
836
  if __name__ == "__main__":
837
  uvicorn.run("server:app", host="0.0.0.0", port=8000, reload=True)