tudeplom commited on
Commit
c80867b
·
verified ·
1 Parent(s): d457454

Update app.py

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