AbdulWahab14 commited on
Commit
b2ac0aa
·
verified ·
1 Parent(s): 12b4f84

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +183 -221
app.py CHANGED
@@ -4,8 +4,26 @@ import PyPDF2
4
  import re
5
  import os
6
  import io
7
- from google import genai
8
- from google.genai import types
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  # Setup tokens
11
  hf_token = os.getenv("HF_TOKEN")
@@ -16,12 +34,26 @@ print(f"GEMINI_API_KEY: {gemini_key is not None}")
16
 
17
  # Configure Gemini client
18
  client = None
19
- if gemini_key:
20
  try:
21
- client = genai.Client(api_key=gemini_key)
22
- print("✅ Gemini client configured")
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  except Exception as e:
24
  print(f"❌ Gemini config error: {e}")
 
25
 
26
  # Lazy load summarizer
27
  summarizer = None
@@ -39,8 +71,10 @@ def load_summarizer():
39
 
40
  def check_status():
41
  if client:
42
- return "✅ Gemini 2.5 Flash Ready"
43
- return "❌ Add GEMINI_API_KEY to Space Settings"
 
 
44
 
45
  def extract_text_from_pdf(pdf_file):
46
  """Extract text from PDF - handle both file path and bytes"""
@@ -63,12 +97,17 @@ def extract_text_from_pdf(pdf_file):
63
  if hasattr(pdf_file, 'read'):
64
  # File object - read bytes
65
  pdf_bytes = pdf_file.read()
66
- pdf_file.seek(0) # Reset if possible
 
67
  else:
68
  pdf_bytes = pdf_file
69
 
70
  # Create reader from bytes
71
- pdf_stream = io.BytesIO(pdf_bytes) if isinstance(pdf_bytes, bytes) else io.BytesIO(pdf_bytes.encode())
 
 
 
 
72
  pdf_reader = PyPDF2.PdfReader(pdf_stream)
73
 
74
  text = ""
@@ -87,24 +126,57 @@ def extract_text_from_pdf(pdf_file):
87
  except Exception as e:
88
  return None, f"Error reading PDF: {str(e)}"
89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  def summarize_pdf(pdf_file, max_length, min_length):
91
  text, error = extract_text_from_pdf(pdf_file)
92
  if error:
93
  return error
94
 
95
- # Use Gemini if available
96
- if client:
97
- try:
98
- prompt = f"Summarize the following text in {min_length}-{max_length} words. Be concise and clear:\n\n{text[:15000]}"
99
-
100
- response = client.models.generate_content(
101
- model="gemini-2.5-flash",
102
- contents=prompt
103
- )
104
-
105
- return response.text
106
- except Exception as e:
107
- print(f"Gemini summary error: {e}")
108
 
109
  # Fallback to local
110
  summ = load_summarizer()
@@ -117,17 +189,10 @@ def summarize_pdf(pdf_file, max_length, min_length):
117
 
118
  return "Error: No summarization available"
119
 
120
- def generate_essay(prompt, essay_type, word_count, tone):
121
- if not prompt or len(prompt.strip()) < 10:
122
- return "Please provide a detailed prompt (at least 10 characters)."
123
-
124
- if not client:
125
- return """❌ Gemini API key not configured.
126
-
127
- Get your free API key:
128
- 1. Visit: https://aistudio.google.com/app/apikey
129
- 2. Click "Create API Key"
130
- 3. Add to Space Settings → Repository secrets as GEMINI_API_KEY"""
131
 
132
  try:
133
  full_prompt = f"""You are an expert academic writer. Write a {essay_type} essay in {tone} tone.
@@ -141,25 +206,33 @@ Requirements:
141
  - Well-structured body paragraphs with supporting arguments and evidence
142
  - Strong conclusion that summarizes main points
143
  - Use academic vocabulary and formal writing style
144
- - Ensure logical flow between paragraphs
145
 
146
  Write the essay now:"""
147
-
148
- response = client.models.generate_content(
149
- model="gemini-2.5-flash",
150
- contents=full_prompt,
151
- config=types.GenerateContentConfig(
152
- temperature=0.7,
153
- top_p=0.9,
154
- max_output_tokens=min(word_count * 2, 2000)
155
- )
156
- )
157
 
158
- essay = response.text.strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
 
160
- # Clean up any markdown headers if present
161
  essay = re.sub(r'^#+\s*', '', essay)
162
-
163
  word_count_actual = len(essay.split())
164
 
165
  return f"""# {essay_type} Essay: {prompt[:50]}{'...' if len(prompt) > 50 else ''}
@@ -167,31 +240,49 @@ Write the essay now:"""
167
  {essay}
168
 
169
  ---
170
- *~{word_count_actual} words | {tone} tone | Generated with Gemini 2.5 Flash*
171
-
172
- Note: Please review and edit this AI-generated content before submission."""
173
 
174
  except Exception as e:
175
- error_msg = str(e)
176
- print(f"Essay generation error: {error_msg}")
177
- return f"Error: {error_msg}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
  def summarize_text(text, max_length, min_length):
180
  if len(text.strip()) < 100:
181
  return "Please provide at least 100 characters to summarize."
182
 
183
- if client:
184
- try:
185
- prompt = f"Summarize the following text in {min_length}-{max_length} words:\n\n{text[:15000]}"
186
-
187
- response = client.models.generate_content(
188
- model="gemini-2.5-flash",
189
- contents=prompt
190
- )
191
-
192
- return response.text
193
- except Exception as e:
194
- print(f"Gemini text error: {e}")
195
 
196
  # Fallback
197
  summ = load_summarizer()
@@ -206,180 +297,51 @@ def summarize_text(text, max_length, min_length):
206
 
207
  # CSS
208
  custom_css = """
209
- .header {
210
- text-align: center;
211
- margin-bottom: 2rem;
212
- padding: 2rem;
213
- background: linear-gradient(135deg, #059669 0%, #6b7280 100%);
214
- border-radius: 12px;
215
- color: white;
216
- }
217
- .header h1 {
218
- font-size: 2.5rem;
219
- margin-bottom: 0.5rem;
220
- }
221
- .header p {
222
- font-size: 1.2rem;
223
- opacity: 0.9;
224
- }
225
- .status-ok {
226
- background: #d1fae5;
227
- border: 2px solid #059669;
228
- padding: 1rem;
229
- border-radius: 8px;
230
- text-align: center;
231
- color: #065f46;
232
- font-weight: bold;
233
- margin-bottom: 1rem;
234
- }
235
- .status-warn {
236
- background: #fef3c7;
237
- border: 2px solid #f59e0b;
238
- padding: 1rem;
239
- border-radius: 8px;
240
- text-align: center;
241
- color: #92400e;
242
- margin-bottom: 1rem;
243
- }
244
- .info-box {
245
- background: #dbeafe;
246
- border-left: 4px solid #3b82f6;
247
- padding: 1rem;
248
- margin: 1rem 0;
249
- color: #1e40af;
250
- }
251
- .gemini-box {
252
- background: #e0e7ff;
253
- border-left: 4px solid #4f46e5;
254
- padding: 1rem;
255
- margin: 1rem 0;
256
- color: #3730a3;
257
- }
258
  """
259
 
260
- with gr.Blocks(title="Student AI Assistant - Gemini 2.5 Flash") as demo:
261
 
262
- # Status check
263
  status = check_status()
264
  if "✅" in status:
265
  gr.HTML(f'<div class="status-ok">{status}</div>')
266
- else:
267
  gr.HTML(f'<div class="status-warn">{status}</div>')
 
 
268
 
269
- gr.HTML("""
270
- <div class="header">
271
- <h1>🎓 Student AI Assistant</h1>
272
- <p>Powered by Google Gemini 2.5 Flash</p>
273
- </div>
274
- """)
275
-
276
- gr.HTML("""
277
- <div class="gemini-box">
278
- <strong>🚀 Gemini 2.5 Flash Features:</strong><br>
279
- • High-quality essay generation with proper structure<br>
280
- • Fast inference (typically 5-10 seconds)<br>
281
- • 1 million token context window for long PDFs
282
- </div>
283
- """)
284
 
285
  with gr.Tabs():
286
 
287
  with gr.TabItem("📄 PDF Summarizer"):
 
288
  with gr.Row():
289
- with gr.Column():
290
- gr.Markdown("### Upload Document")
291
- pdf_input = gr.File(
292
- label="Upload PDF",
293
- file_types=[".pdf"],
294
- type="binary" # Changed from "filepath" to "binary"
295
- )
296
- with gr.Row():
297
- max_len = gr.Slider(50, 500, 200, step=10, label="Max Summary Length")
298
- min_len = gr.Slider(20, 200, 50, step=10, label="Min Summary Length")
299
- summarize_btn = gr.Button("📝 Summarize PDF", variant="primary")
300
-
301
- with gr.Column():
302
- gr.Markdown("### Summary Result")
303
- pdf_output = gr.Textbox(
304
- label="",
305
- lines=12,
306
- placeholder="Your summary will appear here..."
307
- )
308
 
309
  gr.Markdown("---")
310
- gr.Markdown("### Or Paste Text Directly")
311
-
312
- text_input = gr.Textbox(
313
- label="Paste your text here",
314
- lines=5,
315
- placeholder="Paste lecture notes or any text to summarize..."
316
- )
317
- text_btn = gr.Button("Summarize Text", variant="secondary")
318
- text_output = gr.Textbox(
319
- label="Summary",
320
- lines=8,
321
- placeholder="Summary will appear here..."
322
- )
323
 
324
  with gr.TabItem("✍️ Essay Generator"):
325
- with gr.Row():
326
- with gr.Column():
327
- gr.Markdown("### Essay Parameters")
328
- prompt_input = gr.Textbox(
329
- label="Essay Topic / Prompt",
330
- placeholder="Example: 'The impact of artificial intelligence on modern healthcare'",
331
- lines=3
332
- )
333
- essay_type = gr.Dropdown(
334
- choices=["Argumentative", "Expository", "Descriptive", "Persuasive", "Analytical"],
335
- value="Argumentative",
336
- label="Essay Type"
337
- )
338
- tone = gr.Dropdown(
339
- choices=["Academic", "Formal", "Professional", "Neutral"],
340
- value="Academic",
341
- label="Writing Tone"
342
- )
343
- words = gr.Slider(200, 1000, 500, step=50, label="Target Word Count")
344
- gen_btn = gr.Button("✨ Generate Essay with Gemini", variant="primary")
345
-
346
- with gr.Column():
347
- gr.Markdown("### Generated Essay")
348
- essay_output = gr.Textbox(
349
- label="",
350
- lines=25,
351
- placeholder="Your high-quality essay will appear here..."
352
- )
353
-
354
- gr.Markdown("""
355
- ---
356
- ### 💡 Tips for Best Results:
357
- - **Be specific**: "The impact of social media on teenage mental health" → better than "Social media"
358
- - **Use 300-600 words** for optimal quality
359
- - **Review and edit** AI-generated content before submission
360
- - **PDFs**: Ensure text is selectable (not scanned images)
361
-
362
- **Powered by Google Gemini 2.5 Flash**
363
- """)
364
-
365
- # Event handlers
366
- summarize_btn.click(
367
- fn=summarize_pdf,
368
- inputs=[pdf_input, max_len, min_len],
369
- outputs=pdf_output
370
- )
371
-
372
- text_btn.click(
373
- fn=summarize_text,
374
- inputs=[text_input, max_len, min_len],
375
- outputs=text_output
376
- )
377
 
378
- gen_btn.click(
379
- fn=generate_essay,
380
- inputs=[prompt_input, essay_type, words, tone],
381
- outputs=essay_output
382
- )
383
 
384
  if __name__ == "__main__":
385
  demo.launch(css=custom_css)
 
4
  import re
5
  import os
6
  import io
7
+
8
+ # Try different import methods for google genai
9
+ try:
10
+ from google import genai
11
+ from google.genai import types
12
+ print("✅ Imported google.genai successfully")
13
+ except ImportError:
14
+ try:
15
+ import google.genai as genai
16
+ from google.genai import types
17
+ print("✅ Imported google.genai as module")
18
+ except ImportError:
19
+ try:
20
+ from google_genai import genai
21
+ from google_genai import types
22
+ print("✅ Imported google_genai")
23
+ except ImportError as e:
24
+ print(f"❌ Failed to import google genai: {e}")
25
+ genai = None
26
+ types = None
27
 
28
  # Setup tokens
29
  hf_token = os.getenv("HF_TOKEN")
 
34
 
35
  # Configure Gemini client
36
  client = None
37
+ if gemini_key and genai:
38
  try:
39
+ # Try different initialization methods
40
+ try:
41
+ client = genai.Client(api_key=gemini_key)
42
+ except:
43
+ try:
44
+ client = genai.client.Client(api_key=gemini_key)
45
+ except:
46
+ # Fallback to old SDK if available
47
+ import google.generativeai as old_genai
48
+ old_genai.configure(api_key=gemini_key)
49
+ client = old_genai
50
+ print("✅ Using legacy google.generativeai")
51
+
52
+ if client:
53
+ print("✅ Gemini client configured")
54
  except Exception as e:
55
  print(f"❌ Gemini config error: {e}")
56
+ client = None
57
 
58
  # Lazy load summarizer
59
  summarizer = None
 
71
 
72
  def check_status():
73
  if client:
74
+ return "✅ Gemini Ready"
75
+ elif gemini_key:
76
+ return "⚠️ Gemini key present but SDK not loaded"
77
+ return "❌ Add GEMINI_API_KEY"
78
 
79
  def extract_text_from_pdf(pdf_file):
80
  """Extract text from PDF - handle both file path and bytes"""
 
97
  if hasattr(pdf_file, 'read'):
98
  # File object - read bytes
99
  pdf_bytes = pdf_file.read()
100
+ if hasattr(pdf_file, 'seek'):
101
+ pdf_file.seek(0) # Reset if possible
102
  else:
103
  pdf_bytes = pdf_file
104
 
105
  # Create reader from bytes
106
+ if isinstance(pdf_bytes, bytes):
107
+ pdf_stream = io.BytesIO(pdf_bytes)
108
+ else:
109
+ pdf_stream = io.BytesIO(pdf_bytes.encode() if isinstance(pdf_bytes, str) else pdf_bytes)
110
+
111
  pdf_reader = PyPDF2.PdfReader(pdf_stream)
112
 
113
  text = ""
 
126
  except Exception as e:
127
  return None, f"Error reading PDF: {str(e)}"
128
 
129
+ def summarize_with_gemini(text, max_length, min_length):
130
+ """Try to use Gemini for summarization"""
131
+ if not client or not gemini_key:
132
+ return None
133
+
134
+ try:
135
+ # Try new SDK first
136
+ if hasattr(client, 'models'):
137
+ prompt = f"Summarize the following text in {min_length}-{max_length} words. Be concise and clear:\n\n{text[:15000]}"
138
+
139
+ try:
140
+ response = client.models.generate_content(
141
+ model="gemini-2.5-flash",
142
+ contents=prompt
143
+ )
144
+ return response.text
145
+ except:
146
+ # Try with config
147
+ try:
148
+ response = client.models.generate_content(
149
+ model="gemini-2.5-flash",
150
+ contents=prompt,
151
+ config=types.GenerateContentConfig(
152
+ max_output_tokens=500
153
+ ) if types else None
154
+ )
155
+ return response.text
156
+ except:
157
+ pass
158
+
159
+ # Try legacy SDK
160
+ if hasattr(client, 'GenerativeModel'):
161
+ model = client.GenerativeModel('gemini-2.5-flash')
162
+ prompt = f"Summarize the following text in {min_length}-{max_length} words:\n\n{text[:15000]}"
163
+ response = model.generate_content(prompt)
164
+ return response.text
165
+
166
+ except Exception as e:
167
+ print(f"Gemini summary error: {e}")
168
+
169
+ return None
170
+
171
  def summarize_pdf(pdf_file, max_length, min_length):
172
  text, error = extract_text_from_pdf(pdf_file)
173
  if error:
174
  return error
175
 
176
+ # Try Gemini first
177
+ gemini_result = summarize_with_gemini(text, max_length, min_length)
178
+ if gemini_result:
179
+ return gemini_result
 
 
 
 
 
 
 
 
 
180
 
181
  # Fallback to local
182
  summ = load_summarizer()
 
189
 
190
  return "Error: No summarization available"
191
 
192
+ def generate_essay_with_gemini(prompt, essay_type, word_count, tone):
193
+ """Generate essay using Gemini"""
194
+ if not client or not gemini_key:
195
+ return None
 
 
 
 
 
 
 
196
 
197
  try:
198
  full_prompt = f"""You are an expert academic writer. Write a {essay_type} essay in {tone} tone.
 
206
  - Well-structured body paragraphs with supporting arguments and evidence
207
  - Strong conclusion that summarizes main points
208
  - Use academic vocabulary and formal writing style
 
209
 
210
  Write the essay now:"""
 
 
 
 
 
 
 
 
 
 
211
 
212
+ # Try new SDK
213
+ if hasattr(client, 'models'):
214
+ try:
215
+ response = client.models.generate_content(
216
+ model="gemini-2.5-flash",
217
+ contents=full_prompt
218
+ )
219
+ essay = response.text.strip()
220
+ except:
221
+ # Try with legacy
222
+ if hasattr(client, 'GenerativeModel'):
223
+ model = client.GenerativeModel('gemini-2.5-flash')
224
+ response = model.generate_content(full_prompt)
225
+ essay = response.text.strip()
226
+ else:
227
+ return None
228
+ else:
229
+ # Legacy SDK
230
+ model = client.GenerativeModel('gemini-2.5-flash')
231
+ response = model.generate_content(full_prompt)
232
+ essay = response.text.strip()
233
 
234
+ # Clean up
235
  essay = re.sub(r'^#+\s*', '', essay)
 
236
  word_count_actual = len(essay.split())
237
 
238
  return f"""# {essay_type} Essay: {prompt[:50]}{'...' if len(prompt) > 50 else ''}
 
240
  {essay}
241
 
242
  ---
243
+ *~{word_count_actual} words | {tone} | Gemini*"""
 
 
244
 
245
  except Exception as e:
246
+ print(f"Essay generation error: {e}")
247
+ return None
248
+
249
+ def generate_essay(prompt, essay_type, word_count, tone):
250
+ if not prompt or len(prompt.strip()) < 10:
251
+ return "Please provide a detailed prompt (at least 10 characters)."
252
+
253
+ # Try Gemini first
254
+ if client and gemini_key:
255
+ gemini_result = generate_essay_with_gemini(prompt, essay_type, word_count, tone)
256
+ if gemini_result:
257
+ return gemini_result
258
+
259
+ # Template fallback
260
+ return f"""❌ AI generation not available.
261
+
262
+ Template Essay: {prompt}
263
+
264
+ Introduction:
265
+ {prompt} is an important topic that requires careful consideration. This essay explores its key aspects.
266
+
267
+ Body:
268
+ The significance of {prompt} cannot be overstated. Various perspectives exist on this matter, with experts debating the best approaches. Research continues to reveal new insights.
269
+
270
+ Conclusion:
271
+ In conclusion, {prompt} represents a complex issue that demands attention.
272
+
273
+ ---
274
+ *Template fallback - Gemini SDK issue*
275
+
276
+ Check: 1) GEMINI_API_KEY is set 2) google-genai package is installed"""
277
 
278
  def summarize_text(text, max_length, min_length):
279
  if len(text.strip()) < 100:
280
  return "Please provide at least 100 characters to summarize."
281
 
282
+ # Try Gemini
283
+ gemini_result = summarize_with_gemini(text, max_length, min_length)
284
+ if gemini_result:
285
+ return gemini_result
 
 
 
 
 
 
 
 
286
 
287
  # Fallback
288
  summ = load_summarizer()
 
297
 
298
  # CSS
299
  custom_css = """
300
+ .header { text-align: center; margin-bottom: 2rem; padding: 2rem; background: linear-gradient(135deg, #059669, #6b7280); border-radius: 12px; color: white; }
301
+ .header h1 { font-size: 2.5rem; margin-bottom: 0.5rem; }
302
+ .status-ok { background: #d1fae5; border: 2px solid #059669; padding: 1rem; border-radius: 8px; text-align: center; color: #065f46; font-weight: bold; margin-bottom: 1rem; }
303
+ .status-warn { background: #fef3c7; border: 2px solid #f59e0b; padding: 1rem; border-radius: 8px; text-align: center; color: #92400e; margin-bottom: 1rem; }
304
+ .status-error { background: #fee2e2; border: 2px solid #ef4444; padding: 1rem; border-radius: 8px; text-align: center; color: #991b1b; margin-bottom: 1rem; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
305
  """
306
 
307
+ with gr.Blocks(title="Student AI Assistant") as demo:
308
 
 
309
  status = check_status()
310
  if "✅" in status:
311
  gr.HTML(f'<div class="status-ok">{status}</div>')
312
+ elif "⚠️" in status:
313
  gr.HTML(f'<div class="status-warn">{status}</div>')
314
+ else:
315
+ gr.HTML(f'<div class="status-error">{status}</div>')
316
 
317
+ gr.HTML('<div class="header"><h1>🎓 Student AI Assistant</h1><p>Essay & PDF Tools</p></div>')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
318
 
319
  with gr.Tabs():
320
 
321
  with gr.TabItem("📄 PDF Summarizer"):
322
+ pdf_input = gr.File(label="Upload PDF", file_types=[".pdf"], type="binary")
323
  with gr.Row():
324
+ max_len = gr.Slider(50, 500, 200, step=10, label="Max Length")
325
+ min_len = gr.Slider(20, 200, 50, step=10, label="Min Length")
326
+ summarize_btn = gr.Button("📝 Summarize PDF", variant="primary")
327
+ pdf_output = gr.Textbox(label="Summary", lines=12)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
 
329
  gr.Markdown("---")
330
+ text_input = gr.Textbox(label="Or paste text", lines=5)
331
+ text_btn = gr.Button("Summarize Text")
332
+ text_output = gr.Textbox(label="Summary", lines=8)
 
 
 
 
 
 
 
 
 
 
333
 
334
  with gr.TabItem("✍️ Essay Generator"):
335
+ prompt_input = gr.Textbox(label="Essay Topic", placeholder="Example: 'The impact of AI on education'", lines=3)
336
+ essay_type = gr.Dropdown(["Argumentative", "Expository", "Descriptive", "Persuasive"], value="Argumentative")
337
+ tone = gr.Dropdown(["Academic", "Formal", "Neutral"], value="Academic")
338
+ words = gr.Slider(200, 1000, 500, step=50, label="Word Count")
339
+ gen_btn = gr.Button(" Generate Essay", variant="primary")
340
+ essay_output = gr.Textbox(label="Generated Essay", lines=25)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
 
342
+ summarize_btn.click(summarize_pdf, [pdf_input, max_len, min_len], pdf_output)
343
+ text_btn.click(summarize_text, [text_input, max_len, min_len], text_output)
344
+ gen_btn.click(generate_essay, [prompt_input, essay_type, words, tone], essay_output)
 
 
345
 
346
  if __name__ == "__main__":
347
  demo.launch(css=custom_css)