Phani1008 commited on
Commit
44f5184
Β·
verified Β·
1 Parent(s): 349f090

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +248 -0
app.py ADDED
@@ -0,0 +1,248 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import whisper
3
+ from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
4
+ import textwrap
5
+
6
+ # =========================
7
+ # 1. PAGE CONFIG
8
+ # =========================
9
+ st.set_page_config(
10
+ page_title="AI Meeting & Lecture Summarizer",
11
+ page_icon="🧠",
12
+ layout="wide"
13
+ )
14
+
15
+ st.title("🧠 AI Meeting & Lecture Summarizer")
16
+ st.write(
17
+ """
18
+ Upload a **recorded class / meeting audio file** or paste a **transcript**, and this app will:
19
+ - βœ… Transcribe (if audio)
20
+ - πŸ“ Summarize the content
21
+ - βœ… Extract **Action Items**
22
+ - πŸ“Œ Extract **Key Points / Decisions**
23
+ """
24
+ )
25
+
26
+ # =========================
27
+ # 2. LOAD MODELS (CACHED)
28
+ # =========================
29
+
30
+ @st.cache_resource
31
+ def load_whisper_model(model_name: str = "small"):
32
+ """
33
+ Load Whisper ASR model once and cache it.
34
+ """
35
+ asr_model = whisper.load_model(model_name)
36
+ return asr_model
37
+
38
+ @st.cache_resource
39
+ def load_summarization_model():
40
+ """
41
+ Load BART summarization model and tokenizer once and cache them.
42
+ """
43
+ model_name = "facebook/bart-large-cnn"
44
+ tokenizer = AutoTokenizer.from_pretrained(model_name)
45
+ model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
46
+ return tokenizer, model
47
+
48
+ tokenizer, summarizer_model = load_summarization_model()
49
+
50
+ # =========================
51
+ # 3. CORE SUMMARIZATION FUNCTIONS
52
+ # =========================
53
+
54
+ def summarize_text(text, max_len=120, min_len=40):
55
+ """
56
+ Summarize a given text using the BART model.
57
+ """
58
+ # 1. Tokenize text
59
+ inputs = tokenizer(
60
+ text,
61
+ max_length=1024, # BART max input length
62
+ truncation=True,
63
+ return_tensors="pt"
64
+ )
65
+
66
+ # 2. Generate summary token IDs
67
+ summary_ids = summarizer_model.generate(
68
+ inputs["input_ids"],
69
+ num_beams=5,
70
+ length_penalty=1.2,
71
+ no_repeat_ngram_size=3,
72
+ max_length=max_len,
73
+ min_length=min_len,
74
+ temperature=0.7,
75
+ top_k=50,
76
+ top_p=0.95,
77
+ early_stopping=True,
78
+ )
79
+
80
+ # 3. Decode token IDs to text
81
+ summary = tokenizer.decode(summary_ids[0], skip_special_tokens=True)
82
+ return summary
83
+
84
+
85
+ def summarize_long_text(text, max_chunk_chars=3000, max_len=120, min_len=40):
86
+ """
87
+ Handle long transcripts by:
88
+ 1. Splitting into chunks
89
+ 2. Summarizing each chunk
90
+ 3. Summarizing the combined summaries
91
+ """
92
+ if len(text) <= max_chunk_chars:
93
+ return summarize_text(text, max_len=max_len, min_len=min_len)
94
+
95
+ # Split by lines into manageable chunks
96
+ chunks = []
97
+ current_chunk = ""
98
+
99
+ for line in text.splitlines():
100
+ if len(current_chunk) + len(line) + 1 <= max_chunk_chars:
101
+ current_chunk += " " + line
102
+ else:
103
+ chunks.append(current_chunk.strip())
104
+ current_chunk = line
105
+
106
+ if current_chunk.strip():
107
+ chunks.append(current_chunk.strip())
108
+
109
+ partial_summaries = []
110
+ for i, chunk in enumerate(chunks, start=1):
111
+ with st.spinner(f"Summarizing chunk {i}/{len(chunks)} (length={len(chunk)} chars)..."):
112
+ part = summarize_text(chunk, max_len=max_len, min_len=min_len)
113
+ partial_summaries.append(part)
114
+
115
+ # Combine partial summaries and summarize again
116
+ combined = " ".join(partial_summaries)
117
+ final_summary = summarize_text(combined, max_len=max_len, min_len=min_len)
118
+ return final_summary
119
+
120
+
121
+ def extract_action_items(transcript_text: str) -> str:
122
+ """
123
+ Use summarization to extract action items via an instruction-style prompt.
124
+ """
125
+ prompt = (
126
+ "You are an assistant that reads a meeting or class transcript and extracts ACTION ITEMS.\n"
127
+ "Action items are specific tasks that someone needs to do in the future.\n\n"
128
+ "Transcript:\n"
129
+ f"{transcript_text}\n\n"
130
+ "Now list the ACTION ITEMS as clear bullet points:\n"
131
+ "- "
132
+ )
133
+
134
+ action_items_summary = summarize_long_text(
135
+ prompt,
136
+ max_chunk_chars=3000,
137
+ max_len=200,
138
+ min_len=60
139
+ )
140
+ return action_items_summary
141
+
142
+
143
+ def extract_key_points(transcript_text: str) -> str:
144
+ """
145
+ Use summarization to extract key points and decisions via an instruction-style prompt.
146
+ """
147
+ prompt = (
148
+ "You are an assistant that reads a meeting or lecture transcript and extracts the KEY POINTS.\n"
149
+ "Key points are the most important ideas, topics discussed, and decisions made.\n\n"
150
+ "Transcript:\n"
151
+ f"{transcript_text}\n\n"
152
+ "Now summarize the KEY POINTS and DECISIONS as bullet points:\n"
153
+ "- "
154
+ )
155
+
156
+ key_points_summary = summarize_long_text(
157
+ prompt,
158
+ max_chunk_chars=3000,
159
+ max_len=220,
160
+ min_len=80
161
+ )
162
+ return key_points_summary
163
+
164
+
165
+ # =========================
166
+ # 4. SIDEBAR: INPUT MODE
167
+ # =========================
168
+
169
+ st.sidebar.header("Input Options")
170
+ input_mode = st.sidebar.radio(
171
+ "Choose input type:",
172
+ ["Upload Audio File", "Paste Transcript Text"]
173
+ )
174
+
175
+ # =========================
176
+ # 5. MAIN LOGIC
177
+ # =========================
178
+
179
+ transcript_text = None
180
+
181
+ if input_mode == "Upload Audio File":
182
+ st.subheader("πŸŽ™ Upload your meeting / lecture recording")
183
+
184
+ audio_file = st.file_uploader(
185
+ "Upload an audio/video file (mp3, wav, m4a, mp4, etc.)",
186
+ type=["mp3", "wav", "m4a", "mp4"]
187
+ )
188
+
189
+ if audio_file is not None:
190
+ st.audio(audio_file)
191
+
192
+ if st.button("Transcribe & Summarize"):
193
+ with st.spinner("Loading Whisper model and transcribing audio..."):
194
+ asr_model = load_whisper_model("small")
195
+ # Save uploaded file to disk for Whisper
196
+ temp_filename = "temp_uploaded_audio"
197
+ with open(temp_filename, "wb") as f:
198
+ f.write(audio_file.read())
199
+
200
+ # Transcribe
201
+ result = asr_model.transcribe(temp_filename, language="en")
202
+ transcript_text = result["text"]
203
+
204
+ st.success("βœ… Transcription complete!")
205
+ st.write("### πŸ“„ Transcript (preview)")
206
+ st.write(textwrap.shorten(transcript_text, width=1000, placeholder=" ..."))
207
+
208
+ elif input_mode == "Paste Transcript Text":
209
+ st.subheader("πŸ“„ Paste your transcript text")
210
+
211
+ transcript_text = st.text_area(
212
+ "Paste the full transcript here (meeting, class, lecture, etc.)",
213
+ height=250
214
+ )
215
+
216
+ if transcript_text.strip() == "":
217
+ transcript_text = None
218
+
219
+ # =========================
220
+ # 6. RUN SUMMARIZATION ONCE WE HAVE TRANSCRIPT
221
+ # =========================
222
+
223
+ if transcript_text:
224
+ st.markdown("---")
225
+ st.subheader("🧠 AI Analysis")
226
+
227
+ if st.button("Generate Summary & Action Items"):
228
+ with st.spinner("Summarizing the transcript..."):
229
+ main_summary = summarize_long_text(transcript_text)
230
+
231
+ with st.spinner("Extracting action items..."):
232
+ action_items = extract_action_items(transcript_text)
233
+
234
+ with st.spinner("Extracting key points..."):
235
+ key_points = extract_key_points(transcript_text)
236
+
237
+ # Display results
238
+ st.markdown("### πŸ“ Main Summary")
239
+ st.write(main_summary)
240
+
241
+ st.markdown("### βœ… Action Items")
242
+ st.write(action_items)
243
+
244
+ st.markdown("### πŸ“Œ Key Points & Decisions")
245
+ st.write(key_points)
246
+
247
+ else:
248
+ st.info("πŸ‘† Upload an audio file or paste a transcript to get started.")