initial commit
This commit is contained in:
192
app.py
Normal file
192
app.py
Normal file
@@ -0,0 +1,192 @@
|
||||
from flask import Flask, render_template, request, jsonify, session
|
||||
import json
|
||||
import random
|
||||
import re
|
||||
import os
|
||||
from datetime import datetime
|
||||
from config import config
|
||||
|
||||
# Create Flask application
|
||||
app = Flask(__name__)
|
||||
|
||||
# Configure the application
|
||||
config_name = os.environ.get('FLASK_CONFIG', 'default')
|
||||
app.config.from_object(config[config_name])
|
||||
config[config_name].init_app(app)
|
||||
|
||||
# Function to parse markdown and extract questions
|
||||
def parse_markdown_questions():
|
||||
with open(app.config['MARKDOWN_FILE'], 'r', encoding='utf-8') as file:
|
||||
content = file.read()
|
||||
|
||||
questions = []
|
||||
|
||||
# Split content by questions using ### as separator
|
||||
question_blocks = re.split(r'\n### (\d+)\n', content)[1:] # Ignore first empty element
|
||||
|
||||
for i in range(0, len(question_blocks), 2):
|
||||
if i + 1 >= len(question_blocks):
|
||||
break
|
||||
|
||||
question_num = int(question_blocks[i])
|
||||
question_content = question_blocks[i + 1].strip()
|
||||
|
||||
# Check if there's an image at the beginning (now supports both local and remote URLs)
|
||||
has_image = ('
|
||||
image_url = ""
|
||||
if has_image:
|
||||
# Try local images first, then remote
|
||||
img_match = re.search(r'!\[\]\((/static/images/[^)]+)\)', question_content)
|
||||
if not img_match:
|
||||
img_match = re.search(r'!\[\]\((https://sierdgtt\.mtc\.gob\.pe/Content/img-data/[^)]+)\)', question_content)
|
||||
|
||||
if img_match:
|
||||
image_url = img_match.group(1)
|
||||
question_content = re.sub(r'!\[\]\([^)]+\)\n*', '', question_content).strip()
|
||||
|
||||
# Separate question from options
|
||||
lines = question_content.split('\n')
|
||||
question_lines = []
|
||||
option_lines = []
|
||||
in_options = False
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
if re.match(r'^✅?\s*[a-d]\)', line):
|
||||
in_options = True
|
||||
option_lines.append(line)
|
||||
elif not in_options:
|
||||
question_lines.append(line)
|
||||
|
||||
question_text = ' '.join(question_lines).strip()
|
||||
|
||||
# Extract options and correct answer
|
||||
options = []
|
||||
correct_option = ""
|
||||
|
||||
for line in option_lines:
|
||||
original_line = line.strip()
|
||||
|
||||
# Check if this line has the ✅
|
||||
if '✅' in original_line:
|
||||
# Extract the letter of the correct option
|
||||
match = re.search(r'✅\s*([a-d])\)', original_line)
|
||||
if match:
|
||||
correct_option = match.group(1)
|
||||
|
||||
# Clean the line by removing ✅ completely and any extra spaces
|
||||
clean_line = re.sub(r'✅\s*', '', original_line)
|
||||
clean_line = re.sub(r'✅', '', clean_line) # In case there's ✅ without spaces
|
||||
clean_line = clean_line.strip()
|
||||
options.append(clean_line)
|
||||
|
||||
if len(options) >= 2 and correct_option and question_text: # Validate we have complete data
|
||||
questions.append({
|
||||
'id': question_num,
|
||||
'question': question_text,
|
||||
'options': options,
|
||||
'correct': correct_option,
|
||||
'image': image_url,
|
||||
'has_image': has_image
|
||||
})
|
||||
|
||||
return sorted(questions, key=lambda x: x['id'])
|
||||
|
||||
# Load questions when starting the application
|
||||
QUESTIONS = parse_markdown_questions()
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('index.html', total_questions=len(QUESTIONS))
|
||||
|
||||
@app.route('/study')
|
||||
def study():
|
||||
return render_template('study.html')
|
||||
|
||||
@app.route('/practice')
|
||||
def practice():
|
||||
return render_template('practice.html')
|
||||
|
||||
@app.route('/exam')
|
||||
def exam():
|
||||
return render_template('exam.html')
|
||||
|
||||
@app.route('/api/questions')
|
||||
def get_questions():
|
||||
mode = request.args.get('mode', 'all')
|
||||
count = request.args.get('count', type=int)
|
||||
|
||||
if mode == 'random':
|
||||
questions = random.sample(QUESTIONS, min(count or 20, len(QUESTIONS)))
|
||||
elif mode == 'range':
|
||||
start = request.args.get('start', 1, type=int)
|
||||
end = request.args.get('end', len(QUESTIONS), type=int)
|
||||
questions = [q for q in QUESTIONS if start <= q['id'] <= end]
|
||||
else:
|
||||
questions = QUESTIONS
|
||||
|
||||
return jsonify(questions)
|
||||
|
||||
@app.route('/api/question/<int:question_id>')
|
||||
def get_question(question_id):
|
||||
question = next((q for q in QUESTIONS if q['id'] == question_id), None)
|
||||
if question:
|
||||
return jsonify(question)
|
||||
return jsonify({'error': 'Pregunta no encontrada'}), 404
|
||||
|
||||
@app.route('/api/check_answer', methods=['POST'])
|
||||
def check_answer():
|
||||
data = request.json
|
||||
question_id = data.get('question_id')
|
||||
user_answer = data.get('answer')
|
||||
|
||||
question = next((q for q in QUESTIONS if q['id'] == question_id), None)
|
||||
if not question:
|
||||
return jsonify({'error': 'Pregunta no encontrada'}), 404
|
||||
|
||||
is_correct = user_answer == question['correct']
|
||||
|
||||
return jsonify({
|
||||
'correct': is_correct,
|
||||
'correct_answer': question['correct'],
|
||||
'explanation': f"La respuesta correcta es: {question['correct']}"
|
||||
})
|
||||
|
||||
@app.route('/api/stats')
|
||||
def get_stats():
|
||||
# Statistics are now handled completely in client localStorage
|
||||
# This endpoint returns default stats for compatibility
|
||||
return jsonify({
|
||||
'total_answered': 0,
|
||||
'correct_answers': 0,
|
||||
'incorrect_answers': 0,
|
||||
'accuracy': 0,
|
||||
'message': 'Stats handled by localStorage'
|
||||
})
|
||||
|
||||
@app.route('/api/update_stats', methods=['POST'])
|
||||
def update_stats():
|
||||
# Statistics are now handled completely in client localStorage
|
||||
# This endpoint only confirms that the update was received
|
||||
data = request.json
|
||||
is_correct = data.get('correct', False)
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': 'Stats updated in localStorage',
|
||||
'received_correct': is_correct
|
||||
})
|
||||
|
||||
@app.route('/api/reset_stats', methods=['POST'])
|
||||
def reset_stats():
|
||||
"""Confirm that statistics were reset in localStorage"""
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': 'Estadísticas restablecidas correctamente en localStorage'
|
||||
})
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True, host='0.0.0.0', port=5000)
|
||||
Reference in New Issue
Block a user