Commit
·
cdfb731
0
Parent(s):
First version
Browse files- .gitignore +2 -0
- README.md +142 -0
- app.py +70 -0
- requirements.txt +2 -0
- static/script.js +37 -0
- templates/client.html +22 -0
- templates/host.html +19 -0
.gitignore
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
/.venv
|
README.md
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Here's a professional `README.md` for the quiz application project:
|
| 2 |
+
# Real-Time Quiz Application
|
| 3 |
+
|
| 4 |
+
A Python-based real-time quiz application designed to mimic the functionality of **Mentimeter**, allowing a host to control the quiz and participants (clients) to join, answer questions, and receive immediate feedback. The application is built using **Flask** and **Socket.IO** for seamless web-based interaction, and it offers a clean, responsive front-end using **HTML**, **CSS**, and **Bootstrap**.
|
| 5 |
+
|
| 6 |
+
## Features
|
| 7 |
+
|
| 8 |
+
- **Real-Time Communication**: Uses **Socket.IO** for instant updates between the host and clients.
|
| 9 |
+
- **Participant Management**: Tracks connected clients, showing their usernames and responses in real time.
|
| 10 |
+
- **Interactive Host Control**: The host can change questions, see live results, and control the flow of the quiz.
|
| 11 |
+
- **Simple and Responsive Front-End**: Clean design using Bootstrap for a pleasant user experience across devices.
|
| 12 |
+
- **Scalable Design**: Easily expandable to support more questions, features, and visualizations.
|
| 13 |
+
|
| 14 |
+
## Project Structure
|
| 15 |
+
|
| 16 |
+
```bash
|
| 17 |
+
Real-Time-Quiz-Application/
|
| 18 |
+
│
|
| 19 |
+
├── app.py # Main Flask application
|
| 20 |
+
├── templates/
|
| 21 |
+
│ ├── client.html # Client interface
|
| 22 |
+
│ └── host.html # Host interface
|
| 23 |
+
├── static/
|
| 24 |
+
│ ├── style.css # Optional custom styles (Bootstrap already integrated)
|
| 25 |
+
│ └── script.js # JavaScript for real-time interactions
|
| 26 |
+
├── requirements.txt # Python dependencies
|
| 27 |
+
└── README.md # Project documentation
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
## Requirements
|
| 31 |
+
|
| 32 |
+
Ensure you have Python 3.6+ installed. The required dependencies are listed in `requirements.txt`:
|
| 33 |
+
|
| 34 |
+
- **Flask**: The web framework used for developing the application.
|
| 35 |
+
- **Flask-SocketIO**: Enables real-time WebSocket communication between the server and clients.
|
| 36 |
+
|
| 37 |
+
Install dependencies with:
|
| 38 |
+
|
| 39 |
+
```bash
|
| 40 |
+
pip install -r requirements.txt
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
## How to Run the Application
|
| 44 |
+
|
| 45 |
+
1. **Clone the repository**:
|
| 46 |
+
```bash
|
| 47 |
+
git clone https://github.com/ruslanmv/Real-Time-Quiz-Application.git
|
| 48 |
+
cd Real-Time-Quiz-Application
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
2. **Install dependencies**:
|
| 52 |
+
```bash
|
| 53 |
+
pip install -r requirements.txt
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
3. **Run the application**:
|
| 57 |
+
```bash
|
| 58 |
+
python app.py
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
4. **Access the application**:
|
| 62 |
+
- **Host interface**: [http://127.0.0.1:5000/host](http://127.0.0.1:5000/host)
|
| 63 |
+
- **Client interface**: [http://127.0.0.1:5000/client](http://127.0.0.1:5000/client)
|
| 64 |
+
|
| 65 |
+
## Application Overview
|
| 66 |
+
|
| 67 |
+
### Host Interface
|
| 68 |
+
|
| 69 |
+
The host controls the flow of the quiz:
|
| 70 |
+
- **View Questions**: See the current question and available options.
|
| 71 |
+
- **Next Question**: Advance to the next question.
|
| 72 |
+
- **Live Results**: View participant responses and statistics in real time.
|
| 73 |
+
|
| 74 |
+
### Client Interface
|
| 75 |
+
|
| 76 |
+
Participants join the quiz and interact with the questions:
|
| 77 |
+
- **Join the Quiz**: Enter a temporary username to participate.
|
| 78 |
+
- **Receive Questions**: Answer questions as they appear, with four possible options.
|
| 79 |
+
- **Live Feedback**: See the result of each question based on group responses.
|
| 80 |
+
|
| 81 |
+
## Demonstration
|
| 82 |
+
|
| 83 |
+
For demonstration purposes, this version includes only **two questions**. The questions are stored in `app.py` as follows:
|
| 84 |
+
|
| 85 |
+
```python
|
| 86 |
+
questions = [
|
| 87 |
+
{"question": "What is the capital of France?", "options": ["Paris", "London", "Berlin", "Rome"]},
|
| 88 |
+
{"question": "What is the largest planet?", "options": ["Earth", "Mars", "Jupiter", "Saturn"]}
|
| 89 |
+
]
|
| 90 |
+
```
|
| 91 |
+
|
| 92 |
+
### Adding More Questions
|
| 93 |
+
|
| 94 |
+
To add more questions, simply update the `questions` list in `app.py`. Ensure each question follows the structure:
|
| 95 |
+
```python
|
| 96 |
+
{"question": "Your question here?", "options": ["Option1", "Option2", "Option3", "Option4"]}
|
| 97 |
+
```
|
| 98 |
+
|
| 99 |
+
## Scaling the Application
|
| 100 |
+
|
| 101 |
+
This application is built to be easily scalable:
|
| 102 |
+
- **Add More Features**: Integrate additional features such as timed questions, answer explanations, or leaderboard tracking.
|
| 103 |
+
- **Expand Real-Time Visuals**: Enhance client-side interactivity with more detailed results or progress tracking.
|
| 104 |
+
- **Deploy the App**: Use services like **Heroku**, **AWS**, or **Docker** to deploy the application for larger audiences.
|
| 105 |
+
|
| 106 |
+
## Dependencies
|
| 107 |
+
|
| 108 |
+
Ensure you have the following dependencies installed, as listed in `requirements.txt`:
|
| 109 |
+
|
| 110 |
+
```
|
| 111 |
+
Flask
|
| 112 |
+
Flask-SocketIO
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
### Installing Dependencies
|
| 116 |
+
|
| 117 |
+
```bash
|
| 118 |
+
pip install -r requirements.txt
|
| 119 |
+
```
|
| 120 |
+
|
| 121 |
+
## Troubleshooting
|
| 122 |
+
|
| 123 |
+
- **No participants showing up**: Ensure all participants join the `/client` interface and submit their usernames correctly.
|
| 124 |
+
- **WebSocket issues**: Make sure your firewall or browser settings are not blocking WebSocket connections.
|
| 125 |
+
- **Server not starting**: Check that Flask and Flask-SocketIO are installed correctly.
|
| 126 |
+
|
| 127 |
+
## Contributing
|
| 128 |
+
|
| 129 |
+
Contributions are welcome! Feel free to submit a pull request or open an issue to improve the functionality, design, or documentation of this application.
|
| 130 |
+
|
| 131 |
+
## License
|
| 132 |
+
|
| 133 |
+
This project is open-source and licensed under the MIT License.
|
| 134 |
+
|
| 135 |
+
## Contact
|
| 136 |
+
|
| 137 |
+
For any inquiries or suggestions, please reach out to:
|
| 138 |
+
|
| 139 |
+
- **Name**: Ruslan Magana Vsevolodovna
|
| 140 |
+
- **Email**: [email protected]
|
| 141 |
+
- **GitHub**: [https://github.com/ruslanmv](https://github.com/ruslanmv)
|
| 142 |
+
|
app.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from flask import Flask, render_template, request
|
| 2 |
+
from flask_socketio import SocketIO, emit, join_room, leave_room
|
| 3 |
+
import random
|
| 4 |
+
|
| 5 |
+
app = Flask(__name__)
|
| 6 |
+
app.config['SECRET_KEY'] = 'your_secret_key'
|
| 7 |
+
socketio = SocketIO(app)
|
| 8 |
+
|
| 9 |
+
# Store questions and participants
|
| 10 |
+
questions = [
|
| 11 |
+
{"question": "What is the capital of France?", "options": ["Paris", "London", "Berlin", "Rome"]},
|
| 12 |
+
{"question": "What is the largest planet?", "options": ["Earth", "Mars", "Jupiter", "Saturn"]}
|
| 13 |
+
]
|
| 14 |
+
current_question = {"index": 0, "answers": {}}
|
| 15 |
+
participants = {}
|
| 16 |
+
|
| 17 |
+
@app.route('/')
|
| 18 |
+
def index():
|
| 19 |
+
return "Welcome to the Quiz App"
|
| 20 |
+
|
| 21 |
+
@app.route('/client')
|
| 22 |
+
def client():
|
| 23 |
+
return render_template('client.html')
|
| 24 |
+
|
| 25 |
+
@app.route('/host')
|
| 26 |
+
def host():
|
| 27 |
+
return render_template('host.html')
|
| 28 |
+
|
| 29 |
+
@socketio.on('join')
|
| 30 |
+
def on_join(data):
|
| 31 |
+
username = data['username']
|
| 32 |
+
participants[request.sid] = username
|
| 33 |
+
join_room('quiz')
|
| 34 |
+
emit('update_participants', participants, room='quiz')
|
| 35 |
+
print(f"{username} joined the quiz.")
|
| 36 |
+
|
| 37 |
+
@socketio.on('disconnect')
|
| 38 |
+
def on_leave():
|
| 39 |
+
if request.sid in participants:
|
| 40 |
+
username = participants[request.sid]
|
| 41 |
+
leave_room('quiz')
|
| 42 |
+
del participants[request.sid]
|
| 43 |
+
emit('update_participants', participants, room='quiz')
|
| 44 |
+
print(f"{username} left the quiz.")
|
| 45 |
+
|
| 46 |
+
@socketio.on('request_question')
|
| 47 |
+
def send_question():
|
| 48 |
+
index = current_question['index']
|
| 49 |
+
question = questions[index]
|
| 50 |
+
emit('new_question', question, room=request.sid)
|
| 51 |
+
|
| 52 |
+
@socketio.on('submit_answer')
|
| 53 |
+
def receive_answer(data):
|
| 54 |
+
username = participants.get(request.sid, "Unknown")
|
| 55 |
+
answer = data['answer']
|
| 56 |
+
current_question['answers'][username] = answer
|
| 57 |
+
emit('update_results', current_question['answers'], room='quiz')
|
| 58 |
+
|
| 59 |
+
@socketio.on('next_question')
|
| 60 |
+
def next_question():
|
| 61 |
+
current_question['index'] += 1
|
| 62 |
+
current_question['answers'] = {}
|
| 63 |
+
if current_question['index'] < len(questions):
|
| 64 |
+
question = questions[current_question['index']]
|
| 65 |
+
emit('new_question', question, room='quiz')
|
| 66 |
+
else:
|
| 67 |
+
emit('quiz_end', room='quiz')
|
| 68 |
+
|
| 69 |
+
if __name__ == '__main__':
|
| 70 |
+
socketio.run(app, debug=True)
|
requirements.txt
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Flask
|
| 2 |
+
flask-socketio
|
static/script.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const socket = io();
|
| 2 |
+
let username;
|
| 3 |
+
|
| 4 |
+
function joinQuiz() {
|
| 5 |
+
username = document.getElementById('username').value;
|
| 6 |
+
socket.emit('join', { username: username });
|
| 7 |
+
document.getElementById('quiz-content').style.display = 'block';
|
| 8 |
+
socket.emit('request_question');
|
| 9 |
+
}
|
| 10 |
+
|
| 11 |
+
socket.on('new_question', (data) => {
|
| 12 |
+
document.getElementById('question-text').innerText = data.question;
|
| 13 |
+
const options = data.options.map((opt, index) =>
|
| 14 |
+
`<button onclick="submitAnswer('${opt}')" class="btn btn-secondary">${opt}</button>`
|
| 15 |
+
).join('');
|
| 16 |
+
document.getElementById('options').innerHTML = options;
|
| 17 |
+
});
|
| 18 |
+
|
| 19 |
+
function submitAnswer(answer) {
|
| 20 |
+
socket.emit('submit_answer', { answer: answer });
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
function nextQuestion() {
|
| 24 |
+
socket.emit('next_question');
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
socket.on('update_results', (data) => {
|
| 28 |
+
let resultsText = '';
|
| 29 |
+
for (let user in data) {
|
| 30 |
+
resultsText += `<p>${user}: ${data[user]}</p>`;
|
| 31 |
+
}
|
| 32 |
+
document.getElementById('results').innerHTML = resultsText;
|
| 33 |
+
});
|
| 34 |
+
|
| 35 |
+
socket.on('quiz_end', () => {
|
| 36 |
+
alert('Quiz has ended!');
|
| 37 |
+
});
|
templates/client.html
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Quiz Client</title>
|
| 7 |
+
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
|
| 8 |
+
</head>
|
| 9 |
+
<body>
|
| 10 |
+
<div class="container">
|
| 11 |
+
<h2>Join the Quiz</h2>
|
| 12 |
+
<input type="text" id="username" placeholder="Enter your name" class="form-control">
|
| 13 |
+
<button onclick="joinQuiz()" class="btn btn-primary mt-2">Join</button>
|
| 14 |
+
<div id="quiz-content" style="display: none;">
|
| 15 |
+
<h3 id="question-text"></h3>
|
| 16 |
+
<div id="options"></div>
|
| 17 |
+
</div>
|
| 18 |
+
</div>
|
| 19 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.0/socket.io.js"></script>
|
| 20 |
+
<script src="/static/script.js"></script>
|
| 21 |
+
</body>
|
| 22 |
+
</html>
|
templates/host.html
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Quiz Host</title>
|
| 7 |
+
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
|
| 8 |
+
</head>
|
| 9 |
+
<body>
|
| 10 |
+
<div class="container">
|
| 11 |
+
<h2>Quiz Host</h2>
|
| 12 |
+
<button onclick="nextQuestion()" class="btn btn-success">Next Question</button>
|
| 13 |
+
<h3 id="question-text"></h3>
|
| 14 |
+
<div id="results"></div>
|
| 15 |
+
</div>
|
| 16 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.0/socket.io.js"></script>
|
| 17 |
+
<script src="/static/script.js"></script>
|
| 18 |
+
</body>
|
| 19 |
+
</html>
|