Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -15,7 +15,7 @@ app = FastAPI()
|
|
| 15 |
|
| 16 |
app.add_middleware(
|
| 17 |
CORSMiddleware,
|
| 18 |
-
allow_origins=["https://studyscribe.framer.ai/"], # Replace "*" with your
|
| 19 |
allow_credentials=True,
|
| 20 |
allow_methods=["*"],
|
| 21 |
allow_headers=["*"],
|
|
@@ -51,20 +51,45 @@ async def log_requests(request: Request, call_next):
|
|
| 51 |
def transcribe_audio(audio_file_path):
|
| 52 |
try:
|
| 53 |
with open(audio_file_path, "rb") as audio_file:
|
| 54 |
-
transcript = openai.Audio.transcribe("whisper-1", audio_file)
|
| 55 |
-
return transcript
|
| 56 |
except Exception as e:
|
| 57 |
logger.error(f"Error in transcribe_audio: {e}")
|
| 58 |
raise HTTPException(status_code=500, detail="Error during audio transcription.")
|
| 59 |
|
| 60 |
-
def split_audio_file(audio_file_path,
|
| 61 |
audio = AudioSegment.from_file(audio_file_path)
|
| 62 |
duration_ms = len(audio)
|
| 63 |
chunks = []
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
chunks.append(chunk)
|
|
|
|
|
|
|
| 68 |
return chunks
|
| 69 |
|
| 70 |
def summarize_text(text, lesson_plan):
|
|
@@ -100,13 +125,13 @@ def summarize_text(text, lesson_plan):
|
|
| 100 |
|
| 101 |
def generate_lecture_notes(summaries, lesson_plan):
|
| 102 |
try:
|
| 103 |
-
summaries_text = "\n".join([f"
|
| 104 |
|
| 105 |
system_prompt = "You are an assistant that generates detailed lecture notes based on summaries and a lesson plan."
|
| 106 |
user_prompt = f"""
|
| 107 |
-
Using the summarized text
|
| 108 |
|
| 109 |
-
Summarized
|
| 110 |
{summaries_text}
|
| 111 |
|
| 112 |
Lesson Plan:
|
|
@@ -168,19 +193,38 @@ async def process_files(
|
|
| 168 |
else:
|
| 169 |
raise HTTPException(status_code=400, detail="No valid audio input provided.")
|
| 170 |
|
| 171 |
-
|
| 172 |
-
audio_chunks = split_audio_file(tmp_file_path,
|
| 173 |
|
| 174 |
summarized_texts = []
|
|
|
|
|
|
|
| 175 |
for index, chunk in enumerate(audio_chunks):
|
| 176 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as chunk_file:
|
| 177 |
chunk.export(chunk_file.name, format="wav")
|
| 178 |
chunk_file_path = chunk_file.name
|
| 179 |
|
| 180 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
|
| 182 |
-
|
| 183 |
-
|
|
|
|
| 184 |
|
| 185 |
os.unlink(chunk_file_path)
|
| 186 |
|
|
|
|
| 15 |
|
| 16 |
app.add_middleware(
|
| 17 |
CORSMiddleware,
|
| 18 |
+
allow_origins=["https://studyscribe.framer.ai/"], # Replace "*" with your frontend URL in production
|
| 19 |
allow_credentials=True,
|
| 20 |
allow_methods=["*"],
|
| 21 |
allow_headers=["*"],
|
|
|
|
| 51 |
def transcribe_audio(audio_file_path):
|
| 52 |
try:
|
| 53 |
with open(audio_file_path, "rb") as audio_file:
|
| 54 |
+
transcript = openai.Audio.transcribe("whisper-1", audio_file, response_format="verbose_json")
|
| 55 |
+
return transcript
|
| 56 |
except Exception as e:
|
| 57 |
logger.error(f"Error in transcribe_audio: {e}")
|
| 58 |
raise HTTPException(status_code=500, detail="Error during audio transcription.")
|
| 59 |
|
| 60 |
+
def split_audio_file(audio_file_path, max_chunk_size_mb=24):
|
| 61 |
audio = AudioSegment.from_file(audio_file_path)
|
| 62 |
duration_ms = len(audio)
|
| 63 |
chunks = []
|
| 64 |
+
start_ms = 0
|
| 65 |
+
|
| 66 |
+
while start_ms < duration_ms:
|
| 67 |
+
chunk_duration_ms = min(5 * 60 * 1000, duration_ms - start_ms) # Start with 5 minutes
|
| 68 |
+
chunk = audio[start_ms:start_ms + chunk_duration_ms]
|
| 69 |
+
|
| 70 |
+
while True:
|
| 71 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as temp_chunk_file:
|
| 72 |
+
chunk.export(temp_chunk_file.name, format="wav")
|
| 73 |
+
temp_chunk_file.flush()
|
| 74 |
+
file_size_bytes = os.path.getsize(temp_chunk_file.name)
|
| 75 |
+
file_size_mb = file_size_bytes / (1024 * 1024)
|
| 76 |
+
temp_chunk_file.close()
|
| 77 |
+
os.unlink(temp_chunk_file.name)
|
| 78 |
+
|
| 79 |
+
if file_size_mb <= max_chunk_size_mb:
|
| 80 |
+
# Chunk size is acceptable
|
| 81 |
+
break
|
| 82 |
+
else:
|
| 83 |
+
# Reduce chunk duration
|
| 84 |
+
if chunk_duration_ms <= 60 * 1000:
|
| 85 |
+
# Minimum chunk duration reached (1 minute), cannot reduce further
|
| 86 |
+
raise Exception("Cannot split audio into chunks small enough to meet the size limit.")
|
| 87 |
+
chunk_duration_ms -= 60 * 1000 # Reduce by 1 minute
|
| 88 |
+
chunk = audio[start_ms:start_ms + chunk_duration_ms]
|
| 89 |
+
|
| 90 |
chunks.append(chunk)
|
| 91 |
+
start_ms += chunk_duration_ms
|
| 92 |
+
|
| 93 |
return chunks
|
| 94 |
|
| 95 |
def summarize_text(text, lesson_plan):
|
|
|
|
| 125 |
|
| 126 |
def generate_lecture_notes(summaries, lesson_plan):
|
| 127 |
try:
|
| 128 |
+
summaries_text = "\n".join([f"At {item['timestamp']}: {item['summary']}" for item in summaries])
|
| 129 |
|
| 130 |
system_prompt = "You are an assistant that generates detailed lecture notes based on summaries and a lesson plan."
|
| 131 |
user_prompt = f"""
|
| 132 |
+
Using the summarized text segments below and the lesson plan, create detailed lecture notes.
|
| 133 |
|
| 134 |
+
Summarized Segments:
|
| 135 |
{summaries_text}
|
| 136 |
|
| 137 |
Lesson Plan:
|
|
|
|
| 193 |
else:
|
| 194 |
raise HTTPException(status_code=400, detail="No valid audio input provided.")
|
| 195 |
|
| 196 |
+
# Use the updated split_audio_file function
|
| 197 |
+
audio_chunks = split_audio_file(tmp_file_path, max_chunk_size_mb=24)
|
| 198 |
|
| 199 |
summarized_texts = []
|
| 200 |
+
current_chunk_start_time = 0
|
| 201 |
+
|
| 202 |
for index, chunk in enumerate(audio_chunks):
|
| 203 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as chunk_file:
|
| 204 |
chunk.export(chunk_file.name, format="wav")
|
| 205 |
chunk_file_path = chunk_file.name
|
| 206 |
|
| 207 |
+
# Transcribe chunk
|
| 208 |
+
transcript = transcribe_audio(chunk_file_path)
|
| 209 |
+
segments = transcript.get('segments', [])
|
| 210 |
+
|
| 211 |
+
for segment in segments:
|
| 212 |
+
# Adjust the segment timestamps to account for the chunk's position in the full audio
|
| 213 |
+
segment_start = segment['start'] + current_chunk_start_time
|
| 214 |
+
segment_end = segment['end'] + current_chunk_start_time
|
| 215 |
+
segment_text = segment['text']
|
| 216 |
+
|
| 217 |
+
# Summarize the segment
|
| 218 |
+
summary = summarize_text(segment_text, lesson_plan)
|
| 219 |
+
|
| 220 |
+
summarized_texts.append({
|
| 221 |
+
'timestamp': f"{segment_start:.2f} - {segment_end:.2f}",
|
| 222 |
+
'summary': summary
|
| 223 |
+
})
|
| 224 |
|
| 225 |
+
# Update the chunk start time
|
| 226 |
+
chunk_duration = len(chunk) / 1000.0 # duration in seconds
|
| 227 |
+
current_chunk_start_time += chunk_duration
|
| 228 |
|
| 229 |
os.unlink(chunk_file_path)
|
| 230 |
|