Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -70,7 +70,6 @@ def reset_leaderboard():
|
|
| 70 |
json.dump({"scores": []}, f, indent=2)
|
| 71 |
|
| 72 |
# ---------------- Roadmaps & Data ----------------
|
| 73 |
-
# (includes Class 6..10, JEE Main, NEET, B.Tech 1st..Final Year)
|
| 74 |
ROADMAPS = {
|
| 75 |
"Class 6": {
|
| 76 |
"objective": "Build curiosity, logical thinking, basic problem-solving and gentle programming.",
|
|
@@ -368,368 +367,6 @@ int main() {
|
|
| 368 |
}""",
|
| 369 |
"explanation": "Singly linked list implementation with dynamic memory allocation. Includes node creation, insertion at end, deletion by value, and display functions.",
|
| 370 |
"video_url": "https://www.youtube.com/embed/dq3F3e9o2DM"
|
| 371 |
-
},
|
| 372 |
-
{
|
| 373 |
-
"title": "Binary Search Tree",
|
| 374 |
-
"problem": "Implement BST with insert, search and inorder traversal",
|
| 375 |
-
"code": """#include <stdio.h>
|
| 376 |
-
#include <stdlib.h>
|
| 377 |
-
|
| 378 |
-
struct Node {
|
| 379 |
-
int data;
|
| 380 |
-
struct Node *left, *right;
|
| 381 |
-
};
|
| 382 |
-
|
| 383 |
-
struct Node* createNode(int data) {
|
| 384 |
-
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
|
| 385 |
-
newNode->data = data;
|
| 386 |
-
newNode->left = newNode->right = NULL;
|
| 387 |
-
return newNode;
|
| 388 |
-
}
|
| 389 |
-
|
| 390 |
-
struct Node* insert(struct Node* root, int data) {
|
| 391 |
-
if (root == NULL)
|
| 392 |
-
return createNode(data);
|
| 393 |
-
|
| 394 |
-
if (data < root->data)
|
| 395 |
-
root->left = insert(root->left, data);
|
| 396 |
-
else if (data > root->data)
|
| 397 |
-
root->right = insert(root->right, data);
|
| 398 |
-
|
| 399 |
-
return root;
|
| 400 |
-
}
|
| 401 |
-
|
| 402 |
-
struct Node* search(struct Node* root, int key) {
|
| 403 |
-
if (root == NULL || root->data == key)
|
| 404 |
-
return root;
|
| 405 |
-
|
| 406 |
-
if (key < root->data)
|
| 407 |
-
return search(root->left, key);
|
| 408 |
-
|
| 409 |
-
return search(root->right, key);
|
| 410 |
-
}
|
| 411 |
-
|
| 412 |
-
void inorder(struct Node* root) {
|
| 413 |
-
if (root != NULL) {
|
| 414 |
-
inorder(root->left);
|
| 415 |
-
printf("%d ", root->data);
|
| 416 |
-
inorder(root->right);
|
| 417 |
-
}
|
| 418 |
-
}
|
| 419 |
-
|
| 420 |
-
int main() {
|
| 421 |
-
struct Node* root = NULL;
|
| 422 |
-
|
| 423 |
-
root = insert(root, 50);
|
| 424 |
-
insert(root, 30);
|
| 425 |
-
insert(root, 20);
|
| 426 |
-
insert(root, 40);
|
| 427 |
-
insert(root, 70);
|
| 428 |
-
insert(root, 60);
|
| 429 |
-
insert(root, 80);
|
| 430 |
-
|
| 431 |
-
printf("Inorder traversal: ");
|
| 432 |
-
inorder(root);
|
| 433 |
-
printf("\\n");
|
| 434 |
-
|
| 435 |
-
int key = 40;
|
| 436 |
-
if (search(root, key) != NULL)
|
| 437 |
-
printf("%d found in BST\\n", key);
|
| 438 |
-
else
|
| 439 |
-
printf("%d not found in BST\\n", key);
|
| 440 |
-
|
| 441 |
-
return 0;
|
| 442 |
-
}""",
|
| 443 |
-
"explanation": "Binary Search Tree implementation with recursive insert, search and inorder traversal. BST property: left < root < right.",
|
| 444 |
-
"video_url": "https://www.youtube.com/embed/cySVml6e_Fc"
|
| 445 |
-
}
|
| 446 |
-
],
|
| 447 |
-
"B.Tech 3rd Year": [
|
| 448 |
-
{
|
| 449 |
-
"title": "Dijkstra's Algorithm",
|
| 450 |
-
"problem": "Implement Dijkstra's algorithm for shortest path finding",
|
| 451 |
-
"code": """#include <stdio.h>
|
| 452 |
-
#include <limits.h>
|
| 453 |
-
|
| 454 |
-
#define V 6
|
| 455 |
-
|
| 456 |
-
int minDistance(int dist[], int sptSet[]) {
|
| 457 |
-
int min = INT_MAX, min_index;
|
| 458 |
-
|
| 459 |
-
for (int v = 0; v < V; v++)
|
| 460 |
-
if (sptSet[v] == 0 && dist[v] <= min)
|
| 461 |
-
min = dist[v], min_index = v;
|
| 462 |
-
|
| 463 |
-
return min_index;
|
| 464 |
-
}
|
| 465 |
-
|
| 466 |
-
void printSolution(int dist[]) {
|
| 467 |
-
printf("Vertex \\t Distance from Source\\n");
|
| 468 |
-
for (int i = 0; i < V; i++)
|
| 469 |
-
printf("%d \\t %d\\n", i, dist[i]);
|
| 470 |
-
}
|
| 471 |
-
|
| 472 |
-
void dijkstra(int graph[V][V], int src) {
|
| 473 |
-
int dist[V];
|
| 474 |
-
int sptSet[V];
|
| 475 |
-
|
| 476 |
-
for (int i = 0; i < V; i++)
|
| 477 |
-
dist[i] = INT_MAX, sptSet[i] = 0;
|
| 478 |
-
|
| 479 |
-
dist[src] = 0;
|
| 480 |
-
|
| 481 |
-
for (int count = 0; count < V - 1; count++) {
|
| 482 |
-
int u = minDistance(dist, sptSet);
|
| 483 |
-
sptSet[u] = 1;
|
| 484 |
-
|
| 485 |
-
for (int v = 0; v < V; v++)
|
| 486 |
-
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX
|
| 487 |
-
&& dist[u] + graph[u][v] < dist[v])
|
| 488 |
-
dist[v] = dist[u] + graph[u][v];
|
| 489 |
-
}
|
| 490 |
-
|
| 491 |
-
printSolution(dist);
|
| 492 |
-
}
|
| 493 |
-
|
| 494 |
-
int main() {
|
| 495 |
-
int graph[V][V] = {
|
| 496 |
-
{0, 4, 0, 0, 0, 0},
|
| 497 |
-
{4, 0, 8, 0, 0, 0},
|
| 498 |
-
{0, 8, 0, 7, 0, 4},
|
| 499 |
-
{0, 0, 7, 0, 9, 14},
|
| 500 |
-
{0, 0, 0, 9, 0, 10},
|
| 501 |
-
{0, 0, 4, 14, 10, 0}
|
| 502 |
-
};
|
| 503 |
-
|
| 504 |
-
dijkstra(graph, 0);
|
| 505 |
-
return 0;
|
| 506 |
-
}""",
|
| 507 |
-
"explanation": "Dijkstra's algorithm finds shortest paths from source to all vertices in a weighted graph. Uses greedy approach with priority queue.",
|
| 508 |
-
"video_url": "https://www.youtube.com/embed/GazC3A4OQTE"
|
| 509 |
-
},
|
| 510 |
-
{
|
| 511 |
-
"title": "Producer-Consumer Problem",
|
| 512 |
-
"problem": "Implement producer-consumer problem using semaphores",
|
| 513 |
-
"code": """#include <stdio.h>
|
| 514 |
-
#include <stdlib.h>
|
| 515 |
-
#include <pthread.h>
|
| 516 |
-
#include <semaphore.h>
|
| 517 |
-
|
| 518 |
-
#define BUFFER_SIZE 5
|
| 519 |
-
|
| 520 |
-
int buffer[BUFFER_SIZE];
|
| 521 |
-
int in = 0, out = 0;
|
| 522 |
-
|
| 523 |
-
sem_t empty, full;
|
| 524 |
-
pthread_mutex_t mutex;
|
| 525 |
-
|
| 526 |
-
void* producer(void* arg) {
|
| 527 |
-
int item;
|
| 528 |
-
for (int i = 0; i < 10; i++) {
|
| 529 |
-
item = rand() % 100;
|
| 530 |
-
|
| 531 |
-
sem_wait(&empty);
|
| 532 |
-
pthread_mutex_lock(&mutex);
|
| 533 |
-
|
| 534 |
-
buffer[in] = item;
|
| 535 |
-
printf("Producer produced: %d\\n", item);
|
| 536 |
-
in = (in + 1) % BUFFER_SIZE;
|
| 537 |
-
|
| 538 |
-
pthread_mutex_unlock(&mutex);
|
| 539 |
-
sem_post(&full);
|
| 540 |
-
}
|
| 541 |
-
return NULL;
|
| 542 |
-
}
|
| 543 |
-
|
| 544 |
-
void* consumer(void* arg) {
|
| 545 |
-
int item;
|
| 546 |
-
for (int i = 0; i < 10; i++) {
|
| 547 |
-
sem_wait(&full);
|
| 548 |
-
pthread_mutex_lock(&mutex);
|
| 549 |
-
|
| 550 |
-
item = buffer[out];
|
| 551 |
-
printf("Consumer consumed: %d\\n", item);
|
| 552 |
-
out = (out + 1) % BUFFER_SIZE;
|
| 553 |
-
|
| 554 |
-
pthread_mutex_unlock(&mutex);
|
| 555 |
-
sem_post(&empty);
|
| 556 |
-
}
|
| 557 |
-
return NULL;
|
| 558 |
-
}
|
| 559 |
-
|
| 560 |
-
int main() {
|
| 561 |
-
pthread_t prod_thread, cons_thread;
|
| 562 |
-
|
| 563 |
-
sem_init(&empty, 0, BUFFER_SIZE);
|
| 564 |
-
sem_init(&full, 0, 0);
|
| 565 |
-
pthread_mutex_init(&mutex, NULL);
|
| 566 |
-
|
| 567 |
-
pthread_create(&prod_thread, NULL, producer, NULL);
|
| 568 |
-
pthread_create(&cons_thread, NULL, consumer, NULL);
|
| 569 |
-
|
| 570 |
-
pthread_join(prod_thread, NULL);
|
| 571 |
-
pthread_join(cons_thread, NULL);
|
| 572 |
-
|
| 573 |
-
sem_destroy(&empty);
|
| 574 |
-
sem_destroy(&full);
|
| 575 |
-
pthread_mutex_destroy(&mutex);
|
| 576 |
-
|
| 577 |
-
return 0;
|
| 578 |
-
}""",
|
| 579 |
-
"explanation": "Producer-Consumer problem solution using semaphores for synchronization. Empty semaphore tracks empty slots, full semaphore tracks filled slots.",
|
| 580 |
-
"video_url": "https://www.youtube.com/embed/ltXjAtncKeo"
|
| 581 |
-
}
|
| 582 |
-
],
|
| 583 |
-
"B.Tech Final Year": [
|
| 584 |
-
{
|
| 585 |
-
"title": "Machine Learning - Linear Regression",
|
| 586 |
-
"problem": "Implement linear regression from scratch in Python",
|
| 587 |
-
"code": """import numpy as np
|
| 588 |
-
import matplotlib.pyplot as plt
|
| 589 |
-
|
| 590 |
-
class LinearRegression:
|
| 591 |
-
def __init__(self, learning_rate=0.01, iterations=1000):
|
| 592 |
-
self.learning_rate = learning_rate
|
| 593 |
-
self.iterations = iterations
|
| 594 |
-
self.weights = None
|
| 595 |
-
self.bias = None
|
| 596 |
-
self.loss_history = []
|
| 597 |
-
|
| 598 |
-
def fit(self, X, y):
|
| 599 |
-
n_samples, n_features = X.shape
|
| 600 |
-
self.weights = np.zeros(n_features)
|
| 601 |
-
self.bias = 0
|
| 602 |
-
|
| 603 |
-
for i in range(self.iterations):
|
| 604 |
-
y_pred = np.dot(X, self.weights) + self.bias
|
| 605 |
-
|
| 606 |
-
# Calculate gradients
|
| 607 |
-
dw = (1/n_samples) * np.dot(X.T, (y_pred - y))
|
| 608 |
-
db = (1/n_samples) * np.sum(y_pred - y)
|
| 609 |
-
|
| 610 |
-
# Update parameters
|
| 611 |
-
self.weights -= self.learning_rate * dw
|
| 612 |
-
self.bias -= self.learning_rate * db
|
| 613 |
-
|
| 614 |
-
# Calculate loss
|
| 615 |
-
loss = np.mean((y_pred - y) ** 2)
|
| 616 |
-
self.loss_history.append(loss)
|
| 617 |
-
|
| 618 |
-
if i % 100 == 0:
|
| 619 |
-
print(f"Iteration {i}, Loss: {loss:.4f}")
|
| 620 |
-
|
| 621 |
-
def predict(self, X):
|
| 622 |
-
return np.dot(X, self.weights) + self.bias
|
| 623 |
-
|
| 624 |
-
# Example usage
|
| 625 |
-
if __name__ == "__main__":
|
| 626 |
-
# Generate sample data
|
| 627 |
-
np.random.seed(42)
|
| 628 |
-
X = 2 * np.random.rand(100, 1)
|
| 629 |
-
y = 4 + 3 * X + np.random.randn(100, 1)
|
| 630 |
-
|
| 631 |
-
# Create and train model
|
| 632 |
-
model = LinearRegression(learning_rate=0.1, iterations=1000)
|
| 633 |
-
model.fit(X, y.ravel())
|
| 634 |
-
|
| 635 |
-
# Make predictions
|
| 636 |
-
X_new = np.array([[0], [2]])
|
| 637 |
-
y_pred = model.predict(X_new)
|
| 638 |
-
|
| 639 |
-
print(f"Predicted for x=0: {y_pred[0]:.2f}")
|
| 640 |
-
print(f"Predicted for x=2: {y_pred[1]:.2f}")
|
| 641 |
-
|
| 642 |
-
# Plot results
|
| 643 |
-
plt.scatter(X, y)
|
| 644 |
-
plt.plot(X_new, y_pred, 'r-')
|
| 645 |
-
plt.title('Linear Regression')
|
| 646 |
-
plt.xlabel('X')
|
| 647 |
-
plt.ylabel('y')
|
| 648 |
-
plt.show()""",
|
| 649 |
-
"explanation": "Linear regression implementation from scratch using gradient descent. Updates weights and bias to minimize mean squared error.",
|
| 650 |
-
"video_url": "https://www.youtube.com/embed/4b4MUYve_U8"
|
| 651 |
-
},
|
| 652 |
-
{
|
| 653 |
-
"title": "Blockchain Implementation",
|
| 654 |
-
"problem": "Simple blockchain implementation in Python",
|
| 655 |
-
"code": """import hashlib
|
| 656 |
-
import time
|
| 657 |
-
import json
|
| 658 |
-
|
| 659 |
-
class Block:
|
| 660 |
-
def __init__(self, index, transactions, timestamp, previous_hash):
|
| 661 |
-
self.index = index
|
| 662 |
-
self.transactions = transactions
|
| 663 |
-
self.timestamp = timestamp
|
| 664 |
-
self.previous_hash = previous_hash
|
| 665 |
-
self.nonce = 0
|
| 666 |
-
self.hash = self.calculate_hash()
|
| 667 |
-
|
| 668 |
-
def calculate_hash(self):
|
| 669 |
-
block_string = json.dumps({
|
| 670 |
-
"index": self.index,
|
| 671 |
-
"transactions": self.transactions,
|
| 672 |
-
"timestamp": self.timestamp,
|
| 673 |
-
"previous_hash": self.previous_hash,
|
| 674 |
-
"nonce": self.nonce
|
| 675 |
-
}, sort_keys=True)
|
| 676 |
-
return hashlib.sha256(block_string.encode()).hexdigest()
|
| 677 |
-
|
| 678 |
-
def mine_block(self, difficulty):
|
| 679 |
-
target = "0" * difficulty
|
| 680 |
-
while self.hash[:difficulty] != target:
|
| 681 |
-
self.nonce += 1
|
| 682 |
-
self.hash = self.calculate_hash()
|
| 683 |
-
print(f"Block mined: {self.hash}")
|
| 684 |
-
|
| 685 |
-
class Blockchain:
|
| 686 |
-
def __init__(self):
|
| 687 |
-
self.chain = [self.create_genesis_block()]
|
| 688 |
-
self.difficulty = 2
|
| 689 |
-
self.pending_transactions = []
|
| 690 |
-
|
| 691 |
-
def create_genesis_block(self):
|
| 692 |
-
return Block(0, ["Genesis Block"], time.time(), "0")
|
| 693 |
-
|
| 694 |
-
def get_latest_block(self):
|
| 695 |
-
return self.chain[-1]
|
| 696 |
-
|
| 697 |
-
def add_transaction(self, transaction):
|
| 698 |
-
self.pending_transactions.append(transaction)
|
| 699 |
-
|
| 700 |
-
def mine_pending_transactions(self):
|
| 701 |
-
block = Block(len(self.chain), self.pending_transactions, time.time(), self.get_latest_block().hash)
|
| 702 |
-
block.mine_block(self.difficulty)
|
| 703 |
-
self.chain.append(block)
|
| 704 |
-
self.pending_transactions = []
|
| 705 |
-
|
| 706 |
-
def is_chain_valid(self):
|
| 707 |
-
for i in range(1, len(self.chain)):
|
| 708 |
-
current_block = self.chain[i]
|
| 709 |
-
previous_block = self.chain[i-1]
|
| 710 |
-
|
| 711 |
-
if current_block.hash != current_block.calculate_hash():
|
| 712 |
-
return False
|
| 713 |
-
if current_block.previous_hash != previous_block.hash:
|
| 714 |
-
return False
|
| 715 |
-
return True
|
| 716 |
-
|
| 717 |
-
# Example usage
|
| 718 |
-
if __name__ == "__main__":
|
| 719 |
-
blockchain = Blockchain()
|
| 720 |
-
|
| 721 |
-
print("Mining block 1...")
|
| 722 |
-
blockchain.add_transaction("Transaction 1")
|
| 723 |
-
blockchain.mine_pending_transactions()
|
| 724 |
-
|
| 725 |
-
print("Mining block 2...")
|
| 726 |
-
blockchain.add_transaction("Transaction 2")
|
| 727 |
-
blockchain.mine_pending_transactions()
|
| 728 |
-
|
| 729 |
-
print(f"Blockchain valid: {blockchain.is_chain_valid()}")
|
| 730 |
-
print(f"Blockchain length: {len(blockchain.chain)}")""",
|
| 731 |
-
"explanation": "Simple blockchain implementation with mining, transaction adding, and chain validation. Uses SHA-256 hashing and proof-of-work.",
|
| 732 |
-
"video_url": "https://www.youtube.com/embed/zVqczFZr124"
|
| 733 |
}
|
| 734 |
]
|
| 735 |
}
|
|
@@ -741,11 +378,10 @@ HACKATHONS = [
|
|
| 741 |
]
|
| 742 |
INTERNSHIPS = [
|
| 743 |
{"name":"Software Engineering Intern","deadline":"2025-10-30","duration":"12 weeks","stipend":"βΉ30,000/month","skills":["Python"],"url":"https://jobs.careers.microsoft.com/us/en/job/1880847/Software-Engineering-Intern","type":"B.Tech","level":"Class 11-12"},
|
| 744 |
-
{"name":"Software Application Development Apprenticeship, March 2026","deadline":"
|
| 745 |
-
{"name":"Full Stack Development Intern","deadline":"2025-09-30","duration":"12 weeks","stipend":"30000k","skills":["Open Source"],"url":"https://www.linkedin.com/jobs/view/full-stack-development-intern-at-sony-research-india-4301264932/","type":"Open Source","level":"B.Tech 2nd-4th Year"}
|
| 746 |
]
|
| 747 |
SCHOLARSHIPS = [
|
| 748 |
-
{"name":"Reliance Foundation Scholarships","deadline":"2026-01-15","amount":"βΉ10000/month","eligibility":"
|
| 749 |
]
|
| 750 |
|
| 751 |
# ---------------- AI Mentor (lightweight) ----------------
|
|
@@ -814,4 +450,392 @@ def mark_session_completed(level, session_title):
|
|
| 814 |
|
| 815 |
def create_dashboard_stats(level):
|
| 816 |
p = load_progress()
|
| 817 |
-
sessions = ROADMAPS.get(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
json.dump({"scores": []}, f, indent=2)
|
| 71 |
|
| 72 |
# ---------------- Roadmaps & Data ----------------
|
|
|
|
| 73 |
ROADMAPS = {
|
| 74 |
"Class 6": {
|
| 75 |
"objective": "Build curiosity, logical thinking, basic problem-solving and gentle programming.",
|
|
|
|
| 367 |
}""",
|
| 368 |
"explanation": "Singly linked list implementation with dynamic memory allocation. Includes node creation, insertion at end, deletion by value, and display functions.",
|
| 369 |
"video_url": "https://www.youtube.com/embed/dq3F3e9o2DM"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 370 |
}
|
| 371 |
]
|
| 372 |
}
|
|
|
|
| 378 |
]
|
| 379 |
INTERNSHIPS = [
|
| 380 |
{"name":"Software Engineering Intern","deadline":"2025-10-30","duration":"12 weeks","stipend":"βΉ30,000/month","skills":["Python"],"url":"https://jobs.careers.microsoft.com/us/en/job/1880847/Software-Engineering-Intern","type":"B.Tech","level":"Class 11-12"},
|
| 381 |
+
{"name":"Software Application Development Apprenticeship, March 2026","deadline":"2025-10-10","duration":"12 weeks","stipend":"50000k","skills":["Open Source"],"url":"https://www.geekscodes.com/2025/08/google-software-development.html","type":"Open Source","level":"B.Tech 2nd-4th Year"}
|
|
|
|
| 382 |
]
|
| 383 |
SCHOLARSHIPS = [
|
| 384 |
+
{"name":"Reliance Foundation Scholarships","deadline":"2026-01-15","amount":"βΉ10000/month","eligibility":"Secondary,Undergraduate,Postgraduate","url":"https://www.scholarships.reliancefoundation.org/","type":"Merit-based","level":"Secondary,Undergraduate,Postgraduate"}
|
| 385 |
]
|
| 386 |
|
| 387 |
# ---------------- AI Mentor (lightweight) ----------------
|
|
|
|
| 450 |
|
| 451 |
def create_dashboard_stats(level):
|
| 452 |
p = load_progress()
|
| 453 |
+
sessions = ROADMAPS.get(level, {}).get("study_sessions", [])
|
| 454 |
+
completed_sessions = sum(1 for s in sessions if p.get("study_sessions_completed", {}).get(f"{level}_{s['title']}", False))
|
| 455 |
+
total_sessions = len(sessions)
|
| 456 |
+
percent = (completed_sessions / total_sessions * 100) if total_sessions > 0 else 0
|
| 457 |
+
last = p.get("last_study_date", datetime.now().isoformat())[:10]
|
| 458 |
+
html_block = f"""
|
| 459 |
+
<div style='background:linear-gradient(135deg,#dbeafe,#bde4ff);color:#0b3d91;padding:16px;border-radius:10px;'>
|
| 460 |
+
<h3>π― {level} Learning Dashboard</h3>
|
| 461 |
+
<div style='display:flex;justify-content:space-around;flex-wrap:wrap;margin-top:10px;'>
|
| 462 |
+
<div><h4>π {completed_sessions}/{total_sessions}</h4><small>Sessions</small></div>
|
| 463 |
+
<div><h4>β° {p.get('total_hours_studied',0):.1f}</h4><small>Total Hours</small></div>
|
| 464 |
+
<div><h4>π
{last}</h4><small>Last Study</small></div>
|
| 465 |
+
</div>
|
| 466 |
+
<p style='margin-top:12px;'>Overall Progress: <strong>{percent:.1f}%</strong></p>
|
| 467 |
+
<div style='background:#ddd;border-radius:8px;height:10px;'><div style='background:#28a745;height:100%;width:{percent}%;border-radius:8px;'></div></div>
|
| 468 |
+
</div>
|
| 469 |
+
"""
|
| 470 |
+
return html_block
|
| 471 |
+
|
| 472 |
+
def get_code_snippets_interface(level):
|
| 473 |
+
if level not in CODE_SNIPPETS:
|
| 474 |
+
return "<div style='text-align:center;padding:20px;'><h4>No code snippets available for this level</h4></div>"
|
| 475 |
+
|
| 476 |
+
snippets = CODE_SNIPPETS[level]
|
| 477 |
+
progress_data = load_progress()
|
| 478 |
+
snippets_html = "<div style='max-height:520px;overflow-y:auto;'>"
|
| 479 |
+
snippets_html += "<h3>π» Code Snippets & Practice Problems</h3>"
|
| 480 |
+
|
| 481 |
+
for i, snippet in enumerate(snippets):
|
| 482 |
+
snippet_key = f"{level}_{snippet['title']}"
|
| 483 |
+
is_completed = progress_data.get("code_snippets_completed", {}).get(snippet_key, False)
|
| 484 |
+
status_icon = "β
" if is_completed else "π»"
|
| 485 |
+
status_color = "#28a745" if is_completed else "#007bff"
|
| 486 |
+
|
| 487 |
+
snippets_html += f"""
|
| 488 |
+
<div style='padding:12px;margin:8px 0;background:{'#d4edda' if is_completed else '#f8f9fa'};border-radius:8px;border-left:4px solid {status_color};'>
|
| 489 |
+
<h4 style="color:#0b3d91">{status_icon} {html.escape(snippet['title'])}</h4>
|
| 490 |
+
<p><strong>Problem:</strong> {html.escape(snippet['problem'])}</p>
|
| 491 |
+
<details>
|
| 492 |
+
<summary><strong>View Code Solution</strong></summary>
|
| 493 |
+
<pre style='background:#f5f5f5;padding:10px;border-radius:5px;overflow-x:auto;'>{html.escape(snippet['code'])}</pre>
|
| 494 |
+
</details>
|
| 495 |
+
<p><strong>Explanation:</strong> {html.escape(snippet['explanation'])}</p>
|
| 496 |
+
<div style='margin-top:10px;'>
|
| 497 |
+
<iframe width="100%" height="200" src="{snippet['video_url']}" frameborder="0" allowfullscreen></iframe>
|
| 498 |
+
</div>
|
| 499 |
+
</div>
|
| 500 |
+
"""
|
| 501 |
+
snippets_html += "</div>"
|
| 502 |
+
return snippets_html
|
| 503 |
+
|
| 504 |
+
def mark_code_snippet_completed(level, snippet_title):
|
| 505 |
+
if not level or not snippet_title:
|
| 506 |
+
return "β Level and snippet title required."
|
| 507 |
+
p = load_progress()
|
| 508 |
+
key = f"{level}_{snippet_title}"
|
| 509 |
+
p.setdefault("code_snippets_completed", {})
|
| 510 |
+
current = p["code_snippets_completed"].get(key, False)
|
| 511 |
+
p["code_snippets_completed"][key] = not current
|
| 512 |
+
save_progress(p)
|
| 513 |
+
action = "completed" if not current else "unmarked"
|
| 514 |
+
return f"β
Code snippet '{snippet_title}' {action}!"
|
| 515 |
+
|
| 516 |
+
# ---------------- Opportunities & Reminders ----------------
|
| 517 |
+
def get_upcoming_deadlines_html():
|
| 518 |
+
today = datetime.now().date()
|
| 519 |
+
items = HACKATHONS + INTERNSHIPS + SCHOLARSHIPS
|
| 520 |
+
deadlines = []
|
| 521 |
+
for it in items:
|
| 522 |
+
dl = it.get("deadline")
|
| 523 |
+
try:
|
| 524 |
+
d = datetime.strptime(dl, "%Y-%m-%d").date()
|
| 525 |
+
days = (d - today).days
|
| 526 |
+
except:
|
| 527 |
+
days = None
|
| 528 |
+
deadlines.append({"name":it.get("name"), "deadline":dl, "days_left":days, "url":it.get("url","#")})
|
| 529 |
+
deadlines = sorted([d for d in deadlines if d['days_left'] is None or d['days_left']>=0], key=lambda x: (x['days_left'] if x['days_left'] is not None else 999))
|
| 530 |
+
if not deadlines:
|
| 531 |
+
return "<div style='padding:12px;text-align:center;'><h4>No upcoming deadlines</h4></div>"
|
| 532 |
+
html_block = "<div style='max-height:420px;overflow-y:auto;'>"
|
| 533 |
+
for d in deadlines[:12]:
|
| 534 |
+
left = f"{d['days_left']} days left" if d['days_left'] is not None else "N/A"
|
| 535 |
+
html_block += f"<div style='padding:10px;margin:8px 0;background:white;border-radius:8px;'><h4>{html.escape(d['name'])}</h4><p>π
{d['deadline']} | {left}</p><a href='{d['url']}' target='_blank'>More</a></div>"
|
| 536 |
+
html_block += "</div>"
|
| 537 |
+
return html_block
|
| 538 |
+
|
| 539 |
+
def create_hackathon_interface_html():
|
| 540 |
+
html_block = "<div style='max-height:420px;overflow-y:auto;'>"
|
| 541 |
+
for h in HACKATHONS:
|
| 542 |
+
try:
|
| 543 |
+
days = (datetime.strptime(h['deadline'],'%Y-%m-%d').date() - datetime.now().date()).days
|
| 544 |
+
except:
|
| 545 |
+
days = "N/A"
|
| 546 |
+
html_block += f"<div style='padding:12px;margin:8px 0;background:linear-gradient(135deg,#dbeafe,#bde4ff);color:#0b3d91;border-radius:8px;'><h4>π {h['name']}</h4><p>π
{h['deadline']} | {days} days left</p><p>Eligibility: {h['eligibility']}</p><a href='{h['url']}' style='color:#0b3d91' target='_blank'>Apply</a></div>"
|
| 547 |
+
html_block += "</div>"
|
| 548 |
+
return html_block
|
| 549 |
+
|
| 550 |
+
def create_internship_interface_html():
|
| 551 |
+
html_block = "<div style='max-height:420px;overflow-y:auto;'>"
|
| 552 |
+
for it in INTERNSHIPS:
|
| 553 |
+
try:
|
| 554 |
+
days = (datetime.strptime(it['deadline'],'%Y-%m-%d').date() - datetime.now().date()).days
|
| 555 |
+
except:
|
| 556 |
+
days = "N/A"
|
| 557 |
+
html_block += f"<div style='padding:12px;margin:8px 0;background:linear-gradient(135deg,#e6f4ff,#cfeeff);color:#0b3d91;border-radius:8px;'><h4>πΌ {it['name']}</h4><p>π
{it['deadline']} | {days} days left</p><p>Duration: {it.get('duration')}</p><a href='{it['url']}' style='color:#0b3d91' target='_blank'>Apply</a></div>"
|
| 558 |
+
html_block += "</div>"
|
| 559 |
+
return html_block
|
| 560 |
+
|
| 561 |
+
def create_scholarship_interface_html():
|
| 562 |
+
html_block = "<div style='max-height:420px;overflow-y:auto;'>"
|
| 563 |
+
for s in SCHOLARSHIPS:
|
| 564 |
+
try:
|
| 565 |
+
days = (datetime.strptime(s['deadline'],'%Y-%m-%d').date() - datetime.now().date()).days
|
| 566 |
+
except:
|
| 567 |
+
days = "N/A"
|
| 568 |
+
html_block += f"<div style='padding:12px;margin:8px 0;background:linear-gradient(135deg,#e0f7ff,#cdeeff);color:#0b3d91;border-radius:8px;'><h4>π {s['name']}</h4><p>π
{s['deadline']} | {days} days left</p><p>Amount: {s.get('amount')}</p><a href='{s['url']}' style='color:#0b3d91' target='_blank'>Apply</a></div>"
|
| 569 |
+
html_block += "</div>"
|
| 570 |
+
return html_block
|
| 571 |
+
|
| 572 |
+
def set_custom_reminder(reminder_type, reminder_name, reminder_date, reminder_notes):
|
| 573 |
+
if not reminder_name or not reminder_date:
|
| 574 |
+
return "β Name and date required."
|
| 575 |
+
try:
|
| 576 |
+
datetime.strptime(reminder_date, "%Y-%m-%d")
|
| 577 |
+
except ValueError:
|
| 578 |
+
return "β Invalid date format. Use YYYY-MM-DD."
|
| 579 |
+
data = load_opportunities()
|
| 580 |
+
data.setdefault("reminders", [])
|
| 581 |
+
new = {
|
| 582 |
+
"type": reminder_type or "Personal",
|
| 583 |
+
"name": reminder_name,
|
| 584 |
+
"date": reminder_date,
|
| 585 |
+
"notes": reminder_notes or "",
|
| 586 |
+
"set_date": datetime.now().isoformat(),
|
| 587 |
+
"completed": False
|
| 588 |
+
}
|
| 589 |
+
data["reminders"].append(new)
|
| 590 |
+
save_opportunities(data)
|
| 591 |
+
return f"β
Reminder set for {reminder_date}: {reminder_name}"
|
| 592 |
+
|
| 593 |
+
def get_custom_reminders_html():
|
| 594 |
+
data = load_opportunities()
|
| 595 |
+
rems = data.get("reminders", [])
|
| 596 |
+
if not rems:
|
| 597 |
+
return "<div style='text-align:center;padding:12px;'><h4>No custom reminders.</h4></div>"
|
| 598 |
+
html_block = "<div style='max-height:420px;overflow-y:auto;'>"
|
| 599 |
+
for idx, r in enumerate(rems):
|
| 600 |
+
try:
|
| 601 |
+
d = datetime.strptime(r['date'], "%Y-%m-%d").date()
|
| 602 |
+
days_left = (d - datetime.now().date()).days
|
| 603 |
+
left_text = f"{days_left} days left"
|
| 604 |
+
except:
|
| 605 |
+
left_text = "N/A"
|
| 606 |
+
color = "#28a745" if r.get("completed") else "#ff6b6b"
|
| 607 |
+
status = "β
" if r.get("completed") else "β³"
|
| 608 |
+
html_block += f"""
|
| 609 |
+
<div style='padding:10px;margin:8px 0;background:white;border-left:6px solid {color};border-radius:8px;'>
|
| 610 |
+
<h4>{status} [{idx}] {html.escape(r['type'])}: {html.escape(r['name'])}</h4>
|
| 611 |
+
<p>π
{r['date']} | {left_text}</p>
|
| 612 |
+
<p>π {html.escape(r.get('notes',''))}</p>
|
| 613 |
+
<p style='font-size:12px;color:#666;'>Set on: {r['set_date'][:10]}</p>
|
| 614 |
+
</div>
|
| 615 |
+
"""
|
| 616 |
+
html_block += "</div>"
|
| 617 |
+
return html_block
|
| 618 |
+
|
| 619 |
+
def mark_reminder_completed(index):
|
| 620 |
+
data = load_opportunities()
|
| 621 |
+
rems = data.get("reminders", [])
|
| 622 |
+
try:
|
| 623 |
+
idx = int(index)
|
| 624 |
+
if idx < 0 or idx >= len(rems):
|
| 625 |
+
return "β Invalid index"
|
| 626 |
+
except:
|
| 627 |
+
return "β Invalid index"
|
| 628 |
+
rems[idx]['completed'] = True
|
| 629 |
+
save_opportunities(data)
|
| 630 |
+
return "β
Reminder marked completed."
|
| 631 |
+
|
| 632 |
+
def delete_reminder(index):
|
| 633 |
+
data = load_opportunities()
|
| 634 |
+
rems = data.get("reminders", [])
|
| 635 |
+
try:
|
| 636 |
+
idx = int(index)
|
| 637 |
+
if idx < 0 or idx >= len(rems):
|
| 638 |
+
return "β Invalid index"
|
| 639 |
+
except:
|
| 640 |
+
return "β Invalid index"
|
| 641 |
+
name = rems[idx].get("name","")
|
| 642 |
+
rems.pop(idx)
|
| 643 |
+
save_opportunities(data)
|
| 644 |
+
return f"ποΈ Reminder '{name}' deleted."
|
| 645 |
+
|
| 646 |
+
# ---------------- GRADIO UI ----------------
|
| 647 |
+
custom_css = """
|
| 648 |
+
.gradio-container {
|
| 649 |
+
background: linear-gradient(135deg, #eaf6ff 0%, #d5efff 100%);
|
| 650 |
+
min-height: 100vh;
|
| 651 |
+
padding: 24px;
|
| 652 |
+
color: #0b3d91;
|
| 653 |
+
}
|
| 654 |
+
.gradio-container .container {
|
| 655 |
+
background: rgba(255,255,255,0.04);
|
| 656 |
+
border-radius: 12px;
|
| 657 |
+
padding: 16px;
|
| 658 |
+
}
|
| 659 |
+
"""
|
| 660 |
+
|
| 661 |
+
with gr.Blocks(title="Road2Success β Learning Dashboard", theme=gr.themes.Soft(), css=custom_css) as app:
|
| 662 |
+
gr.Markdown("# π Road2Success β Learning Dashboard")
|
| 663 |
+
gr.Markdown("*Professional roadmap, AI mentor, hackathon prep & leaderboard*")
|
| 664 |
+
|
| 665 |
+
with gr.Tabs():
|
| 666 |
+
# Learning Dashboard
|
| 667 |
+
with gr.TabItem("π Learning Dashboard"):
|
| 668 |
+
with gr.Row():
|
| 669 |
+
with gr.Column(scale=2):
|
| 670 |
+
gr.Markdown("### Select Level")
|
| 671 |
+
level_choice = gr.Radio(choices=list(ROADMAPS.keys()), value=list(ROADMAPS.keys())[0], label="Level")
|
| 672 |
+
refresh_btn = gr.Button("π Refresh")
|
| 673 |
+
stats_display = gr.HTML()
|
| 674 |
+
with gr.Column(scale=3):
|
| 675 |
+
progress_plot = gr.Plot()
|
| 676 |
+
|
| 677 |
+
with gr.Row():
|
| 678 |
+
with gr.Column(scale=2):
|
| 679 |
+
gr.Markdown("### Study Materials")
|
| 680 |
+
materials_html = gr.HTML()
|
| 681 |
+
with gr.Column(scale=1):
|
| 682 |
+
gr.Markdown("### Quick Actions")
|
| 683 |
+
session_dropdown = gr.Dropdown(label="Session", choices=[])
|
| 684 |
+
mark_session_btn = gr.Button("Mark Session Complete")
|
| 685 |
+
action_status = gr.Textbox(interactive=False, label="Action status")
|
| 686 |
+
|
| 687 |
+
gr.Markdown("### Code Snippets")
|
| 688 |
+
code_snippets_html = gr.HTML()
|
| 689 |
+
snippet_dropdown = gr.Dropdown(label="Code Snippet", choices=[])
|
| 690 |
+
mark_snippet_btn = gr.Button("Mark Snippet Complete")
|
| 691 |
+
snippet_status = gr.Textbox(interactive=False, label="Snippet status")
|
| 692 |
+
|
| 693 |
+
reset_btn = gr.Button("β οΈ Reset Dashboard", variant="danger")
|
| 694 |
+
reset_status = gr.Textbox(interactive=False, label="Reset status")
|
| 695 |
+
|
| 696 |
+
# Study Roadmaps
|
| 697 |
+
with gr.TabItem("π Study Roadmaps"):
|
| 698 |
+
gr.Markdown("## πΊοΈ Study Roadmaps")
|
| 699 |
+
roadmap_level = gr.Dropdown(choices=list(ROADMAPS.keys()), value=list(ROADMAPS.keys())[0], label="Select Level")
|
| 700 |
+
show_roadmap_btn = gr.Button("Show Roadmap")
|
| 701 |
+
roadmap_html = gr.HTML()
|
| 702 |
+
|
| 703 |
+
# Opportunities & Reminders
|
| 704 |
+
with gr.TabItem("π Opportunities & Reminders"):
|
| 705 |
+
gr.Markdown("## π Opportunities Hub")
|
| 706 |
+
with gr.Row():
|
| 707 |
+
with gr.Column(scale=2):
|
| 708 |
+
opp_overview = gr.HTML()
|
| 709 |
+
gr.Markdown("### Hackathons")
|
| 710 |
+
hack_html = gr.HTML()
|
| 711 |
+
gr.Markdown("### Internships")
|
| 712 |
+
intern_html = gr.HTML()
|
| 713 |
+
gr.Markdown("### Scholarships")
|
| 714 |
+
schol_html = gr.HTML()
|
| 715 |
+
with gr.Column(scale=1):
|
| 716 |
+
gr.Markdown("### Set Custom Reminder")
|
| 717 |
+
r_type = gr.Dropdown(["Hackathon","Internship","Scholarship","Exam","Project","Personal"], label="Type")
|
| 718 |
+
r_name = gr.Textbox(label="Name")
|
| 719 |
+
r_date = gr.Textbox(label="Date (YYYY-MM-DD)")
|
| 720 |
+
r_notes = gr.Textbox(label="Notes", lines=2)
|
| 721 |
+
set_reminder_btn = gr.Button("Set Reminder")
|
| 722 |
+
set_out = gr.Textbox(interactive=False, label="Set status")
|
| 723 |
+
gr.Markdown("### Your Reminders (0-based index shown)")
|
| 724 |
+
reminders_html = gr.HTML()
|
| 725 |
+
rem_index = gr.Textbox(label="Reminder index (0-based)")
|
| 726 |
+
mark_done_btn = gr.Button("Mark Done")
|
| 727 |
+
del_btn = gr.Button("Delete Reminder")
|
| 728 |
+
rem_action_status = gr.Textbox(interactive=False, label="Reminder action status")
|
| 729 |
+
|
| 730 |
+
# AI Mentor
|
| 731 |
+
with gr.TabItem("π€ AI Mentor"):
|
| 732 |
+
gr.Markdown("## π¬ AI Mentor (simple fallback)")
|
| 733 |
+
prompt = gr.Textbox(label="Ask a question", lines=3)
|
| 734 |
+
short_toggle = gr.Checkbox(label="Short answer", value=True)
|
| 735 |
+
eli5_toggle = gr.Checkbox(label="Explain simply", value=False)
|
| 736 |
+
ask_btn = gr.Button("Ask Mentor")
|
| 737 |
+
mentor_out = gr.Textbox(lines=6, label="Mentor output")
|
| 738 |
+
|
| 739 |
+
# -- Core update function
|
| 740 |
+
def update_dashboard(level):
|
| 741 |
+
sessions = ROADMAPS.get(level, {}).get("study_sessions", [])
|
| 742 |
+
session_titles = [s['title'] for s in sessions]
|
| 743 |
+
|
| 744 |
+
# Get code snippets for the level
|
| 745 |
+
snippet_titles = []
|
| 746 |
+
if level in CODE_SNIPPETS:
|
| 747 |
+
snippet_titles = [s['title'] for s in CODE_SNIPPETS[level]]
|
| 748 |
+
|
| 749 |
+
stats = create_dashboard_stats(level)
|
| 750 |
+
completed_sessions = sum(1 for s in sessions if load_progress().get("study_sessions_completed", {}).get(f"{level}_{s['title']}", False))
|
| 751 |
+
fig = create_progress_chart(level, completed_sessions, len(sessions))
|
| 752 |
+
|
| 753 |
+
materials = get_study_materials_interface(level)
|
| 754 |
+
code_snippets = get_code_snippets_interface(level)
|
| 755 |
+
opps = get_upcoming_deadlines_html()
|
| 756 |
+
|
| 757 |
+
return (gr.update(choices=session_titles, value=(session_titles[0] if session_titles else None)),
|
| 758 |
+
gr.update(choices=snippet_titles, value=(snippet_titles[0] if snippet_titles else None)),
|
| 759 |
+
stats, fig, materials, code_snippets, opps)
|
| 760 |
+
|
| 761 |
+
def refresh_all(level):
|
| 762 |
+
session_update, snippet_update, stats, fig, materials, code_snippets, opps = update_dashboard(level)
|
| 763 |
+
reminders = get_custom_reminders_html()
|
| 764 |
+
hack = create_hackathon_interface_html()
|
| 765 |
+
intern = create_internship_interface_html()
|
| 766 |
+
schol = create_scholarship_interface_html()
|
| 767 |
+
return session_update, snippet_update, stats, fig, materials, code_snippets, opps, reminders, hack, intern, schol
|
| 768 |
+
|
| 769 |
+
def reset_dashboard():
|
| 770 |
+
save_progress(default_progress_data())
|
| 771 |
+
save_opportunities(default_opportunities_data())
|
| 772 |
+
reset_leaderboard()
|
| 773 |
+
return "β
Dashboard reset to defaults."
|
| 774 |
+
|
| 775 |
+
# Wire events
|
| 776 |
+
level_choice.change(update_dashboard, inputs=[level_choice],
|
| 777 |
+
outputs=[session_dropdown, snippet_dropdown, stats_display, progress_plot, materials_html, code_snippets_html, opp_overview])
|
| 778 |
+
|
| 779 |
+
refresh_btn.click(update_dashboard, inputs=[level_choice],
|
| 780 |
+
outputs=[session_dropdown, snippet_dropdown, stats_display, progress_plot, materials_html, code_snippets_html, opp_overview])
|
| 781 |
+
|
| 782 |
+
mark_session_btn.click(mark_session_completed, inputs=[level_choice, session_dropdown], outputs=[action_status]).then(
|
| 783 |
+
update_dashboard, inputs=[level_choice],
|
| 784 |
+
outputs=[session_dropdown, snippet_dropdown, stats_display, progress_plot, materials_html, code_snippets_html, opp_overview]
|
| 785 |
+
)
|
| 786 |
+
|
| 787 |
+
mark_snippet_btn.click(mark_code_snippet_completed, inputs=[level_choice, snippet_dropdown], outputs=[snippet_status]).then(
|
| 788 |
+
update_dashboard, inputs=[level_choice],
|
| 789 |
+
outputs=[session_dropdown, snippet_dropdown, stats_display, progress_plot, materials_html, code_snippets_html, opp_overview]
|
| 790 |
+
)
|
| 791 |
+
|
| 792 |
+
reset_btn.click(reset_dashboard, outputs=[reset_status]).then(
|
| 793 |
+
refresh_all, inputs=[level_choice],
|
| 794 |
+
outputs=[session_dropdown, snippet_dropdown, stats_display, progress_plot, materials_html, code_snippets_html, opp_overview, reminders_html, hack_html, intern_html, schol_html]
|
| 795 |
+
)
|
| 796 |
+
|
| 797 |
+
# Study roadmap
|
| 798 |
+
def show_roadmap(level):
|
| 799 |
+
r = ROADMAPS.get(level, {})
|
| 800 |
+
html_block = f"<div style='padding:16px;background:linear-gradient(135deg,#dbeafe,#bde4ff);color:#0b3d91;border-radius:10px;'><h2>{level} - Learning Path</h2>"
|
| 801 |
+
html_block += f"<h4>Objective</h4><p>{r.get('objective','')}</p>"
|
| 802 |
+
html_block += "<h4>Subjects</h4><ul>"
|
| 803 |
+
for sub in r.get('subjects', []):
|
| 804 |
+
html_block += f"<li>{sub}</li>"
|
| 805 |
+
html_block += "</ul><h4>Projects</h4><ul>"
|
| 806 |
+
for proj in r.get('projects', []):
|
| 807 |
+
html_block += f"<li>{proj}</li>"
|
| 808 |
+
html_block += "</ul>"
|
| 809 |
+
html_block += f"<p><strong>Weekly hours:</strong> {r.get('weekly_hours','N/A')}</p></div>"
|
| 810 |
+
return html_block
|
| 811 |
+
|
| 812 |
+
show_roadmap_btn.click(show_roadmap, inputs=[roadmap_level], outputs=[roadmap_html])
|
| 813 |
+
|
| 814 |
+
# Opportunities and reminders
|
| 815 |
+
app.load(lambda: get_upcoming_deadlines_html(), outputs=[opp_overview])
|
| 816 |
+
app.load(lambda: create_hackathon_interface_html(), outputs=[hack_html])
|
| 817 |
+
app.load(lambda: create_internship_interface_html(), outputs=[intern_html])
|
| 818 |
+
app.load(lambda: create_scholarship_interface_html(), outputs=[schol_html])
|
| 819 |
+
app.load(lambda: get_custom_reminders_html(), outputs=[reminders_html])
|
| 820 |
+
|
| 821 |
+
set_reminder_btn.click(set_custom_reminder, inputs=[r_type, r_name, r_date, r_notes], outputs=[set_out]).then(
|
| 822 |
+
lambda: get_custom_reminders_html(), outputs=[reminders_html]
|
| 823 |
+
).then(lambda: get_upcoming_deadlines_html(), outputs=[opp_overview])
|
| 824 |
+
|
| 825 |
+
mark_done_btn.click(mark_reminder_completed, inputs=[rem_index], outputs=[rem_action_status]).then(
|
| 826 |
+
lambda: get_custom_reminders_html(), outputs=[reminders_html]
|
| 827 |
+
).then(lambda: get_upcoming_deadlines_html(), outputs=[opp_overview])
|
| 828 |
+
|
| 829 |
+
del_btn.click(delete_reminder, inputs=[rem_index], outputs=[rem_action_status]).then(
|
| 830 |
+
lambda: get_custom_reminders_html(), outputs=[reminders_html]
|
| 831 |
+
).then(lambda: get_upcoming_deadlines_html(), outputs=[opp_overview])
|
| 832 |
+
|
| 833 |
+
ask_btn.click(ai_mentor_query, inputs=[prompt, short_toggle, eli5_toggle], outputs=[mentor_out])
|
| 834 |
+
|
| 835 |
+
# Initial load
|
| 836 |
+
app.load(lambda: update_dashboard(list(ROADMAPS.keys())[0]),
|
| 837 |
+
outputs=[session_dropdown, snippet_dropdown, stats_display, progress_plot, materials_html, code_snippets_html, opp_overview])
|
| 838 |
+
|
| 839 |
+
# Launch Gradio app
|
| 840 |
+
if __name__ == "__main__":
|
| 841 |
+
app.launch(share=True)
|