HK0712 commited on
Commit
a965b51
·
1 Parent(s): 449b23e

pre-loaded models

Browse files
Files changed (1) hide show
  1. main.py +107 -32
main.py CHANGED
@@ -1,19 +1,95 @@
1
- # main.py (Final, Typo-Fixed Version)
2
 
 
 
 
 
3
  import os
4
  import importlib
5
  import uvicorn
6
  import shutil
 
7
  from datetime import datetime
8
- from fastapi import FastAPI, File, UploadFile, Form, HTTPException, APIRouter # 確保 APIRouter 被正確匯入
 
9
  from fastapi.middleware.cors import CORSMiddleware
10
 
11
- # --- 應用程式設定 ---
12
- app = FastAPI(title="Pronunciation Analysis API")
13
- # 【【【【【 終 極 拼 寫 修 正 這 裡 】】】】】
14
- api_router = APIRouter(prefix="/api/v1") # 將 APouter 改為 APIRouter
 
 
 
15
 
16
- # --- CORS 設定 (保持不) ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  origins = ["*"]
18
  app.add_middleware(
19
  CORSMiddleware,
@@ -23,35 +99,33 @@ app.add_middleware(
23
  allow_headers=["*"],
24
  )
25
 
26
- # --- 全域變數和初始化邏輯 (保持不變) ---
27
- TEMP_DIR = "/tmp/temp_audio"
28
- ANALYZERS = {}
29
-
30
- if not os.path.exists(TEMP_DIR):
31
- os.makedirs(TEMP_DIR)
32
 
 
33
  def get_analyzer_module(language: str):
34
  if language in ANALYZERS:
35
  return ANALYZERS[language]
36
 
 
 
37
  try:
38
- print(f"首次請求 '{language}',正在動態載入模組...")
39
  analyzer_module = importlib.import_module(f"analyzer.ASR_{language}")
40
-
41
- print(f"正在呼叫 analyzer.ASR_{language}.load_model()...")
42
  analyzer_module.load_model()
43
-
44
  ANALYZERS[language] = analyzer_module
45
- print(f"'{language}' 分析器模組載入成功並快取。")
46
  return analyzer_module
47
  except ImportError:
48
- print(f"錯誤:找不到 '{language}' 的分析器模組 (analyzer.ASR_{language}.py)")
49
- raise HTTPException(status_code=400, detail=f"不支援的語言: {language}")
50
  except Exception as e:
51
- print(f"錯誤:載入語言 '{language}' 的模型時發生嚴重錯誤: {e}")
52
- raise HTTPException(status_code=500, detail=f"載入語言 '{language}' 的模型失敗。")
53
 
54
- # --- API 端點 (保持不變) ---
55
  @api_router.post("/recognize")
56
  async def recognize_speech_api(
57
  file: UploadFile = File(...),
@@ -59,31 +133,32 @@ async def recognize_speech_api(
59
  language: str = Form(...)
60
  ):
61
  analyzer_module = get_analyzer_module(language)
62
-
63
  base_filename = os.path.basename(file.filename)
64
  temp_file_path = os.path.join(TEMP_DIR, f"{datetime.now().strftime('%Y%m%d%H%M%S')}-{base_filename}")
65
-
66
- print(f"使用 '{language}' 分析器處理檔案: {temp_file_path}")
67
-
68
  try:
69
  with open(temp_file_path, "wb") as buffer:
70
  shutil.copyfileobj(file.file, buffer)
71
-
72
  result = analyzer_module.analyze(temp_file_path, target_sentence)
73
  return result
74
  except Exception as e:
75
- print(f"處理請求時發生未預期的錯誤: {e}")
76
  raise HTTPException(status_code=500, detail=str(e))
77
  finally:
78
  if os.path.exists(temp_file_path):
79
  os.remove(temp_file_path)
80
 
 
81
  app.include_router(api_router)
82
 
83
- # --- 主程式入口 (保持不變) ---
 
 
 
84
  if __name__ == "__main__":
85
  print("="*60)
86
- print("啟動 FastAPI 伺服器 (http://localhost:8000 )...")
87
- print("請手動運行 ngrok: ngrok http 8000" )
88
  print("="*60)
 
89
  uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
 
1
+ # main.py
2
 
3
+ # =======================================================================
4
+ # 1. 匯入區 (Imports)
5
+ # 所有需要的模組都放在檔案的最頂部。
6
+ # =======================================================================
7
  import os
8
  import importlib
9
  import uvicorn
10
  import shutil
11
+ import re # <--- 【【新增】】為了動態掃描檔案
12
  from datetime import datetime
13
+ from contextlib import asynccontextmanager
14
+ from fastapi import FastAPI, File, UploadFile, Form, HTTPException, APIRouter
15
  from fastapi.middleware.cors import CORSMiddleware
16
 
17
+ # =======================================================================
18
+ # 2. 全域變數與配置區 (Global Variables & Config)
19
+ # 應用程式啟動前,定義好所有全域會用到的變數。
20
+ # =======================================================================
21
+ # 【【修改】】不再硬編碼,讓它們在啟動時被動態填充
22
+ SUPPORTED_LANGUAGES = []
23
+ ANALYZERS = {}
24
 
25
+ # 【【新增】】讀取環境數「信號旗」
26
+ APP_ENV = os.getenv('APP_ENV', 'development')
27
+
28
+ # 【【新增】】這個臨時目錄的定義也放在這裡,保持整潔
29
+ TEMP_DIR = "/tmp/temp_audio"
30
+ if not os.path.exists(TEMP_DIR):
31
+ os.makedirs(TEMP_DIR)
32
+
33
+ # =======================================================================
34
+ # 3. 應用程式生命週期管理區 (Application Lifespan Management)
35
+ # 這是最核心的新增部分,它控制著應用程式啟動和關閉時的行為。
36
+ # =======================================================================
37
+ # 【【新增】】動態掃描 analyzer/ 資料夾的輔助函數
38
+ def discover_supported_languages():
39
+ global SUPPORTED_LANGUAGES
40
+ analyzer_dir = 'analyzer'
41
+ pattern = re.compile(r"ASR_(.+)\.py$")
42
+ try:
43
+ for filename in os.listdir(analyzer_dir):
44
+ match = pattern.match(filename)
45
+ if match:
46
+ language_code = match.group(1)
47
+ SUPPORTED_LANGUAGES.append(language_code)
48
+ if not SUPPORTED_LANGUAGES:
49
+ print("WARNING: No language analyzer modules found in 'analyzer' directory.")
50
+ else:
51
+ print(f"Discovered supported languages: {', '.join(SUPPORTED_LANGUAGES)}")
52
+ except FileNotFoundError:
53
+ print(f"ERROR: The '{analyzer_dir}' directory was not found.")
54
+ SUPPORTED_LANGUAGES = []
55
+
56
+ # 【【新增】】FastAPI 的 lifespan 管理器
57
+ @asynccontextmanager
58
+ async def lifespan(app: FastAPI):
59
+ # --- 應用程式啟動時執行的程式碼 ---
60
+ print("="*60)
61
+ print(f"Application starting up in '{APP_ENV}' mode.")
62
+
63
+ discover_supported_languages() # 首先,動態發現支援的語言
64
+
65
+ if APP_ENV == "production":
66
+ print("Production mode detected. Eager loading all models...")
67
+ for lang in SUPPORTED_LANGUAGES:
68
+ try:
69
+ print(f"--- Loading model for language: {lang} ---")
70
+ analyzer_module = importlib.import_module(f"analyzer.ASR_{lang}")
71
+ analyzer_module.load_model()
72
+ ANALYZERS[lang] = analyzer_module
73
+ print(f"--- Model for {lang} loaded successfully. ---")
74
+ except Exception as e:
75
+ print(f"FATAL: Failed to load model for {lang}. Error: {e}")
76
+ print("All models pre-loaded. Application is ready for requests.")
77
+ else:
78
+ print("Development mode detected. Models will be loaded on-demand (lazily).")
79
+
80
+ print("="*60)
81
+ yield # <--- 應用程式在這裡運行
82
+ # --- 應用程式關閉時執行的程式碼 ---
83
+ print("Application shutting down.")
84
+
85
+ # =======================================================================
86
+ # 4. FastAPI 應用程式實例化與中介軟體設定區
87
+ # 創建 FastAPI app 物件,並掛載所有需要的設定。
88
+ # =======================================================================
89
+ # 【【修改】】告訴 FastAPI 使用我們上面定義的 lifespan
90
+ app = FastAPI(title="Pronunciation Analysis API", lifespan=lifespan)
91
+
92
+ # CORS 中介軟體設定 (不變)
93
  origins = ["*"]
94
  app.add_middleware(
95
  CORSMiddleware,
 
99
  allow_headers=["*"],
100
  )
101
 
102
+ # =======================================================================
103
+ # 5. 核心業務邏輯與 API 端點區
104
+ # 定義所有 API 的路由和處理函數。
105
+ # =======================================================================
106
+ api_router = APIRouter(prefix="/api/v1")
 
107
 
108
+ # 【【修改】】這是我們新的、更簡潔的 get_analyzer_module 函數
109
  def get_analyzer_module(language: str):
110
  if language in ANALYZERS:
111
  return ANALYZERS[language]
112
 
113
+ # 這段程式碼只會在開發模式下被執行
114
+ print(f"'{language}' not in cache. Loading on-demand (development mode)...")
115
  try:
 
116
  analyzer_module = importlib.import_module(f"analyzer.ASR_{language}")
 
 
117
  analyzer_module.load_model()
 
118
  ANALYZERS[language] = analyzer_module
119
+ print(f"'{language}' analyzer loaded and cached successfully.")
120
  return analyzer_module
121
  except ImportError:
122
+ print(f"Error: Analyzer module for '{language}' not found (analyzer.ASR_{language}.py).")
123
+ raise HTTPException(status_code=400, detail=f"Unsupported language: {language}")
124
  except Exception as e:
125
+ print(f"Error: A critical error occurred while loading the model for '{language}': {e}")
126
+ raise HTTPException(status_code=500, detail=f"Failed to load model for language '{language}'.")
127
 
128
+ # API 端點定義 (不變)
129
  @api_router.post("/recognize")
130
  async def recognize_speech_api(
131
  file: UploadFile = File(...),
 
133
  language: str = Form(...)
134
  ):
135
  analyzer_module = get_analyzer_module(language)
 
136
  base_filename = os.path.basename(file.filename)
137
  temp_file_path = os.path.join(TEMP_DIR, f"{datetime.now().strftime('%Y%m%d%H%M%S')}-{base_filename}")
138
+ print(f"Processing file: {temp_file_path} with '{language}' analyzer.")
 
 
139
  try:
140
  with open(temp_file_path, "wb") as buffer:
141
  shutil.copyfileobj(file.file, buffer)
 
142
  result = analyzer_module.analyze(temp_file_path, target_sentence)
143
  return result
144
  except Exception as e:
145
+ print(f"An unexpected error occurred during request processing: {e}")
146
  raise HTTPException(status_code=500, detail=str(e))
147
  finally:
148
  if os.path.exists(temp_file_path):
149
  os.remove(temp_file_path)
150
 
151
+ # 將路由掛載到主應用上
152
  app.include_router(api_router)
153
 
154
+ # =======================================================================
155
+ # 6. 主程式入口 (Main Entry Point)
156
+ # 當您直接運行 `python main.py` 時,這部分程式碼會被執行。
157
+ # =======================================================================
158
  if __name__ == "__main__":
159
  print("="*60)
160
+ print("Starting FastAPI server in development mode (http://localhost:8000 )...")
161
+ print("Run ngrok manually if needed: ngrok http 8000" )
162
  print("="*60)
163
+ # uvicorn 會自動找到 app 物件並運行它
164
  uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)