hamza2923 commited on
Commit
816272b
·
verified ·
1 Parent(s): e1e9bea

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -15
app.py CHANGED
@@ -8,24 +8,43 @@ from threading import Semaphore
8
  import os
9
  from werkzeug.utils import secure_filename
10
  import tempfile
11
- from moviepy.editor import VideoFileClip # Added for video processing
 
 
12
 
13
  app = Flask(__name__)
14
 
15
  # Configuration
16
- MAX_CONCURRENT_REQUESTS = 2 # Adjust based on server capacity
17
- MAX_FILE_DURATION = 60 * 30 # 30 minutes maximum duration (adjust as needed)
18
  TEMPORARY_FOLDER = tempfile.gettempdir()
19
  ALLOWED_AUDIO_EXTENSIONS = {'mp3', 'wav', 'ogg', 'm4a', 'flac', 'aac', 'wma', 'opus', 'aiff'}
20
  ALLOWED_VIDEO_EXTENSIONS = {'mp4', 'avi', 'mov', 'mkv', 'webm', 'flv', 'wmv', 'mpeg', 'mpg', '3gp'}
21
  ALLOWED_EXTENSIONS = ALLOWED_AUDIO_EXTENSIONS.union(ALLOWED_VIDEO_EXTENSIONS)
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  # Device check for faster-whisper
24
  device = "cuda" if torch.cuda.is_available() else "cpu"
25
  compute_type = "float16" if device == "cuda" else "int8"
26
  print(f"Using device: {device} with compute_type: {compute_type}")
27
 
28
- # Faster Whisper setup with optimized parameters for long audio
29
  beamsize = 2
30
  wmodel = WhisperModel(
31
  "guillaumekln/faster-whisper-small",
@@ -43,7 +62,6 @@ def allowed_file(filename):
43
  filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
44
 
45
  def cleanup_temp_files(*file_paths):
46
- """Ensure temporary files are deleted after processing"""
47
  for file_path in file_paths:
48
  try:
49
  if file_path and os.path.exists(file_path):
@@ -52,7 +70,6 @@ def cleanup_temp_files(*file_paths):
52
  print(f"Error cleaning up temp file {file_path}: {str(e)}")
53
 
54
  def extract_audio_from_video(video_path, output_audio_path):
55
- """Extract audio from a video file and save it as a temporary audio file"""
56
  try:
57
  video = VideoFileClip(video_path)
58
  if video.duration > MAX_FILE_DURATION:
@@ -64,9 +81,26 @@ def extract_audio_from_video(video_path, output_audio_path):
64
  except Exception as e:
65
  raise Exception(f"Failed to extract audio from video: {str(e)}")
66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  @app.route("/health", methods=["GET"])
68
  def health_check():
69
- """Endpoint to check if API is running"""
70
  return jsonify({
71
  'status': 'API is running',
72
  'timestamp': datetime.datetime.now().isoformat(),
@@ -79,7 +113,6 @@ def health_check():
79
 
80
  @app.route("/status/busy", methods=["GET"])
81
  def server_busy():
82
- """Endpoint to check if server is busy"""
83
  is_busy = active_requests >= MAX_CONCURRENT_REQUESTS
84
  return jsonify({
85
  'is_busy': is_busy,
@@ -100,18 +133,19 @@ def transcribe():
100
  temp_audio_path = None
101
 
102
  try:
103
- if 'file' not in request.files:
104
- return jsonify({'error': 'No file provided'}), 400
105
 
106
  file = request.files['file']
 
107
  if not (file and allowed_file(file.filename)):
108
  return jsonify({'error': f'Invalid file format. Supported: {", ".join(ALLOWED_EXTENSIONS)}'}), 400
109
 
110
- # Save uploaded file to temporary location
111
  temp_file_path = os.path.join(TEMPORARY_FOLDER, secure_filename(file.filename))
112
  file.save(temp_file_path)
113
 
114
- # Check if file is a video and extract audio if necessary
115
  file_extension = file.filename.rsplit('.', 1)[1].lower()
116
  if file_extension in ALLOWED_VIDEO_EXTENSIONS:
117
  temp_audio_path = os.path.join(TEMPORARY_FOLDER, f"temp_audio_{int(time.time())}.wav")
@@ -120,7 +154,7 @@ def transcribe():
120
  else:
121
  transcription_file = temp_file_path
122
 
123
- # Transcribe the audio file
124
  segments, _ = wmodel.transcribe(
125
  transcription_file,
126
  beam_size=beamsize,
@@ -131,9 +165,14 @@ def transcribe():
131
  )
132
 
133
  full_text = " ".join(segment.text for segment in segments)
 
 
 
 
 
134
  return jsonify({
135
  'transcription': full_text,
136
- 'file_type': 'video' if file_extension in ALLOWED_VIDEO_EXTENSIONS else 'audio'
137
  }), 200
138
 
139
  except Exception as e:
@@ -146,7 +185,6 @@ def transcribe():
146
  print(f"Processed in {time.time()-start_time:.2f}s (Active: {active_requests})")
147
 
148
  if __name__ == "__main__":
149
- # Create temporary folder if it doesn't exist
150
  if not os.path.exists(TEMPORARY_FOLDER):
151
  os.makedirs(TEMPORARY_FOLDER)
152
 
 
8
  import os
9
  from werkzeug.utils import secure_filename
10
  import tempfile
11
+ from moviepy.editor import VideoFileClip
12
+ import firebase_admin
13
+ from firebase_admin import credentials, messaging # Added for FCM
14
 
15
  app = Flask(__name__)
16
 
17
  # Configuration
18
+ MAX_CONCURRENT_REQUESTS = 2
19
+ MAX_FILE_DURATION = 60 * 30
20
  TEMPORARY_FOLDER = tempfile.gettempdir()
21
  ALLOWED_AUDIO_EXTENSIONS = {'mp3', 'wav', 'ogg', 'm4a', 'flac', 'aac', 'wma', 'opus', 'aiff'}
22
  ALLOWED_VIDEO_EXTENSIONS = {'mp4', 'avi', 'mov', 'mkv', 'webm', 'flv', 'wmv', 'mpeg', 'mpg', '3gp'}
23
  ALLOWED_EXTENSIONS = ALLOWED_AUDIO_EXTENSIONS.union(ALLOWED_VIDEO_EXTENSIONS)
24
 
25
+
26
+ # Initialize Firebase Admin SDK using environment variables
27
+ firebase_credentials = {
28
+ "type": "service_account",
29
+ "project_id": os.getenv("FIREBASE_PROJECT_ID"),
30
+ "private_key_id": os.getenv("FIREBASE_PRIVATE_KEY_ID"),
31
+ "private_key": os.getenv("FIREBASE_PRIVATE_KEY").replace("\\n", "\n"),
32
+ "client_email": os.getenv("FIREBASE_CLIENT_EMAIL"),
33
+ "client_id": os.getenv("FIREBASE_CLIENT_ID"),
34
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
35
+ "token_uri": "https://oauth2.googleapis.com/token",
36
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
37
+ "client_x509_cert_url": f"https://www.googleapis.com/robot/v1/metadata/x509/{os.getenv('FIREBASE_CLIENT_EMAIL')}"
38
+ }
39
+ cred = credentials.Certificate(firebase_credentials)
40
+ firebase_admin.initialize_app(cred)
41
+
42
  # Device check for faster-whisper
43
  device = "cuda" if torch.cuda.is_available() else "cpu"
44
  compute_type = "float16" if device == "cuda" else "int8"
45
  print(f"Using device: {device} with compute_type: {compute_type}")
46
 
47
+ # Faster Whisper setup
48
  beamsize = 2
49
  wmodel = WhisperModel(
50
  "guillaumekln/faster-whisper-small",
 
62
  filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
63
 
64
  def cleanup_temp_files(*file_paths):
 
65
  for file_path in file_paths:
66
  try:
67
  if file_path and os.path.exists(file_path):
 
70
  print(f"Error cleaning up temp file {file_path}: {str(e)}")
71
 
72
  def extract_audio_from_video(video_path, output_audio_path):
 
73
  try:
74
  video = VideoFileClip(video_path)
75
  if video.duration > MAX_FILE_DURATION:
 
81
  except Exception as e:
82
  raise Exception(f"Failed to extract audio from video: {str(e)}")
83
 
84
+ def send_fcm_data_message(fcm_token, transcription, file_type):
85
+ """Send a silent FCM data message with transcription details"""
86
+ try:
87
+ message = messaging.Message(
88
+ data={
89
+ 'transcription': transcription,
90
+ 'file_type': file_type,
91
+ 'timestamp': datetime.datetime.now().isoformat()
92
+ },
93
+ token=fcm_token
94
+ )
95
+ response = messaging.send(message)
96
+ print(f"FCM message sent: {response}")
97
+ return True
98
+ except Exception as e:
99
+ print(f"Error sending FCM message: {str(e)}")
100
+ return False
101
+
102
  @app.route("/health", methods=["GET"])
103
  def health_check():
 
104
  return jsonify({
105
  'status': 'API is running',
106
  'timestamp': datetime.datetime.now().isoformat(),
 
113
 
114
  @app.route("/status/busy", methods=["GET"])
115
  def server_busy():
 
116
  is_busy = active_requests >= MAX_CONCURRENT_REQUESTS
117
  return jsonify({
118
  'is_busy': is_busy,
 
133
  temp_audio_path = None
134
 
135
  try:
136
+ if 'file' not in request.files or 'fcm_token' not in request.form:
137
+ return jsonify({'error': 'Missing file or FCM token'}), 400
138
 
139
  file = request.files['file']
140
+ fcm_token = request.form['fcm_token']
141
  if not (file and allowed_file(file.filename)):
142
  return jsonify({'error': f'Invalid file format. Supported: {", ".join(ALLOWED_EXTENSIONS)}'}), 400
143
 
144
+ # Save uploaded file
145
  temp_file_path = os.path.join(TEMPORARY_FOLDER, secure_filename(file.filename))
146
  file.save(temp_file_path)
147
 
148
+ # Handle video/audio
149
  file_extension = file.filename.rsplit('.', 1)[1].lower()
150
  if file_extension in ALLOWED_VIDEO_EXTENSIONS:
151
  temp_audio_path = os.path.join(TEMPORARY_FOLDER, f"temp_audio_{int(time.time())}.wav")
 
154
  else:
155
  transcription_file = temp_file_path
156
 
157
+ # Transcribe
158
  segments, _ = wmodel.transcribe(
159
  transcription_file,
160
  beam_size=beamsize,
 
165
  )
166
 
167
  full_text = " ".join(segment.text for segment in segments)
168
+ file_type = 'video' if file_extension in ALLOWED_VIDEO_EXTENSIONS else 'audio'
169
+
170
+ # Send FCM data message
171
+ send_fcm_data_message(fcm_token, full_text, file_type)
172
+
173
  return jsonify({
174
  'transcription': full_text,
175
+ 'file_type': file_type
176
  }), 200
177
 
178
  except Exception as e:
 
185
  print(f"Processed in {time.time()-start_time:.2f}s (Active: {active_requests})")
186
 
187
  if __name__ == "__main__":
 
188
  if not os.path.exists(TEMPORARY_FOLDER):
189
  os.makedirs(TEMPORARY_FOLDER)
190