MrSimple01 commited on
Commit
42638f9
·
verified ·
1 Parent(s): 33b3cd8

Update src/quiz_processing.py

Browse files
Files changed (1) hide show
  1. src/quiz_processing.py +86 -157
src/quiz_processing.py CHANGED
@@ -7,60 +7,7 @@ from typing import Dict, Any, List, Optional
7
  from transformers import AutoTokenizer
8
  from sentence_transformers import SentenceTransformer
9
  from huggingface_hub import login
10
- from src.prompts import SYSTEM_PROMPT
11
-
12
- # Define the prompt templates directly in this file since they're referenced but missing
13
- SUMMARY_PROMPT_TEMPLATE = """You are an expert content analyst specialized in creating professional, actionable summaries of educational content.
14
-
15
- Please analyze the following text to create a comprehensive yet concise summary that will be valuable to readers. Break down the content into 2-3 meaningful segments, each focused on a key topic or theme.
16
-
17
- For each segment of the content, provide:
18
- 1. A descriptive topic name
19
- 2. 3-5 key concepts or terms that are central to understanding this segment
20
- 3. A concise summary paragraph (3-5 sentences) that captures the essential information
21
-
22
- The text to analyze is:
23
- {text}
24
-
25
- FORMAT YOUR RESPONSE STRICTLY AS A JSON OBJECT AS FOLLOWS (with no other text, explanation or formatting):
26
- {
27
- "segments": [
28
- {
29
- "topic_name": "Title for the first segment",
30
- "key_concepts": ["Key concept 1", "Key concept 2", "Key concept 3"],
31
- "summary": "Concise summary paragraph for this segment that captures the essential information."
32
- },
33
- {
34
- "topic_name": "Title for the second segment",
35
- "key_concepts": ["Key concept 1", "Key concept 2", "Key concept 3"],
36
- "summary": "Concise summary paragraph for this segment that captures the essential information."
37
- }
38
- ]
39
- }"""
40
-
41
- QUIZ_PROMPT_TEMPLATE = """You are an expert quiz creator specialized in creating educational assessments.
42
-
43
- Please analyze the following text and create 5 multiple-choice quiz questions that test understanding of the key concepts and information presented in the text. For each question:
44
- 1. Write a clear, concise question
45
- 2. Create 4 answer options (A, B, C, D) with exactly one correct answer
46
-
47
- The text to analyze is:
48
- {text}
49
-
50
- FORMAT YOUR RESPONSE STRICTLY AS A JSON OBJECT AS FOLLOWS (with no other text, explanation or formatting):
51
- {
52
- "quiz_questions": [
53
- {
54
- "question": "The full text of the question?",
55
- "options": [
56
- { "text": "First option text", "correct": false },
57
- { "text": "Second option text", "correct": true },
58
- { "text": "Third option text", "correct": false },
59
- { "text": "Fourth option text", "correct": false }
60
- ]
61
- }
62
- ]
63
- }"""
64
 
65
  GEMINI_MODEL = "gemini-2.0-flash"
66
  DEFAULT_TEMPERATURE = 0.7
@@ -132,60 +79,22 @@ def generate_with_gemini(text, api_key, language, content_type="summary"):
132
 
133
  try:
134
  content = response.content
135
- # First try to find JSON within code blocks
136
- json_match = re.search(r'```(?:json)?\s*([\s\S]*?)\s*```', content)
137
 
138
  if json_match:
139
  json_str = json_match.group(1)
140
  else:
141
- # Then try to find JSON with curly braces
142
  json_match = re.search(r'(\{[\s\S]*\})', content)
143
  if json_match:
144
  json_str = json_match.group(1)
145
  else:
146
- # If we still don't have JSON, try to clean and parse the content directly
147
  json_str = content
148
 
149
- # Clean up the JSON string
150
- json_str = json_str.strip()
151
-
152
- # Try to parse the JSON
153
- try:
154
- function_call = json.loads(json_str)
155
- return function_call
156
- except json.JSONDecodeError:
157
- # If direct parsing fails, try to fix common issues
158
- # Remove markdown formatting or extra text
159
- cleaned_json = re.sub(r'^[^{]*', '', json_str)
160
- cleaned_json = re.sub(r'[^}]*$', '', cleaned_json)
161
- return json.loads(cleaned_json)
162
-
163
- except json.JSONDecodeError as e:
164
- # Fall back to a default structure
165
- if content_type == "summary":
166
- return {
167
- "segments": [
168
- {
169
- "topic_name": "Content Analysis",
170
- "key_concepts": ["AI Processing", "Text Analysis"],
171
- "summary": "The model was unable to produce a properly formatted JSON response. Please try again with a different text sample."
172
- }
173
- ]
174
- }
175
- else:
176
- return {
177
- "quiz_questions": [
178
- {
179
- "question": "Unable to generate quiz questions from the provided text.",
180
- "options": [
181
- {"text": "Try again", "correct": true},
182
- {"text": "Use different text", "correct": false},
183
- {"text": "Adjust the prompt", "correct": false},
184
- {"text": "Contact support", "correct": false}
185
- ]
186
- }
187
- ]
188
- }
189
  except Exception as e:
190
  raise Exception(f"Error calling API: {str(e)}")
191
 
@@ -193,33 +102,79 @@ def format_summary_for_display(results, language="English"):
193
  output = []
194
 
195
  if language == "Uzbek":
196
- segment_header = "QISM"
197
- key_concepts_header = "ASOSIY TUSHUNCHALAR"
198
- summary_header = "QISQACHA MAZMUN"
 
 
199
  elif language == "Russian":
200
- segment_header = "СЕГМЕНТ"
201
- key_concepts_header = "КЛЮЧЕВЫЕ ПОНЯТИЯ"
202
- summary_header = "КРАТКОЕ СОДЕРЖАНИЕ"
 
 
203
  else:
204
- segment_header = "SEGMENT"
205
- key_concepts_header = "KEY CONCEPTS"
206
- summary_header = "SUMMARY"
 
 
207
 
208
- segments = results.get("segments", [])
209
- if not segments:
210
- return "No segments were generated. Please try again with a different text sample."
211
-
212
- for i, segment in enumerate(segments):
213
- topic = segment["topic_name"]
214
- segment_num = i + 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  output.append(f"\n\n{'='*40}")
216
- output.append(f"{segment_header} {segment_num}: {topic}")
217
  output.append(f"{'='*40}\n")
218
- output.append(f"{key_concepts_header}:")
219
- for concept in segment["key_concepts"]:
220
- output.append(f" {concept}")
221
- output.append(f"\n{summary_header}:")
222
- output.append(segment["summary"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
 
224
  return "\n".join(output)
225
 
@@ -238,9 +193,6 @@ def format_quiz_for_display(results, language="English"):
238
  output.append(f"{'='*40}\n")
239
 
240
  quiz_questions = results.get("quiz_questions", [])
241
- if not quiz_questions:
242
- return "No quiz questions were generated. Please try again with a different text sample."
243
-
244
  for i, q in enumerate(quiz_questions):
245
  output.append(f"\n{i+1}. {q['question']}")
246
  for j, option in enumerate(q['options']):
@@ -252,9 +204,6 @@ def format_quiz_for_display(results, language="English"):
252
 
253
  def analyze_document(text, gemini_api_key, language, content_type="summary"):
254
  try:
255
- if not text or len(text.strip()) < 100:
256
- return "Error: Text is too short to analyze. Please provide a longer text sample.", None, None
257
-
258
  start_time = time.time()
259
  text_parts = split_text_by_tokens(text)
260
 
@@ -262,8 +211,7 @@ def analyze_document(text, gemini_api_key, language, content_type="summary"):
262
  output_tokens = 0
263
 
264
  if content_type == "summary":
265
- all_results = {"segments": []}
266
- segment_counter = 1
267
 
268
  for part in text_parts:
269
  actual_prompt = SUMMARY_PROMPT_TEMPLATE.format(text=part)
@@ -272,24 +220,17 @@ def analyze_document(text, gemini_api_key, language, content_type="summary"):
272
 
273
  analysis = generate_with_gemini(part, gemini_api_key, language, "summary")
274
 
275
- if "segments" in analysis and analysis["segments"]:
276
- for segment in analysis["segments"]:
277
- segment["segment_number"] = segment_counter
278
- all_results["segments"].append(segment)
279
- segment_counter += 1
280
- else:
281
- # Add a default segment if none were returned
282
- all_results["segments"].append({
283
- "segment_number": segment_counter,
284
- "topic_name": "Content Analysis",
285
- "key_concepts": ["Text Processing", "AI Analysis", "Document Summarization"],
286
- "summary": "The system was unable to generate detailed segments from this text portion. This may be due to the complexity of the content or formatting issues. Consider breaking the text into smaller, more focused sections."
287
- })
288
- segment_counter += 1
289
 
290
  formatted_output = format_summary_for_display(all_results, language)
291
-
292
- else: # Quiz generation
293
  all_results = {"quiz_questions": []}
294
 
295
  for part in text_parts:
@@ -299,23 +240,11 @@ def analyze_document(text, gemini_api_key, language, content_type="summary"):
299
 
300
  analysis = generate_with_gemini(part, gemini_api_key, language, "quiz")
301
 
302
- if "quiz_questions" in analysis and analysis["quiz_questions"]:
303
  remaining_slots = 10 - len(all_results["quiz_questions"])
304
  if remaining_slots > 0:
305
  questions_to_add = analysis["quiz_questions"][:remaining_slots]
306
  all_results["quiz_questions"].extend(questions_to_add)
307
- else:
308
- # Add a default question if none were returned
309
- if len(all_results["quiz_questions"]) < 10:
310
- all_results["quiz_questions"].append({
311
- "question": "What is the main purpose of text analysis in educational contexts?",
312
- "options": [
313
- {"text": "To change the original meaning of the text", "correct": False},
314
- {"text": "To extract key concepts and facilitate understanding", "correct": True},
315
- {"text": "To reduce text to exactly half its original length", "correct": False},
316
- {"text": "To eliminate all technical terminology", "correct": False}
317
- ]
318
- })
319
 
320
  formatted_output = format_quiz_for_display(all_results, language)
321
 
 
7
  from transformers import AutoTokenizer
8
  from sentence_transformers import SentenceTransformer
9
  from huggingface_hub import login
10
+ from src.prompts import SUMMARY_PROMPT_TEMPLATE, QUIZ_PROMPT_TEMPLATE
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
  GEMINI_MODEL = "gemini-2.0-flash"
13
  DEFAULT_TEMPERATURE = 0.7
 
79
 
80
  try:
81
  content = response.content
82
+ json_match = re.search(r'```json\s*([\s\S]*?)\s*```', content)
 
83
 
84
  if json_match:
85
  json_str = json_match.group(1)
86
  else:
 
87
  json_match = re.search(r'(\{[\s\S]*\})', content)
88
  if json_match:
89
  json_str = json_match.group(1)
90
  else:
 
91
  json_str = content
92
 
93
+ # Parse the JSON
94
+ function_call = json.loads(json_str)
95
+ return function_call
96
+ except json.JSONDecodeError:
97
+ raise Exception("Could not parse JSON from LLM response")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  except Exception as e:
99
  raise Exception(f"Error calling API: {str(e)}")
100
 
 
102
  output = []
103
 
104
  if language == "Uzbek":
105
+ title_header = "SARLAVHA"
106
+ overview_header = "UMUMIY KO'RINISH"
107
+ key_points_header = "ASOSIY NUQTALAR"
108
+ key_entities_header = "ASOSIY SHAXSLAR VA TUSHUNCHALAR"
109
+ conclusion_header = "XULOSA"
110
  elif language == "Russian":
111
+ title_header = "ЗАГОЛОВОК"
112
+ overview_header = "ОБЗОР"
113
+ key_points_header = "КЛЮЧЕВЫЕ МОМЕНТЫ"
114
+ key_entities_header = "КЛЮЧЕВЫЕ ОБЪЕКТЫ"
115
+ conclusion_header = "ЗАКЛЮЧЕНИЕ"
116
  else:
117
+ title_header = "TITLE"
118
+ overview_header = "OVERVIEW"
119
+ key_points_header = "KEY POINTS"
120
+ key_entities_header = "KEY ENTITIES"
121
+ conclusion_header = "CONCLUSION"
122
 
123
+ if "summary" not in results:
124
+ if "segments" in results:
125
+ segments = results.get("segments", [])
126
+ for i, segment in enumerate(segments):
127
+ topic = segment.get("topic_name", f"Section {i+1}")
128
+ segment_num = i + 1
129
+ output.append(f"\n\n{'='*40}")
130
+ output.append(f"SEGMENT {segment_num}: {topic}")
131
+ output.append(f"{'='*40}\n")
132
+
133
+ if "key_concepts" in segment:
134
+ output.append("KEY CONCEPTS:")
135
+ for concept in segment["key_concepts"]:
136
+ output.append(f"• {concept}")
137
+
138
+ if "summary" in segment:
139
+ output.append("\nSUMMARY:")
140
+ output.append(segment["summary"])
141
+
142
+ return "\n".join(output)
143
+ else:
144
+ return "Error: Could not parse summary results. Invalid format received."
145
+
146
+ summary = results["summary"]
147
+ if "title" in summary:
148
  output.append(f"\n\n{'='*40}")
149
+ output.append(f"{title_header}: {summary['title']}")
150
  output.append(f"{'='*40}\n")
151
+
152
+ # Overview
153
+ if "overview" in summary:
154
+ output.append(f"{overview_header}:")
155
+ output.append(f"{summary['overview']}\n")
156
+
157
+ # Key Points
158
+ if "key_points" in summary and summary["key_points"]:
159
+ output.append(f"{key_points_header}:")
160
+ for theme_group in summary["key_points"]:
161
+ if "theme" in theme_group:
162
+ output.append(f"\n{theme_group['theme']}:")
163
+ if "points" in theme_group:
164
+ for point in theme_group["points"]:
165
+ output.append(f"• {point}")
166
+
167
+ # Key Entities
168
+ if "key_entities" in summary and summary["key_entities"]:
169
+ output.append(f"\n{key_entities_header}:")
170
+ for entity in summary["key_entities"]:
171
+ if "name" in entity and "description" in entity:
172
+ output.append(f"• **{entity['name']}**: {entity['description']}")
173
+
174
+ # Conclusion
175
+ if "conclusion" in summary:
176
+ output.append(f"\n{conclusion_header}:")
177
+ output.append(summary["conclusion"])
178
 
179
  return "\n".join(output)
180
 
 
193
  output.append(f"{'='*40}\n")
194
 
195
  quiz_questions = results.get("quiz_questions", [])
 
 
 
196
  for i, q in enumerate(quiz_questions):
197
  output.append(f"\n{i+1}. {q['question']}")
198
  for j, option in enumerate(q['options']):
 
204
 
205
  def analyze_document(text, gemini_api_key, language, content_type="summary"):
206
  try:
 
 
 
207
  start_time = time.time()
208
  text_parts = split_text_by_tokens(text)
209
 
 
211
  output_tokens = 0
212
 
213
  if content_type == "summary":
214
+ all_results = {}
 
215
 
216
  for part in text_parts:
217
  actual_prompt = SUMMARY_PROMPT_TEMPLATE.format(text=part)
 
220
 
221
  analysis = generate_with_gemini(part, gemini_api_key, language, "summary")
222
 
223
+ if not all_results and "summary" in analysis:
224
+ all_results = analysis
225
+ elif "summary" in analysis:
226
+ if "key_points" in analysis["summary"] and "key_points" in all_results["summary"]:
227
+ all_results["summary"]["key_points"].extend(analysis["summary"]["key_points"])
228
+ if "key_entities" in analysis["summary"] and "key_entities" in all_results["summary"]:
229
+ all_results["summary"]["key_entities"].extend(analysis["summary"]["key_entities"])
 
 
 
 
 
 
 
230
 
231
  formatted_output = format_summary_for_display(all_results, language)
232
+
233
+ else:
234
  all_results = {"quiz_questions": []}
235
 
236
  for part in text_parts:
 
240
 
241
  analysis = generate_with_gemini(part, gemini_api_key, language, "quiz")
242
 
243
+ if "quiz_questions" in analysis:
244
  remaining_slots = 10 - len(all_results["quiz_questions"])
245
  if remaining_slots > 0:
246
  questions_to_add = analysis["quiz_questions"][:remaining_slots]
247
  all_results["quiz_questions"].extend(questions_to_add)
 
 
 
 
 
 
 
 
 
 
 
 
248
 
249
  formatted_output = format_quiz_for_display(all_results, language)
250