-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathroutes.py
252 lines (233 loc) · 9.58 KB
/
routes.py
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
import base64
import io
import logging
from fastapi import APIRouter, HTTPException, Depends
from pydantic import BaseModel
from utils import denoise_with_rnnoise, get_error_arrays, get_pause_count, split_into_phonemes, processLP
from schemas import TextData, audioData, PhonemesRequest, PhonemesResponse, ErrorArraysResponse, AudioProcessingResponse
from typing import List
import jiwer
import eng_to_ipa as p
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
router = APIRouter()
@router.post('/getTextMatrices', response_model=ErrorArraysResponse, summary="Compute Text Matrices", description="Computes WER, CER, insertion, deletion, substitution, confidence char list, missing char list, construct text", responses={
400: {
"description": "Bad Request",
"content": {
"application/json": {
"example": {"detail": "Reference text must be provided."}
}
}
},
422: {
"description": "Unprocessable Entity",
"content": {
"application/json": {
"example": {
"detail": [
{
"loc": ["body", "text"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
}
}
},
500: {
"description": "Internal Server Error",
"content": {
"application/json": {
"example": {"detail": "Unexpected error: Error processing characters: <error_message>"}
}
}
}
})
async def compute_errors(data: TextData):
try:
# Validate input data
if not data.reference:
raise HTTPException(status_code=400, detail="Reference text must be provided.")
reference = data.reference
hypothesis = data.hypothesis if data.hypothesis is not None else ""
language = data.language
# Validate language
allowed_languages = {"en", "ta", "te", "kn", "hi"}
if language not in allowed_languages:
raise HTTPException(status_code=400, detail=f"Unsupported language: {language}. Supported languages are: {', '.join(allowed_languages)}")
# Process character-level differences
try:
charOut = jiwer.process_characters(reference, hypothesis)
except Exception as e:
logger.error(f"Error processing characters: {str(e)}")
raise HTTPException(status_code=500, detail=f"Error processing characters: {str(e)}")
# Compute WER
try:
wer = jiwer.wer(reference, hypothesis)
except Exception as e:
logger.error(f"Error computing WER: {str(e)}")
raise HTTPException(status_code=500, detail=f"Error computing WER: {str(e)}")
confidence_char_list = []
missing_char_list = []
construct_text = ""
if language == "en":
try:
confidence_char_list, missing_char_list, construct_text = processLP(reference, hypothesis)
except Exception as e:
logger.error(f"Error processing LP: {str(e)}")
raise HTTPException(status_code=500, detail=f"Error processing LP: {str(e)}")
# Extract error arrays
try:
error_arrays = get_error_arrays(charOut.alignments, reference, hypothesis)
except Exception as e:
logger.error(f"Error extracting error arrays: {str(e)}")
raise HTTPException(status_code=500, detail=f"Error extracting error arrays: {str(e)}")
return {
"wer": wer,
"cer": charOut.cer,
"insertion": error_arrays['insertion'],
"insertion_count": len(error_arrays['insertion']),
"deletion": error_arrays['deletion'],
"deletion_count": len(error_arrays['deletion']),
"substitution": error_arrays['substitution'],
"substitution_count": len(error_arrays['substitution']),
"confidence_char_list": confidence_char_list,
"missing_char_list": missing_char_list,
"construct_text": construct_text
}
except HTTPException as e:
raise e
except Exception as e:
logger.error(f"Unexpected error: {str(e)}")
raise HTTPException(status_code=500, detail=f"Unexpected error: {str(e)}")
@router.post("/getPhonemes", response_model=PhonemesResponse, summary="Get Phonemes", description="Converts text into phonemes.", responses={
400: {
"description": "Bad Request",
"content": {
"application/json": {
"example": {"detail": "Input text cannot be empty."}
}
}
},
422: {
"description": "Unprocessable Entity",
"content": {
"application/json": {
"example": {
"detail": [
{
"loc": ["body", "text"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
}
}
},
500: {
"description": "Internal Server Error",
"content": {
"application/json": {
"example": {"detail": "Unexpected error: Error getting phonemes: <error_message>"}
}
}
}
})
async def get_phonemes(data: PhonemesRequest):
try:
if not data.text.strip():
raise HTTPException(status_code=400, detail="Input text cannot be empty.")
phonemesList = split_into_phonemes(p.convert(data.text))
return {"phonemes": phonemesList}
except HTTPException as e:
raise e
except Exception as e:
logger.error(f"Error getting phonemes: {str(e)}")
raise HTTPException(status_code=500, detail=f"Error getting phonemes: {str(e)}")
@router.post('/audio_processing', response_model=AudioProcessingResponse, summary="Process Audio", description="Processes audio by denoising and detecting pauses.", responses={
400: {
"description": "Bad Request",
"content": {
"application/json": {
"example": {"detail": "Base64 string of audio must be provided."}
}
}
},
422: {
"description": "Unprocessable Entity",
"content": {
"application/json": {
"example": {
"detail": [
{
"loc": ["body", "text"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
}
}
},
500: {
"description": "Internal Server Error",
"content": {
"application/json": {
"example": {"detail": "Unexpected error: <error_message>"}
}
}
}
})
async def audio_processing(data: audioData):
try:
# Validate input data
if not data.base64_string:
raise HTTPException(status_code=400, detail="Base64 string of audio must be provided.")
if not data.contentType:
raise HTTPException(status_code=400, detail="Content type must be specified.")
try:
audio_data = data.base64_string
audio_bytes = base64.b64decode(audio_data)
audio_io = io.BytesIO(audio_bytes)
except Exception as e:
logger.error(f"Invalid base64 string: {str(e)}")
raise HTTPException(status_code=400, detail=f"Invalid base64 string: {str(e)}")
pause_count = 0
denoised_audio_base64 = ""
if data.enablePauseCount:
try:
pause_count = get_pause_count(audio_io)
if pause_count is None:
logger.error("Error during pause count detection")
raise HTTPException(status_code=500, detail="Error during pause count detection")
except Exception as e:
logger.error(f"Error during pause count detection: {str(e)}")
raise HTTPException(status_code=500, detail=f"Error during pause count detection: {str(e)}")
if data.enableDenoiser:
try:
denoised_audio_base64 = denoise_with_rnnoise(audio_data, data.contentType)
if denoised_audio_base64 is None:
logger.error("Error during audio denoising")
raise HTTPException(status_code=500, detail="Error during audio denoising")
except ValueError as e:
logger.error(f"Value error in denoise_with_rnnoise: {str(e)}")
raise HTTPException(status_code=400, detail=f"Value error in denoise_with_rnnoise: {str(e)}")
except RuntimeError as e:
logger.error(f"Runtime error in denoise_with_rnnoise: {str(e)}")
raise HTTPException(status_code=500, detail=f"Runtime error in denoise_with_rnnoise: {str(e)}")
except Exception as e:
logger.error(f"Unexpected error in denoise_with_rnnoise: {str(e)}")
raise HTTPException(status_code=500, detail=f"Unexpected error in denoise_with_rnnoise: {str(e)}")
return {
"denoised_audio_base64": denoised_audio_base64,
"pause_count": pause_count
}
except HTTPException as e:
raise e
except Exception as e:
logger.error(f"Unexpected error: {str(e)}")
raise HTTPException(status_code=500, detail=f"Unexpected error: {str(e)}")