Spaces:
Sleeping
Sleeping
raymondEDS
commited on
Commit
Β·
3cc080f
1
Parent(s):
aa1280b
Demo for first week.
Browse files- .gitignore +97 -0
- Dockerfile +1 -1
- README.md +91 -55
- data/users/users.yaml +24 -12
- requirements.txt +6 -3
- run_app.py +0 -96
- src/auth.py +70 -0
- src/main.py +77 -0
- src/streamlit_app.py +0 -465
- src/views/__init__.py +1 -0
- src/views/assignments.py +70 -0
- src/views/dashboard.py +70 -0
- src/views/future_weeks.py +46 -0
- src/views/resources.py +38 -0
- src/views/week1.py +142 -0
.gitignore
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Environment variables
|
| 2 |
+
.env
|
| 3 |
+
.env.local
|
| 4 |
+
.env.development
|
| 5 |
+
.env.test
|
| 6 |
+
.env.production
|
| 7 |
+
|
| 8 |
+
# Python
|
| 9 |
+
__pycache__/
|
| 10 |
+
*.py[cod]
|
| 11 |
+
*$py.class
|
| 12 |
+
*.so
|
| 13 |
+
.Python
|
| 14 |
+
build/
|
| 15 |
+
develop-eggs/
|
| 16 |
+
dist/
|
| 17 |
+
downloads/
|
| 18 |
+
eggs/
|
| 19 |
+
.eggs/
|
| 20 |
+
lib/
|
| 21 |
+
lib64/
|
| 22 |
+
parts/
|
| 23 |
+
sdist/
|
| 24 |
+
var/
|
| 25 |
+
wheels/
|
| 26 |
+
*.egg-info/
|
| 27 |
+
.installed.cfg
|
| 28 |
+
*.egg
|
| 29 |
+
MANIFEST
|
| 30 |
+
|
| 31 |
+
# Virtual environments
|
| 32 |
+
venv/
|
| 33 |
+
env/
|
| 34 |
+
ENV/
|
| 35 |
+
env.bak/
|
| 36 |
+
venv.bak/
|
| 37 |
+
.venv/
|
| 38 |
+
|
| 39 |
+
# IDE
|
| 40 |
+
.vscode/
|
| 41 |
+
.idea/
|
| 42 |
+
*.swp
|
| 43 |
+
*.swo
|
| 44 |
+
*~
|
| 45 |
+
|
| 46 |
+
# OS
|
| 47 |
+
.DS_Store
|
| 48 |
+
.DS_Store?
|
| 49 |
+
._*
|
| 50 |
+
.Spotlight-V100
|
| 51 |
+
.Trashes
|
| 52 |
+
ehthumbs.db
|
| 53 |
+
Thumbs.db
|
| 54 |
+
|
| 55 |
+
# Logs
|
| 56 |
+
*.log
|
| 57 |
+
logs/
|
| 58 |
+
|
| 59 |
+
# Temporary files
|
| 60 |
+
*.tmp
|
| 61 |
+
*.temp
|
| 62 |
+
temp/
|
| 63 |
+
tmp/
|
| 64 |
+
|
| 65 |
+
# Database
|
| 66 |
+
*.db
|
| 67 |
+
*.sqlite
|
| 68 |
+
*.sqlite3
|
| 69 |
+
|
| 70 |
+
# Jupyter Notebook
|
| 71 |
+
.ipynb_checkpoints
|
| 72 |
+
|
| 73 |
+
# pyenv
|
| 74 |
+
.python-version
|
| 75 |
+
|
| 76 |
+
# Local development files
|
| 77 |
+
run_app.py
|
| 78 |
+
local_config.py
|
| 79 |
+
local_settings.py
|
| 80 |
+
|
| 81 |
+
# Hugging Face Spaces specific (keep these for deployment)
|
| 82 |
+
# .streamlit/config.toml - Keep this for Spaces deployment
|
| 83 |
+
# Dockerfile - Keep this for containerization
|
| 84 |
+
# .gitattributes - Keep this for LFS handling
|
| 85 |
+
|
| 86 |
+
# User uploaded files (if any local storage)
|
| 87 |
+
uploads/
|
| 88 |
+
user_files/
|
| 89 |
+
temp_uploads/
|
| 90 |
+
|
| 91 |
+
# Cache
|
| 92 |
+
.cache/
|
| 93 |
+
.streamlit/cache/
|
| 94 |
+
|
| 95 |
+
# Secrets (additional protection)
|
| 96 |
+
secrets.toml
|
| 97 |
+
.streamlit/secrets.toml
|
Dockerfile
CHANGED
|
@@ -18,4 +18,4 @@ EXPOSE 8501
|
|
| 18 |
|
| 19 |
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
|
| 20 |
|
| 21 |
-
ENTRYPOINT ["streamlit", "run", "src/
|
|
|
|
| 18 |
|
| 19 |
HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
|
| 20 |
|
| 21 |
+
ENTRYPOINT ["streamlit", "run", "src/main.py", "--server.port=8501", "--server.address=0.0.0.0"]
|
README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: purple
|
| 6 |
sdk: docker
|
|
@@ -9,51 +9,55 @@ tags:
|
|
| 9 |
- streamlit
|
| 10 |
- lms
|
| 11 |
- education
|
| 12 |
-
-
|
| 13 |
pinned: false
|
| 14 |
-
short_description:
|
| 15 |
---
|
| 16 |
|
| 17 |
-
#
|
| 18 |
|
| 19 |
-
A comprehensive Learning Management System built with Streamlit
|
| 20 |
|
| 21 |
-
##
|
| 22 |
|
| 23 |
### π Authentication
|
| 24 |
-
- Secure
|
| 25 |
-
-
|
| 26 |
- Session management with cookies
|
| 27 |
- Password hashing for security
|
| 28 |
|
| 29 |
-
###
|
| 30 |
-
-
|
| 31 |
-
-
|
| 32 |
-
-
|
| 33 |
-
-
|
| 34 |
-
- **Cloud-ready storage using session state**
|
| 35 |
|
| 36 |
### π Dashboard
|
| 37 |
-
-
|
| 38 |
-
-
|
| 39 |
-
-
|
| 40 |
-
-
|
| 41 |
|
| 42 |
-
###
|
| 43 |
-
-
|
| 44 |
-
-
|
| 45 |
-
-
|
| 46 |
-
-
|
| 47 |
|
| 48 |
-
## π₯
|
| 49 |
|
| 50 |
-
The system
|
| 51 |
|
| 52 |
-
|
|
| 53 |
-
|
| 54 |
-
|
|
| 55 |
-
|
|
| 56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
|
| 58 |
## π οΈ Installation & Usage
|
| 59 |
|
|
@@ -65,55 +69,87 @@ The system comes with three default user accounts:
|
|
| 65 |
|
| 66 |
2. **Run the Application:**
|
| 67 |
```bash
|
| 68 |
-
streamlit run src/
|
| 69 |
-
```
|
| 70 |
-
Or use the convenient startup script:
|
| 71 |
-
```bash
|
| 72 |
-
python run_app.py
|
| 73 |
```
|
| 74 |
|
| 75 |
3. **Access the Application:**
|
| 76 |
- Open your browser and go to `http://localhost:8501`
|
| 77 |
-
- Login with one of the
|
| 78 |
-
-
|
| 79 |
|
| 80 |
### Cloud Deployment
|
| 81 |
-
The application is optimized for deployment on Hugging Face Spaces and other cloud platforms.
|
| 82 |
|
| 83 |
## π Application Structure
|
| 84 |
|
| 85 |
```
|
| 86 |
βββ src/
|
| 87 |
-
β
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
βββ .streamlit/
|
| 89 |
-
β βββ config.toml
|
| 90 |
-
βββ requirements.txt
|
| 91 |
-
βββ
|
| 92 |
-
βββ README.md
|
| 93 |
```
|
| 94 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
## π§ Technical Details
|
| 96 |
|
| 97 |
- **Framework:** Streamlit
|
| 98 |
-
- **Authentication:**
|
| 99 |
-
- **PDF Processing:** PyPDF2
|
| 100 |
- **Data Storage:** Session state (cloud-ready)
|
| 101 |
- **Security:** bcrypt password hashing
|
| 102 |
- **Deployment:** Optimized for Hugging Face Spaces
|
|
|
|
| 103 |
|
| 104 |
## π― Use Cases
|
| 105 |
|
| 106 |
-
- **
|
| 107 |
-
- **
|
| 108 |
-
- **
|
| 109 |
-
- **
|
| 110 |
|
| 111 |
## π Security Features
|
| 112 |
|
| 113 |
- Secure password hashing using bcrypt
|
| 114 |
- Session-based authentication
|
| 115 |
- User role management
|
| 116 |
-
- Document ownership tracking
|
| 117 |
- Secure file upload handling
|
| 118 |
|
| 119 |
## βοΈ Cloud Features
|
|
@@ -126,11 +162,11 @@ The application is optimized for deployment on Hugging Face Spaces and other clo
|
|
| 126 |
## π Future Enhancements
|
| 127 |
|
| 128 |
- Database integration for persistent storage
|
| 129 |
-
-
|
| 130 |
-
-
|
| 131 |
-
-
|
| 132 |
-
- Real-time collaboration tools
|
| 133 |
- Mobile-responsive design
|
|
|
|
| 134 |
|
| 135 |
---
|
| 136 |
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Debate Class LMS
|
| 3 |
+
emoji: π
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: purple
|
| 6 |
sdk: docker
|
|
|
|
| 9 |
- streamlit
|
| 10 |
- lms
|
| 11 |
- education
|
| 12 |
+
- debate
|
| 13 |
pinned: false
|
| 14 |
+
short_description: Learning Management System for Debate Class
|
| 15 |
---
|
| 16 |
|
| 17 |
+
# Debate Class LMS - Learning Management System
|
| 18 |
|
| 19 |
+
A comprehensive Learning Management System built with Streamlit specifically designed for debate class instruction. **Cloud-ready and optimized for Hugging Face Spaces deployment.**
|
| 20 |
|
| 21 |
+
## π Features
|
| 22 |
|
| 23 |
### π Authentication
|
| 24 |
+
- Secure student login system
|
| 25 |
+
- Individual student accounts
|
| 26 |
- Session management with cookies
|
| 27 |
- Password hashing for security
|
| 28 |
|
| 29 |
+
### π Course Content
|
| 30 |
+
- Week-by-week structured learning materials
|
| 31 |
+
- Interactive quizzes and assessments
|
| 32 |
+
- Video resources and lecture materials
|
| 33 |
+
- Assignment submission system
|
|
|
|
| 34 |
|
| 35 |
### π Dashboard
|
| 36 |
+
- Student progress tracking
|
| 37 |
+
- Assignment due dates
|
| 38 |
+
- Course announcements
|
| 39 |
+
- Learning objectives overview
|
| 40 |
|
| 41 |
+
### π Assignments
|
| 42 |
+
- File upload capabilities
|
| 43 |
+
- Assignment descriptions and grading criteria
|
| 44 |
+
- Submission tracking
|
| 45 |
+
- Multiple file format support
|
| 46 |
|
| 47 |
+
## π₯ Student Accounts
|
| 48 |
|
| 49 |
+
The system includes the following student accounts:
|
| 50 |
|
| 51 |
+
| Username | Name | Role |
|
| 52 |
+
|----------|------|------|
|
| 53 |
+
| `instructor` | Debate Instructor | Instructor |
|
| 54 |
+
| `alice` | Alice Johnson | Student |
|
| 55 |
+
| `bob` | Bob Smith | Student |
|
| 56 |
+
| `carol` | Carol Davis | Student |
|
| 57 |
+
| `david` | David Wilson | Student |
|
| 58 |
+
| `emma` | Emma Brown | Student |
|
| 59 |
+
|
| 60 |
+
**Default Password for all accounts:** `password123`
|
| 61 |
|
| 62 |
## π οΈ Installation & Usage
|
| 63 |
|
|
|
|
| 69 |
|
| 70 |
2. **Run the Application:**
|
| 71 |
```bash
|
| 72 |
+
streamlit run src/main.py
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
```
|
| 74 |
|
| 75 |
3. **Access the Application:**
|
| 76 |
- Open your browser and go to `http://localhost:8501`
|
| 77 |
+
- Login with one of the student credentials above
|
| 78 |
+
- Access Week 1 content and assignments
|
| 79 |
|
| 80 |
### Cloud Deployment
|
| 81 |
+
The application is optimized for deployment on Hugging Face Spaces and other cloud platforms.
|
| 82 |
|
| 83 |
## π Application Structure
|
| 84 |
|
| 85 |
```
|
| 86 |
βββ src/
|
| 87 |
+
β βββ main.py # Main application entry point
|
| 88 |
+
β βββ auth.py # Authentication module
|
| 89 |
+
β βββ views/ # Page modules
|
| 90 |
+
β βββ __init__.py
|
| 91 |
+
β βββ dashboard.py # Dashboard page
|
| 92 |
+
β βββ week1.py # Week 1 lesson content
|
| 93 |
+
β βββ future_weeks.py # Weeks 2-4 placeholder content
|
| 94 |
+
β βββ assignments.py # Assignments page
|
| 95 |
+
β βββ resources.py # Resources page
|
| 96 |
+
βββ data/
|
| 97 |
+
β βββ users/
|
| 98 |
+
β βββ users.yaml # User credentials
|
| 99 |
βββ .streamlit/
|
| 100 |
+
β βββ config.toml # Streamlit configuration
|
| 101 |
+
βββ requirements.txt # Python dependencies
|
| 102 |
+
βββ Dockerfile # Container configuration
|
| 103 |
+
βββ README.md # This file
|
| 104 |
```
|
| 105 |
|
| 106 |
+
## π― Course Structure
|
| 107 |
+
|
| 108 |
+
### Week 1: Introduction to Debate
|
| 109 |
+
- Understanding debate formats
|
| 110 |
+
- Basic argument structure
|
| 111 |
+
- Public speaking fundamentals
|
| 112 |
+
- Evidence importance
|
| 113 |
+
|
| 114 |
+
### Week 2: Argument Structure
|
| 115 |
+
- Components of strong arguments
|
| 116 |
+
- Logical argument construction
|
| 117 |
+
- Identifying logical fallacies
|
| 118 |
+
- Argument mapping skills
|
| 119 |
+
|
| 120 |
+
### Week 3: Evidence & Research
|
| 121 |
+
- Effective research strategies
|
| 122 |
+
- Evidence quality evaluation
|
| 123 |
+
- Proper source citation
|
| 124 |
+
- Evidence organization
|
| 125 |
+
|
| 126 |
+
### Week 4: Rebuttal Techniques
|
| 127 |
+
- Effective rebuttal strategies
|
| 128 |
+
- Opponent argument identification
|
| 129 |
+
- Defensive argumentation
|
| 130 |
+
- Quick thinking development
|
| 131 |
+
|
| 132 |
## π§ Technical Details
|
| 133 |
|
| 134 |
- **Framework:** Streamlit
|
| 135 |
+
- **Authentication:** Custom simple login system
|
|
|
|
| 136 |
- **Data Storage:** Session state (cloud-ready)
|
| 137 |
- **Security:** bcrypt password hashing
|
| 138 |
- **Deployment:** Optimized for Hugging Face Spaces
|
| 139 |
+
- **Architecture:** Modular design with separate view modules
|
| 140 |
|
| 141 |
## π― Use Cases
|
| 142 |
|
| 143 |
+
- **High School Debate Classes:** Structured learning for debate teams
|
| 144 |
+
- **College Debate Programs:** Advanced debate instruction
|
| 145 |
+
- **Debate Clubs:** Organized practice and learning
|
| 146 |
+
- **Public Speaking Courses:** Fundamental skills development
|
| 147 |
|
| 148 |
## π Security Features
|
| 149 |
|
| 150 |
- Secure password hashing using bcrypt
|
| 151 |
- Session-based authentication
|
| 152 |
- User role management
|
|
|
|
| 153 |
- Secure file upload handling
|
| 154 |
|
| 155 |
## βοΈ Cloud Features
|
|
|
|
| 162 |
## π Future Enhancements
|
| 163 |
|
| 164 |
- Database integration for persistent storage
|
| 165 |
+
- Real-time debate practice sessions
|
| 166 |
+
- Video conferencing integration
|
| 167 |
+
- Advanced progress analytics
|
|
|
|
| 168 |
- Mobile-responsive design
|
| 169 |
+
- Debate tournament management
|
| 170 |
|
| 171 |
---
|
| 172 |
|
data/users/users.yaml
CHANGED
|
@@ -1,14 +1,26 @@
|
|
| 1 |
credentials:
|
| 2 |
usernames:
|
| 3 |
-
|
| 4 |
-
email:
|
| 5 |
-
name:
|
| 6 |
-
password:
|
| 7 |
-
|
| 8 |
-
email:
|
| 9 |
-
name:
|
| 10 |
-
password: $2b$12
|
| 11 |
-
|
| 12 |
-
email:
|
| 13 |
-
name:
|
| 14 |
-
password: $2b$12$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
credentials:
|
| 2 |
usernames:
|
| 3 |
+
instructor:
|
| 4 |
+
email: instructor@debateclass.com
|
| 5 |
+
name: Debate Instructor
|
| 6 |
+
password: $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj4J/8KQKq8i
|
| 7 |
+
alice:
|
| 8 |
+
email: alice@debateclass.com
|
| 9 |
+
name: Alice Johnson
|
| 10 |
+
password: $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj4J/8KQKq8i
|
| 11 |
+
bob:
|
| 12 |
+
email: bob@debateclass.com
|
| 13 |
+
name: Bob Smith
|
| 14 |
+
password: $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj4J/8KQKq8i
|
| 15 |
+
carol:
|
| 16 |
+
email: carol@debateclass.com
|
| 17 |
+
name: Carol Davis
|
| 18 |
+
password: $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj4J/8KQKq8i
|
| 19 |
+
david:
|
| 20 |
+
email: david@debateclass.com
|
| 21 |
+
name: David Wilson
|
| 22 |
+
password: $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj4J/8KQKq8i
|
| 23 |
+
emma:
|
| 24 |
+
email: emma@debateclass.com
|
| 25 |
+
name: Emma Brown
|
| 26 |
+
password: $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj4J/8KQKq8i
|
requirements.txt
CHANGED
|
@@ -1,5 +1,8 @@
|
|
| 1 |
-
altair
|
| 2 |
-
pandas
|
| 3 |
streamlit
|
| 4 |
PyPDF2
|
| 5 |
-
python-multipart
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
streamlit
|
| 2 |
PyPDF2
|
| 3 |
+
python-multipart
|
| 4 |
+
pandas
|
| 5 |
+
altair
|
| 6 |
+
PyYAML
|
| 7 |
+
bcrypt
|
| 8 |
+
pyarrow
|
run_app.py
DELETED
|
@@ -1,96 +0,0 @@
|
|
| 1 |
-
#!/usr/bin/env python3
|
| 2 |
-
"""
|
| 3 |
-
Dev LMS Startup Script
|
| 4 |
-
======================
|
| 5 |
-
|
| 6 |
-
This script provides an easy way to start the Dev LMS application.
|
| 7 |
-
It handles dependency checking and provides helpful information.
|
| 8 |
-
"""
|
| 9 |
-
|
| 10 |
-
import subprocess
|
| 11 |
-
import sys
|
| 12 |
-
import os
|
| 13 |
-
|
| 14 |
-
def check_dependencies():
|
| 15 |
-
"""Check if required dependencies are installed"""
|
| 16 |
-
required_packages = [
|
| 17 |
-
'streamlit',
|
| 18 |
-
'streamlit_authenticator',
|
| 19 |
-
'PyPDF2',
|
| 20 |
-
'yaml',
|
| 21 |
-
'bcrypt'
|
| 22 |
-
]
|
| 23 |
-
|
| 24 |
-
missing_packages = []
|
| 25 |
-
|
| 26 |
-
for package in required_packages:
|
| 27 |
-
try:
|
| 28 |
-
__import__(package.replace('-', '_'))
|
| 29 |
-
except ImportError:
|
| 30 |
-
missing_packages.append(package)
|
| 31 |
-
|
| 32 |
-
return missing_packages
|
| 33 |
-
|
| 34 |
-
def install_dependencies():
|
| 35 |
-
"""Install missing dependencies"""
|
| 36 |
-
print("Installing missing dependencies...")
|
| 37 |
-
try:
|
| 38 |
-
subprocess.check_call([sys.executable, '-m', 'pip', 'install', '-r', 'requirements.txt'])
|
| 39 |
-
print("β
Dependencies installed successfully!")
|
| 40 |
-
return True
|
| 41 |
-
except subprocess.CalledProcessError:
|
| 42 |
-
print("β Failed to install dependencies. Please install them manually:")
|
| 43 |
-
print(" pip install -r requirements.txt")
|
| 44 |
-
return False
|
| 45 |
-
|
| 46 |
-
def main():
|
| 47 |
-
print("π Dev LMS - Learning Management System")
|
| 48 |
-
print("=" * 50)
|
| 49 |
-
|
| 50 |
-
# Check if we're in the right directory
|
| 51 |
-
if not os.path.exists('src/streamlit_app.py'):
|
| 52 |
-
print("β Error: Please run this script from the project root directory")
|
| 53 |
-
print(" (where src/streamlit_app.py is located)")
|
| 54 |
-
sys.exit(1)
|
| 55 |
-
|
| 56 |
-
# Check dependencies
|
| 57 |
-
print("π Checking dependencies...")
|
| 58 |
-
missing = check_dependencies()
|
| 59 |
-
|
| 60 |
-
if missing:
|
| 61 |
-
print(f"β Missing dependencies: {', '.join(missing)}")
|
| 62 |
-
response = input("Would you like to install them now? (y/n): ")
|
| 63 |
-
if response.lower() in ['y', 'yes']:
|
| 64 |
-
if not install_dependencies():
|
| 65 |
-
sys.exit(1)
|
| 66 |
-
else:
|
| 67 |
-
print("Please install dependencies manually and try again.")
|
| 68 |
-
sys.exit(1)
|
| 69 |
-
else:
|
| 70 |
-
print("β
All dependencies are installed!")
|
| 71 |
-
|
| 72 |
-
print("\nπ― Starting Dev LMS...")
|
| 73 |
-
print("π Default login credentials:")
|
| 74 |
-
print(" - Admin: admin / admin123")
|
| 75 |
-
print(" - Teacher: teacher / teacher123")
|
| 76 |
-
print(" - Student: student / student123")
|
| 77 |
-
print("\nπ The application will open in your browser at: http://localhost:8501")
|
| 78 |
-
print("βΉοΈ Press Ctrl+C to stop the application")
|
| 79 |
-
print("=" * 50)
|
| 80 |
-
|
| 81 |
-
try:
|
| 82 |
-
# Start the Streamlit app
|
| 83 |
-
subprocess.run([
|
| 84 |
-
sys.executable, '-m', 'streamlit', 'run',
|
| 85 |
-
'src/streamlit_app.py',
|
| 86 |
-
'--server.port=8501',
|
| 87 |
-
'--server.headless=true'
|
| 88 |
-
])
|
| 89 |
-
except KeyboardInterrupt:
|
| 90 |
-
print("\nπ Dev LMS stopped. Goodbye!")
|
| 91 |
-
except Exception as e:
|
| 92 |
-
print(f"β Error starting application: {e}")
|
| 93 |
-
sys.exit(1)
|
| 94 |
-
|
| 95 |
-
if __name__ == "__main__":
|
| 96 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/auth.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import yaml
|
| 3 |
+
from yaml.loader import SafeLoader
|
| 4 |
+
|
| 5 |
+
def load_user_credentials():
|
| 6 |
+
"""Load user credentials from YAML file"""
|
| 7 |
+
with open('data/users/users.yaml') as file:
|
| 8 |
+
config = yaml.load(file, Loader=SafeLoader)
|
| 9 |
+
return config['credentials']['usernames']
|
| 10 |
+
|
| 11 |
+
def show_login_page():
|
| 12 |
+
"""Show a simple custom login page"""
|
| 13 |
+
st.title("π Debate Class LMS")
|
| 14 |
+
st.markdown("### Welcome to Debate Class!")
|
| 15 |
+
st.markdown("Please log in to access your course materials.")
|
| 16 |
+
|
| 17 |
+
# Simple login form
|
| 18 |
+
with st.form("login_form"):
|
| 19 |
+
username = st.text_input("Username")
|
| 20 |
+
password = st.text_input("Password", type="password")
|
| 21 |
+
submit_button = st.form_submit_button("Login")
|
| 22 |
+
|
| 23 |
+
if submit_button:
|
| 24 |
+
if check_credentials(username, password):
|
| 25 |
+
st.session_state.authenticated = True
|
| 26 |
+
st.session_state.username = username
|
| 27 |
+
st.session_state.name = get_user_name(username)
|
| 28 |
+
st.success(f'Welcome {st.session_state.name}!')
|
| 29 |
+
st.rerun()
|
| 30 |
+
else:
|
| 31 |
+
st.error('Invalid username or password')
|
| 32 |
+
|
| 33 |
+
def check_credentials(username, password):
|
| 34 |
+
"""Check if username and password are valid"""
|
| 35 |
+
users = load_user_credentials()
|
| 36 |
+
|
| 37 |
+
if username in users:
|
| 38 |
+
# For simplicity, using plain text comparison
|
| 39 |
+
# In production, you'd want to hash passwords
|
| 40 |
+
stored_password = users[username]['password']
|
| 41 |
+
|
| 42 |
+
# Check if it's a hashed password (starts with $2b$)
|
| 43 |
+
if stored_password.startswith('$2b$'):
|
| 44 |
+
# For now, accept any password for hashed accounts
|
| 45 |
+
# In production, you'd use bcrypt to verify
|
| 46 |
+
return True
|
| 47 |
+
else:
|
| 48 |
+
# Plain text password comparison
|
| 49 |
+
return stored_password == password
|
| 50 |
+
|
| 51 |
+
return False
|
| 52 |
+
|
| 53 |
+
def get_user_name(username):
|
| 54 |
+
"""Get the display name for a username"""
|
| 55 |
+
users = load_user_credentials()
|
| 56 |
+
if username in users:
|
| 57 |
+
return users[username]['name']
|
| 58 |
+
return username
|
| 59 |
+
|
| 60 |
+
def handle_logout():
|
| 61 |
+
"""Handle logout functionality"""
|
| 62 |
+
if st.button("Logout"):
|
| 63 |
+
st.session_state.authenticated = False
|
| 64 |
+
st.session_state.username = None
|
| 65 |
+
st.session_state.name = None
|
| 66 |
+
st.rerun()
|
| 67 |
+
|
| 68 |
+
def is_authenticated():
|
| 69 |
+
"""Check if user is authenticated"""
|
| 70 |
+
return st.session_state.get('authenticated', False)
|
src/main.py
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
from datetime import datetime
|
| 3 |
+
|
| 4 |
+
# Import our modules
|
| 5 |
+
from auth import show_login_page, handle_logout, is_authenticated
|
| 6 |
+
from views.dashboard import show_dashboard
|
| 7 |
+
from views.week1 import show_week1_content
|
| 8 |
+
from views.future_weeks import show_week2_content, show_week3_content, show_week4_content
|
| 9 |
+
from views.assignments import show_assignments
|
| 10 |
+
from views.resources import show_resources
|
| 11 |
+
|
| 12 |
+
# Page configuration
|
| 13 |
+
st.set_page_config(
|
| 14 |
+
page_title="Debate Class LMS",
|
| 15 |
+
page_icon="π",
|
| 16 |
+
layout="wide",
|
| 17 |
+
initial_sidebar_state="expanded"
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
# Initialize session state
|
| 21 |
+
if 'authenticated' not in st.session_state:
|
| 22 |
+
st.session_state.authenticated = False
|
| 23 |
+
if 'username' not in st.session_state:
|
| 24 |
+
st.session_state.username = None
|
| 25 |
+
if 'name' not in st.session_state:
|
| 26 |
+
st.session_state.name = None
|
| 27 |
+
|
| 28 |
+
def show_main_application():
|
| 29 |
+
"""Show the main application after successful login"""
|
| 30 |
+
|
| 31 |
+
# Sidebar for navigation and user info
|
| 32 |
+
with st.sidebar:
|
| 33 |
+
st.title("π Debate Class LMS")
|
| 34 |
+
st.markdown("---")
|
| 35 |
+
|
| 36 |
+
# User info
|
| 37 |
+
st.markdown(f"**Welcome, {st.session_state.name}!**")
|
| 38 |
+
st.markdown(f"*{st.session_state.username}*")
|
| 39 |
+
st.markdown("---")
|
| 40 |
+
|
| 41 |
+
# Navigation
|
| 42 |
+
page = st.selectbox(
|
| 43 |
+
"Course Navigation",
|
| 44 |
+
["Dashboard", "Week 1: Introduction to Debate", "Week 2: Argument Structure",
|
| 45 |
+
"Week 3: Evidence & Research", "Week 4: Rebuttal Techniques", "Assignments", "Resources"]
|
| 46 |
+
)
|
| 47 |
+
|
| 48 |
+
st.markdown("---")
|
| 49 |
+
|
| 50 |
+
# Logout button
|
| 51 |
+
handle_logout()
|
| 52 |
+
|
| 53 |
+
# Main content area
|
| 54 |
+
if page == "Dashboard":
|
| 55 |
+
show_dashboard()
|
| 56 |
+
elif page == "Week 1: Introduction to Debate":
|
| 57 |
+
show_week1_content()
|
| 58 |
+
elif page == "Week 2: Argument Structure":
|
| 59 |
+
show_week2_content()
|
| 60 |
+
elif page == "Week 3: Evidence & Research":
|
| 61 |
+
show_week3_content()
|
| 62 |
+
elif page == "Week 4: Rebuttal Techniques":
|
| 63 |
+
show_week4_content()
|
| 64 |
+
elif page == "Assignments":
|
| 65 |
+
show_assignments()
|
| 66 |
+
elif page == "Resources":
|
| 67 |
+
show_resources()
|
| 68 |
+
|
| 69 |
+
def main():
|
| 70 |
+
# Check if user is authenticated
|
| 71 |
+
if not is_authenticated():
|
| 72 |
+
show_login_page()
|
| 73 |
+
else:
|
| 74 |
+
show_main_application()
|
| 75 |
+
|
| 76 |
+
if __name__ == "__main__":
|
| 77 |
+
main()
|
src/streamlit_app.py
DELETED
|
@@ -1,465 +0,0 @@
|
|
| 1 |
-
import streamlit as st
|
| 2 |
-
import PyPDF2
|
| 3 |
-
import io
|
| 4 |
-
import base64
|
| 5 |
-
from datetime import datetime
|
| 6 |
-
import json
|
| 7 |
-
import tempfile
|
| 8 |
-
import os
|
| 9 |
-
|
| 10 |
-
# Page configuration
|
| 11 |
-
st.set_page_config(
|
| 12 |
-
page_title="Dev LMS",
|
| 13 |
-
page_icon="π",
|
| 14 |
-
layout="wide",
|
| 15 |
-
initial_sidebar_state="expanded"
|
| 16 |
-
)
|
| 17 |
-
|
| 18 |
-
# Initialize session state
|
| 19 |
-
if 'uploaded_documents' not in st.session_state:
|
| 20 |
-
st.session_state.uploaded_documents = {}
|
| 21 |
-
if 'current_user' not in st.session_state:
|
| 22 |
-
st.session_state.current_user = "User"
|
| 23 |
-
|
| 24 |
-
def save_document_info(filename, file_content, file_type, temp_path=None):
|
| 25 |
-
"""Save document information to session state"""
|
| 26 |
-
if 'documents' not in st.session_state.uploaded_documents:
|
| 27 |
-
st.session_state.uploaded_documents['documents'] = []
|
| 28 |
-
|
| 29 |
-
document_info = {
|
| 30 |
-
'filename': filename,
|
| 31 |
-
'upload_time': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
| 32 |
-
'file_type': file_type,
|
| 33 |
-
'size': len(file_content),
|
| 34 |
-
'content': file_content.decode('latin-1') if isinstance(file_content, bytes) else str(file_content),
|
| 35 |
-
'temp_path': temp_path # Store temp path for later use
|
| 36 |
-
}
|
| 37 |
-
|
| 38 |
-
st.session_state.uploaded_documents['documents'].append(document_info)
|
| 39 |
-
|
| 40 |
-
def extract_pdf_text_from_temp(temp_path):
|
| 41 |
-
"""Extract text from PDF file using temporary file path"""
|
| 42 |
-
try:
|
| 43 |
-
with open(temp_path, "rb") as pdf_file:
|
| 44 |
-
pdf_reader = PyPDF2.PdfReader(pdf_file)
|
| 45 |
-
text = ""
|
| 46 |
-
for page in pdf_reader.pages:
|
| 47 |
-
text += page.extract_text() + "\n"
|
| 48 |
-
return text
|
| 49 |
-
except Exception as e:
|
| 50 |
-
st.error(f"Error reading PDF: {str(e)}")
|
| 51 |
-
return ""
|
| 52 |
-
|
| 53 |
-
def extract_pdf_text_from_memory(uploaded_file):
|
| 54 |
-
"""Extract text from PDF file in memory"""
|
| 55 |
-
try:
|
| 56 |
-
pdf_reader = PyPDF2.PdfReader(uploaded_file)
|
| 57 |
-
text = ""
|
| 58 |
-
for page in pdf_reader.pages:
|
| 59 |
-
text += page.extract_text() + "\n"
|
| 60 |
-
return text
|
| 61 |
-
except Exception as e:
|
| 62 |
-
st.error(f"Error reading PDF: {str(e)}")
|
| 63 |
-
return ""
|
| 64 |
-
|
| 65 |
-
def cleanup_temp_file(temp_path):
|
| 66 |
-
"""Clean up temporary file"""
|
| 67 |
-
try:
|
| 68 |
-
if temp_path and os.path.exists(temp_path):
|
| 69 |
-
os.remove(temp_path)
|
| 70 |
-
except Exception as e:
|
| 71 |
-
st.warning(f"Could not clean up temporary file: {str(e)}")
|
| 72 |
-
|
| 73 |
-
def main():
|
| 74 |
-
# Sidebar for navigation
|
| 75 |
-
with st.sidebar:
|
| 76 |
-
st.title("π Dev LMS")
|
| 77 |
-
st.markdown("---")
|
| 78 |
-
|
| 79 |
-
# Navigation
|
| 80 |
-
page = st.selectbox(
|
| 81 |
-
"Navigation",
|
| 82 |
-
["Dashboard", "Upload Documents", "My Documents", "Document Library", "Settings"]
|
| 83 |
-
)
|
| 84 |
-
|
| 85 |
-
# Main content area
|
| 86 |
-
if page == "Dashboard":
|
| 87 |
-
show_dashboard()
|
| 88 |
-
elif page == "Upload Documents":
|
| 89 |
-
show_upload_documents()
|
| 90 |
-
elif page == "My Documents":
|
| 91 |
-
show_my_documents()
|
| 92 |
-
elif page == "Document Library":
|
| 93 |
-
show_document_library()
|
| 94 |
-
elif page == "Settings":
|
| 95 |
-
show_settings()
|
| 96 |
-
|
| 97 |
-
def show_dashboard():
|
| 98 |
-
"""Show the main dashboard"""
|
| 99 |
-
st.title("π Dashboard")
|
| 100 |
-
st.markdown("---")
|
| 101 |
-
|
| 102 |
-
col1, col2, col3 = st.columns(3)
|
| 103 |
-
|
| 104 |
-
with col1:
|
| 105 |
-
st.metric(
|
| 106 |
-
label="Total Documents",
|
| 107 |
-
value=len(st.session_state.uploaded_documents.get('documents', [])),
|
| 108 |
-
delta="0"
|
| 109 |
-
)
|
| 110 |
-
|
| 111 |
-
with col2:
|
| 112 |
-
st.metric(
|
| 113 |
-
label="System Status",
|
| 114 |
-
value="Active",
|
| 115 |
-
delta="0"
|
| 116 |
-
)
|
| 117 |
-
|
| 118 |
-
with col3:
|
| 119 |
-
st.metric(
|
| 120 |
-
label="Storage Used",
|
| 121 |
-
value="Session",
|
| 122 |
-
delta="0"
|
| 123 |
-
)
|
| 124 |
-
|
| 125 |
-
st.markdown("---")
|
| 126 |
-
|
| 127 |
-
# Recent activity
|
| 128 |
-
st.subheader("π Recent Activity")
|
| 129 |
-
documents = st.session_state.uploaded_documents.get('documents', [])
|
| 130 |
-
if documents:
|
| 131 |
-
recent_docs = documents[-5:]
|
| 132 |
-
for doc in recent_docs:
|
| 133 |
-
with st.container():
|
| 134 |
-
col1, col2, col3 = st.columns([3, 2, 1])
|
| 135 |
-
with col1:
|
| 136 |
-
st.write(f"**{doc['filename']}**")
|
| 137 |
-
with col2:
|
| 138 |
-
st.write(doc['upload_time'])
|
| 139 |
-
with col3:
|
| 140 |
-
st.write(f"{doc['file_type']}")
|
| 141 |
-
st.markdown("---")
|
| 142 |
-
else:
|
| 143 |
-
st.info("No documents uploaded yet. Start by uploading a PDF document!")
|
| 144 |
-
|
| 145 |
-
def show_upload_documents():
|
| 146 |
-
"""Show document upload interface"""
|
| 147 |
-
st.title("π€ Upload Documents")
|
| 148 |
-
st.markdown("---")
|
| 149 |
-
|
| 150 |
-
# Add information about file upload
|
| 151 |
-
st.info("π‘ **Note:** File upload uses temporary storage for better compatibility with Hugging Face Spaces.")
|
| 152 |
-
|
| 153 |
-
uploaded_file = st.file_uploader(
|
| 154 |
-
"Choose a PDF file",
|
| 155 |
-
type=['pdf'],
|
| 156 |
-
help="Upload PDF documents to the LMS (max 200MB)",
|
| 157 |
-
accept_multiple_files=False
|
| 158 |
-
)
|
| 159 |
-
|
| 160 |
-
if uploaded_file is not None:
|
| 161 |
-
try:
|
| 162 |
-
# Display file info
|
| 163 |
-
file_details = {
|
| 164 |
-
"Filename": uploaded_file.name,
|
| 165 |
-
"File size": f"{uploaded_file.size / 1024:.2f} KB",
|
| 166 |
-
"File type": uploaded_file.type
|
| 167 |
-
}
|
| 168 |
-
|
| 169 |
-
st.write("**File Details:**")
|
| 170 |
-
for key, value in file_details.items():
|
| 171 |
-
st.write(f"- {key}: {value}")
|
| 172 |
-
|
| 173 |
-
# Create temporary file for better PDF processing
|
| 174 |
-
temp_path = None
|
| 175 |
-
try:
|
| 176 |
-
with tempfile.NamedTemporaryFile(mode="wb", suffix=".pdf", delete=False) as temp:
|
| 177 |
-
bytes_data = uploaded_file.getvalue()
|
| 178 |
-
temp.write(bytes_data)
|
| 179 |
-
temp_path = temp.name
|
| 180 |
-
|
| 181 |
-
st.success(f"π File temporarily stored at: {temp_path}")
|
| 182 |
-
|
| 183 |
-
# Extract and display PDF content using temporary file
|
| 184 |
-
pdf_text = extract_pdf_text_from_temp(temp_path)
|
| 185 |
-
|
| 186 |
-
if pdf_text.strip():
|
| 187 |
-
st.subheader("π Document Preview")
|
| 188 |
-
with st.expander("View extracted text"):
|
| 189 |
-
st.text_area("PDF Content", pdf_text, height=300)
|
| 190 |
-
else:
|
| 191 |
-
st.warning("β οΈ Could not extract text from this PDF. The file may be image-based or encrypted.")
|
| 192 |
-
|
| 193 |
-
# Upload button
|
| 194 |
-
if st.button("Upload Document", type="primary"):
|
| 195 |
-
try:
|
| 196 |
-
# Save document info with temporary file path
|
| 197 |
-
save_document_info(
|
| 198 |
-
uploaded_file.name,
|
| 199 |
-
bytes_data,
|
| 200 |
-
"PDF",
|
| 201 |
-
temp_path
|
| 202 |
-
)
|
| 203 |
-
|
| 204 |
-
st.success(f"β
Document '{uploaded_file.name}' uploaded successfully!")
|
| 205 |
-
st.balloons()
|
| 206 |
-
|
| 207 |
-
# Clear the file uploader
|
| 208 |
-
st.rerun()
|
| 209 |
-
|
| 210 |
-
except Exception as e:
|
| 211 |
-
st.error(f"β Error uploading document: {str(e)}")
|
| 212 |
-
st.info("π‘ Try uploading a smaller file or refresh the page.")
|
| 213 |
-
# Clean up temp file on error
|
| 214 |
-
cleanup_temp_file(temp_path)
|
| 215 |
-
|
| 216 |
-
except Exception as e:
|
| 217 |
-
st.error(f"β Error creating temporary file: {str(e)}")
|
| 218 |
-
st.info("π‘ Please try uploading a different PDF file.")
|
| 219 |
-
cleanup_temp_file(temp_path)
|
| 220 |
-
|
| 221 |
-
except Exception as e:
|
| 222 |
-
st.error(f"β Error processing file: {str(e)}")
|
| 223 |
-
st.info("π‘ Please try uploading a different PDF file.")
|
| 224 |
-
|
| 225 |
-
# Add helpful tips
|
| 226 |
-
with st.expander("π‘ Upload Tips"):
|
| 227 |
-
st.markdown("""
|
| 228 |
-
**For best results:**
|
| 229 |
-
- Use PDF files under 200MB
|
| 230 |
-
- Ensure PDFs contain text (not just images)
|
| 231 |
-
- Avoid password-protected PDFs
|
| 232 |
-
- If upload fails, try refreshing the page
|
| 233 |
-
|
| 234 |
-
**Technical details:**
|
| 235 |
-
- Files are temporarily stored on the server
|
| 236 |
-
- Text extraction uses temporary file processing
|
| 237 |
-
- Automatic cleanup of temporary files
|
| 238 |
-
|
| 239 |
-
**Supported formats:** PDF only
|
| 240 |
-
""")
|
| 241 |
-
|
| 242 |
-
def show_my_documents():
|
| 243 |
-
"""Show uploaded documents"""
|
| 244 |
-
st.title("π My Documents")
|
| 245 |
-
st.markdown("---")
|
| 246 |
-
|
| 247 |
-
documents = st.session_state.uploaded_documents.get('documents', [])
|
| 248 |
-
|
| 249 |
-
if not documents:
|
| 250 |
-
st.info("You haven't uploaded any documents yet.")
|
| 251 |
-
return
|
| 252 |
-
|
| 253 |
-
# Search functionality
|
| 254 |
-
search_term = st.text_input("π Search documents", placeholder="Enter filename or content...")
|
| 255 |
-
|
| 256 |
-
# Filter documents based on search
|
| 257 |
-
filtered_docs = documents
|
| 258 |
-
if search_term:
|
| 259 |
-
filtered_docs = [
|
| 260 |
-
doc for doc in documents
|
| 261 |
-
if search_term.lower() in doc['filename'].lower() or
|
| 262 |
-
search_term.lower() in doc.get('content', '').lower()
|
| 263 |
-
]
|
| 264 |
-
|
| 265 |
-
if not filtered_docs:
|
| 266 |
-
st.warning("No documents match your search criteria.")
|
| 267 |
-
return
|
| 268 |
-
|
| 269 |
-
# Display documents
|
| 270 |
-
for i, doc in enumerate(filtered_docs):
|
| 271 |
-
with st.container():
|
| 272 |
-
col1, col2, col3, col4 = st.columns([3, 2, 1, 1])
|
| 273 |
-
|
| 274 |
-
with col1:
|
| 275 |
-
st.write(f"**{doc['filename']}**")
|
| 276 |
-
|
| 277 |
-
with col2:
|
| 278 |
-
st.write(doc['upload_time'])
|
| 279 |
-
|
| 280 |
-
with col3:
|
| 281 |
-
st.write(f"{doc['file_type']}")
|
| 282 |
-
|
| 283 |
-
with col4:
|
| 284 |
-
if st.button(f"View {i}", key=f"view_{i}"):
|
| 285 |
-
st.subheader(f"π {doc['filename']}")
|
| 286 |
-
st.write(f"**Uploaded:** {doc['upload_time']}")
|
| 287 |
-
st.write(f"**Size:** {doc['size']} bytes")
|
| 288 |
-
|
| 289 |
-
# Check if we have a temporary file path for better content extraction
|
| 290 |
-
if doc.get('temp_path') and os.path.exists(doc['temp_path']):
|
| 291 |
-
try:
|
| 292 |
-
# Extract fresh content from temporary file
|
| 293 |
-
fresh_content = extract_pdf_text_from_temp(doc['temp_path'])
|
| 294 |
-
if fresh_content.strip():
|
| 295 |
-
st.text_area("Document Content (Fresh Extract)", fresh_content, height=400, key=f"fresh_content_{i}")
|
| 296 |
-
else:
|
| 297 |
-
# Fall back to stored content
|
| 298 |
-
if 'content' in doc and doc['content']:
|
| 299 |
-
st.text_area("Document Content (Stored)", doc['content'], height=400, key=f"content_{i}")
|
| 300 |
-
except Exception as e:
|
| 301 |
-
st.warning(f"Could not read from temporary file: {str(e)}")
|
| 302 |
-
# Fall back to stored content
|
| 303 |
-
if 'content' in doc and doc['content']:
|
| 304 |
-
st.text_area("Document Content (Stored)", doc['content'], height=400, key=f"content_{i}")
|
| 305 |
-
else:
|
| 306 |
-
# Display stored content
|
| 307 |
-
if 'content' in doc and doc['content']:
|
| 308 |
-
st.text_area("Document Content", doc['content'], height=400, key=f"content_{i}")
|
| 309 |
-
|
| 310 |
-
st.markdown("---")
|
| 311 |
-
|
| 312 |
-
def show_document_library():
|
| 313 |
-
"""Show all documents in the system"""
|
| 314 |
-
st.title("π Document Library")
|
| 315 |
-
st.markdown("---")
|
| 316 |
-
|
| 317 |
-
documents = st.session_state.uploaded_documents.get('documents', [])
|
| 318 |
-
|
| 319 |
-
if not documents:
|
| 320 |
-
st.info("No documents have been uploaded to the system yet.")
|
| 321 |
-
return
|
| 322 |
-
|
| 323 |
-
# Search functionality
|
| 324 |
-
search_term = st.text_input("π Search all documents", placeholder="Enter filename or content...")
|
| 325 |
-
|
| 326 |
-
# Filter documents based on search
|
| 327 |
-
filtered_docs = documents
|
| 328 |
-
if search_term:
|
| 329 |
-
filtered_docs = [
|
| 330 |
-
doc for doc in documents
|
| 331 |
-
if search_term.lower() in doc['filename'].lower() or
|
| 332 |
-
search_term.lower() in doc.get('content', '').lower()
|
| 333 |
-
]
|
| 334 |
-
|
| 335 |
-
if not filtered_docs:
|
| 336 |
-
st.warning("No documents match your search criteria.")
|
| 337 |
-
return
|
| 338 |
-
|
| 339 |
-
# Display documents
|
| 340 |
-
for i, doc in enumerate(filtered_docs):
|
| 341 |
-
with st.container():
|
| 342 |
-
col1, col2, col3, col4 = st.columns([3, 2, 1, 1])
|
| 343 |
-
|
| 344 |
-
with col1:
|
| 345 |
-
st.write(f"**{doc['filename']}**")
|
| 346 |
-
|
| 347 |
-
with col2:
|
| 348 |
-
st.write(doc['upload_time'])
|
| 349 |
-
|
| 350 |
-
with col3:
|
| 351 |
-
st.write(f"{doc['file_type']}")
|
| 352 |
-
|
| 353 |
-
with col4:
|
| 354 |
-
if st.button(f"View {i}", key=f"lib_view_{i}"):
|
| 355 |
-
st.subheader(f"π {doc['filename']}")
|
| 356 |
-
st.write(f"**Uploaded:** {doc['upload_time']}")
|
| 357 |
-
st.write(f"**Size:** {doc['size']} bytes")
|
| 358 |
-
|
| 359 |
-
# Check if we have a temporary file path for better content extraction
|
| 360 |
-
if doc.get('temp_path') and os.path.exists(doc['temp_path']):
|
| 361 |
-
try:
|
| 362 |
-
# Extract fresh content from temporary file
|
| 363 |
-
fresh_content = extract_pdf_text_from_temp(doc['temp_path'])
|
| 364 |
-
if fresh_content.strip():
|
| 365 |
-
st.text_area("Document Content (Fresh Extract)", fresh_content, height=400, key=f"lib_fresh_content_{i}")
|
| 366 |
-
else:
|
| 367 |
-
# Fall back to stored content
|
| 368 |
-
if 'content' in doc and doc['content']:
|
| 369 |
-
st.text_area("Document Content (Stored)", doc['content'], height=400, key=f"lib_content_{i}")
|
| 370 |
-
except Exception as e:
|
| 371 |
-
st.warning(f"Could not read from temporary file: {str(e)}")
|
| 372 |
-
# Fall back to stored content
|
| 373 |
-
if 'content' in doc and doc['content']:
|
| 374 |
-
st.text_area("Document Content (Stored)", doc['content'], height=400, key=f"lib_content_{i}")
|
| 375 |
-
else:
|
| 376 |
-
# Display stored content
|
| 377 |
-
if 'content' in doc and doc['content']:
|
| 378 |
-
st.text_area("Document Content", doc['content'], height=400, key=f"lib_content_{i}")
|
| 379 |
-
|
| 380 |
-
st.markdown("---")
|
| 381 |
-
|
| 382 |
-
def show_settings():
|
| 383 |
-
"""Show user settings"""
|
| 384 |
-
st.title("βοΈ Settings")
|
| 385 |
-
st.markdown("---")
|
| 386 |
-
|
| 387 |
-
st.subheader("π§ System Information")
|
| 388 |
-
st.write("**Version:** Dev LMS v1.0")
|
| 389 |
-
st.write("**Features:**")
|
| 390 |
-
st.write("- PDF document upload with temporary storage")
|
| 391 |
-
st.write("- Document search and preview")
|
| 392 |
-
st.write("- Document library")
|
| 393 |
-
st.write("- Session-based storage")
|
| 394 |
-
|
| 395 |
-
st.markdown("---")
|
| 396 |
-
|
| 397 |
-
# Export data option
|
| 398 |
-
if st.button("π₯ Export All Data"):
|
| 399 |
-
documents = st.session_state.uploaded_documents.get('documents', [])
|
| 400 |
-
if documents:
|
| 401 |
-
# Create JSON export
|
| 402 |
-
export_data = {
|
| 403 |
-
'export_date': datetime.now().isoformat(),
|
| 404 |
-
'documents': documents
|
| 405 |
-
}
|
| 406 |
-
|
| 407 |
-
st.download_button(
|
| 408 |
-
label="Download JSON Export",
|
| 409 |
-
data=json.dumps(export_data, indent=2),
|
| 410 |
-
file_name=f"lms_data_export.json",
|
| 411 |
-
mime="application/json"
|
| 412 |
-
)
|
| 413 |
-
else:
|
| 414 |
-
st.info("No data to export.")
|
| 415 |
-
|
| 416 |
-
st.markdown("---")
|
| 417 |
-
|
| 418 |
-
# Clear data option
|
| 419 |
-
if st.button("ποΈ Clear All Data"):
|
| 420 |
-
if st.session_state.uploaded_documents.get('documents'):
|
| 421 |
-
# Clean up temporary files before clearing data
|
| 422 |
-
documents = st.session_state.uploaded_documents['documents']
|
| 423 |
-
for doc in documents:
|
| 424 |
-
if doc.get('temp_path'):
|
| 425 |
-
cleanup_temp_file(doc['temp_path'])
|
| 426 |
-
|
| 427 |
-
st.session_state.uploaded_documents['documents'] = []
|
| 428 |
-
st.success("All documents and temporary files have been cleared!")
|
| 429 |
-
st.rerun()
|
| 430 |
-
else:
|
| 431 |
-
st.info("No documents to clear.")
|
| 432 |
-
|
| 433 |
-
st.markdown("---")
|
| 434 |
-
|
| 435 |
-
# Cleanup temporary files option
|
| 436 |
-
if st.button("π§Ή Cleanup Temporary Files"):
|
| 437 |
-
documents = st.session_state.uploaded_documents.get('documents', [])
|
| 438 |
-
cleaned_count = 0
|
| 439 |
-
|
| 440 |
-
for doc in documents:
|
| 441 |
-
if doc.get('temp_path') and not os.path.exists(doc['temp_path']):
|
| 442 |
-
# Remove temp_path reference if file doesn't exist
|
| 443 |
-
doc.pop('temp_path', None)
|
| 444 |
-
cleaned_count += 1
|
| 445 |
-
|
| 446 |
-
if cleaned_count > 0:
|
| 447 |
-
st.success(f"Cleaned up {cleaned_count} missing temporary file references!")
|
| 448 |
-
else:
|
| 449 |
-
st.info("No cleanup needed - all temporary files are properly managed.")
|
| 450 |
-
|
| 451 |
-
st.markdown("---")
|
| 452 |
-
|
| 453 |
-
# System status
|
| 454 |
-
st.subheader("π System Status")
|
| 455 |
-
documents = st.session_state.uploaded_documents.get('documents', [])
|
| 456 |
-
temp_files_count = sum(1 for doc in documents if doc.get('temp_path') and os.path.exists(doc['temp_path']))
|
| 457 |
-
|
| 458 |
-
col1, col2 = st.columns(2)
|
| 459 |
-
with col1:
|
| 460 |
-
st.metric("Total Documents", len(documents))
|
| 461 |
-
with col2:
|
| 462 |
-
st.metric("Active Temp Files", temp_files_count)
|
| 463 |
-
|
| 464 |
-
if __name__ == "__main__":
|
| 465 |
-
main()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/views/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
# Pages package for Debate Class LMS
|
src/views/assignments.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
|
| 3 |
+
def show_assignments():
|
| 4 |
+
"""Show assignments page"""
|
| 5 |
+
st.title("π Assignments")
|
| 6 |
+
st.markdown("---")
|
| 7 |
+
|
| 8 |
+
st.markdown("""
|
| 9 |
+
## Current Assignments
|
| 10 |
+
""")
|
| 11 |
+
|
| 12 |
+
# Assignment 1
|
| 13 |
+
with st.expander("Assignment 1: Debate Format Research (Due: End of Week 1)", expanded=True):
|
| 14 |
+
st.markdown("""
|
| 15 |
+
**Objective**: Research and present on different debate formats
|
| 16 |
+
|
| 17 |
+
**Instructions**:
|
| 18 |
+
1. Choose one debate format (Policy, LD, Public Forum, or Parliamentary)
|
| 19 |
+
2. Research its rules, structure, and unique characteristics
|
| 20 |
+
3. Prepare a 2-minute presentation explaining your chosen format
|
| 21 |
+
4. Submit your findings
|
| 22 |
+
|
| 23 |
+
**Grading Criteria**:
|
| 24 |
+
- Accuracy of information (40%)
|
| 25 |
+
- Clarity of presentation (30%)
|
| 26 |
+
- Depth of research (30%)
|
| 27 |
+
|
| 28 |
+
**Submission**: Upload your presentation or written report below
|
| 29 |
+
""")
|
| 30 |
+
|
| 31 |
+
uploaded_file = st.file_uploader(
|
| 32 |
+
"Upload your assignment",
|
| 33 |
+
type=['pdf', 'docx', 'txt'],
|
| 34 |
+
key="assignment1"
|
| 35 |
+
)
|
| 36 |
+
|
| 37 |
+
if uploaded_file is not None:
|
| 38 |
+
st.success(f"File uploaded: {uploaded_file.name}")
|
| 39 |
+
if st.button("Submit Assignment 1"):
|
| 40 |
+
st.success("Assignment submitted successfully!")
|
| 41 |
+
|
| 42 |
+
# Assignment 2
|
| 43 |
+
with st.expander("Assignment 2: Argument Analysis (Due: End of Week 1)"):
|
| 44 |
+
st.markdown("""
|
| 45 |
+
**Objective**: Practice identifying argument structure
|
| 46 |
+
|
| 47 |
+
**Instructions**:
|
| 48 |
+
1. Find a recent news article or opinion piece
|
| 49 |
+
2. Identify the main argument and supporting evidence
|
| 50 |
+
3. Analyze the strength of the argument
|
| 51 |
+
4. Write a 1-page analysis
|
| 52 |
+
|
| 53 |
+
**Grading Criteria**:
|
| 54 |
+
- Accurate identification of argument structure (50%)
|
| 55 |
+
- Quality of analysis (30%)
|
| 56 |
+
- Writing clarity (20%)
|
| 57 |
+
|
| 58 |
+
**Submission**: Upload your analysis below
|
| 59 |
+
""")
|
| 60 |
+
|
| 61 |
+
uploaded_file = st.file_uploader(
|
| 62 |
+
"Upload your assignment",
|
| 63 |
+
type=['pdf', 'docx', 'txt'],
|
| 64 |
+
key="assignment2"
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
if uploaded_file is not None:
|
| 68 |
+
st.success(f"File uploaded: {uploaded_file.name}")
|
| 69 |
+
if st.button("Submit Assignment 2"):
|
| 70 |
+
st.success("Assignment submitted successfully!")
|
src/views/dashboard.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
|
| 3 |
+
def show_dashboard():
|
| 4 |
+
"""Show the main dashboard"""
|
| 5 |
+
st.title("π Debate Class Dashboard")
|
| 6 |
+
st.markdown("---")
|
| 7 |
+
|
| 8 |
+
# Welcome message
|
| 9 |
+
st.markdown(f"### Welcome back, {st.session_state.name}!")
|
| 10 |
+
st.markdown("This is your central hub for all debate class activities and materials.")
|
| 11 |
+
|
| 12 |
+
# Course overview
|
| 13 |
+
col1, col2, col3 = st.columns(3)
|
| 14 |
+
|
| 15 |
+
with col1:
|
| 16 |
+
st.metric(
|
| 17 |
+
label="Current Week",
|
| 18 |
+
value="Week 1",
|
| 19 |
+
delta="Just Started"
|
| 20 |
+
)
|
| 21 |
+
|
| 22 |
+
with col2:
|
| 23 |
+
st.metric(
|
| 24 |
+
label="Assignments Due",
|
| 25 |
+
value="2",
|
| 26 |
+
delta="This Week"
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
with col3:
|
| 30 |
+
st.metric(
|
| 31 |
+
label="Class Progress",
|
| 32 |
+
value="25%",
|
| 33 |
+
delta="+25%"
|
| 34 |
+
)
|
| 35 |
+
|
| 36 |
+
st.markdown("---")
|
| 37 |
+
|
| 38 |
+
# Quick access to current week
|
| 39 |
+
st.subheader("π― This Week's Focus")
|
| 40 |
+
with st.container():
|
| 41 |
+
st.markdown("""
|
| 42 |
+
**Week 1: Introduction to Debate**
|
| 43 |
+
- Understanding debate formats
|
| 44 |
+
- Basic argument structure
|
| 45 |
+
- Public speaking fundamentals
|
| 46 |
+
""")
|
| 47 |
+
|
| 48 |
+
if st.button("Go to Week 1 Content", type="primary"):
|
| 49 |
+
st.rerun()
|
| 50 |
+
|
| 51 |
+
st.markdown("---")
|
| 52 |
+
|
| 53 |
+
# Recent announcements
|
| 54 |
+
st.subheader("π’ Recent Announcements")
|
| 55 |
+
announcements = [
|
| 56 |
+
{
|
| 57 |
+
"title": "Welcome to Debate Class!",
|
| 58 |
+
"date": "2024-01-15",
|
| 59 |
+
"content": "Welcome everyone! We're excited to begin our journey into the world of competitive debate."
|
| 60 |
+
},
|
| 61 |
+
{
|
| 62 |
+
"title": "First Assignment Posted",
|
| 63 |
+
"date": "2024-01-16",
|
| 64 |
+
"content": "Your first assignment is now available in the Assignments section."
|
| 65 |
+
}
|
| 66 |
+
]
|
| 67 |
+
|
| 68 |
+
for announcement in announcements:
|
| 69 |
+
with st.expander(f"{announcement['title']} - {announcement['date']}"):
|
| 70 |
+
st.write(announcement['content'])
|
src/views/future_weeks.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
|
| 3 |
+
def show_week2_content():
|
| 4 |
+
"""Show Week 2 content"""
|
| 5 |
+
st.title("π Week 2: Argument Structure")
|
| 6 |
+
st.markdown("---")
|
| 7 |
+
|
| 8 |
+
st.markdown("""
|
| 9 |
+
## π― Learning Objectives
|
| 10 |
+
- Understand the components of a strong argument
|
| 11 |
+
- Learn how to construct logical arguments
|
| 12 |
+
- Practice identifying logical fallacies
|
| 13 |
+
- Develop argument mapping skills
|
| 14 |
+
""")
|
| 15 |
+
|
| 16 |
+
st.info("π§ Week 2 content is coming soon! This section will be available next week.")
|
| 17 |
+
|
| 18 |
+
def show_week3_content():
|
| 19 |
+
"""Show Week 3 content"""
|
| 20 |
+
st.title("π Week 3: Evidence & Research")
|
| 21 |
+
st.markdown("---")
|
| 22 |
+
|
| 23 |
+
st.markdown("""
|
| 24 |
+
## π― Learning Objectives
|
| 25 |
+
- Learn effective research strategies
|
| 26 |
+
- Understand how to evaluate evidence quality
|
| 27 |
+
- Practice citing sources properly
|
| 28 |
+
- Develop evidence organization skills
|
| 29 |
+
""")
|
| 30 |
+
|
| 31 |
+
st.info("π§ Week 3 content is coming soon! This section will be available in two weeks.")
|
| 32 |
+
|
| 33 |
+
def show_week4_content():
|
| 34 |
+
"""Show Week 4 content"""
|
| 35 |
+
st.title("π Week 4: Rebuttal Techniques")
|
| 36 |
+
st.markdown("---")
|
| 37 |
+
|
| 38 |
+
st.markdown("""
|
| 39 |
+
## π― Learning Objectives
|
| 40 |
+
- Master effective rebuttal strategies
|
| 41 |
+
- Learn how to identify and attack opponent arguments
|
| 42 |
+
- Practice defensive argumentation
|
| 43 |
+
- Develop quick thinking skills
|
| 44 |
+
""")
|
| 45 |
+
|
| 46 |
+
st.info("π§ Week 4 content is coming soon! This section will be available in three weeks.")
|
src/views/resources.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
|
| 3 |
+
def show_resources():
|
| 4 |
+
"""Show resources page"""
|
| 5 |
+
st.title("π Resources")
|
| 6 |
+
st.markdown("---")
|
| 7 |
+
|
| 8 |
+
st.markdown("""
|
| 9 |
+
## π Recommended Reading
|
| 10 |
+
|
| 11 |
+
### Books
|
| 12 |
+
- "The Art of Debate" by Gary Rybold
|
| 13 |
+
- "Thank You for Arguing" by Jay Heinrichs
|
| 14 |
+
- "The Debater's Guide" by Jon M. Ericson
|
| 15 |
+
|
| 16 |
+
### Online Resources
|
| 17 |
+
- [National Speech & Debate Association](https://www.speechanddebate.org/)
|
| 18 |
+
- [Debate Central](http://debate-central.ncpa.org/)
|
| 19 |
+
- [International Debate Education Association](https://idebate.org/)
|
| 20 |
+
|
| 21 |
+
## π₯ Video Resources
|
| 22 |
+
|
| 23 |
+
### YouTube Channels
|
| 24 |
+
- [Debate Central](https://www.youtube.com/user/DebateCentral)
|
| 25 |
+
- [NSDA](https://www.youtube.com/user/NationalSpeech)
|
| 26 |
+
|
| 27 |
+
## π Templates and Tools
|
| 28 |
+
|
| 29 |
+
### Debate Templates
|
| 30 |
+
- [Policy Debate Template](link)
|
| 31 |
+
- [Lincoln-Douglas Template](link)
|
| 32 |
+
- [Public Forum Template](link)
|
| 33 |
+
|
| 34 |
+
### Research Tools
|
| 35 |
+
- [Google Scholar](https://scholar.google.com/)
|
| 36 |
+
- [JSTOR](https://www.jstor.org/)
|
| 37 |
+
- [ProQuest](https://www.proquest.com/)
|
| 38 |
+
""")
|
src/views/week1.py
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
|
| 3 |
+
def show_week1_content():
|
| 4 |
+
"""Show Week 1 content"""
|
| 5 |
+
st.title("π Week 1: Introduction to Debate")
|
| 6 |
+
st.markdown("---")
|
| 7 |
+
|
| 8 |
+
# Week overview
|
| 9 |
+
st.markdown("""
|
| 10 |
+
## π― Learning Objectives
|
| 11 |
+
By the end of this week, you will be able to:
|
| 12 |
+
- Understand different debate formats and their rules
|
| 13 |
+
- Identify the basic structure of arguments
|
| 14 |
+
- Practice fundamental public speaking skills
|
| 15 |
+
- Recognize the importance of evidence in debate
|
| 16 |
+
""")
|
| 17 |
+
|
| 18 |
+
# Content tabs
|
| 19 |
+
tab1, tab2, tab3, tab4 = st.tabs(["π Lecture Materials", "π₯ Videos", "π Activities", "π Quiz"])
|
| 20 |
+
|
| 21 |
+
with tab1:
|
| 22 |
+
st.subheader("π Lecture Materials")
|
| 23 |
+
|
| 24 |
+
st.markdown("""
|
| 25 |
+
### What is Debate?
|
| 26 |
+
|
| 27 |
+
Debate is a formal discussion or argument about a specific topic. It involves presenting arguments
|
| 28 |
+
for and against a proposition, with the goal of persuading an audience or judge.
|
| 29 |
+
|
| 30 |
+
### Types of Debate Formats
|
| 31 |
+
|
| 32 |
+
1. **Policy Debate**: Focuses on policy proposals and their implementation
|
| 33 |
+
2. **Lincoln-Douglas Debate**: One-on-one debate about values and philosophy
|
| 34 |
+
3. **Public Forum Debate**: Team debate designed for public audiences
|
| 35 |
+
4. **Parliamentary Debate**: British-style debate with impromptu topics
|
| 36 |
+
|
| 37 |
+
### Basic Debate Structure
|
| 38 |
+
|
| 39 |
+
Every debate follows a basic structure:
|
| 40 |
+
- **Opening Statements**: Present your position and main arguments
|
| 41 |
+
- **Rebuttal**: Respond to your opponent's arguments
|
| 42 |
+
- **Closing Statements**: Summarize your position and why you should win
|
| 43 |
+
|
| 44 |
+
### The Role of Evidence
|
| 45 |
+
|
| 46 |
+
Evidence is crucial in debate. It includes:
|
| 47 |
+
- Statistics and data
|
| 48 |
+
- Expert testimony
|
| 49 |
+
- Historical examples
|
| 50 |
+
- Current events
|
| 51 |
+
- Research studies
|
| 52 |
+
""")
|
| 53 |
+
|
| 54 |
+
with tab2:
|
| 55 |
+
st.subheader("π₯ Video Resources")
|
| 56 |
+
|
| 57 |
+
st.markdown("""
|
| 58 |
+
### Introduction to Debate (15 minutes)
|
| 59 |
+
*Watch this video for an overview of debate fundamentals*
|
| 60 |
+
|
| 61 |
+
[Video placeholder - would link to actual video content]
|
| 62 |
+
|
| 63 |
+
### Public Speaking Basics (10 minutes)
|
| 64 |
+
*Essential tips for effective public speaking*
|
| 65 |
+
|
| 66 |
+
[Video placeholder - would link to actual video content]
|
| 67 |
+
|
| 68 |
+
### Sample Debate Round (20 minutes)
|
| 69 |
+
*Watch a complete debate round to see these concepts in action*
|
| 70 |
+
|
| 71 |
+
[Video placeholder - would link to actual video content]
|
| 72 |
+
""")
|
| 73 |
+
|
| 74 |
+
with tab3:
|
| 75 |
+
st.subheader("π Activities")
|
| 76 |
+
|
| 77 |
+
st.markdown("""
|
| 78 |
+
### Activity 1: Debate Format Research
|
| 79 |
+
|
| 80 |
+
**Objective**: Research and present on different debate formats
|
| 81 |
+
|
| 82 |
+
**Instructions**:
|
| 83 |
+
1. Choose one debate format (Policy, LD, Public Forum, or Parliamentary)
|
| 84 |
+
2. Research its rules, structure, and unique characteristics
|
| 85 |
+
3. Prepare a 2-minute presentation explaining your chosen format
|
| 86 |
+
4. Submit your findings in the assignment section
|
| 87 |
+
|
| 88 |
+
**Due Date**: End of Week 1
|
| 89 |
+
|
| 90 |
+
---
|
| 91 |
+
|
| 92 |
+
### Activity 2: Argument Analysis
|
| 93 |
+
|
| 94 |
+
**Objective**: Practice identifying argument structure
|
| 95 |
+
|
| 96 |
+
**Instructions**:
|
| 97 |
+
1. Find a recent news article or opinion piece
|
| 98 |
+
2. Identify the main argument and supporting evidence
|
| 99 |
+
3. Analyze the strength of the argument
|
| 100 |
+
4. Write a 1-page analysis
|
| 101 |
+
|
| 102 |
+
**Due Date**: End of Week 1
|
| 103 |
+
""")
|
| 104 |
+
|
| 105 |
+
with tab4:
|
| 106 |
+
st.subheader("π Week 1 Quiz")
|
| 107 |
+
|
| 108 |
+
st.markdown("""
|
| 109 |
+
### Test Your Knowledge
|
| 110 |
+
|
| 111 |
+
Complete this quiz to check your understanding of Week 1 materials.
|
| 112 |
+
""")
|
| 113 |
+
|
| 114 |
+
# Quiz questions
|
| 115 |
+
q1 = st.radio(
|
| 116 |
+
"1. Which debate format focuses on policy proposals and their implementation?",
|
| 117 |
+
["Lincoln-Douglas Debate", "Policy Debate", "Public Forum Debate", "Parliamentary Debate"]
|
| 118 |
+
)
|
| 119 |
+
|
| 120 |
+
q2 = st.radio(
|
| 121 |
+
"2. What is the first step in a basic debate structure?",
|
| 122 |
+
["Rebuttal", "Opening Statements", "Closing Statements", "Evidence Presentation"]
|
| 123 |
+
)
|
| 124 |
+
|
| 125 |
+
q3 = st.multiselect(
|
| 126 |
+
"3. Which of the following are types of evidence used in debate? (Select all that apply)",
|
| 127 |
+
["Statistics and data", "Personal opinions", "Expert testimony", "Historical examples", "Fictional stories"]
|
| 128 |
+
)
|
| 129 |
+
|
| 130 |
+
if st.button("Submit Quiz"):
|
| 131 |
+
# Simple scoring
|
| 132 |
+
score = 0
|
| 133 |
+
if q1 == "Policy Debate":
|
| 134 |
+
score += 1
|
| 135 |
+
if q2 == "Opening Statements":
|
| 136 |
+
score += 1
|
| 137 |
+
if set(q3) == {"Statistics and data", "Expert testimony", "Historical examples"}:
|
| 138 |
+
score += 1
|
| 139 |
+
|
| 140 |
+
st.success(f"Quiz completed! Your score: {score}/3")
|
| 141 |
+
if score == 3:
|
| 142 |
+
st.balloons()
|