File size: 4,690 Bytes
23590ba
edcef16
 
475d403
65f7061
d114f5b
 
65f7061
 
4164780
d114f5b
4164780
65f7061
 
 
 
 
c80867b
 
 
07478ab
250b797
 
65f7061
 
 
 
 
 
d114f5b
 
 
 
65f7061
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d114f5b
 
 
 
 
 
65f7061
d114f5b
 
 
 
65f7061
 
 
4164780
65f7061
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d114f5b
 
65f7061
d114f5b
65f7061
b90ae45
65f7061
 
d114f5b
b90ae45
d114f5b
65f7061
d114f5b
 
 
 
 
 
65f7061
 
475d403
65f7061
 
 
 
d114f5b
 
65f7061
 
 
4164780
65f7061
d114f5b
4164780
65f7061
 
 
 
 
 
 
981b713
9225a67
6357dfa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import json
import tempfile
import ffmpeg
import os

from flask import Flask, request, jsonify
from flask_cors import CORS


from vosk import Model, KaldiRecognizer
from flasgger import Swagger

# Thư mục chứa model




MODEL_PATH = "model/vosk-model"
print("\u2705 Đang tải model Vosk...")
model = Model(MODEL_PATH)

@app.route("/")
def home():
    """API Home
    ---
    responses:
      200:
        description: API đang chạy
    """
    return "\u2705 Vosk STT API đang chạy!"

@app.route("/stt", methods=["POST"])
def stt():
    """Chuyển đổi giọng nói thành văn bản (Speech-to-Text)
    ---
    consumes:
      - multipart/form-data
    parameters:
      - in: formData
        name: file
        type: file
        required: true
        description: File âm thanh WebM (sẽ được chuyển đổi sang WAV mono PCM)
    responses:
      200:
        description: Kết quả chuyển đổi văn bản
        schema:
          type: object
          properties:
            text:
              type: string
              example: "Xin chào thế giới"
      400:
        description: Lỗi nếu file âm thanh không hợp lệ hoặc không tìm thấy
      500:
        description: Lỗi server nội bộ
    """
    if "file" not in request.files:
        return jsonify({"error": "Không tìm thấy file âm thanh! Vui lòng gửi trường 'file'."}), 400

        webm_path = temp_webm_file.name
        audio_file.save(webm_path)

    # Kiểm tra kích thước tệp
    if os.path.getsize(webm_path) < 100:
        os.remove(webm_path)
        return jsonify({"error": "Tệp âm thanh quá nhỏ hoặc rỗng!"}), 400

    # Đường dẫn file WAV tạm thời sau khi chuyển đổi
    wav_path = None
    wf = None
    try:
        # Kiểm tra tệp WebM bằng ffprobe trước khi chuyển đổi
        try:
            probe = ffmpeg.probe(webm_path)
            if 'streams' not in probe or not any(s['codec_type'] == 'audio' for s in probe['streams']):
                raise ValueError("Tệp không chứa luồng âm thanh hợp lệ!")
        except ffmpeg.Error as e:
            error_message = e.stderr.decode('utf-8') if e.stderr else str(e)
            return jsonify({"error": f"Lỗi kiểm tra tệp WebM: {error_message}"}), 500

        # Chuyển đổi WebM sang WAV mono PCM
        wav_path = tempfile.mktemp(suffix=".wav")
        stream = ffmpeg.input(webm_path)
        stream = ffmpeg.output(
            stream,
            wav_path,
            acodec="pcm_s16le",  # PCM 16-bit signed little-endian
            ac=1,               # Mono
            ar=16000,           # Tần số mẫu 16kHz, phù hợp với Vosk
            format="wav"
        )
        # Thêm cờ -vn để bỏ qua video nếu có và -y để ghi đè
        ffmpeg.run(stream, overwrite_output=True, quiet=True, capture_stdout=True, capture_stderr=True)

        # Mở file WAV đã chuyển đổi
        wf = wave.open(wav_path, "rb")

        # Kiểm tra định dạng WAV mono PCM
        if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE":
            return jsonify({"error": "Định dạng WAV sau chuyển đổi không đúng!"}), 400


        # Khởi tạo KaldiRecognizer
        rec = KaldiRecognizer(model, wf.getframerate())
        result_text = ""

        # Đọc và xử lý dữ liệu âm thanh
        while True:
            data = wf.readframes(4000)
            if len(data) == 0:
                result_text += result.get("text", "") + " "
            else:
                partial_result = json.loads(rec.PartialResult())
                if partial_result.get("partial", ""):
                    result_text += partial_result["partial"] + " "

        # Trả về kết quả đã xử lý
        final_text = result_text.strip()
        if not final_text:
            final_text = "Không nh��n diện được nội dung âm thanh."
        return jsonify({"text": final_text})

    except ffmpeg.Error as e:
        error_message = e.stderr.decode('utf-8') if e.stderr else str(e)
        return jsonify({"error": f"Lỗi chuyển đổi âm thanh từ WebM sang WAV: {error_message}"}), 500
    except Exception as e:
        return jsonify({"error": f"Lỗi xử lý âm thanh: {str(e)}"}), 500

    finally:
        # Đóng file WAV nếu đã mở
        if wf is not None:
            wf.close()
        # Xóa các file tạm
        for path in [webm_path, wav_path]:
            if path and os.path.exists(path):
                os.remove(path)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=7860, debug=True)