abhishekjoel commited on
Commit
b4c4e5e
·
verified ·
1 Parent(s): 9063eef

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +209 -34
app.py CHANGED
@@ -1,48 +1,223 @@
1
  import streamlit as st
2
- from utils import split_audio, transcribe_audio, generate_lesson_plan
3
- import os
4
  import openai
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- # Set up OpenAI API key
7
  openai.api_key = os.getenv("OPENAI_API_KEY")
8
 
9
- st.title("Lecture Notes Generator")
10
- st.write("Upload an audio recording of the lecture.")
 
11
 
12
- # Create a two-column layout
13
- col1, col2 = st.columns([1, 2])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
- with col1:
16
- # File upload for audio
17
- audio_file = st.file_uploader("Choose an audio file (max 25MB)", type=["mp3", "wav"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
- if st.button("Generate Notes"):
20
- if audio_file is not None:
21
- # Save the uploaded file
22
- with open("uploaded_audio.mp3", "wb") as f:
23
- f.write(audio_file.getbuffer())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
- # Split audio into chunks
26
- chunks = split_audio("uploaded_audio.mp3")
 
 
 
 
27
 
28
- # Transcribe audio
29
- transcriptions, timestamps = transcribe_audio(chunks)
 
 
 
 
 
 
 
 
30
 
31
- # Generate lesson plan from the transcription
32
- lesson_plan = generate_lesson_plan(transcriptions)
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
- # Display results in the second column
35
- with col2:
36
- st.subheader("Transcription with Timestamps")
37
- for ts, text in zip(timestamps, transcriptions):
38
- st.write(f"{ts}: {text}")
 
 
39
 
40
- st.subheader("Generated Lesson Plan")
41
- st.markdown(lesson_plan)
42
- else:
43
- st.error("Please upload an audio file.")
 
 
 
44
 
45
- with col2:
46
- # Initially empty
47
- st.subheader("Lecture Notes and Lesson Plan")
48
- st.write("Upload an audio file to generate notes.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
 
 
2
  import openai
3
+ import os
4
+ from datetime import datetime
5
+ import json
6
+ from dotenv import load_dotenv
7
+ from pydub import AudioSegment
8
+ import tempfile
9
+ import math
10
+ from pathlib import Path
11
+ import shutil
12
+
13
+ # Load environment variables
14
+ load_dotenv()
15
 
16
+ # Initialize OpenAI client
17
  openai.api_key = os.getenv("OPENAI_API_KEY")
18
 
19
+ # Constants
20
+ MAX_FILE_SIZE = 25 * 1024 * 1024 # 25MB in bytes (OpenAI API limit)
21
+ CHUNK_LENGTH = 10 * 60 * 1000 # 10 minutes in milliseconds
22
 
23
+ @st.cache_data
24
+ def save_uploaded_file(uploaded_file):
25
+ """Save uploaded file to a temporary directory and return the path"""
26
+ try:
27
+ temp_dir = tempfile.mkdtemp() # Create temporary directory
28
+ file_extension = Path(uploaded_file.name).suffix # Get file extension
29
+ temp_path = os.path.join(temp_dir, f"input_audio{file_extension}")
30
+
31
+ # Save uploaded file
32
+ with open(temp_path, "wb") as f:
33
+ f.write(uploaded_file.getvalue())
34
+
35
+ return temp_path, temp_dir
36
+ except Exception as e:
37
+ st.error(f"Error saving file: {str(e)}")
38
+ return None, None
39
 
40
+ def process_audio_file(file_path, temp_dir):
41
+ """Process and potentially chunk the audio file"""
42
+ try:
43
+ # Load the audio file using pydub
44
+ audio = AudioSegment.from_file(file_path)
45
+
46
+ # If file size is under the limit, return as a single chunk
47
+ if os.path.getsize(file_path) <= MAX_FILE_SIZE:
48
+ return [file_path]
49
+
50
+ # Otherwise, chunk the audio into smaller parts
51
+ chunks = []
52
+ total_length = len(audio)
53
+ num_chunks = math.ceil(total_length / CHUNK_LENGTH)
54
+
55
+ for i in range(num_chunks):
56
+ start_time = i * CHUNK_LENGTH
57
+ end_time = min((i + 1) * CHUNK_LENGTH, total_length)
58
+ chunk = audio[start_time:end_time]
59
+ chunk_path = os.path.join(temp_dir, f"chunk_{i}.mp3")
60
+
61
+ # Export chunk with adjustments
62
+ chunk = chunk.set_channels(1) # Convert to mono
63
+ chunk = chunk.set_frame_rate(16000) # Set sample rate to 16kHz
64
+ chunk.export(chunk_path, format="mp3", parameters=["-q:a", "0"])
65
+
66
+ chunks.append(chunk_path)
67
+ if not os.path.exists(chunk_path) or os.path.getsize(chunk_path) == 0:
68
+ raise Exception(f"Failed to create chunk {i}")
69
+
70
+ return chunks
71
+ except Exception as e:
72
+ st.error(f"Error processing audio: {str(e)}")
73
+ return None
74
 
75
+ def transcribe_audio_chunks(chunks):
76
+ """Transcribe audio chunks and combine transcriptions"""
77
+ all_segments = []
78
+ current_time_offset = 0
79
+
80
+ for i, chunk_path in enumerate(chunks):
81
+ try:
82
+ st.write(f"Processing chunk {i+1} of {len(chunks)}...")
83
+ with open(chunk_path, "rb") as audio:
84
+ transcript = openai.Audio.transcribe(
85
+ model="whisper-1",
86
+ file=audio,
87
+ response_format="verbose_json"
88
+ )
89
+
90
+ for segment in transcript['segments']:
91
+ segment['start'] += current_time_offset
92
+ segment['end'] += current_time_offset
93
+ all_segments.extend(transcript['segments'])
94
+
95
+ # Update time offset for next chunk
96
+ current_time_offset += len(AudioSegment.from_file(chunk_path)) / 1000 # Convert to seconds
97
+
98
+ except Exception as e:
99
+ st.error(f"Error in transcription of chunk {i+1}: {str(e)}")
100
+ return None
101
+
102
+ if all_segments:
103
+ return all_segments
104
+ return None
105
 
106
+ def format_timestamp(seconds):
107
+ """Convert seconds to HH:MM:SS format"""
108
+ hours = int(seconds // 3600)
109
+ minutes = int((seconds % 3600) // 60)
110
+ seconds = int(seconds % 60)
111
+ return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
112
 
113
+ def generate_lesson_plan(transcript):
114
+ """Generate a structured lesson plan from the transcript using GPT-4"""
115
+ try:
116
+ system_prompt = """You are an educational content expert. Generate a detailed lesson plan from the lecture transcript.
117
+ The lesson plan should include:
118
+ 1. Main Topics
119
+ 2. Subtopics
120
+ 3. Key Learning Objectives
121
+ 4. Important Concepts
122
+ Format the output in markdown with clear hierarchical structure."""
123
 
124
+ response = openai.ChatCompletion.create(
125
+ model="gpt-4-turbo",
126
+ messages=[
127
+ {"role": "system", "content": system_prompt},
128
+ {"role": "user", "content": f"Generate a lesson plan from this transcript:\n{transcript}"}
129
+ ],
130
+ temperature=0.3,
131
+ max_tokens=2000
132
+ )
133
+
134
+ return response.choices[0]['message']['content']
135
+ except Exception as e:
136
+ st.error(f"Error generating lesson plan: {str(e)}")
137
+ return None
138
 
139
+ def format_transcript_with_timestamps(segments):
140
+ """Format transcript with timestamps in a readable format"""
141
+ formatted_text = "# Lecture Transcript with Timestamps\n\n"
142
+ for segment in segments:
143
+ start_time = format_timestamp(segment['start'])
144
+ formatted_text += f"**[{start_time}]** {segment['text']}\n\n"
145
+ return formatted_text
146
 
147
+ def cleanup_files(temp_dir):
148
+ """Safely clean up temporary files"""
149
+ try:
150
+ if temp_dir and os.path.exists(temp_dir):
151
+ shutil.rmtree(temp_dir)
152
+ except Exception as e:
153
+ st.warning(f"Warning: Could not clean up temporary files: {str(e)}")
154
 
155
+ # Streamlit UI
156
+ def main():
157
+ st.set_page_config(page_title="Lecture Notes Generator", layout="wide")
158
+
159
+ st.title("🎓 Lecture Notes Generator")
160
+
161
+ col1, col2 = st.columns([1, 3])
162
+
163
+ with col1:
164
+ st.header("Upload Recording")
165
+ uploaded_file = st.file_uploader("Choose an audio file", type=['mp3', 'wav', 'm4a'])
166
+
167
+ if uploaded_file:
168
+ st.audio(uploaded_file)
169
+ file_size = uploaded_file.size / (1024 * 1024) # Convert to MB
170
+ st.info(f"File size: {file_size:.2f} MB")
171
+
172
+ if st.button("Generate Notes", type="primary", use_container_width=True):
173
+ with col2:
174
+ tab1, tab2 = st.tabs(["📝 Transcript", "📋 Lesson Plan"])
175
+
176
+ with st.spinner("Processing audio..."):
177
+ temp_path, temp_dir = save_uploaded_file(uploaded_file)
178
+
179
+ if temp_path and temp_dir:
180
+ try:
181
+ chunks = process_audio_file(temp_path, temp_dir)
182
+
183
+ if chunks:
184
+ transcript_data = transcribe_audio_chunks(chunks)
185
+
186
+ if transcript_data:
187
+ formatted_transcript = format_transcript_with_timestamps(transcript_data)
188
+ lesson_plan = generate_lesson_plan(formatted_transcript)
189
+
190
+ with tab1:
191
+ st.markdown(formatted_transcript)
192
+ st.download_button(
193
+ label="Download Transcript",
194
+ data=formatted_transcript,
195
+ file_name=f"transcript_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md",
196
+ mime="text/markdown"
197
+ )
198
+
199
+ with tab2:
200
+ if lesson_plan:
201
+ st.markdown(lesson_plan)
202
+ st.download_button(
203
+ label="Download Lesson Plan",
204
+ data=lesson_plan,
205
+ file_name=f"lesson_plan_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md",
206
+ mime="text/markdown"
207
+ )
208
+ finally:
209
+ cleanup_files(temp_dir)
210
+
211
+ if not uploaded_file:
212
+ with col2:
213
+ st.info("""
214
+ 👈 Start by uploading an audio file on the left side.
215
+
216
+ The system will automatically:
217
+ 1. Transcribe the lecture with timestamps
218
+ 2. Generate a structured lesson plan
219
+ 3. Provide downloadable versions of both
220
+ """)
221
+
222
+ if __name__ == "__main__":
223
+ main()