bitsnaps commited on
Commit
aa4e39d
·
verified ·
1 Parent(s): 3c44f93

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +372 -72
main.py CHANGED
@@ -1,4 +1,4 @@
1
- import os, io, uuid, json, wave
2
  import aiohttp
3
  import aiofiles
4
  import asyncio
@@ -84,7 +84,6 @@ else:
84
  SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
85
  Base = declarative_base()
86
 
87
- # SQLAlchemy Models
88
  # SQLAlchemy Models
89
  class UserModel(Base):
90
  __tablename__ = "users"
@@ -161,6 +160,25 @@ class Transcription(TranscriptionBase):
161
  class Config:
162
  from_attributes = True
163
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  # Add these utilities
165
  oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
166
 
@@ -185,7 +203,7 @@ os.makedirs("uploads", exist_ok=True)
185
 
186
  # Mount static files
187
  app.mount("/static", StaticFiles(directory="static"), name="static")
188
- app.mount("/uploads", StaticFiles(directory="uploads"), name="uploads")
189
 
190
  # Initialize database
191
  def init_db():
@@ -426,21 +444,6 @@ async def login_for_access_token(
426
  detail=f"Internal server error: {str(e)}"
427
  )
428
 
429
- # @app.post("/token", response_model=Token)
430
- # async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)):
431
- # user = authenticate_user(db, form_data.username, form_data.password)
432
- # if not user:
433
- # raise HTTPException(
434
- # status_code=401,
435
- # detail="Incorrect username or password",
436
- # headers={"WWW-Authenticate": "Bearer"},
437
- # )
438
- # access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
439
- # access_token = create_access_token(
440
- # data={"sub": user.username}, expires_delta=access_token_expires
441
- # )
442
- # return {"access_token": access_token, "token_type": "bearer"}
443
-
444
  @app.post("/api/signup")
445
  async def signup(user: UserCreate, db: Session = Depends(get_db)):
446
  try:
@@ -482,17 +485,6 @@ async def signup(user: UserCreate, db: Session = Depends(get_db)):
482
  detail=f"An error occurred: {str(e)}"
483
  )
484
 
485
- # Modify the existing routes to require authentication
486
- @app.get("/api/me", response_model=User)
487
- async def read_users_me(current_user: User = Depends(get_current_user)):
488
- return current_user
489
-
490
- @app.get("/", response_class=HTMLResponse)
491
- async def read_index():
492
- async with aiofiles.open("index.html", mode="r") as f:
493
- content = await f.read()
494
- return HTMLResponse(content=content)
495
-
496
  # Helper function to split audio into chunks
497
  def split_audio_chunks(
498
  file_path: str,
@@ -648,6 +640,244 @@ def combine_results(results: list, response_format: str):
648
 
649
  return final
650
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
651
  @app.post("/api/upload")
652
  async def create_upload_file(
653
  current_user: User = Depends(get_current_user),
@@ -696,6 +926,40 @@ async def create_upload_file(
696
  if start_sample >= end_sample:
697
  raise HTTPException(400, "Invalid time range")
698
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
699
  # Slice the audio data
700
  audio_data = audio_data[start_sample:end_sample]
701
 
@@ -703,6 +967,12 @@ async def create_upload_file(
703
  sliced_path = f"{temp_path}_sliced.flac"
704
  sf.write(sliced_path, audio_data, sample_rate, format='FLAC')
705
 
 
 
 
 
 
 
706
  # Split into FLAC chunks
707
  chunks = split_audio_chunks(
708
  sliced_path,
@@ -728,6 +998,14 @@ async def create_upload_file(
728
  # Combine results
729
  combined = combine_results(results, response_format)
730
 
 
 
 
 
 
 
 
 
731
  # Cleanup
732
  for chunk in chunks:
733
  os.remove(chunk["path"])
@@ -744,29 +1022,6 @@ async def create_upload_file(
744
  os.remove(sliced_path)
745
  raise HTTPException(500, str(e))
746
 
747
- @app.post("/api/upload-audio")
748
- async def upload_audio(
749
- request: Request,
750
- current_user: User = Depends(get_current_user),
751
- db: Session = Depends(get_db)
752
- ):
753
- try:
754
- form_data = await request.form()
755
- file = form_data["file"]
756
-
757
- file_id = str(uuid.uuid4())
758
- filename = f"{file_id}_{file.filename}"
759
- file_path = os.path.join("uploads", filename)
760
- print(f"file_path: ${file_path}")
761
-
762
- contents = await file.read()
763
- async with aiofiles.open(file_path, "wb") as f:
764
- await f.write(contents)
765
-
766
- return JSONResponse({"filename": filename})
767
- except Exception as e:
768
- raise HTTPException(status_code=500, detail=str(e))
769
-
770
  @app.post("/api/upload-audio-chunk")
771
  async def upload_audio_chunk(
772
  file: UploadFile = File(...),
@@ -812,8 +1067,11 @@ async def finalize_audio_upload(
812
  metadata_path = os.path.join(upload_path, "metadata.txt")
813
  filename = f"{uuid.uuid4()}.mp3" # Default filename
814
 
 
 
 
815
  # Combine all chunks into final file
816
- output_path = os.path.join(UPLOAD_DIR, filename)
817
 
818
  with open(output_path, "wb") as outfile:
819
  # Get all chunks sorted by offset
@@ -851,24 +1109,52 @@ async def get_audio_files(
851
  current_user: User = Depends(get_current_user)
852
  ):
853
  try:
854
- # Scan uploads directory for audio files
855
- upload_dir = os.path.join(os.getcwd(), UPLOAD_DIR)
856
  file_list = []
857
 
858
- for filename in os.listdir(upload_dir):
859
- file_path = os.path.join(upload_dir, filename)
860
- if os.path.isfile(file_path) and not filename.startswith('.'):
861
- # Get file stats
862
- file_stats = os.stat(file_path)
863
- file_size = os.path.getsize(file_path)
864
-
865
- file_list.append({
866
- "id": filename, # Use filename as ID
867
- "filename": filename,
868
- "original_filename": filename,
869
- "size": file_size,
870
- "uploaded_at": datetime.fromtimestamp(file_stats.st_mtime).isoformat()
871
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
872
 
873
  # Sort by upload date (newest first)
874
  file_list.sort(key=lambda x: x["uploaded_at"], reverse=True)
@@ -881,11 +1167,25 @@ async def get_audio_files(
881
  @app.delete("/api/audio-files/{filename}")
882
  async def delete_audio_file(
883
  filename: str,
884
- current_user: User = Depends(get_current_user)
 
 
885
  ):
886
  try:
887
- # Check if file exists in uploads directory
888
- file_path = os.path.join(os.getcwd(), UPLOAD_DIR, filename)
 
 
 
 
 
 
 
 
 
 
 
 
889
  if not os.path.exists(file_path):
890
  raise HTTPException(status_code=404, detail="Audio file not found")
891
 
 
1
+ import os, io, uuid, json, wave, math
2
  import aiohttp
3
  import aiofiles
4
  import asyncio
 
84
  SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
85
  Base = declarative_base()
86
 
 
87
  # SQLAlchemy Models
88
  class UserModel(Base):
89
  __tablename__ = "users"
 
160
  class Config:
161
  from_attributes = True
162
 
163
+ # Add this with other SQLAlchemy models
164
+ class UserCreditModel(Base):
165
+ __tablename__ = "user_credits"
166
+
167
+ id = Column(Integer, primary_key=True, index=True)
168
+ user_id = Column(Integer, ForeignKey("users.id"))
169
+ minutes_used = Column(Integer, default=0)
170
+ minutes_quota = Column(Integer, default=10) # Default to 10 minutes
171
+ last_updated = Column(String, default=lambda: datetime.utcnow().isoformat())
172
+
173
+ class UserCredit(BaseModel):
174
+ user_id: int
175
+ minutes_used: int
176
+ minutes_quota: int
177
+ last_updated: str
178
+
179
+ class Config:
180
+ from_attributes = True
181
+
182
  # Add these utilities
183
  oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
184
 
 
203
 
204
  # Mount static files
205
  app.mount("/static", StaticFiles(directory="static"), name="static")
206
+ app.mount("/uploads", StaticFiles(directory=UPLOAD_DIR), name="uploads")
207
 
208
  # Initialize database
209
  def init_db():
 
444
  detail=f"Internal server error: {str(e)}"
445
  )
446
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
447
  @app.post("/api/signup")
448
  async def signup(user: UserCreate, db: Session = Depends(get_db)):
449
  try:
 
485
  detail=f"An error occurred: {str(e)}"
486
  )
487
 
 
 
 
 
 
 
 
 
 
 
 
488
  # Helper function to split audio into chunks
489
  def split_audio_chunks(
490
  file_path: str,
 
640
 
641
  return final
642
 
643
+ def get_user_upload_dir(user_id):
644
+ """Get the upload directory for a specific user"""
645
+ user_dir = os.path.join(UPLOAD_DIR, str(user_id))
646
+ os.makedirs(user_dir, exist_ok=True)
647
+ return user_dir
648
+
649
+ @app.get("/api/me", response_model=User)
650
+ async def read_users_me(current_user: User = Depends(get_current_user)):
651
+ return current_user
652
+
653
+ @app.get("/", response_class=HTMLResponse)
654
+ async def read_index():
655
+ async with aiofiles.open("index.html", mode="r") as f:
656
+ content = await f.read()
657
+ return HTMLResponse(content=content)
658
+
659
+ @app.get("/api/credits")
660
+ async def get_user_credits(
661
+ current_user: User = Depends(get_current_user),
662
+ db: Session = Depends(get_db)
663
+ ):
664
+ try:
665
+ # Get user credit information
666
+ user_credit = db.query(UserCreditModel).filter(
667
+ UserCreditModel.user_id == current_user.id
668
+ ).first()
669
+
670
+ if not user_credit:
671
+ # Create new credit record if it doesn't exist
672
+ user_credit = UserCreditModel(
673
+ user_id=current_user.id,
674
+ minutes_used=0,
675
+ minutes_quota=10,
676
+ last_updated=datetime.utcnow().isoformat()
677
+ )
678
+ db.add(user_credit)
679
+ db.commit()
680
+ db.refresh(user_credit)
681
+
682
+ return {
683
+ "user_id": user_credit.user_id,
684
+ "minutes_used": user_credit.minutes_used,
685
+ "minutes_quota": user_credit.minutes_quota,
686
+ "minutes_remaining": max(0, user_credit.minutes_quota - user_credit.minutes_used),
687
+ "last_updated": user_credit.last_updated
688
+ }
689
+ except Exception as e:
690
+ print(f"Error getting user credits: {str(e)}")
691
+ raise HTTPException(status_code=500, detail=str(e))
692
+
693
+ @app.get("/api/admin/credits")
694
+ async def get_all_user_credits(
695
+ current_user: User = Depends(get_current_active_admin),
696
+ db: Session = Depends(get_db)
697
+ ):
698
+ try:
699
+ # Get all user credit information
700
+ user_credits = db.query(UserCreditModel).all()
701
+
702
+ # Get usernames for each user_id
703
+ user_data = {}
704
+ for user in db.query(UserModel).all():
705
+ user_data[user.id] = user.username
706
+
707
+ return [
708
+ {
709
+ "user_id": credit.user_id,
710
+ "username": user_data.get(credit.user_id, "Unknown"),
711
+ "minutes_used": credit.minutes_used,
712
+ "minutes_quota": credit.minutes_quota,
713
+ "minutes_remaining": max(0, credit.minutes_quota - credit.minutes_used),
714
+ "last_updated": credit.last_updated
715
+ }
716
+ for credit in user_credits
717
+ ]
718
+ except Exception as e:
719
+ print(f"Error getting all user credits: {str(e)}")
720
+ raise HTTPException(status_code=500, detail=str(e))
721
+
722
+ @app.put("/api/admin/credits/{user_id}")
723
+ async def update_user_credits(
724
+ user_id: int,
725
+ credit_update: dict,
726
+ current_user: User = Depends(get_current_active_admin),
727
+ db: Session = Depends(get_db)
728
+ ):
729
+ try:
730
+ # Validate input
731
+ if not any(field in credit_update for field in ["minutes_used", "minutes_quota"]):
732
+ raise HTTPException(status_code=400, detail="At least one of minutes_used or minutes_quota is required")
733
+
734
+ # Get user credit record
735
+ user_credit = db.query(UserCreditModel).filter(
736
+ UserCreditModel.user_id == user_id
737
+ ).first()
738
+
739
+ if not user_credit:
740
+ # Create new credit record if it doesn't exist
741
+ user = db.query(UserModel).filter(UserModel.id == user_id).first()
742
+ if not user:
743
+ raise HTTPException(status_code=404, detail="User not found")
744
+
745
+ minutes_used = credit_update.get("minutes_used", 0)
746
+ minutes_quota = credit_update.get("minutes_quota", 60) # Default quota
747
+
748
+ if not isinstance(minutes_used, int) or minutes_used < 0:
749
+ raise HTTPException(status_code=400, detail="minutes_used must be a non-negative integer")
750
+
751
+ if not isinstance(minutes_quota, int) or minutes_quota < 0:
752
+ raise HTTPException(status_code=400, detail="minutes_quota must be a non-negative integer")
753
+
754
+ user_credit = UserCreditModel(
755
+ user_id=user_id,
756
+ minutes_used=minutes_used,
757
+ minutes_quota=minutes_quota,
758
+ last_updated=datetime.utcnow().isoformat()
759
+ )
760
+ db.add(user_credit)
761
+ else:
762
+ # Update existing credit record
763
+ if "minutes_used" in credit_update:
764
+ minutes_used = credit_update["minutes_used"]
765
+ if not isinstance(minutes_used, int) or minutes_used < 0:
766
+ raise HTTPException(status_code=400, detail="minutes_used must be a non-negative integer")
767
+ user_credit.minutes_used = minutes_used
768
+
769
+ if "minutes_quota" in credit_update:
770
+ minutes_quota = credit_update["minutes_quota"]
771
+ if not isinstance(minutes_quota, int) or minutes_quota < 0:
772
+ raise HTTPException(status_code=400, detail="minutes_quota must be a non-negative integer")
773
+ user_credit.minutes_quota = minutes_quota
774
+
775
+ user_credit.last_updated = datetime.utcnow().isoformat()
776
+
777
+ db.commit()
778
+ db.refresh(user_credit)
779
+
780
+ # Get username for response
781
+ user = db.query(UserModel).filter(UserModel.id == user_id).first()
782
+ username = user.username if user else "Unknown"
783
+
784
+ return {
785
+ "user_id": user_credit.user_id,
786
+ "username": username,
787
+ "minutes_used": user_credit.minutes_used,
788
+ "minutes_quota": user_credit.minutes_quota,
789
+ "minutes_remaining": max(0, user_credit.minutes_quota - user_credit.minutes_used),
790
+ "last_updated": user_credit.last_updated
791
+ }
792
+ except Exception as e:
793
+ print(f"Error updating user credits: {str(e)}")
794
+ raise HTTPException(status_code=500, detail=str(e))
795
+
796
+ @app.post("/api/admin/credits/{user_id}/reset-quota")
797
+ async def reset_user_quota(
798
+ user_id: int,
799
+ quota_data: dict,
800
+ current_user: User = Depends(get_current_active_admin),
801
+ db: Session = Depends(get_db)
802
+ ):
803
+ try:
804
+ new_quota = quota_data.get("new_quota")
805
+ if new_quota is None:
806
+ raise HTTPException(status_code=400, detail="new_quota field is required")
807
+
808
+ if not isinstance(new_quota, int) or new_quota < 0:
809
+ raise HTTPException(status_code=400, detail="new_quota must be a non-negative integer")
810
+
811
+ # Get user credit record
812
+ user_credit = db.query(UserCreditModel).filter(
813
+ UserCreditModel.user_id == user_id
814
+ ).first()
815
+
816
+ if not user_credit:
817
+ # Create new credit record if it doesn't exist
818
+ user = db.query(UserModel).filter(UserModel.id == user_id).first()
819
+ if not user:
820
+ raise HTTPException(status_code=404, detail="User not found")
821
+
822
+ user_credit = UserCreditModel(
823
+ user_id=user_id,
824
+ minutes_used=0,
825
+ minutes_quota=new_quota,
826
+ last_updated=datetime.utcnow().isoformat()
827
+ )
828
+ db.add(user_credit)
829
+ else:
830
+ # Update existing credit record
831
+ user_credit.minutes_quota = new_quota
832
+ user_credit.last_updated = datetime.utcnow().isoformat()
833
+
834
+ db.commit()
835
+ db.refresh(user_credit)
836
+
837
+ # Get username for response
838
+ user = db.query(UserModel).filter(UserModel.id == user_id).first()
839
+ username = user.username if user else "Unknown"
840
+
841
+ return {
842
+ "user_id": user_credit.user_id,
843
+ "username": username,
844
+ "minutes_used": user_credit.minutes_used,
845
+ "minutes_quota": user_credit.minutes_quota,
846
+ "minutes_remaining": max(0, user_credit.minutes_quota - user_credit.minutes_used),
847
+ "last_updated": user_credit.last_updated
848
+ }
849
+ except Exception as e:
850
+ print(f"Error resetting user quota: {str(e)}")
851
+ raise HTTPException(status_code=500, detail=str(e))
852
+
853
+ @app.post("/api/upload-audio")
854
+ async def upload_audio(
855
+ request: Request,
856
+ current_user: User = Depends(get_current_user),
857
+ db: Session = Depends(get_db)
858
+ ):
859
+ try:
860
+ form_data = await request.form()
861
+ file = form_data["file"]
862
+
863
+ file_id = str(uuid.uuid4())
864
+ filename = f"{file_id}_{file.filename}"
865
+
866
+ # Get user-specific upload directory
867
+ user_upload_dir = get_user_upload_dir(current_user.id)
868
+
869
+ # Create the full file path in the user's directory
870
+ file_path = os.path.join(user_upload_dir, filename)
871
+ print(f"file_path: ${file_path}")
872
+
873
+ contents = await file.read()
874
+ async with aiofiles.open(file_path, "wb") as f:
875
+ await f.write(contents)
876
+
877
+ return JSONResponse({"filename": filename})
878
+ except Exception as e:
879
+ raise HTTPException(status_code=500, detail=str(e))
880
+
881
  @app.post("/api/upload")
882
  async def create_upload_file(
883
  current_user: User = Depends(get_current_user),
 
926
  if start_sample >= end_sample:
927
  raise HTTPException(400, "Invalid time range")
928
 
929
+ # Calculate audio duration in minutes
930
+ audio_duration_seconds = (end_sample - start_sample) / sample_rate
931
+ audio_duration_minutes = math.ceil(audio_duration_seconds / 60) # Round up to nearest minute
932
+
933
+ # Check user quota
934
+ user_credit = db.query(UserCreditModel).filter(
935
+ UserCreditModel.user_id == current_user.id
936
+ ).first()
937
+
938
+ if not user_credit:
939
+ # Create new credit record if it doesn't exist
940
+ user_credit = UserCreditModel(
941
+ user_id=current_user.id,
942
+ minutes_used=0,
943
+ minutes_quota=60, # Default quota
944
+ last_updated=datetime.utcnow().isoformat()
945
+ )
946
+ db.add(user_credit)
947
+ db.commit()
948
+ db.refresh(user_credit)
949
+
950
+ # Check if user has enough quota
951
+ minutes_remaining = max(0, user_credit.minutes_quota - user_credit.minutes_used)
952
+ if audio_duration_minutes > minutes_remaining:
953
+ raise HTTPException(
954
+ status_code=403,
955
+ detail=f"Quota exceeded. You have {minutes_remaining} minutes remaining, but this audio requires {audio_duration_minutes} minutes."
956
+ )
957
+
958
+ # Update user credits
959
+ user_credit.minutes_used += audio_duration_minutes
960
+ user_credit.last_updated = datetime.utcnow().isoformat()
961
+ db.commit()
962
+
963
  # Slice the audio data
964
  audio_data = audio_data[start_sample:end_sample]
965
 
 
967
  sliced_path = f"{temp_path}_sliced.flac"
968
  sf.write(sliced_path, audio_data, sample_rate, format='FLAC')
969
 
970
+ # check sliced_path file size if it exceeded the limit
971
+ file_size = os.path.getsize(sliced_path)
972
+ if file_size > MAX_FILE_SIZE:
973
+ print(f"Slice: {sliced_path} exceeds the limit of {MAX_FILE_SIZE / (1024 * 1024)}MB")
974
+ # raise HTTPException(400, f"File size exceeds the limit of {MAX_FILE_SIZE / (1024 * 1024)}MB")
975
+
976
  # Split into FLAC chunks
977
  chunks = split_audio_chunks(
978
  sliced_path,
 
998
  # Combine results
999
  combined = combine_results(results, response_format)
1000
 
1001
+ # Add credit usage information to response
1002
+ combined["metadata"]["credit_usage"] = {
1003
+ "minutes_used": audio_duration_minutes,
1004
+ "total_minutes_used": user_credit.minutes_used,
1005
+ "minutes_quota": user_credit.minutes_quota,
1006
+ "minutes_remaining": max(0, user_credit.minutes_quota - user_credit.minutes_used)
1007
+ }
1008
+
1009
  # Cleanup
1010
  for chunk in chunks:
1011
  os.remove(chunk["path"])
 
1022
  os.remove(sliced_path)
1023
  raise HTTPException(500, str(e))
1024
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1025
  @app.post("/api/upload-audio-chunk")
1026
  async def upload_audio_chunk(
1027
  file: UploadFile = File(...),
 
1067
  metadata_path = os.path.join(upload_path, "metadata.txt")
1068
  filename = f"{uuid.uuid4()}.mp3" # Default filename
1069
 
1070
+ # Get user-specific upload directory
1071
+ user_upload_dir = get_user_upload_dir(current_user.id)
1072
+
1073
  # Combine all chunks into final file
1074
+ output_path = os.path.join(user_upload_dir, filename)
1075
 
1076
  with open(output_path, "wb") as outfile:
1077
  # Get all chunks sorted by offset
 
1109
  current_user: User = Depends(get_current_user)
1110
  ):
1111
  try:
 
 
1112
  file_list = []
1113
 
1114
+ if current_user.is_admin:
1115
+ # Admin can see all files
1116
+ for user_id in os.listdir(UPLOAD_DIR):
1117
+ user_dir = os.path.join(UPLOAD_DIR, user_id)
1118
+ if os.path.isdir(user_dir):
1119
+ # Get username for this user_id
1120
+ db = next(get_db())
1121
+ user = db.query(UserModel).filter(UserModel.id == int(user_id)).first()
1122
+ username = user.username if user else f"User {user_id}"
1123
+
1124
+ for filename in os.listdir(user_dir):
1125
+ file_path = os.path.join(user_dir, filename)
1126
+ if os.path.isfile(file_path) and not filename.startswith('.'):
1127
+ # Get file stats
1128
+ file_stats = os.stat(file_path)
1129
+ file_size = os.path.getsize(file_path)
1130
+
1131
+ file_list.append({
1132
+ "id": filename,
1133
+ "filename": filename,
1134
+ "original_filename": filename,
1135
+ "size": file_size,
1136
+ "uploaded_at": datetime.fromtimestamp(file_stats.st_mtime).isoformat(),
1137
+ "user_id": int(user_id),
1138
+ "username": username
1139
+ })
1140
+ else:
1141
+ # Regular users can only see their own files
1142
+ user_dir = get_user_upload_dir(current_user.id)
1143
+
1144
+ for filename in os.listdir(user_dir):
1145
+ file_path = os.path.join(user_dir, filename)
1146
+ if os.path.isfile(file_path) and not filename.startswith('.'):
1147
+ # Get file stats
1148
+ file_stats = os.stat(file_path)
1149
+ file_size = os.path.getsize(file_path)
1150
+
1151
+ file_list.append({
1152
+ "id": filename,
1153
+ "filename": filename,
1154
+ "original_filename": filename,
1155
+ "size": file_size,
1156
+ "uploaded_at": datetime.fromtimestamp(file_stats.st_mtime).isoformat()
1157
+ })
1158
 
1159
  # Sort by upload date (newest first)
1160
  file_list.sort(key=lambda x: x["uploaded_at"], reverse=True)
 
1167
  @app.delete("/api/audio-files/{filename}")
1168
  async def delete_audio_file(
1169
  filename: str,
1170
+ user_id: int = None,
1171
+ current_user: User = Depends(get_current_user),
1172
+ db: Session = Depends(get_db)
1173
  ):
1174
  try:
1175
+ # Determine which user's file to delete
1176
+ target_user_id = user_id if current_user.is_admin and user_id else current_user.id
1177
+
1178
+ # Check if user exists if admin is deleting another user's file
1179
+ if current_user.is_admin and user_id and user_id != current_user.id:
1180
+ user = db.query(UserModel).filter(UserModel.id == user_id).first()
1181
+ if not user:
1182
+ raise HTTPException(status_code=404, detail="User not found")
1183
+
1184
+ # Get the user's upload directory
1185
+ user_upload_dir = get_user_upload_dir(target_user_id)
1186
+
1187
+ # Check if file exists in the user's directory
1188
+ file_path = os.path.join(user_upload_dir, filename)
1189
  if not os.path.exists(file_path):
1190
  raise HTTPException(status_code=404, detail="Audio file not found")
1191