flysuper commited on
Commit
d528f06
·
verified ·
1 Parent(s): 81ac1d1

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +133 -2
app.py CHANGED
@@ -18,6 +18,8 @@ import json
18
  from urllib.parse import urlparse
19
  import tempfile
20
  import shutil
 
 
21
 
22
  app = FastAPI(
23
  title="Edge TTS API",
@@ -38,6 +40,11 @@ app.add_middleware(
38
  OUTPUT_DIR = tempfile.mkdtemp(prefix="edge_tts_")
39
  os.makedirs(OUTPUT_DIR, exist_ok=True)
40
 
 
 
 
 
 
41
  # 掛載靜態文件(如果存在)
42
  if os.path.exists("static"):
43
  app.mount("/static", StaticFiles(directory="static"), name="static")
@@ -61,6 +68,71 @@ def _is_origin_allowed(request: Request) -> bool:
61
  # 在 Hugging Face Spaces 環境中,允許所有來源
62
  return True
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  @app.get("/")
65
  async def root():
66
  """根路徑,返回 API 信息"""
@@ -71,9 +143,13 @@ async def root():
71
  "GET /voices": "獲取所有可用語音",
72
  "POST /tts": "文字轉語音",
73
  "GET /tts": "文字轉語音 (GET 方法)",
74
- "GET /health": "健康檢查"
 
 
 
 
75
  },
76
- "note": "此服務部署在 Hugging Face Spaces 上"
77
  }
78
 
79
  @app.get("/health")
@@ -235,6 +311,61 @@ async def delete_audio_file(file_id: str):
235
  except Exception as e:
236
  raise HTTPException(status_code=500, detail=f"文件刪除失敗: {str(e)}")
237
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  # 清理函數(可選)
239
  @app.on_event("shutdown")
240
  async def cleanup():
 
18
  from urllib.parse import urlparse
19
  import tempfile
20
  import shutil
21
+ import time
22
+ from datetime import datetime, timedelta
23
 
24
  app = FastAPI(
25
  title="Edge TTS API",
 
40
  OUTPUT_DIR = tempfile.mkdtemp(prefix="edge_tts_")
41
  os.makedirs(OUTPUT_DIR, exist_ok=True)
42
 
43
+ # 檔案清理設定
44
+ FILE_CLEANUP_INTERVAL = 300 # 5分鐘清理一次
45
+ FILE_MAX_AGE = 1800 # 檔案最大存活時間:30分鐘
46
+ MAX_FILES = 100 # 最大檔案數量
47
+
48
  # 掛載靜態文件(如果存在)
49
  if os.path.exists("static"):
50
  app.mount("/static", StaticFiles(directory="static"), name="static")
 
68
  # 在 Hugging Face Spaces 環境中,允許所有來源
69
  return True
70
 
71
+ # 檔案清理函數
72
+ def cleanup_old_files():
73
+ """清理過期的音頻檔案"""
74
+ try:
75
+ if not os.path.exists(OUTPUT_DIR):
76
+ return
77
+
78
+ current_time = time.time()
79
+ files = []
80
+
81
+ # 獲取所有檔案及其修改時間
82
+ for filename in os.listdir(OUTPUT_DIR):
83
+ if filename.endswith('.mp3'):
84
+ file_path = os.path.join(OUTPUT_DIR, filename)
85
+ file_mtime = os.path.getmtime(file_path)
86
+ files.append((file_path, file_mtime, filename))
87
+
88
+ # 按修改時間排序(最新的在前)
89
+ files.sort(key=lambda x: x[1], reverse=True)
90
+
91
+ deleted_count = 0
92
+
93
+ # 刪除過期檔案
94
+ for file_path, file_mtime, filename in files:
95
+ file_age = current_time - file_mtime
96
+
97
+ # 如果檔案超過最大存活時間,刪除它
98
+ if file_age > FILE_MAX_AGE:
99
+ try:
100
+ os.remove(file_path)
101
+ deleted_count += 1
102
+ print(f"刪除過期檔案: {filename}")
103
+ except Exception as e:
104
+ print(f"刪除檔案失敗 {filename}: {e}")
105
+
106
+ # 如果檔案數量超過限制,刪除最舊的檔案
107
+ remaining_files = len(files) - deleted_count
108
+ if remaining_files > MAX_FILES:
109
+ files_to_delete = files[MAX_FILES:]
110
+ for file_path, _, filename in files_to_delete:
111
+ try:
112
+ if os.path.exists(file_path):
113
+ os.remove(file_path)
114
+ deleted_count += 1
115
+ print(f"刪除超量檔案: {filename}")
116
+ except Exception as e:
117
+ print(f"刪除檔案失敗 {filename}: {e}")
118
+
119
+ if deleted_count > 0:
120
+ print(f"清理完成,共刪除 {deleted_count} 個檔案")
121
+
122
+ except Exception as e:
123
+ print(f"檔案清理過程中發生錯誤: {e}")
124
+
125
+ # 背景清理任務
126
+ async def background_cleanup():
127
+ """背景檔案清理任務"""
128
+ while True:
129
+ try:
130
+ cleanup_old_files()
131
+ await asyncio.sleep(FILE_CLEANUP_INTERVAL)
132
+ except Exception as e:
133
+ print(f"背景清理任務錯誤: {e}")
134
+ await asyncio.sleep(60) # 錯誤時等待1分鐘再重試
135
+
136
  @app.get("/")
137
  async def root():
138
  """根路徑,返回 API 信息"""
 
143
  "GET /voices": "獲取所有可用語音",
144
  "POST /tts": "文字轉語音",
145
  "GET /tts": "文字轉語音 (GET 方法)",
146
+ "GET /health": "健康檢查",
147
+ "GET /audio/{file_id}.mp3": "獲取音頻文件",
148
+ "DELETE /audio/{file_id}.mp3": "刪除音頻文件",
149
+ "POST /cleanup": "手動觸發檔案清理",
150
+ "GET /storage-info": "獲取儲存空間資訊"
151
  },
152
+ "note": "此服務部署在 Hugging Face Spaces 上,具有自動檔案清理功能"
153
  }
154
 
155
  @app.get("/health")
 
311
  except Exception as e:
312
  raise HTTPException(status_code=500, detail=f"文件刪除失敗: {str(e)}")
313
 
314
+ @app.post("/cleanup")
315
+ async def manual_cleanup():
316
+ """手動觸發檔案清理"""
317
+ try:
318
+ cleanup_old_files()
319
+ return {"success": True, "message": "手動清理完成"}
320
+ except Exception as e:
321
+ raise HTTPException(status_code=500, detail=f"清理失敗: {str(e)}")
322
+
323
+ @app.get("/storage-info")
324
+ async def get_storage_info():
325
+ """獲取儲存空間資訊"""
326
+ try:
327
+ if not os.path.exists(OUTPUT_DIR):
328
+ return {"files": 0, "total_size": 0, "max_files": MAX_FILES, "max_age": FILE_MAX_AGE}
329
+
330
+ files = []
331
+ total_size = 0
332
+
333
+ for filename in os.listdir(OUTPUT_DIR):
334
+ if filename.endswith('.mp3'):
335
+ file_path = os.path.join(OUTPUT_DIR, filename)
336
+ file_size = os.path.getsize(file_path)
337
+ file_mtime = os.path.getmtime(file_path)
338
+ file_age = time.time() - file_mtime
339
+
340
+ files.append({
341
+ "filename": filename,
342
+ "size": file_size,
343
+ "age_seconds": int(file_age),
344
+ "age_minutes": int(file_age / 60)
345
+ })
346
+ total_size += file_size
347
+
348
+ return {
349
+ "files": len(files),
350
+ "total_size": total_size,
351
+ "total_size_mb": round(total_size / (1024 * 1024), 2),
352
+ "max_files": MAX_FILES,
353
+ "max_age_seconds": FILE_MAX_AGE,
354
+ "max_age_minutes": int(FILE_MAX_AGE / 60),
355
+ "cleanup_interval_seconds": FILE_CLEANUP_INTERVAL,
356
+ "cleanup_interval_minutes": int(FILE_CLEANUP_INTERVAL / 60),
357
+ "file_list": files[:10] # 只顯示前10個檔案
358
+ }
359
+ except Exception as e:
360
+ raise HTTPException(status_code=500, detail=f"獲取儲存資訊失敗: {str(e)}")
361
+
362
+ # 應用啟動事件
363
+ @app.on_event("startup")
364
+ async def startup_event():
365
+ """應用啟動時啟動背景清理任務"""
366
+ asyncio.create_task(background_cleanup())
367
+ print("背景檔案清理任務已啟動")
368
+
369
  # 清理函數(可選)
370
  @app.on_event("shutdown")
371
  async def cleanup():