aboalaa1472 commited on
Commit
f42bf2c
Β·
verified Β·
1 Parent(s): a6bc748

Upload 2 files

Browse files
Files changed (2) hide show
  1. requirements_txt (1).txt +5 -0
  2. study_schedule_app.py +381 -0
requirements_txt (1).txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ gradio>=4.0.0
2
+ pandas>=1.5.0
3
+ reportlab>=4.0.0
4
+ Pillow>=9.0.0
5
+ datetime
study_schedule_app.py ADDED
@@ -0,0 +1,381 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ from datetime import datetime, timedelta
4
+ from reportlab.lib.pagesizes import letter, A4
5
+ from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer, Image
6
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
7
+ from reportlab.lib.units import inch
8
+ from reportlab.lib import colors
9
+ from reportlab.lib.enums import TA_CENTER, TA_LEFT
10
+ import io
11
+ import os
12
+ from PIL import Image as PILImage
13
+
14
+ def generate_schedule(start_date, end_date, off_days, num_lessons, logo_file=None):
15
+ """
16
+ Generate study schedule based on user inputs
17
+ """
18
+ try:
19
+ # Convert string dates to datetime objects
20
+ start = datetime.strptime(start_date, "%Y-%m-%d")
21
+ end = datetime.strptime(end_date, "%Y-%m-%d")
22
+
23
+ # Validate date range
24
+ if start >= end:
25
+ return "❌ Error: Start date must be before end date!", None, None
26
+
27
+ # Convert off_days to weekday numbers (Monday=0, Sunday=6)
28
+ day_mapping = {
29
+ "Monday": 0, "Tuesday": 1, "Wednesday": 2, "Thursday": 3,
30
+ "Friday": 4, "Saturday": 5, "Sunday": 6
31
+ }
32
+ off_weekdays = [day_mapping[day] for day in off_days]
33
+
34
+ # Generate all valid study dates
35
+ valid_dates = []
36
+ current_date = start
37
+
38
+ while current_date <= end:
39
+ if current_date.weekday() not in off_weekdays:
40
+ valid_dates.append(current_date)
41
+ current_date += timedelta(days=1)
42
+
43
+ if not valid_dates:
44
+ return "❌ Error: No valid study days found in the selected range!", None, None
45
+
46
+ if len(valid_dates) < num_lessons:
47
+ return f"❌ Error: Not enough study days ({len(valid_dates)}) for {num_lessons} lessons. Please extend your date range or reduce off-days.", None, None
48
+
49
+ # Distribute lessons across available days
50
+ schedule_data = []
51
+ lessons_per_day = [1] * len(valid_dates)
52
+
53
+ # If we have fewer days than lessons, distribute extra lessons
54
+ if len(valid_dates) < num_lessons:
55
+ extra_lessons = num_lessons - len(valid_dates)
56
+ for i in range(extra_lessons):
57
+ lessons_per_day[i % len(valid_dates)] += 1
58
+
59
+ # Create schedule
60
+ lesson_counter = 1
61
+ for i, date in enumerate(valid_dates):
62
+ if lesson_counter > num_lessons:
63
+ break
64
+
65
+ for _ in range(lessons_per_day[i]):
66
+ if lesson_counter <= num_lessons:
67
+ schedule_data.append({
68
+ "Date": date.strftime("%Y-%m-%d"),
69
+ "Day": date.strftime("%A"),
70
+ "Session": f"Session {lesson_counter}"
71
+ })
72
+ lesson_counter += 1
73
+
74
+ # Create DataFrame for display
75
+ df = pd.DataFrame(schedule_data)
76
+
77
+ # Generate summary
78
+ total_days = len(valid_dates)
79
+ total_weeks = (end - start).days // 7 + 1
80
+ summary = f"""
81
+ πŸ“Š **Schedule Summary:**
82
+ β€’ Total Lessons: {num_lessons}
83
+ β€’ Study Period: {start_date} to {end_date}
84
+ β€’ Available Study Days: {total_days}
85
+ β€’ Estimated Duration: ~{total_weeks} weeks
86
+ β€’ Off Days: {', '.join(off_days) if off_days else 'None'}
87
+ """
88
+
89
+ return summary, df, schedule_data
90
+
91
+ except ValueError as e:
92
+ return f"❌ Error: Invalid date format. Please use YYYY-MM-DD format.", None, None
93
+ except Exception as e:
94
+ return f"❌ Error: {str(e)}", None, None
95
+
96
+ def create_pdf(schedule_data, start_date, end_date, off_days, num_lessons, logo_file=None):
97
+ """
98
+ Create PDF from schedule data
99
+ """
100
+ try:
101
+ # Create a bytes buffer for the PDF
102
+ buffer = io.BytesIO()
103
+
104
+ # Create PDF document
105
+ doc = SimpleDocTemplate(buffer, pagesize=A4, rightMargin=72, leftMargin=72,
106
+ topMargin=72, bottomMargin=18)
107
+
108
+ # Container for the 'Flowable' objects
109
+ elements = []
110
+
111
+ # Define styles
112
+ styles = getSampleStyleSheet()
113
+ title_style = ParagraphStyle(
114
+ 'CustomTitle',
115
+ parent=styles['Heading1'],
116
+ fontSize=24,
117
+ spaceAfter=30,
118
+ alignment=TA_CENTER,
119
+ textColor=colors.HexColor('#2E86AB')
120
+ )
121
+
122
+ subtitle_style = ParagraphStyle(
123
+ 'CustomSubtitle',
124
+ parent=styles['Normal'],
125
+ fontSize=12,
126
+ spaceAfter=20,
127
+ alignment=TA_CENTER,
128
+ textColor=colors.HexColor('#666666')
129
+ )
130
+
131
+ # Add logo if provided
132
+ if logo_file is not None:
133
+ try:
134
+ # Save uploaded file temporarily
135
+ logo_path = "temp_logo.png"
136
+ with open(logo_path, "wb") as f:
137
+ f.write(logo_file)
138
+
139
+ # Add logo to PDF
140
+ logo = Image(logo_path, width=2*inch, height=1*inch)
141
+ logo.hAlign = 'CENTER'
142
+ elements.append(logo)
143
+ elements.append(Spacer(1, 20))
144
+
145
+ # Clean up temp file
146
+ os.remove(logo_path)
147
+ except:
148
+ pass # Skip logo if there's an error
149
+
150
+ # Add title
151
+ title = Paragraph("πŸ“š Study Schedule", title_style)
152
+ elements.append(title)
153
+
154
+ # Add subtitle with details
155
+ subtitle_text = f"""
156
+ Study Period: {start_date} to {end_date}<br/>
157
+ Total Lessons: {num_lessons}<br/>
158
+ Off Days: {', '.join(off_days) if off_days else 'None'}
159
+ """
160
+ subtitle = Paragraph(subtitle_text, subtitle_style)
161
+ elements.append(subtitle)
162
+ elements.append(Spacer(1, 30))
163
+
164
+ # Create table data
165
+ table_data = [['Date', 'Day', 'Session']] # Header
166
+ for item in schedule_data:
167
+ table_data.append([item['Date'], item['Day'], item['Session']])
168
+
169
+ # Create table
170
+ table = Table(table_data, colWidths=[2*inch, 1.5*inch, 2*inch])
171
+
172
+ # Style the table
173
+ table.setStyle(TableStyle([
174
+ # Header styling
175
+ ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#2E86AB')),
176
+ ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
177
+ ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
178
+ ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
179
+ ('FONTSIZE', (0, 0), (-1, 0), 12),
180
+
181
+ # Body styling
182
+ ('BACKGROUND', (0, 1), (-1, -1), colors.beige),
183
+ ('TEXTCOLOR', (0, 1), (-1, -1), colors.black),
184
+ ('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
185
+ ('FONTSIZE', (0, 1), (-1, -1), 10),
186
+
187
+ # Grid and borders
188
+ ('GRID', (0, 0), (-1, -1), 1, colors.black),
189
+ ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
190
+
191
+ # Alternating row colors
192
+ ('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.HexColor('#F5F5F5')])
193
+ ]))
194
+
195
+ elements.append(table)
196
+
197
+ # Build PDF
198
+ doc.build(elements)
199
+
200
+ # Get the value of the BytesIO buffer
201
+ pdf_data = buffer.getvalue()
202
+ buffer.close()
203
+
204
+ return pdf_data
205
+
206
+ except Exception as e:
207
+ print(f"PDF creation error: {str(e)}")
208
+ return None
209
+
210
+ def create_csv(schedule_data):
211
+ """
212
+ Create CSV from schedule data
213
+ """
214
+ try:
215
+ df = pd.DataFrame(schedule_data)
216
+ csv_buffer = io.StringIO()
217
+ df.to_csv(csv_buffer, index=False)
218
+ return csv_buffer.getvalue()
219
+ except Exception as e:
220
+ print(f"CSV creation error: {str(e)}")
221
+ return None
222
+
223
+ def process_schedule(start_date, end_date, off_days, num_lessons, logo_file):
224
+ """
225
+ Main processing function for Gradio interface
226
+ """
227
+ # Generate schedule
228
+ summary, df, schedule_data = generate_schedule(start_date, end_date, off_days, num_lessons, logo_file)
229
+
230
+ if schedule_data is None:
231
+ return summary, None, None, None
232
+
233
+ # Create PDF
234
+ pdf_data = create_pdf(schedule_data, start_date, end_date, off_days, num_lessons, logo_file)
235
+
236
+ # Create CSV
237
+ csv_data = create_csv(schedule_data)
238
+
239
+ # Save files temporarily for download
240
+ pdf_path = None
241
+ csv_path = None
242
+
243
+ if pdf_data:
244
+ pdf_path = "study_schedule.pdf"
245
+ with open(pdf_path, "wb") as f:
246
+ f.write(pdf_data)
247
+
248
+ if csv_data:
249
+ csv_path = "study_schedule.csv"
250
+ with open(csv_path, "w") as f:
251
+ f.write(csv_data)
252
+
253
+ return summary, df, pdf_path, csv_path
254
+
255
+ # Create Gradio interface
256
+ def create_interface():
257
+ with gr.Blocks(
258
+ title="πŸ“š Study Schedule Generator",
259
+ theme=gr.themes.Soft(),
260
+ css="""
261
+ .main-header {
262
+ text-align: center;
263
+ color: #2E86AB;
264
+ margin-bottom: 2rem;
265
+ }
266
+ .info-box {
267
+ background: #f0f9ff;
268
+ padding: 1rem;
269
+ border-radius: 8px;
270
+ border-left: 4px solid #2E86AB;
271
+ margin: 1rem 0;
272
+ }
273
+ """
274
+ ) as demo:
275
+
276
+ gr.Markdown(
277
+ """
278
+ # πŸ“š Study Schedule Generator
279
+
280
+ <div class="info-box">
281
+ <strong>How it works:</strong><br>
282
+ 1. Set your study period (start and end dates)<br>
283
+ 2. Choose your off-days (days you don't want to study)<br>
284
+ 3. Set the number of lessons to schedule<br>
285
+ 4. Optionally upload a logo for your PDF<br>
286
+ 5. Generate your personalized study schedule!
287
+ </div>
288
+ """,
289
+ elem_classes=["main-header"]
290
+ )
291
+
292
+ with gr.Row():
293
+ with gr.Column(scale=1):
294
+ gr.Markdown("### πŸ“… Schedule Settings")
295
+
296
+ start_date = gr.Textbox(
297
+ label="Start Date",
298
+ placeholder="YYYY-MM-DD (e.g., 2025-07-01)",
299
+ value="2025-07-01"
300
+ )
301
+
302
+ end_date = gr.Textbox(
303
+ label="End Date",
304
+ placeholder="YYYY-MM-DD (e.g., 2025-08-30)",
305
+ value="2025-08-30"
306
+ )
307
+
308
+ num_lessons = gr.Slider(
309
+ minimum=1,
310
+ maximum=200,
311
+ value=90,
312
+ step=1,
313
+ label="Number of Lessons"
314
+ )
315
+
316
+ off_days = gr.CheckboxGroup(
317
+ choices=["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
318
+ label="Off Days (Days you don't want to study)",
319
+ value=["Sunday"]
320
+ )
321
+
322
+ logo_file = gr.File(
323
+ label="Upload Logo (Optional)",
324
+ file_types=["image"],
325
+ type="binary"
326
+ )
327
+
328
+ generate_btn = gr.Button("πŸš€ Generate Schedule", variant="primary", size="lg")
329
+
330
+ with gr.Row():
331
+ with gr.Column():
332
+ gr.Markdown("### πŸ“Š Results")
333
+
334
+ summary_output = gr.Markdown()
335
+ schedule_table = gr.Dataframe(
336
+ headers=["Date", "Day", "Session"],
337
+ interactive=False
338
+ )
339
+
340
+ with gr.Row():
341
+ pdf_download = gr.File(label="πŸ“„ Download PDF", visible=False)
342
+ csv_download = gr.File(label="πŸ“Š Download CSV", visible=False)
343
+
344
+ # Event handler
345
+ generate_btn.click(
346
+ fn=process_schedule,
347
+ inputs=[start_date, end_date, off_days, num_lessons, logo_file],
348
+ outputs=[summary_output, schedule_table, pdf_download, csv_download]
349
+ ).then(
350
+ lambda: [gr.update(visible=True), gr.update(visible=True)],
351
+ outputs=[pdf_download, csv_download]
352
+ )
353
+
354
+ # Example section
355
+ gr.Markdown(
356
+ """
357
+ ### πŸ’‘ Tips:
358
+ - **Date Format**: Use YYYY-MM-DD format (e.g., 2025-07-01)
359
+ - **Off Days**: Select days you want to skip (weekends, holidays, etc.)
360
+ - **Lessons**: Adjust the number based on your course requirements
361
+ - **Logo**: Upload PNG, JPG, or other image formats for PDF branding
362
+
363
+ ### 🎯 Example:
364
+ - Start: 2025-07-01, End: 2025-08-30
365
+ - Off Days: Friday, Sunday
366
+ - Lessons: 90
367
+ - This creates a schedule with 1-2 lessons per available day
368
+ """
369
+ )
370
+
371
+ return demo
372
+
373
+ if __name__ == "__main__":
374
+ # Create and launch the interface
375
+ demo = create_interface()
376
+ demo.launch(
377
+ server_name="0.0.0.0",
378
+ server_port=7860,
379
+ share=False,
380
+ debug=False
381
+ )