Spaces:
Running
Running
t commited on
Commit ·
daae428
1
Parent(s): ef01286
fix: resolve NameError in processing.py and restore missing question routes
Browse files- Fixed NameError 'p_info' in process_crop_v2 by using correct variable name.
- Restored '/get_topic_suggestions' and '/classified/update_single' routes in questions.py that were lost during modularization.
- routes/processing.py +1 -1
- routes/questions.py +67 -0
routes/processing.py
CHANGED
|
@@ -100,7 +100,7 @@ def process_crop_v2():
|
|
| 100 |
max_idx = conn.execute('SELECT MAX(image_index) FROM images WHERE session_id = ?', (session_id,)).fetchone()[0]
|
| 101 |
next_idx = (max_idx if max_idx is not None else -1) + 1
|
| 102 |
for i, p_box in enumerate(processed_boxes):
|
| 103 |
-
conn.execute('INSERT INTO images (session_id, image_index, filename, original_name, processed_filename, image_type, box_id) VALUES (?, ?, ?, ?, ?, ?, ?)', (session_id, next_idx + i,
|
| 104 |
img_id = conn.execute('SELECT last_insert_rowid()').fetchone()[0]
|
| 105 |
conn.execute("INSERT INTO questions (session_id, image_id, question_number, status, marked_solution, actual_solution) VALUES (?, ?, ?, ?, ?, ?)", (session_id, img_id, p_box.get('question_number'), p_box.get('status', 'unattempted'), p_box.get('marked_solution'), p_box.get('actual_solution')))
|
| 106 |
conn.commit(); os.remove(temp_path); return jsonify({'success': True, 'processed_count': len(processed_boxes)})
|
|
|
|
| 100 |
max_idx = conn.execute('SELECT MAX(image_index) FROM images WHERE session_id = ?', (session_id,)).fetchone()[0]
|
| 101 |
next_idx = (max_idx if max_idx is not None else -1) + 1
|
| 102 |
for i, p_box in enumerate(processed_boxes):
|
| 103 |
+
conn.execute('INSERT INTO images (session_id, image_index, filename, original_name, processed_filename, image_type, box_id) VALUES (?, ?, ?, ?, ?, ?, ?)', (session_id, next_idx + i, p_box['original_filename'], f"Page {page_index + 1} - Q{i + 1}", p_box['processed_filename'], 'cropped', p_box['box_id']))
|
| 104 |
img_id = conn.execute('SELECT last_insert_rowid()').fetchone()[0]
|
| 105 |
conn.execute("INSERT INTO questions (session_id, image_id, question_number, status, marked_solution, actual_solution) VALUES (?, ?, ?, ?, ?, ?)", (session_id, img_id, p_box.get('question_number'), p_box.get('status', 'unattempted'), p_box.get('marked_solution'), p_box.get('actual_solution')))
|
| 106 |
conn.commit(); os.remove(temp_path); return jsonify({'success': True, 'processed_count': len(processed_boxes)})
|
routes/questions.py
CHANGED
|
@@ -3,10 +3,77 @@ from flask import current_app, request, jsonify, render_template, flash, redirec
|
|
| 3 |
from .common import main_bp, get_db_connection, login_required, current_user
|
| 4 |
from processing import resize_image_if_needed, call_nim_ocr_api, extract_question_number_from_ocr_result
|
| 5 |
from strings import ROUTE_SAVE_QUESTIONS, ROUTE_EXTRACT_QUESTION_NUMBER, ROUTE_EXTRACT_ALL_QUESTION_NUMBERS, METHOD_POST
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
NVIDIA_API_KEY = os.getenv("NVIDIA_API_KEY")
|
| 8 |
NVIDIA_NIM_AVAILABLE = bool(NVIDIA_API_KEY)
|
| 9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
@main_bp.route('/question_entry_v2/<session_id>')
|
| 11 |
@login_required
|
| 12 |
def question_entry_v2(session_id):
|
|
|
|
| 3 |
from .common import main_bp, get_db_connection, login_required, current_user
|
| 4 |
from processing import resize_image_if_needed, call_nim_ocr_api, extract_question_number_from_ocr_result
|
| 5 |
from strings import ROUTE_SAVE_QUESTIONS, ROUTE_EXTRACT_QUESTION_NUMBER, ROUTE_EXTRACT_ALL_QUESTION_NUMBERS, METHOD_POST
|
| 6 |
+
import requests
|
| 7 |
+
import json
|
| 8 |
+
from nvidia_prompts import BIOLOGY_PROMPT_TEMPLATE, CHEMISTRY_PROMPT_TEMPLATE, PHYSICS_PROMPT_TEMPLATE, MATHEMATICS_PROMPT_TEMPLATE
|
| 9 |
|
| 10 |
NVIDIA_API_KEY = os.getenv("NVIDIA_API_KEY")
|
| 11 |
NVIDIA_NIM_AVAILABLE = bool(NVIDIA_API_KEY)
|
| 12 |
|
| 13 |
+
def get_nvidia_prompt(subject, input_questions):
|
| 14 |
+
if subject.lower() == 'biology': return BIOLOGY_PROMPT_TEMPLATE.format(input_questions=input_questions)
|
| 15 |
+
if subject.lower() == 'chemistry': return CHEMISTRY_PROMPT_TEMPLATE.format(input_questions=input_questions)
|
| 16 |
+
if subject.lower() == 'physics': return PHYSICS_PROMPT_TEMPLATE.format(input_questions=input_questions)
|
| 17 |
+
if subject.lower() == 'mathematics': return MATHEMATICS_PROMPT_TEMPLATE.format(input_questions=input_questions)
|
| 18 |
+
return None
|
| 19 |
+
|
| 20 |
+
@main_bp.route('/get_topic_suggestions', methods=['POST'])
|
| 21 |
+
@login_required
|
| 22 |
+
def get_topic_suggestions():
|
| 23 |
+
data = request.json
|
| 24 |
+
question_text, image_id, subject = data.get('question_text'), data.get('image_id'), data.get('subject')
|
| 25 |
+
if not subject: return jsonify({'error': 'Subject is required'}), 400
|
| 26 |
+
if not question_text and image_id:
|
| 27 |
+
try:
|
| 28 |
+
conn = get_db_connection()
|
| 29 |
+
row = conn.execute('SELECT question_text, processed_filename, i.session_id FROM questions q JOIN images i ON q.image_id = i.id WHERE i.id = ?', (image_id,)).fetchone()
|
| 30 |
+
if row:
|
| 31 |
+
if row['question_text']: question_text = row['question_text']
|
| 32 |
+
else:
|
| 33 |
+
image_path = os.path.join(current_app.config['PROCESSED_FOLDER'], row['processed_filename'])
|
| 34 |
+
if os.path.exists(image_path):
|
| 35 |
+
question_text = " ".join(item['text_prediction']['text'] for item in call_nim_ocr_api(resize_image_if_needed(image_path))['data'][0]['text_detections'])
|
| 36 |
+
conn.execute('UPDATE questions SET question_text = ? WHERE image_id = ?', (question_text, image_id))
|
| 37 |
+
conn.commit()
|
| 38 |
+
conn.close()
|
| 39 |
+
except Exception as e: return jsonify({'error': f"OCR failed: {str(e)}"}), 500
|
| 40 |
+
if not question_text: return jsonify({'error': 'Could not obtain question text.'}), 400
|
| 41 |
+
prompt_content = get_nvidia_prompt(subject, f"1. {question_text}")
|
| 42 |
+
if not prompt_content: return jsonify({'error': f'Unsupported subject: {subject}'}), 400
|
| 43 |
+
if not NVIDIA_API_KEY: return jsonify({'error': 'NVIDIA_API_KEY not set'}), 500
|
| 44 |
+
try:
|
| 45 |
+
res = requests.post('https://integrate.api.nvidia.com/v1/chat/completions', headers={'Authorization': f'Bearer {NVIDIA_API_KEY}', 'Accept': 'application/json', 'Content-Type': 'application/json'}, json={"model": "nvidia/nemotron-3-nano-30b-a3b", "messages": [{"content": prompt_content, "role": "user"}], "temperature": 0.2, "top_p": 1, "max_tokens": 1024, "stream": False}, timeout=30)
|
| 46 |
+
res.raise_for_status()
|
| 47 |
+
content = res.json()['choices'][0]['message']['content']
|
| 48 |
+
if "```json" in content: content = content.split("```json")[1].split("```")[0].strip()
|
| 49 |
+
elif "```" in content: content = content.split("```")[1].split("```")[0].strip()
|
| 50 |
+
data = json.loads(content)
|
| 51 |
+
suggestions = []
|
| 52 |
+
if data.get('data'):
|
| 53 |
+
suggestions.append(data['data'][0].get('chapter_title', 'Unclassified'))
|
| 54 |
+
if 'other_possible_chapters' in data['data'][0]:
|
| 55 |
+
others = data['data'][0]['other_possible_chapters']
|
| 56 |
+
if isinstance(others, list): suggestions.extend(others)
|
| 57 |
+
return jsonify({'success': True, 'suggestions': suggestions, 'full_response': data})
|
| 58 |
+
except Exception as e: return jsonify({'error': str(e)}), 500
|
| 59 |
+
|
| 60 |
+
@main_bp.route('/classified/update_single', methods=['POST'])
|
| 61 |
+
@login_required
|
| 62 |
+
def update_question_classification_single():
|
| 63 |
+
data = request.json
|
| 64 |
+
image_id, subject, chapter = data.get('image_id'), data.get('subject'), data.get('chapter')
|
| 65 |
+
if not image_id: return jsonify({'error': 'Image ID is required'}), 400
|
| 66 |
+
try:
|
| 67 |
+
conn = get_db_connection()
|
| 68 |
+
owner = conn.execute("SELECT s.user_id FROM images i JOIN sessions s ON i.session_id = s.id WHERE i.id = ?", (image_id,)).fetchone()
|
| 69 |
+
if not owner or owner['user_id'] != current_user.id:
|
| 70 |
+
conn.close(); return jsonify({'error': 'Unauthorized'}), 403
|
| 71 |
+
conn.execute('UPDATE questions SET subject = ?, chapter = ? WHERE image_id = ?', (subject, chapter, image_id))
|
| 72 |
+
conn.commit(); conn.close()
|
| 73 |
+
return jsonify({'success': True})
|
| 74 |
+
except Exception as e: return jsonify({'error': str(e)}), 500
|
| 75 |
+
|
| 76 |
+
|
| 77 |
@main_bp.route('/question_entry_v2/<session_id>')
|
| 78 |
@login_required
|
| 79 |
def question_entry_v2(session_id):
|