banao-tech commited on
Commit
279e214
Β·
verified Β·
1 Parent(s): a9138a5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +428 -305
app.py CHANGED
@@ -252,6 +252,15 @@ st.markdown("""
252
  box-shadow: 0 10px 30px rgba(0,0,0,0.5);
253
  border: 1px solid var(--border-color);
254
  }
 
 
 
 
 
 
 
 
 
255
  </style>
256
  """, unsafe_allow_html=True)
257
 
@@ -262,6 +271,102 @@ if 'session_ids' not in st.session_state:
262
  st.session_state.session_ids = []
263
  if 'authenticated' not in st.session_state:
264
  st.session_state.authenticated = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
 
266
  # Authentication check
267
  if not st.session_state.authenticated:
@@ -304,333 +409,351 @@ if not st.session_state.authenticated:
304
  """, unsafe_allow_html=True)
305
  st.stop()
306
 
307
- # Main app header
308
- st.markdown('<h1 class="main-header">πŸ“š Base Course Personalization</h1>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
309
 
310
- # Logout button in top right
311
- col1, col2, col3 = st.columns([2, 1, 1])
312
- with col3:
313
  if st.button("πŸ”“ Logout", key="logout_btn"):
314
  st.session_state.authenticated = False
315
  st.session_state.topics_list = [{"topic_title": "What is Flask", "chapter_title": "Introduction to Flask"}]
316
  st.session_state.session_ids = []
 
317
  st.rerun()
318
 
319
- # Topics Section (Outside form for dynamic interaction)
320
- st.markdown('<div class="section-header">πŸ“‹ Topics Configuration</div>', unsafe_allow_html=True)
 
 
 
 
 
 
321
 
322
- # Display existing topics with better styling
323
- for i, topic in enumerate(st.session_state.topics_list):
324
- st.markdown(f'<div class="topic-container">', unsafe_allow_html=True)
325
- st.markdown(f'<div class="topic-header">πŸ“– Topic {i+1}</div>', unsafe_allow_html=True)
326
-
327
- col1, col2, col3 = st.columns([3, 3, 1])
328
- with col1:
329
- topic_title = st.text_input(
330
- "Topic Title",
331
- value=topic["topic_title"],
332
- key=f"topic_title_{i}",
333
- help="Enter the topic title"
334
- )
335
- st.session_state.topics_list[i]["topic_title"] = topic_title
336
-
337
- with col2:
338
- chapter_title = st.text_input(
339
- "Chapter Title",
340
- value=topic["chapter_title"],
341
- key=f"chapter_title_{i}",
342
- help="Enter the chapter title"
343
- )
344
- st.session_state.topics_list[i]["chapter_title"] = chapter_title
345
-
346
- with col3:
347
- if len(st.session_state.topics_list) > 1:
348
- st.markdown("<br>", unsafe_allow_html=True) # Add spacing
349
- if st.button("πŸ—‘οΈ", key=f"remove_{i}", help="Remove this topic"):
350
- st.session_state.topics_list.pop(i)
351
- st.rerun()
352
-
353
- st.markdown('</div>', unsafe_allow_html=True)
354
-
355
- # Add/Remove topic buttons outside the form
356
- st.markdown('<div class="action-buttons">', unsafe_allow_html=True)
357
- col1, col2, col3, col4 = st.columns([2, 2, 2, 4])
358
- with col1:
359
- if st.button("βž• Add Topic", key="add_topic", help="Add a new topic"):
360
- st.session_state.topics_list.append({
361
- "topic_title": f"Topic {len(st.session_state.topics_list) + 1}",
362
- "chapter_title": f"Chapter {len(st.session_state.topics_list) + 1}"
363
- })
364
- st.rerun()
365
- with col2:
366
- if st.button("πŸ”„ Reset All", key="reset_topics", help="Reset to default topics"):
367
- st.session_state.topics_list = [{"topic_title": "What is Flask", "chapter_title": "Introduction to Flask"}]
368
- st.rerun()
369
- st.markdown('</div>', unsafe_allow_html=True)
370
 
371
- # Main Form (for settings and submission)
372
- with st.form("personalization_form", clear_on_submit=False):
373
- # Language & Voice Settings Section
374
- st.markdown('<div class="section-header">πŸ—£οΈ Language & Voice Settings</div>', unsafe_allow_html=True)
375
-
376
- col1, col2, col3 = st.columns(3)
377
  with col1:
378
- target_language = st.selectbox(
379
- "Target Language",
380
- ["english", "hindi", "marathi", "kannada", "punjabi","gujarati"],
381
- index=0,
382
- format_func=lambda x: x.capitalize(),
383
- help="Select the target language for content generation"
384
- )
385
-
386
  with col2:
387
- tts_gender = st.selectbox(
388
- "Voice Gender",
389
- ["male", "female"],
390
- index=0,
391
- format_func=lambda x: x.capitalize(),
392
- help="Select the voice gender for text-to-speech"
393
- )
394
-
395
- with col3:
396
- tts_voice = st.selectbox(
397
- "Voice Style",
398
- ["alloy", "echo", "fable", "onyx", "nova", "shimmer"],
399
- index=3, # Default to "onyx"
400
- format_func=lambda x: x.capitalize(),
401
- help="Select the voice style for text-to-speech"
402
- )
403
 
404
- # Technical Settings Section
405
- st.markdown('<div class="section-header">πŸ’» Technical Settings</div>', unsafe_allow_html=True)
406
-
407
- col1, col2 = st.columns(2)
408
- with col1:
409
- # Comprehensive list of programming languages, frameworks, and databases
410
- tech_options = [
411
- # Programming Languages
412
- "Python", "Java", "JavaScript", "TypeScript", "C++", "C#", "C", "Go", "Rust", "Swift",
413
- "Kotlin", "Scala", "Ruby", "PHP", "Perl", "R", "MATLAB", "Dart", "Objective-C", "Assembly",
414
- "Haskell", "Erlang", "Elixir", "F#", "Clojure", "Lua", "Julia", "Groovy", "VB.NET", "COBOL",
415
- "Fortran", "Pascal", "Delphi", "Ada", "Prolog", "Lisp", "Scheme", "OCaml", "ML",
416
-
417
- # Web Technologies
418
- "HTML", "CSS", "SASS", "LESS", "Bootstrap", "Tailwind CSS", "Material-UI",
419
-
420
- # Frontend Frameworks/Libraries
421
- "React", "Vue.js", "Angular", "Svelte", "Next.js", "Nuxt.js", "Gatsby", "Ember.js",
422
- "Backbone.js", "jQuery", "Alpine.js", "Lit", "Stencil", "Ionic", "React Native",
423
- "Flutter", "Xamarin", "Cordova", "PhoneGap",
424
-
425
- # Backend Frameworks
426
- "Node.js", "Express.js", "Nest.js", "Django", "Flask", "FastAPI", "Pyramid", "Tornado",
427
- "Spring Boot", "Spring MVC", "Struts", "Hibernate", "ASP.NET", "ASP.NET Core",
428
- "Ruby on Rails", "Sinatra", "Laravel", "Symfony", "CodeIgniter", "CakePHP", "Zend",
429
- "Gin", "Echo", "Fiber", "Actix", "Rocket", "Warp", "Axum",
430
-
431
- # Mobile Development
432
- "Android (Java)", "Android (Kotlin)", "iOS (Swift)", "iOS (Objective-C)",
433
-
434
- # Game Development
435
- "Unity", "Unreal Engine", "Godot", "GameMaker Studio", "Construct", "Phaser",
436
-
437
- # Database Technologies
438
- "MySQL", "PostgreSQL", "SQLite", "Microsoft SQL Server", "Oracle Database",
439
- "MongoDB", "Redis", "Cassandra", "DynamoDB", "Firebase", "Supabase",
440
- "CouchDB", "Neo4j", "InfluxDB", "TimescaleDB", "ClickHouse", "Apache Spark",
441
- "Elasticsearch", "Apache Solr", "Amazon RDS", "Google Cloud SQL",
442
-
443
- # Cloud & DevOps
444
- "AWS", "Google Cloud Platform", "Microsoft Azure", "Digital Ocean", "Heroku",
445
- "Docker", "Kubernetes", "Terraform", "Ansible", "Jenkins", "GitLab CI", "GitHub Actions",
446
- "Nginx", "Apache", "Linux", "Ubuntu", "CentOS", "Red Hat",
447
-
448
- # Data Science & AI/ML
449
- "TensorFlow", "PyTorch", "Scikit-learn", "Pandas", "NumPy", "Matplotlib", "Seaborn",
450
- "Jupyter", "Apache Airflow", "Apache Kafka", "Apache Flink", "Hadoop", "Spark",
451
- "Tableau", "Power BI", "D3.js", "Plotly", "OpenCV", "Keras", "XGBoost",
452
-
453
- # Testing Frameworks
454
- "Jest", "Mocha", "Chai", "Cypress", "Selenium", "Playwright", "Puppeteer",
455
- "JUnit", "TestNG", "Mockito", "PyTest", "unittest", "RSpec", "PHPUnit",
456
-
457
- # Other Technologies
458
- "GraphQL", "REST API", "gRPC", "WebSocket", "Apache Kafka", "RabbitMQ",
459
- "Blockchain", "Solidity", "Web3", "Ethereum", "Bitcoin", "Smart Contracts",
460
- "Microservices", "Serverless", "Lambda Functions", "API Gateway"
461
- ]
462
 
463
- # Sort the options alphabetically
464
- tech_options.sort()
 
 
 
 
 
 
 
465
 
466
- programming_language = st.selectbox(
467
- "Programming Language / Technology",
468
- tech_options,
469
- index=tech_options.index("Python") if "Python" in tech_options else 0,
470
- help="Select the primary programming language, framework, or technology for examples"
471
- )
472
- with col2:
473
- st.markdown("<br>", unsafe_allow_html=True) # Add spacing
474
- toggle_hinglish = st.toggle("Enable Hinglish", value=True, help="Enable mixing of Hindi and English")
475
-
476
- # Submit button
477
- st.markdown("<br>", unsafe_allow_html=True)
478
- col1, col2, col3 = st.columns([1, 2, 1])
479
- with col2:
480
- submitted = st.form_submit_button("πŸš€ Generate Base Course", use_container_width=True)
 
 
481
 
482
- # Handle submission
483
- if submitted:
484
- # Use the topics from session state directly
485
- topics_to_process = st.session_state.topics_list
486
-
487
- # Validate inputs
488
- valid_topics = []
489
- for topic in topics_to_process:
490
- if topic["topic_title"].strip() and topic["chapter_title"].strip():
491
- valid_topics.append(topic)
492
-
493
- if not valid_topics:
494
- st.error("❌ Please enter at least one topic with both topic title and chapter title")
495
- else:
496
- # Show loading state with better animation
497
- with st.spinner("🎬 Generating your personalized course... This may take a few moments."):
498
- progress_bar = st.progress(0)
499
- for i in range(100):
500
- time.sleep(0.02) # Simulating progress
501
- progress_bar.progress(i + 1)
502
-
503
- # Hardcoded values
504
- course_id = DEFAULT_COURSE_ID
505
- user_id = DEFAULT_USER_ID
506
- personalization_id = DEFAULT_PERSONALIZATION_ID
507
-
508
- # Create user profile (hardcoded)
509
- user_profile = {
510
- "personalized": True,
511
- "user_name": "System User",
512
- "user_age": 25,
513
- "user_gender": "male",
514
- "user_tech_knowledge": "beginner",
515
- "user_preferred_activity": "coding, learning, technology",
516
- "user_food": "healthy food, vegetarian",
517
- "user_physical_activities": "walking, yoga",
518
- "learning_style": "visual",
519
- "target_language": target_language,
520
- "tts_gender": tts_gender,
521
- "tts_voice": tts_voice,
522
- "toggle_hinglish": toggle_hinglish,
523
- "run_visualization": False,
524
- "subtitle": "",
525
- "age_group": "18-25"
526
- }
527
-
528
- # Create settings
529
- settings = {
530
- "target_language": target_language,
531
- "tts_gender": tts_gender,
532
- "tts_voice": tts_voice,
533
- "toggle_hinglish": toggle_hinglish,
534
- "run_visualization": False,
535
- "subtitle": "",
536
- "programming_language": programming_language,
537
- "slide_colour": "blue",
538
- "video_type": "base_video"
539
- }
540
 
541
- # Generate topics data with user input for titles and hardcoded values for others
542
- topics_data = []
543
- for i, topic in enumerate(valid_topics):
544
- topics_data.append({
545
- "topic_id": 10834 + i, # Hardcoded with increment
546
- "topic_title": topic["topic_title"].strip(),
547
- "chapter_id": 647, # Hardcoded
548
- "chapter_title": topic["chapter_title"].strip(), # User input
549
- "course_id": course_id,
550
- "video_url": f"https://techlearn-dev.s3.ap-south-1.amazonaws.com/course_videos/47/647/172906{4365+i*50}.mp4", # Hardcoded with variation
551
- "video_duration": 462 + i*20, # Hardcoded with variation
552
- "sequence_number": i + 1,
553
- })
554
 
555
- # Create payload (always multiple topics structure)
556
- payload = {
557
- "personalization_id": personalization_id,
558
- "user_id": user_id,
559
- "course_id": course_id,
560
- "total_videos": len(topics_data),
561
- "created_at": datetime.utcnow().isoformat(),
562
- "user_profile": user_profile,
563
- "topics": topics_data,
564
- "settings": settings
565
- }
566
 
567
- # Make API call
568
- try:
569
- headers = {
570
- 'Content-Type': 'application/json'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
571
  }
572
 
573
- response = requests.post(API_ENDPOINT, json=payload, headers=headers, timeout=API_TIMEOUT)
 
 
 
 
 
 
 
 
 
 
 
574
 
575
- if response.status_code == 200:
576
- response_data = response.json()
577
- session_ids = response_data.get("session_ids", [])
578
-
579
- st.success("πŸŽ‰ Base Course started successfully!")
580
-
581
- # Store session IDs in session state
582
- st.session_state.session_ids.extend(session_ids)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
583
 
584
- # Display results in a clean format
585
- st.markdown("### πŸ“Š Generation Summary")
586
 
587
- col1, col2 = st.columns(2)
588
- with col1:
589
- st.markdown(f"""
590
- **Course ID**: `{course_id}`
591
- **Programming Language**: {programming_language.capitalize()}
592
- **Target Language**: {target_language.capitalize()}
593
- """)
594
- with col2:
595
- st.markdown(f"""
596
- **Voice**: {tts_voice.capitalize()} ({tts_gender.capitalize()})
597
- **Topics Count**: {len(valid_topics)}
598
- **Hinglish**: {"Enabled" if toggle_hinglish else "Disabled"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
599
  """)
600
-
601
- # Display session IDs
602
- if session_ids:
603
- st.markdown("### πŸ” Session Tracking IDs")
604
- for i, session_id in enumerate(session_ids, 1):
605
- st.markdown(f'<div class="session-info">πŸ“ <strong>Session {i}:</strong> <code>{session_id}</code></div>', unsafe_allow_html=True)
606
-
607
- # Display API response
608
- with st.expander("πŸ“Š View Full API Response", expanded=False):
609
- st.markdown('<div class="api-response">', unsafe_allow_html=True)
610
- st.json(response_data)
611
- st.markdown('</div>', unsafe_allow_html=True)
612
-
613
- # Information about tracking
614
- st.info(f"""
615
- πŸ’‘ **Tracking Information**
616
- You can track the progress of your video generation using the session IDs above.
617
- The processing status will be updated in DynamoDB table: `{SESSION_TABLE}`
618
- Region: `{DYNAMODB_REGION}`
619
- """)
620
-
621
- else:
622
- st.error(f"❌ API Error: {response.status_code}")
623
- if response.text:
624
- st.error(f"**Error Details**: {response.text}")
625
 
626
- except requests.exceptions.Timeout:
627
- st.error("⏰ Request timed out. Please try again later.")
628
- except requests.exceptions.ConnectionError:
629
- st.error("🌐 Connection error. Please check your internet connection.")
630
- except Exception as e:
631
- st.error(f"❌ API call failed: {str(e)}")
632
-
633
- # Show payload for debugging
634
- with st.expander("πŸ› Debug Information", expanded=False):
635
- st.warning("Request payload for debugging:")
636
- st.json(payload)
 
 
 
 
 
 
252
  box-shadow: 0 10px 30px rgba(0,0,0,0.5);
253
  border: 1px solid var(--border-color);
254
  }
255
+
256
+ /* Navigation tab styling */
257
+ .nav-tabs {
258
+ background-color: var(--card-background);
259
+ padding: 1rem;
260
+ border-radius: 10px;
261
+ margin-bottom: 2rem;
262
+ border: 1px solid var(--border-color);
263
+ }
264
  </style>
265
  """, unsafe_allow_html=True)
266
 
 
271
  st.session_state.session_ids = []
272
  if 'authenticated' not in st.session_state:
273
  st.session_state.authenticated = False
274
+ if 'current_page' not in st.session_state:
275
+ st.session_state.current_page = "Course Personalization"
276
+
277
+ # Admin Dashboard Functions
278
+ def fetch_sessions():
279
+ """Fetch all sessions from DynamoDB"""
280
+ try:
281
+ dynamodb = boto3.client(
282
+ "dynamodb",
283
+ region_name=DYNAMODB_REGION,
284
+ aws_access_key_id=AWS_ACCESS_KEY_ID,
285
+ aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
286
+ )
287
+
288
+ response = dynamodb.scan(TableName=SESSION_TABLE)
289
+ items = response.get("Items", [])
290
+ sessions = []
291
+ for item in items:
292
+ sessions.append({
293
+ "session_id": item.get("session_id", {}).get("S"),
294
+ "status": item.get("status", {}).get("S", "unknown"),
295
+ "node": item.get("node", {}).get("S", "-"),
296
+ "updated_at": item.get("updated_at", {}).get("S", "-"),
297
+ "video_url": item.get("video_url", {}).get("S", None),
298
+ })
299
+ return sessions
300
+ except Exception as e:
301
+ st.error(f"⚠️ Error fetching sessions: {e}")
302
+ return []
303
+
304
+ def render_admin_dashboard():
305
+ """Render the admin dashboard page"""
306
+ st.markdown("<h1 style='color:#4F97FF;text-align:center;'>πŸ“Š Base Video Generation Dashboard</h1>", unsafe_allow_html=True)
307
+
308
+ # Auto-refresh controls
309
+ col1, col2, col3 = st.columns([1, 1, 2])
310
+ with col1:
311
+ if st.button("πŸ”„ Refresh Now", key="manual_refresh"):
312
+ st.rerun()
313
+
314
+ with col2:
315
+ auto_refresh = st.toggle("Auto Refresh (15s)", value=False)
316
+
317
+ # Fetch sessions
318
+ sessions = fetch_sessions()
319
+
320
+ if not sessions:
321
+ st.warning("No sessions found yet.")
322
+ st.info("Sessions will appear here once you start generating courses from the Course Personalization page.")
323
+ else:
324
+ # Display session count
325
+ st.markdown(f"### πŸ“ˆ Found {len(sessions)} session(s)")
326
+
327
+ # Sort sessions by updated_at (newest first)
328
+ try:
329
+ sessions.sort(key=lambda x: x['updated_at'] if x['updated_at'] != '-' else '1970-01-01', reverse=True)
330
+ except:
331
+ pass
332
+
333
+ # Display sessions
334
+ for i, session in enumerate(sessions):
335
+ status_color = {
336
+ 'completed': 'lime',
337
+ 'processing': 'orange',
338
+ 'in_progress': 'orange',
339
+ 'running': 'orange',
340
+ 'failed': 'red',
341
+ 'error': 'red'
342
+ }.get(session['status'].lower(), 'yellow')
343
+
344
+ with st.container():
345
+ st.markdown(f"""
346
+ <div style="background:#2D2D2D;padding:1.5rem;border-radius:12px;margin-bottom:1rem;border:1px solid #444;">
347
+ <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:1rem;">
348
+ <h4 style="color:#4F97FF;margin:0;">πŸ†” Session {i+1}</h4>
349
+ <span style="background:{status_color};color:black;padding:0.3rem 0.8rem;border-radius:15px;font-size:0.8rem;font-weight:bold;">{session['status'].upper()}</span>
350
+ </div>
351
+ <div style="display:grid;grid-template-columns:1fr 1fr;gap:1rem;">
352
+ <div>
353
+ <b>Session ID:</b><br><code style="background:#1A1A1A;padding:0.3rem;border-radius:4px;">{session['session_id']}</code>
354
+ </div>
355
+ <div>
356
+ <b>Current Node:</b><br><span style="color:#E0E0E0;">{session['node']}</span>
357
+ </div>
358
+ </div>
359
+ <div style="margin-top:1rem;">
360
+ <b>⏱️ Last Update:</b> <span style="color:#888;">{session['updated_at']}</span>
361
+ </div>
362
+ {f"<div style='margin-top:1rem;'><b>πŸŽ₯ Final Video:</b> <a href='{session['video_url']}' target='_blank' style='color:#4F97FF;'>πŸ“Ί Watch Video</a></div>" if session['video_url'] else ""}
363
+ </div>
364
+ """, unsafe_allow_html=True)
365
+
366
+ # Auto-refresh mechanism
367
+ if auto_refresh:
368
+ time.sleep(15)
369
+ st.rerun()
370
 
371
  # Authentication check
372
  if not st.session_state.authenticated:
 
409
  """, unsafe_allow_html=True)
410
  st.stop()
411
 
412
+ # Navigation and Header (after login)
413
+ col1, col2, col3, col4 = st.columns([3, 2, 2, 1])
414
+ with col1:
415
+ st.markdown('<h1 class="main-header">πŸ“š Base Course Management</h1>', unsafe_allow_html=True)
416
+
417
+ with col2:
418
+ page = st.selectbox(
419
+ "πŸ“‹ Navigate to:",
420
+ ["Course Personalization", "Admin Dashboard"],
421
+ index=0 if st.session_state.current_page == "Course Personalization" else 1,
422
+ key="page_selector"
423
+ )
424
+ st.session_state.current_page = page
425
 
426
+ with col4:
 
 
427
  if st.button("πŸ”“ Logout", key="logout_btn"):
428
  st.session_state.authenticated = False
429
  st.session_state.topics_list = [{"topic_title": "What is Flask", "chapter_title": "Introduction to Flask"}]
430
  st.session_state.session_ids = []
431
+ st.session_state.current_page = "Course Personalization"
432
  st.rerun()
433
 
434
+ # Page routing
435
+ if st.session_state.current_page == "Admin Dashboard":
436
+ render_admin_dashboard()
437
+ else:
438
+ # Course Personalization Page (Original Content)
439
+
440
+ # Topics Section (Outside form for dynamic interaction)
441
+ st.markdown('<div class="section-header">πŸ“‹ Topics Configuration</div>', unsafe_allow_html=True)
442
 
443
+ # Display existing topics with better styling
444
+ for i, topic in enumerate(st.session_state.topics_list):
445
+ st.markdown(f'<div class="topic-container">', unsafe_allow_html=True)
446
+ st.markdown(f'<div class="topic-header">πŸ“– Topic {i+1}</div>', unsafe_allow_html=True)
447
+
448
+ col1, col2, col3 = st.columns([3, 3, 1])
449
+ with col1:
450
+ topic_title = st.text_input(
451
+ "Topic Title",
452
+ value=topic["topic_title"],
453
+ key=f"topic_title_{i}",
454
+ help="Enter the topic title"
455
+ )
456
+ st.session_state.topics_list[i]["topic_title"] = topic_title
457
+
458
+ with col2:
459
+ chapter_title = st.text_input(
460
+ "Chapter Title",
461
+ value=topic["chapter_title"],
462
+ key=f"chapter_title_{i}",
463
+ help="Enter the chapter title"
464
+ )
465
+ st.session_state.topics_list[i]["chapter_title"] = chapter_title
466
+
467
+ with col3:
468
+ if len(st.session_state.topics_list) > 1:
469
+ st.markdown("<br>", unsafe_allow_html=True) # Add spacing
470
+ if st.button("πŸ—‘οΈ", key=f"remove_{i}", help="Remove this topic"):
471
+ st.session_state.topics_list.pop(i)
472
+ st.rerun()
473
+
474
+ st.markdown('</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
 
476
+ # Add/Remove topic buttons outside the form
477
+ st.markdown('<div class="action-buttons">', unsafe_allow_html=True)
478
+ col1, col2, col3, col4 = st.columns([2, 2, 2, 4])
 
 
 
479
  with col1:
480
+ if st.button("βž• Add Topic", key="add_topic", help="Add a new topic"):
481
+ st.session_state.topics_list.append({
482
+ "topic_title": f"Topic {len(st.session_state.topics_list) + 1}",
483
+ "chapter_title": f"Chapter {len(st.session_state.topics_list) + 1}"
484
+ })
485
+ st.rerun()
 
 
486
  with col2:
487
+ if st.button("πŸ”„ Reset All", key="reset_topics", help="Reset to default topics"):
488
+ st.session_state.topics_list = [{"topic_title": "What is Flask", "chapter_title": "Introduction to Flask"}]
489
+ st.rerun()
490
+ st.markdown('</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
491
 
492
+ # Main Form (for settings and submission)
493
+ with st.form("personalization_form", clear_on_submit=False):
494
+ # Language & Voice Settings Section
495
+ st.markdown('<div class="section-header">πŸ—£οΈ Language & Voice Settings</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
496
 
497
+ col1, col2, col3 = st.columns(3)
498
+ with col1:
499
+ target_language = st.selectbox(
500
+ "Target Language",
501
+ ["english", "hindi", "marathi", "kannada", "punjabi","gujarati"],
502
+ index=0,
503
+ format_func=lambda x: x.capitalize(),
504
+ help="Select the target language for content generation"
505
+ )
506
 
507
+ with col2:
508
+ tts_gender = st.selectbox(
509
+ "Voice Gender",
510
+ ["male", "female"],
511
+ index=0,
512
+ format_func=lambda x: x.capitalize(),
513
+ help="Select the voice gender for text-to-speech"
514
+ )
515
+
516
+ with col3:
517
+ tts_voice = st.selectbox(
518
+ "Voice Style",
519
+ ["alloy", "echo", "fable", "onyx", "nova", "shimmer"],
520
+ index=3, # Default to "onyx"
521
+ format_func=lambda x: x.capitalize(),
522
+ help="Select the voice style for text-to-speech"
523
+ )
524
 
525
+ # Technical Settings Section
526
+ st.markdown('<div class="section-header">πŸ’» Technical Settings</div>', unsafe_allow_html=True)
527
+
528
+ col1, col2 = st.columns(2)
529
+ with col1:
530
+ # Comprehensive list of programming languages, frameworks, and databases
531
+ tech_options = [
532
+ # Programming Languages
533
+ "Python", "Java", "JavaScript", "TypeScript", "C++", "C#", "C", "Go", "Rust", "Swift",
534
+ "Kotlin", "Scala", "Ruby", "PHP", "Perl", "R", "MATLAB", "Dart", "Objective-C", "Assembly",
535
+ "Haskell", "Erlang", "Elixir", "F#", "Clojure", "Lua", "Julia", "Groovy", "VB.NET", "COBOL",
536
+ "Fortran", "Pascal", "Delphi", "Ada", "Prolog", "Lisp", "Scheme", "OCaml", "ML",
537
+
538
+ # Web Technologies
539
+ "HTML", "CSS", "SASS", "LESS", "Bootstrap", "Tailwind CSS", "Material-UI",
540
+
541
+ # Frontend Frameworks/Libraries
542
+ "React", "Vue.js", "Angular", "Svelte", "Next.js", "Nuxt.js", "Gatsby", "Ember.js",
543
+ "Backbone.js", "jQuery", "Alpine.js", "Lit", "Stencil", "Ionic", "React Native",
544
+ "Flutter", "Xamarin", "Cordova", "PhoneGap",
545
+
546
+ # Backend Frameworks
547
+ "Node.js", "Express.js", "Nest.js", "Django", "Flask", "FastAPI", "Pyramid", "Tornado",
548
+ "Spring Boot", "Spring MVC", "Struts", "Hibernate", "ASP.NET", "ASP.NET Core",
549
+ "Ruby on Rails", "Sinatra", "Laravel", "Symfony", "CodeIgniter", "CakePHP", "Zend",
550
+ "Gin", "Echo", "Fiber", "Actix", "Rocket", "Warp", "Axum",
551
+
552
+ # Mobile Development
553
+ "Android (Java)", "Android (Kotlin)", "iOS (Swift)", "iOS (Objective-C)",
554
+
555
+ # Game Development
556
+ "Unity", "Unreal Engine", "Godot", "GameMaker Studio", "Construct", "Phaser",
557
+
558
+ # Database Technologies
559
+ "MySQL", "PostgreSQL", "SQLite", "Microsoft SQL Server", "Oracle Database",
560
+ "MongoDB", "Redis", "Cassandra", "DynamoDB", "Firebase", "Supabase",
561
+ "CouchDB", "Neo4j", "InfluxDB", "TimescaleDB", "ClickHouse", "Apache Spark",
562
+ "Elasticsearch", "Apache Solr", "Amazon RDS", "Google Cloud SQL",
563
+
564
+ # Cloud & DevOps
565
+ "AWS", "Google Cloud Platform", "Microsoft Azure", "Digital Ocean", "Heroku",
566
+ "Docker", "Kubernetes", "Terraform", "Ansible", "Jenkins", "GitLab CI", "GitHub Actions",
567
+ "Nginx", "Apache", "Linux", "Ubuntu", "CentOS", "Red Hat",
568
+
569
+ # Data Science & AI/ML
570
+ "TensorFlow", "PyTorch", "Scikit-learn", "Pandas", "NumPy", "Matplotlib", "Seaborn",
571
+ "Jupyter", "Apache Airflow", "Apache Kafka", "Apache Flink", "Hadoop", "Spark",
572
+ "Tableau", "Power BI", "D3.js", "Plotly", "OpenCV", "Keras", "XGBoost",
573
+
574
+ # Testing Frameworks
575
+ "Jest", "Mocha", "Chai", "Cypress", "Selenium", "Playwright", "Puppeteer",
576
+ "JUnit", "TestNG", "Mockito", "PyTest", "unittest", "RSpec", "PHPUnit",
577
+
578
+ # Other Technologies
579
+ "GraphQL", "REST API", "gRPC", "WebSocket", "Apache Kafka", "RabbitMQ",
580
+ "Blockchain", "Solidity", "Web3", "Ethereum", "Bitcoin", "Smart Contracts",
581
+ "Microservices", "Serverless", "Lambda Functions", "API Gateway"
582
+ ]
583
 
584
+ # Sort the options alphabetically
585
+ tech_options.sort()
 
 
 
 
 
 
 
 
 
 
 
586
 
587
+ programming_language = st.selectbox(
588
+ "Programming Language / Technology",
589
+ tech_options,
590
+ index=tech_options.index("Python") if "Python" in tech_options else 0,
591
+ help="Select the primary programming language, framework, or technology for examples"
592
+ )
593
+ with col2:
594
+ st.markdown("<br>", unsafe_allow_html=True) # Add spacing
595
+ toggle_hinglish = st.toggle("Enable Hinglish", value=True, help="Enable mixing of Hindi and English")
 
 
596
 
597
+ # Submit button
598
+ st.markdown("<br>", unsafe_allow_html=True)
599
+ col1, col2, col3 = st.columns([1, 2, 1])
600
+ with col2:
601
+ submitted = st.form_submit_button("πŸš€ Generate Base Course", use_container_width=True)
602
+
603
+ # Handle submission
604
+ if submitted:
605
+ # Use the topics from session state directly
606
+ topics_to_process = st.session_state.topics_list
607
+
608
+ # Validate inputs
609
+ valid_topics = []
610
+ for topic in topics_to_process:
611
+ if topic["topic_title"].strip() and topic["chapter_title"].strip():
612
+ valid_topics.append(topic)
613
+
614
+ if not valid_topics:
615
+ st.error("❌ Please enter at least one topic with both topic title and chapter title")
616
+ else:
617
+ # Show loading state with better animation
618
+ with st.spinner("🎬 Generating your personalized course... This may take a few moments."):
619
+ progress_bar = st.progress(0)
620
+ for i in range(100):
621
+ time.sleep(0.02) # Simulating progress
622
+ progress_bar.progress(i + 1)
623
+
624
+ # Hardcoded values
625
+ course_id = DEFAULT_COURSE_ID
626
+ user_id = DEFAULT_USER_ID
627
+ personalization_id = DEFAULT_PERSONALIZATION_ID
628
+
629
+ # Create user profile (hardcoded)
630
+ user_profile = {
631
+ "personalized": True,
632
+ "user_name": "System User",
633
+ "user_age": 25,
634
+ "user_gender": "male",
635
+ "user_tech_knowledge": "beginner",
636
+ "user_preferred_activity": "coding, learning, technology",
637
+ "user_food": "healthy food, vegetarian",
638
+ "user_physical_activities": "walking, yoga",
639
+ "learning_style": "visual",
640
+ "target_language": target_language,
641
+ "tts_gender": tts_gender,
642
+ "tts_voice": tts_voice,
643
+ "toggle_hinglish": toggle_hinglish,
644
+ "run_visualization": False,
645
+ "subtitle": "",
646
+ "age_group": "18-25"
647
  }
648
 
649
+ # Create settings
650
+ settings = {
651
+ "target_language": target_language,
652
+ "tts_gender": tts_gender,
653
+ "tts_voice": tts_voice,
654
+ "toggle_hinglish": toggle_hinglish,
655
+ "run_visualization": False,
656
+ "subtitle": "",
657
+ "programming_language": programming_language,
658
+ "slide_colour": "blue",
659
+ "video_type": "base_video"
660
+ }
661
 
662
+ # Generate topics data with user input for titles and hardcoded values for others
663
+ topics_data = []
664
+ for i, topic in enumerate(valid_topics):
665
+ topics_data.append({
666
+ "topic_id": 10834 + i, # Hardcoded with increment
667
+ "topic_title": topic["topic_title"].strip(),
668
+ "chapter_id": 647, # Hardcoded
669
+ "chapter_title": topic["chapter_title"].strip(), # User input
670
+ "course_id": course_id,
671
+ "video_url": f"https://techlearn-dev.s3.ap-south-1.amazonaws.com/course_videos/47/647/172906{4365+i*50}.mp4", # Hardcoded with variation
672
+ "video_duration": 462 + i*20, # Hardcoded with variation
673
+ "sequence_number": i + 1,
674
+ })
675
+
676
+ # Create payload (always multiple topics structure)
677
+ payload = {
678
+ "personalization_id": personalization_id,
679
+ "user_id": user_id,
680
+ "course_id": course_id,
681
+ "total_videos": len(topics_data),
682
+ "created_at": datetime.utcnow().isoformat(),
683
+ "user_profile": user_profile,
684
+ "topics": topics_data,
685
+ "settings": settings
686
+ }
687
+
688
+ # Make API call
689
+ try:
690
+ headers = {
691
+ 'Content-Type': 'application/json'
692
+ }
693
 
694
+ response = requests.post(API_ENDPOINT, json=payload, headers=headers, timeout=API_TIMEOUT)
 
695
 
696
+ if response.status_code == 200:
697
+ response_data = response.json()
698
+ session_ids = response_data.get("session_ids", [])
699
+
700
+ st.success("πŸŽ‰ Base Course started successfully!")
701
+
702
+ # Store session IDs in session state
703
+ st.session_state.session_ids.extend(session_ids)
704
+
705
+ # Display results in a clean format
706
+ st.markdown("### πŸ“Š Generation Summary")
707
+
708
+ col1, col2 = st.columns(2)
709
+ with col1:
710
+ st.markdown(f"""
711
+ **Course ID**: {course_id}
712
+ **Programming Language**: {programming_language.capitalize()}
713
+ **Target Language**: {target_language.capitalize()}
714
+ """)
715
+ with col2:
716
+ st.markdown(f"""
717
+ **Voice**: {tts_voice.capitalize()} ({tts_gender.capitalize()})
718
+ **Topics Count**: {len(valid_topics)}
719
+ **Hinglish**: {"Enabled" if toggle_hinglish else "Disabled"}
720
+ """)
721
+
722
+ # Display session IDs
723
+ if session_ids:
724
+ st.markdown("### πŸ” Session Tracking IDs")
725
+ for i, session_id in enumerate(session_ids, 1):
726
+ st.markdown(f'<div class="session-info">πŸ“ <strong>Session {i}:</strong> <code>{session_id}</code></div>', unsafe_allow_html=True)
727
+
728
+ # Display API response
729
+ with st.expander("πŸ“Š View Full API Response", expanded=False):
730
+ st.markdown('<div class="api-response">', unsafe_allow_html=True)
731
+ st.json(response_data)
732
+ st.markdown('</div>', unsafe_allow_html=True)
733
+
734
+ # Information about tracking
735
+ st.info(f"""
736
+ πŸ’‘ **Tracking Information**
737
+ You can track the progress of your video generation using the session IDs above.
738
+ The processing status will be updated in DynamoDB table: {SESSION_TABLE}
739
+ Region: {DYNAMODB_REGION}
740
+
741
+ πŸ‘‰ **Next Steps**: Switch to the "Admin Dashboard" to monitor your session progress in real-time!
742
  """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
743
 
744
+ else:
745
+ st.error(f"❌ API Error: {response.status_code}")
746
+ if response.text:
747
+ st.error(f"**Error Details**: {response.text}")
748
+
749
+ except requests.exceptions.Timeout:
750
+ st.error("⏰ Request timed out. Please try again later.")
751
+ except requests.exceptions.ConnectionError:
752
+ st.error("🌐 Connection error. Please check your internet connection.")
753
+ except Exception as e:
754
+ st.error(f"❌ API call failed: {str(e)}")
755
+
756
+ # Show payload for debugging
757
+ with st.expander("πŸ› Debug Information", expanded=False):
758
+ st.warning("Request payload for debugging:")
759
+ st.json(payload)