tudeplom commited on
Commit
65f7061
·
verified ·
1 Parent(s): 475d403

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -34
app.py CHANGED
@@ -1,86 +1,140 @@
1
  import json
2
  import tempfile
3
  import ffmpeg
4
- import wave # ✅ Fix lỗi thiếu import wave
5
  import os
 
6
  from flask import Flask, request, jsonify
7
  from flask_cors import CORS
 
 
8
  from vosk import Model, KaldiRecognizer
9
  from flasgger import Swagger
10
 
11
- # Load model Vosk
 
 
 
 
12
  MODEL_PATH = "model/vosk-model"
13
  print("\u2705 Đang tải model Vosk...")
14
  model = Model(MODEL_PATH)
15
 
16
- # Khởi tạo Flask app
17
- app = Flask(__name__)
18
- CORS(app)
19
- Swagger(app)
20
-
21
  @app.route("/")
22
  def home():
 
 
 
 
 
 
23
  return "\u2705 Vosk STT API đang chạy!"
24
 
25
  @app.route("/stt", methods=["POST"])
26
  def stt():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  if "file" not in request.files:
28
  return jsonify({"error": "Không tìm thấy file âm thanh! Vui lòng gửi trường 'file'."}), 400
29
 
30
- audio_file = request.files["file"]
31
- if audio_file.filename == "":
32
- return jsonify({"error": "Không có file được chọn!"}), 400
33
-
34
- # Lưu file WebM tạm thời
35
- with tempfile.NamedTemporaryFile(suffix=".webm", delete=False) as temp_webm_file:
36
  webm_path = temp_webm_file.name
37
  audio_file.save(webm_path)
38
 
39
- # Kiểm tra kích thước file
40
  if os.path.getsize(webm_path) < 100:
41
  os.remove(webm_path)
42
  return jsonify({"error": "Tệp âm thanh quá nhỏ hoặc rỗng!"}), 400
43
 
44
- # Xử tệp WebM -> WAV
45
- wav_path = tempfile.mktemp(suffix=".wav")
 
46
  try:
47
- ffmpeg.input(webm_path).output(
48
- wav_path, acodec="pcm_s16le", ac=1, ar=16000
49
- ).run(overwrite_output=True, quiet=True)
50
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  wf = wave.open(wav_path, "rb")
52
 
53
- # Kiểm tra WAV đúng chuẩn không
54
  if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE":
55
- wf.close()
56
- return jsonify({"error": "Định dạng WAV không hợp lệ!"}), 400
57
 
58
- # Chạy Vosk để nhận diện giọng nói
 
59
  rec = KaldiRecognizer(model, wf.getframerate())
60
  result_text = ""
61
 
 
62
  while True:
63
  data = wf.readframes(4000)
64
  if len(data) == 0:
65
- break
66
- if rec.AcceptWaveform(data):
67
- result = json.loads(rec.Result())
68
  result_text += result.get("text", "") + " "
69
  else:
70
  partial_result = json.loads(rec.PartialResult())
71
- result_text += partial_result.get("partial", "") + " "
72
-
73
- wf.close() # ✅ Fix lỗi quên đóng file
74
 
75
- final_text = result_text.strip() or "Không nhận diện được nội dung âm thanh." # ✅ Fix lỗi Unicode
 
 
 
76
  return jsonify({"text": final_text})
77
 
 
 
 
78
  except Exception as e:
79
- return jsonify({"error": f"Lỗi xử lý: {str(e)}"}), 500
80
 
81
  finally:
82
- os.remove(webm_path) if os.path.exists(webm_path) else None
83
- os.remove(wav_path) if os.path.exists(wav_path) else None
 
 
 
 
 
84
 
85
  if __name__ == "__main__":
86
  app.run(host="0.0.0.0", port=7860, debug=True)
 
1
  import json
2
  import tempfile
3
  import ffmpeg
 
4
  import os
5
+
6
  from flask import Flask, request, jsonify
7
  from flask_cors import CORS
8
+
9
+
10
  from vosk import Model, KaldiRecognizer
11
  from flasgger import Swagger
12
 
13
+ # Thư mục chứa model
14
+
15
+
16
+
17
+
18
  MODEL_PATH = "model/vosk-model"
19
  print("\u2705 Đang tải model Vosk...")
20
  model = Model(MODEL_PATH)
21
 
 
 
 
 
 
22
  @app.route("/")
23
  def home():
24
+ """API Home
25
+ ---
26
+ responses:
27
+ 200:
28
+ description: API đang chạy
29
+ """
30
  return "\u2705 Vosk STT API đang chạy!"
31
 
32
  @app.route("/stt", methods=["POST"])
33
  def stt():
34
+ """Chuyển đổi giọng nói thành văn bản (Speech-to-Text)
35
+ ---
36
+ consumes:
37
+ - multipart/form-data
38
+ parameters:
39
+ - in: formData
40
+ name: file
41
+ type: file
42
+ required: true
43
+ description: File âm thanh WebM (sẽ được chuyển đổi sang WAV mono PCM)
44
+ responses:
45
+ 200:
46
+ description: Kết quả chuyển đổi văn bản
47
+ schema:
48
+ type: object
49
+ properties:
50
+ text:
51
+ type: string
52
+ example: "Xin chào thế giới"
53
+ 400:
54
+ description: Lỗi nếu file âm thanh không hợp lệ hoặc không tìm thấy
55
+ 500:
56
+ description: Lỗi server nội bộ
57
+ """
58
  if "file" not in request.files:
59
  return jsonify({"error": "Không tìm thấy file âm thanh! Vui lòng gửi trường 'file'."}), 400
60
 
 
 
 
 
 
 
61
  webm_path = temp_webm_file.name
62
  audio_file.save(webm_path)
63
 
64
+ # Kiểm tra kích thước tệp
65
  if os.path.getsize(webm_path) < 100:
66
  os.remove(webm_path)
67
  return jsonify({"error": "Tệp âm thanh quá nhỏ hoặc rỗng!"}), 400
68
 
69
+ # Đường dẫn file WAV tạm thời sau khi chuyển đổi
70
+ wav_path = None
71
+ wf = None
72
  try:
73
+ # Kiểm tra tệp WebM bằng ffprobe trước khi chuyển đổi
74
+ try:
75
+ probe = ffmpeg.probe(webm_path)
76
+ if 'streams' not in probe or not any(s['codec_type'] == 'audio' for s in probe['streams']):
77
+ raise ValueError("Tệp không chứa luồng âm thanh hợp lệ!")
78
+ except ffmpeg.Error as e:
79
+ error_message = e.stderr.decode('utf-8') if e.stderr else str(e)
80
+ return jsonify({"error": f"Lỗi kiểm tra tệp WebM: {error_message}"}), 500
81
+
82
+ # Chuyển đổi WebM sang WAV mono PCM
83
+ wav_path = tempfile.mktemp(suffix=".wav")
84
+ stream = ffmpeg.input(webm_path)
85
+ stream = ffmpeg.output(
86
+ stream,
87
+ wav_path,
88
+ acodec="pcm_s16le", # PCM 16-bit signed little-endian
89
+ ac=1, # Mono
90
+ ar=16000, # Tần số mẫu 16kHz, phù hợp với Vosk
91
+ format="wav"
92
+ )
93
+ # Thêm cờ -vn để bỏ qua video nếu có và -y để ghi đè
94
+ ffmpeg.run(stream, overwrite_output=True, quiet=True, capture_stdout=True, capture_stderr=True)
95
+
96
+ # Mở file WAV đã chuyển đổi
97
  wf = wave.open(wav_path, "rb")
98
 
99
+ # Kiểm tra định dạng WAV mono PCM
100
  if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE":
101
+ return jsonify({"error": "Định dạng WAV sau chuyển đổi không đúng!"}), 400
 
102
 
103
+
104
+ # Khởi tạo KaldiRecognizer
105
  rec = KaldiRecognizer(model, wf.getframerate())
106
  result_text = ""
107
 
108
+ # Đọc và xử lý dữ liệu âm thanh
109
  while True:
110
  data = wf.readframes(4000)
111
  if len(data) == 0:
 
 
 
112
  result_text += result.get("text", "") + " "
113
  else:
114
  partial_result = json.loads(rec.PartialResult())
115
+ if partial_result.get("partial", ""):
116
+ result_text += partial_result["partial"] + " "
 
117
 
118
+ # Trả về kết quả đã xử
119
+ final_text = result_text.strip()
120
+ if not final_text:
121
+ final_text = "Không nh��n diện được nội dung âm thanh."
122
  return jsonify({"text": final_text})
123
 
124
+ except ffmpeg.Error as e:
125
+ error_message = e.stderr.decode('utf-8') if e.stderr else str(e)
126
+ return jsonify({"error": f"Lỗi chuyển đổi âm thanh từ WebM sang WAV: {error_message}"}), 500
127
  except Exception as e:
128
+ return jsonify({"error": f"Lỗi xử âm thanh: {str(e)}"}), 500
129
 
130
  finally:
131
+ # Đóng file WAV nếu đã mở
132
+ if wf is not None:
133
+ wf.close()
134
+ # Xóa các file tạm
135
+ for path in [webm_path, wav_path]:
136
+ if path and os.path.exists(path):
137
+ os.remove(path)
138
 
139
  if __name__ == "__main__":
140
  app.run(host="0.0.0.0", port=7860, debug=True)