Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import json | |
| import os | |
| from datetime import datetime | |
| from typing import List, Dict | |
| # File to persist todos | |
| TODO_FILE = "todos.json" | |
| def load_todos() -> List[Dict]: | |
| """Load todos from JSON file""" | |
| if os.path.exists(TODO_FILE): | |
| try: | |
| with open(TODO_FILE, 'r') as f: | |
| return json.load(f) | |
| except: | |
| return [] | |
| return [] | |
| def save_todos(todos: List[Dict]): | |
| """Save todos to JSON file""" | |
| try: | |
| with open(TODO_FILE, 'w') as f: | |
| json.dump(todos, f, indent=2) | |
| except Exception as e: | |
| print(f"Error saving todos: {e}") | |
| def add_todo(task: str, priority: int) -> tuple[List[Dict], str]: | |
| """Add a new todo item""" | |
| if not task.strip(): | |
| return load_todos(), "Task cannot be empty!" | |
| todos = load_todos() | |
| new_todo = { | |
| "id": len(todos) + 1, | |
| "task": task.strip(), | |
| "priority": priority, | |
| "completed": False, | |
| "created": datetime.now().isoformat() | |
| } | |
| todos.append(new_todo) | |
| save_todos(todos) | |
| return todos, f"Added: '{task}' (Priority: {priority})" | |
| def toggle_todo(todo_id: int) -> List[Dict]: | |
| """Toggle todo completion status""" | |
| todos = load_todos() | |
| for todo in todos: | |
| if todo["id"] == todo_id: | |
| todo["completed"] = not todo["completed"] | |
| break | |
| save_todos(todos) | |
| return todos | |
| def delete_todo(todo_id: int) -> List[Dict]: | |
| """Delete a todo item""" | |
| todos = load_todos() | |
| todos = [todo for todo in todos if todo["id"] != todo_id] | |
| # Update IDs to maintain sequential order | |
| for i, todo in enumerate(todos): | |
| todo["id"] = i + 1 | |
| save_todos(todos) | |
| return todos | |
| def get_todos_display(todos: List[Dict]) -> str: | |
| """Format todos for display""" | |
| if not todos: | |
| return "π No todos! Great job!" | |
| lines = [] | |
| sorted_todos = sorted(todos, key=lambda x: (x["priority"], x["id"])) | |
| for todo in sorted_todos: | |
| status = "β " if todo["completed"] else "β³" | |
| priority_emoji = {1: "π₯", 2: "β‘", 3: "π"}.get(todo["priority"], "π") | |
| line = f"{status} [{priority_emoji} P{todo['priority']}] {todo['task']}" | |
| lines.append(line) | |
| return "\n".join(lines) | |
| def clear_completed() -> List[Dict]: | |
| """Remove all completed todos""" | |
| todos = load_todos() | |
| todos = [todo for todo in todos if not todo["completed"]] | |
| # Update IDs | |
| for i, todo in enumerate(todos): | |
| todo["id"] = i + 1 | |
| save_todos(todos) | |
| return todos | |
| # Initialize app with current todos | |
| initial_todos = load_todos() | |
| with gr.Blocks( | |
| title="π Todo App", | |
| theme=gr.themes.Soft(), | |
| css=""" | |
| .todo-header { font-size: 2em; margin-bottom: 1em; } | |
| .priority-selector { display: flex; gap: 1em; align-items: center; } | |
| .todo-list { background: white; border-radius: 10px; padding: 1.5em; min-height: 200px; } | |
| .action-buttons { display: flex; gap: 1em; flex-wrap: wrap; } | |
| """ | |
| ) as demo: | |
| gr.HTML( | |
| """ | |
| <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 2em;"> | |
| <h1 class="todo-header">π My Todo App</h1> | |
| <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" | |
| style="color: #666; text-decoration: none; font-size: 0.9em;"> | |
| Built with <b>anycoder</b> | |
| </a> | |
| </div> | |
| """ | |
| ) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| task_input = gr.Textbox( | |
| label="New Task", | |
| placeholder="What needs to be done?", | |
| lines=2 | |
| ) | |
| priority_input = gr.Slider( | |
| minimum=1, | |
| maximum=3, | |
| value=2, | |
| step=1, | |
| label="Priority", | |
| info="1 = Urgent π₯ | 2 = Important β‘ | 3 = Normal π" | |
| ) | |
| add_btn = gr.Button("β Add Todo", variant="primary", size="lg") | |
| with gr.Column(scale=2): | |
| todos_display = gr.Markdown( | |
| get_todos_display(initial_todos), | |
| label="Your Todos", | |
| elem_classes=["todo-list"] | |
| ) | |
| with gr.Row(): | |
| clear_btn = gr.Button("ποΈ Clear Completed", variant="secondary") | |
| delete_btn = gr.Button("ποΈ Delete Selected", interactive=False, visible=False) | |
| # Status message | |
| status_msg = gr.Textbox( | |
| label="Status", | |
| interactive=False, | |
| visible=False | |
| ) | |
| # Event handlers | |
| add_btn.click( | |
| add_todo, | |
| inputs=[task_input, priority_input], | |
| outputs=[todos_display, status_msg] | |
| ).then( | |
| lambda: gr.update(visible=True), | |
| outputs=[status_msg] | |
| ).then( | |
| gr.update(value=""), | |
| outputs=[task_input] | |
| ) | |
| clear_btn.click( | |
| clear_completed, | |
| outputs=[todos_display] | |
| ) | |
| # Update display when todos change | |
| demo.load( | |
| fn=lambda: get_todos_display(load_todos()), | |
| outputs=todos_display | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |