Fausto Busuito
commited on
Commit
•
9a82c5c
1
Parent(s):
86f7e43
Application changes
Browse files- .gitattributes +0 -35
- Dockerfile +5 -24
- app.py +53 -0
- app/__init__.py +0 -5
- app/routes.py +0 -53
- app/static/css/style.css +0 -34
- app/static/js/script.js +0 -69
- requirements.txt +1 -2
- run.py +0 -6
- static/script.js +2 -0
- static/styles.css +16 -0
- {app/templates → templates}/index.html +6 -4
- {app/templates → templates}/quiz.html +10 -10
- {app/templates → templates}/results.html +12 -2
.gitattributes
DELETED
@@ -1,35 +0,0 @@
|
|
1 |
-
*.7z filter=lfs diff=lfs merge=lfs -text
|
2 |
-
*.arrow filter=lfs diff=lfs merge=lfs -text
|
3 |
-
*.bin filter=lfs diff=lfs merge=lfs -text
|
4 |
-
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
5 |
-
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
6 |
-
*.ftz filter=lfs diff=lfs merge=lfs -text
|
7 |
-
*.gz filter=lfs diff=lfs merge=lfs -text
|
8 |
-
*.h5 filter=lfs diff=lfs merge=lfs -text
|
9 |
-
*.joblib filter=lfs diff=lfs merge=lfs -text
|
10 |
-
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
11 |
-
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
12 |
-
*.model filter=lfs diff=lfs merge=lfs -text
|
13 |
-
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
14 |
-
*.npy filter=lfs diff=lfs merge=lfs -text
|
15 |
-
*.npz filter=lfs diff=lfs merge=lfs -text
|
16 |
-
*.onnx filter=lfs diff=lfs merge=lfs -text
|
17 |
-
*.ot filter=lfs diff=lfs merge=lfs -text
|
18 |
-
*.parquet filter=lfs diff=lfs merge=lfs -text
|
19 |
-
*.pb filter=lfs diff=lfs merge=lfs -text
|
20 |
-
*.pickle filter=lfs diff=lfs merge=lfs -text
|
21 |
-
*.pkl filter=lfs diff=lfs merge=lfs -text
|
22 |
-
*.pt filter=lfs diff=lfs merge=lfs -text
|
23 |
-
*.pth filter=lfs diff=lfs merge=lfs -text
|
24 |
-
*.rar filter=lfs diff=lfs merge=lfs -text
|
25 |
-
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
26 |
-
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
27 |
-
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
28 |
-
*.tar filter=lfs diff=lfs merge=lfs -text
|
29 |
-
*.tflite filter=lfs diff=lfs merge=lfs -text
|
30 |
-
*.tgz filter=lfs diff=lfs merge=lfs -text
|
31 |
-
*.wasm filter=lfs diff=lfs merge=lfs -text
|
32 |
-
*.xz filter=lfs diff=lfs merge=lfs -text
|
33 |
-
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
-
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
-
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Dockerfile
CHANGED
@@ -1,29 +1,10 @@
|
|
1 |
-
|
2 |
-
FROM python:3.9
|
3 |
|
4 |
-
# Create a new user to run the application
|
5 |
-
RUN useradd -m -u 1000 user
|
6 |
-
|
7 |
-
# Set the user for subsequent commands
|
8 |
-
USER user
|
9 |
-
|
10 |
-
# Update the PATH environment variable
|
11 |
-
ENV PATH="/home/user/.local/bin:$PATH"
|
12 |
-
|
13 |
-
# Set the working directory
|
14 |
WORKDIR /app
|
15 |
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
# Install the dependencies listed in requirements.txt
|
20 |
-
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
21 |
-
|
22 |
-
# Copy the entire project into the container
|
23 |
-
COPY --chown=user . /app
|
24 |
|
25 |
-
|
26 |
-
EXPOSE 5000
|
27 |
|
28 |
-
|
29 |
-
CMD ["python", "run.py"]
|
|
|
1 |
+
FROM python:3.9-slim
|
|
|
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
WORKDIR /app
|
4 |
|
5 |
+
COPY requirements.txt requirements.txt
|
6 |
+
RUN pip install -r requirements.txt
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
|
8 |
+
COPY . .
|
|
|
9 |
|
10 |
+
CMD ["python", "app.py"]
|
|
app.py
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from flask import Flask, render_template, request, redirect, url_for, session
|
2 |
+
import json
|
3 |
+
import random
|
4 |
+
import os
|
5 |
+
|
6 |
+
app = Flask(__name__)
|
7 |
+
app.secret_key = 'supersecretkey'
|
8 |
+
|
9 |
+
@app.route('/')
|
10 |
+
def index():
|
11 |
+
return render_template('index.html')
|
12 |
+
|
13 |
+
@app.route('/start', methods=['POST'])
|
14 |
+
def start():
|
15 |
+
session['name'] = request.form['name']
|
16 |
+
session['questions'] = load_questions(request.files['questions'])
|
17 |
+
session['current_question'] = 0
|
18 |
+
session['answers'] = []
|
19 |
+
return redirect(url_for('quiz'))
|
20 |
+
|
21 |
+
@app.route('/quiz', methods=['GET', 'POST'])
|
22 |
+
def quiz():
|
23 |
+
if request.method == 'POST':
|
24 |
+
session['answers'].append(request.form.get('answer'))
|
25 |
+
session['current_question'] += 1
|
26 |
+
if session['current_question'] >= len(session['questions']):
|
27 |
+
return redirect(url_for('results'))
|
28 |
+
return redirect(url_for('quiz'))
|
29 |
+
|
30 |
+
question = session['questions'][session['current_question']]
|
31 |
+
return render_template('quiz.html', question=question)
|
32 |
+
|
33 |
+
@app.route('/results')
|
34 |
+
def results():
|
35 |
+
questions = session['questions']
|
36 |
+
answers = session['answers']
|
37 |
+
score = calculate_score(questions, answers)
|
38 |
+
return render_template('results.html', score=score, questions=questions, answers=answers)
|
39 |
+
|
40 |
+
def load_questions(file):
|
41 |
+
questions = json.load(file)
|
42 |
+
random.shuffle(questions)
|
43 |
+
return questions
|
44 |
+
|
45 |
+
def calculate_score(questions, answers):
|
46 |
+
correct_count = 0
|
47 |
+
for i, question in enumerate(questions):
|
48 |
+
if answers[i] in question['correct']:
|
49 |
+
correct_count += 1
|
50 |
+
return (correct_count / len(questions)) * 100
|
51 |
+
|
52 |
+
if __name__ == '__main__':
|
53 |
+
app.run(debug=True)
|
app/__init__.py
DELETED
@@ -1,5 +0,0 @@
|
|
1 |
-
from flask import Flask
|
2 |
-
|
3 |
-
def create_app():
|
4 |
-
app = Flask(__name__)
|
5 |
-
return app
|
|
|
|
|
|
|
|
|
|
|
|
app/routes.py
DELETED
@@ -1,53 +0,0 @@
|
|
1 |
-
from flask import render_template, request, redirect, url_for, jsonify
|
2 |
-
from app import create_app
|
3 |
-
import json
|
4 |
-
import random
|
5 |
-
|
6 |
-
app = create_app()
|
7 |
-
|
8 |
-
questions = []
|
9 |
-
user_answers = []
|
10 |
-
|
11 |
-
@app.route('/')
|
12 |
-
def index():
|
13 |
-
return render_template('index.html')
|
14 |
-
|
15 |
-
@app.route('/start', methods=['POST'])
|
16 |
-
def start():
|
17 |
-
global questions
|
18 |
-
file = request.files['file']
|
19 |
-
questions = json.load(file)
|
20 |
-
random.shuffle(questions)
|
21 |
-
return redirect(url_for('quiz'))
|
22 |
-
|
23 |
-
@app.route('/quiz')
|
24 |
-
def quiz():
|
25 |
-
return render_template('quiz.html')
|
26 |
-
|
27 |
-
@app.route('/questions')
|
28 |
-
def get_questions():
|
29 |
-
return jsonify(questions)
|
30 |
-
|
31 |
-
@app.route('/submit', methods=['POST'])
|
32 |
-
def submit():
|
33 |
-
global user_answers
|
34 |
-
user_answers = request.json
|
35 |
-
return jsonify({'status': 'success'})
|
36 |
-
|
37 |
-
def results():
|
38 |
-
correct_answers = 0
|
39 |
-
total_questions = len(questions)
|
40 |
-
|
41 |
-
for user_answer in user_answers:
|
42 |
-
question_index = user_answer['questionIndex']
|
43 |
-
selected_options = user_answer['answers']
|
44 |
-
correct_options = questions[question_index]['correct']
|
45 |
-
|
46 |
-
if set(selected_options) == set(correct_options):
|
47 |
-
correct_answers += 1
|
48 |
-
|
49 |
-
score = (correct_answers / total_questions) * 100
|
50 |
-
return render_template('results.html', score=score, total_questions=total_questions, correct_answers=correct_answers)
|
51 |
-
|
52 |
-
if __name__ == '__main__':
|
53 |
-
app.run(debug=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/static/css/style.css
DELETED
@@ -1,34 +0,0 @@
|
|
1 |
-
body {
|
2 |
-
font-family: Arial, sans-serif;
|
3 |
-
margin: 0;
|
4 |
-
padding: 0;
|
5 |
-
display: flex;
|
6 |
-
justify-content: center;
|
7 |
-
align-items: center;
|
8 |
-
height: 100vh;
|
9 |
-
background-color: #f0f0f0;
|
10 |
-
}
|
11 |
-
|
12 |
-
h1 {
|
13 |
-
text-align: center;
|
14 |
-
}
|
15 |
-
|
16 |
-
form {
|
17 |
-
display: flex;
|
18 |
-
flex-direction: column;
|
19 |
-
align-items: center;
|
20 |
-
}
|
21 |
-
|
22 |
-
#quiz-container {
|
23 |
-
text-align: center;
|
24 |
-
}
|
25 |
-
|
26 |
-
#options {
|
27 |
-
margin-top: 20px;
|
28 |
-
}
|
29 |
-
|
30 |
-
button {
|
31 |
-
margin: 10px;
|
32 |
-
padding: 10px 20px;
|
33 |
-
font-size: 16px;
|
34 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/static/js/script.js
DELETED
@@ -1,69 +0,0 @@
|
|
1 |
-
document.addEventListener('DOMContentLoaded', () => {
|
2 |
-
const questionElement = document.getElementById('question');
|
3 |
-
const optionsElement = document.getElementById('options');
|
4 |
-
const prevButton = document.getElementById('prev');
|
5 |
-
const nextButton = document.getElementById('next');
|
6 |
-
const submitButton = document.getElementById('submit');
|
7 |
-
|
8 |
-
let questions = [];
|
9 |
-
let currentQuestionIndex = 0;
|
10 |
-
let userAnswers = [];
|
11 |
-
|
12 |
-
function loadQuestions(data) {
|
13 |
-
questions = data;
|
14 |
-
showQuestion(currentQuestionIndex);
|
15 |
-
}
|
16 |
-
|
17 |
-
function showQuestion(index) {
|
18 |
-
const question = questions[index];
|
19 |
-
questionElement.textContent = question.question;
|
20 |
-
optionsElement.innerHTML = '';
|
21 |
-
question.options.forEach((option, i) => {
|
22 |
-
const optionElement = document.createElement('div');
|
23 |
-
optionElement.innerHTML = `<input type="checkbox" id="option${i}" name="option${i}" value="${String.fromCharCode(65 + i)}">
|
24 |
-
<label for="option${i}">${option}</label>`;
|
25 |
-
optionsElement.appendChild(optionElement);
|
26 |
-
});
|
27 |
-
}
|
28 |
-
|
29 |
-
prevButton.addEventListener('click', () => {
|
30 |
-
if (currentQuestionIndex > 0) {
|
31 |
-
currentQuestionIndex--;
|
32 |
-
showQuestion(currentQuestionIndex);
|
33 |
-
}
|
34 |
-
});
|
35 |
-
|
36 |
-
nextButton.addEventListener('click', () => {
|
37 |
-
if (currentQuestionIndex < questions.length - 1) {
|
38 |
-
currentQuestionIndex++;
|
39 |
-
showQuestion(currentQuestionIndex);
|
40 |
-
}
|
41 |
-
});
|
42 |
-
|
43 |
-
submitButton.addEventListener('click', () => {
|
44 |
-
const selectedOptions = Array.from(document.querySelectorAll('input[type="checkbox"]:checked')).map(input => input.value);
|
45 |
-
userAnswers.push({ questionIndex: currentQuestionIndex, answers: selectedOptions });
|
46 |
-
if (currentQuestionIndex < questions.length - 1) {
|
47 |
-
currentQuestionIndex++;
|
48 |
-
showQuestion(currentQuestionIndex);
|
49 |
-
} else {
|
50 |
-
// Submit the quiz
|
51 |
-
fetch('/submit', {
|
52 |
-
method: 'POST',
|
53 |
-
headers: {
|
54 |
-
'Content-Type': 'application/json'
|
55 |
-
},
|
56 |
-
body: JSON.stringify(userAnswers)
|
57 |
-
})
|
58 |
-
.then(response => response.json())
|
59 |
-
.then(data => {
|
60 |
-
window.location.href = '/results';
|
61 |
-
});
|
62 |
-
}
|
63 |
-
});
|
64 |
-
|
65 |
-
// Fetch questions from the server
|
66 |
-
fetch('/questions')
|
67 |
-
.then(response => response.json())
|
68 |
-
.then(data => loadQuestions(data));
|
69 |
-
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
CHANGED
@@ -1,2 +1 @@
|
|
1 |
-
Flask==2.0.1
|
2 |
-
Werkzeug==2.0.3
|
|
|
1 |
+
Flask==2.0.1
|
|
run.py
DELETED
@@ -1,6 +0,0 @@
|
|
1 |
-
from app import create_app
|
2 |
-
|
3 |
-
app = create_app()
|
4 |
-
|
5 |
-
if __name__ == '__main__':
|
6 |
-
app.run(host='0.0.0.0', port=5000)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static/script.js
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
javascript
|
2 |
+
// This file can be used for any client-side JavaScript if needed.
|
static/styles.css
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
body {
|
2 |
+
font-family: Arial, sans-serif;
|
3 |
+
margin: 20px;
|
4 |
+
}
|
5 |
+
|
6 |
+
h1 {
|
7 |
+
color: #333;
|
8 |
+
}
|
9 |
+
|
10 |
+
form {
|
11 |
+
margin-top: 20px;
|
12 |
+
}
|
13 |
+
|
14 |
+
button {
|
15 |
+
margin-top: 10px;
|
16 |
+
}
|
{app/templates → templates}/index.html
RENAMED
@@ -4,16 +4,18 @@
|
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
<title>Quiz App</title>
|
7 |
-
<link rel="stylesheet" href="{{ url_for('static', filename='
|
8 |
</head>
|
9 |
<body>
|
10 |
<h1>Welcome to the Quiz App</h1>
|
11 |
<form action="/start" method="post" enctype="multipart/form-data">
|
12 |
<label for="name">Enter your name:</label>
|
13 |
<input type="text" id="name" name="name" required>
|
14 |
-
<
|
15 |
-
<
|
|
|
|
|
16 |
<button type="submit">Start Quiz</button>
|
17 |
</form>
|
18 |
</body>
|
19 |
-
</html>
|
|
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
<title>Quiz App</title>
|
7 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
8 |
</head>
|
9 |
<body>
|
10 |
<h1>Welcome to the Quiz App</h1>
|
11 |
<form action="/start" method="post" enctype="multipart/form-data">
|
12 |
<label for="name">Enter your name:</label>
|
13 |
<input type="text" id="name" name="name" required>
|
14 |
+
<br>
|
15 |
+
<label for="questions">Upload questions file:</label>
|
16 |
+
<input type="file" id="questions" name="questions" required>
|
17 |
+
<br>
|
18 |
<button type="submit">Start Quiz</button>
|
19 |
</form>
|
20 |
</body>
|
21 |
+
</html>
|
{app/templates → templates}/quiz.html
RENAMED
@@ -4,17 +4,17 @@
|
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
<title>Quiz</title>
|
7 |
-
<link rel="stylesheet" href="{{ url_for('static', filename='
|
8 |
</head>
|
9 |
<body>
|
10 |
-
<h1>
|
11 |
-
<
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
</body>
|
20 |
</html>
|
|
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
<title>Quiz</title>
|
7 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
8 |
</head>
|
9 |
<body>
|
10 |
+
<h1>Question {{ session['current_question'] + 1 }}</h1>
|
11 |
+
<p>{{ question['question'] }}</p>
|
12 |
+
<form action="/quiz" method="post">
|
13 |
+
{% for option in question['options'] %}
|
14 |
+
<input type="radio" id="{{ loop.index }}" name="answer" value="{{ loop.index }}" required>
|
15 |
+
<label for="{{ loop.index }}">{{ option }}</label><br>
|
16 |
+
{% endfor %}
|
17 |
+
<button type="submit">Next</button>
|
18 |
+
</form>
|
19 |
</body>
|
20 |
</html>
|
{app/templates → templates}/results.html
RENAMED
@@ -4,10 +4,20 @@
|
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
<title>Results</title>
|
7 |
-
<link rel="stylesheet" href="{{ url_for('static', filename='
|
8 |
</head>
|
9 |
<body>
|
10 |
<h1>Results</h1>
|
11 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
</body>
|
13 |
</html>
|
|
|
4 |
<meta charset="UTF-8">
|
5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
<title>Results</title>
|
7 |
+
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
8 |
</head>
|
9 |
<body>
|
10 |
<h1>Results</h1>
|
11 |
+
<p>Your score: {{ score }}%</p>
|
12 |
+
<h2>Your Answers</h2>
|
13 |
+
<ul>
|
14 |
+
{% for i, question in enumerate(questions) %}
|
15 |
+
<li>
|
16 |
+
<p>{{ question['question'] }}</p>
|
17 |
+
<p>Your answer: {{ answers[i] }}</p>
|
18 |
+
<p>Correct answer: {{ question['correct'] }}</p>
|
19 |
+
</li>
|
20 |
+
{% endfor %}
|
21 |
+
</ul>
|
22 |
</body>
|
23 |
</html>
|