clawed 2.3.0__tar.gz → 2.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {clawed-2.3.0 → clawed-2.3.2}/PKG-INFO +1 -1
- {clawed-2.3.0 → clawed-2.3.2}/clawed/__init__.py +1 -1
- {clawed-2.3.0 → clawed-2.3.2}/clawed/export_pptx.py +132 -48
- {clawed-2.3.0 → clawed-2.3.2}/clawed/onboarding.py +22 -5
- {clawed-2.3.0 → clawed-2.3.2}/pyproject.toml +1 -1
- {clawed-2.3.0 → clawed-2.3.2}/.gitignore +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/LICENSE +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/README.md +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/__main__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/_legacy_gateway.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/__init__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/approvals.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/autonomy.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/context.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/core.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/custom_tools.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/drive/__init__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/drive/auth.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/drive/client.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/fake_llm.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/loop.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/memory/__init__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/memory/curriculum.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/memory/curriculum_kb.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/memory/embeddings.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/memory/episodes.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/memory/identity.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/memory/loader.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/memory/preferences.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/planner.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/prompt.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/scheduler.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/__init__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/base.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/configure_profile.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/curriculum_map.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/drive_create_doc.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/drive_create_slides.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/drive_list.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/drive_organize.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/drive_read.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/drive_upload.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/export_document.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/gap_analysis.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/generate_assessment.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/generate_lesson.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/generate_lesson_bundle.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/generate_materials.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/generate_unit.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/ingest_materials.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/parent_comm.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/read_heartbeat.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/read_workspace.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/request_approval.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/schedule_task.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/search_lessons.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/search_my_materials.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/search_standards.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/student_insights.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/sub_packet.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/switch_model.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/agent_core/tools/update_soul.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/analytics.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/__init__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/deps.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/routes/__init__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/routes/chat.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/routes/export.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/routes/feedback.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/routes/gateway_chat.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/routes/generate.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/routes/ingest.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/routes/lessons.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/routes/school.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/routes/settings.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/routes/tools.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/server.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/static/app.js +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/static/style.css +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/static/widget.js +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/templates/analytics.html +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/templates/base.html +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/templates/dashboard.html +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/templates/generate.html +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/templates/index.html +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/templates/lesson.html +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/templates/profile.html +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/templates/settings.html +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/templates/stats.html +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/api/templates/students.html +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/assessment.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/asset_registry.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/auth/__init__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/auth/google_auth.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/bot_state.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/chat.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/cli.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/cli_chat.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/commands/__init__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/commands/_helpers.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/commands/bot.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/commands/config.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/commands/config_llm.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/commands/config_profile.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/commands/export.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/commands/generate.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/commands/generate_assessment.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/commands/generate_unit.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/commands/queue.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/commands/schedule_cmd.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/commands/sub.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/commands/workspace_cmd.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/config.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/corpus.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/curriculum_map.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/database.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/demo/__init__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/demo/demo_assessment.json +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/demo/demo_lesson_science_g6.json +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/demo/demo_lesson_social_studies_g8.json +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/demo/demo_unit_plan.json +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/differentiation.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/doc_export.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/drive.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/evaluation.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/export_docx.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/export_handout.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/export_markdown.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/export_pdf.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/export_templates.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/export_theme.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/exporter.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/feedback.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/formats/__init__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/formats/flipchart.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/formats/notebook.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/formats/xbk.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/gateway.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/gateway_response.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/generation.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/handlers/__init__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/handlers/export.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/handlers/feedback.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/handlers/gaps.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/handlers/generate.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/handlers/ingest.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/handlers/misc.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/handlers/onboard.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/handlers/schedule.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/handlers/standards.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/improver.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/ingestor.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/io.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/lesson.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/llm.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/materials.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/mcp_server.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/memory_engine.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/model_router.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/models.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/openclaw_plugin.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/parent_comm.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/persona.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/planner.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/504_accommodations.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/admin_lesson_plan.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/assessment.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/curriculum_gaps.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/dbq_assessment.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/differentiation.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/formative_assessment.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/iep_modification.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/lesson_plan.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/pacing_guide.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/parent_note.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/persona_extract.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/quiz.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/rubric.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/student_packet.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/sub_packet.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/summative_assessment.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/tiered_assignments.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/unit_plan.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/worksheet.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/prompts/year_map.txt +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/quality.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/reading_report.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/router.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/sanitize.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/scheduler.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/school.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/search.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/skills/__init__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/skills/art.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/skills/base.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/skills/computer_science.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/skills/ela.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/skills/foreign_language.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/skills/history.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/skills/library.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/skills/math.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/skills/music.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/skills/physical_education.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/skills/science.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/skills/social_studies.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/skills/special_education.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/slide_images.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/standards.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/state.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/state_standards.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/student_bot.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/student_cli.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/student_telegram_bot.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/sub_packet.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/task_queue.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/templates_lib.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/tools.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/transports/__init__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/transports/cli.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/transports/openclaw.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/transports/student_telegram.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/transports/telegram.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/transports/web.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/tui.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/tui_chat.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/voice.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/clawed/workspace.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/eduagent/__init__.py +0 -0
- {clawed-2.3.0 → clawed-2.3.2}/eduagent/_compat.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clawed
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.2
|
|
4
4
|
Summary: Claw-ED — personal AI teaching agent. Learns your voice, works while you sleep.
|
|
5
5
|
Project-URL: Homepage, https://github.com/SirhanMacx/Claw-ED
|
|
6
6
|
Project-URL: Documentation, https://github.com/SirhanMacx/Claw-ED#readme
|
|
@@ -17,7 +17,7 @@ if hasattr(sys.stderr, "reconfigure"):
|
|
|
17
17
|
except Exception:
|
|
18
18
|
pass
|
|
19
19
|
|
|
20
|
-
__version__ = "2.3.
|
|
20
|
+
__version__ = "2.3.2"
|
|
21
21
|
__author__ = "Jon Maccarello & Claw-ED contributors"
|
|
22
22
|
__description__ = "Personal AI teaching agent. Learns your voice, works while you sleep."
|
|
23
23
|
|
|
@@ -455,7 +455,7 @@ def export_lesson_pptx(
|
|
|
455
455
|
|
|
456
456
|
# Lesson title -- 44pt white bold, centered
|
|
457
457
|
tb = slide.shapes.add_textbox(
|
|
458
|
-
Inches(1.5), Inches(
|
|
458
|
+
Inches(1.5), Inches(1.5), slide_w - Inches(3.0), Inches(2.5),
|
|
459
459
|
)
|
|
460
460
|
tf = tb.text_frame
|
|
461
461
|
tf.word_wrap = True
|
|
@@ -465,9 +465,30 @@ def export_lesson_pptx(
|
|
|
465
465
|
run.text = lesson.title
|
|
466
466
|
_set_text_props(run, 44, theme["text_light"], bold=True)
|
|
467
467
|
|
|
468
|
-
#
|
|
468
|
+
# Aim -- the driving question, centered below title
|
|
469
|
+
aim_text = lesson.objective
|
|
470
|
+
if aim_text and not aim_text.lower().startswith("students will"):
|
|
471
|
+
aim_display = f"Aim: {aim_text}"
|
|
472
|
+
elif aim_text:
|
|
473
|
+
aim_display = aim_text
|
|
474
|
+
else:
|
|
475
|
+
aim_display = ""
|
|
476
|
+
if aim_display:
|
|
477
|
+
tb_aim = slide.shapes.add_textbox(
|
|
478
|
+
Inches(1.5), Inches(4.0), slide_w - Inches(3.0), Inches(1.0),
|
|
479
|
+
)
|
|
480
|
+
tf_aim = tb_aim.text_frame
|
|
481
|
+
tf_aim.word_wrap = True
|
|
482
|
+
p_aim = tf_aim.paragraphs[0]
|
|
483
|
+
p_aim.alignment = PP_ALIGN.CENTER
|
|
484
|
+
run_aim = p_aim.add_run()
|
|
485
|
+
run_aim.text = aim_display
|
|
486
|
+
_set_text_props(run_aim, 20, "EEEEEE")
|
|
487
|
+
run_aim.font.italic = True
|
|
488
|
+
|
|
489
|
+
# Subtitle: "Teacher Name | Date" -- 16pt
|
|
469
490
|
tb2 = slide.shapes.add_textbox(
|
|
470
|
-
Inches(1.5), Inches(
|
|
491
|
+
Inches(1.5), Inches(5.2), slide_w - Inches(3.0), Inches(0.8),
|
|
471
492
|
)
|
|
472
493
|
tf2 = tb2.text_frame
|
|
473
494
|
tf2.word_wrap = True
|
|
@@ -475,11 +496,10 @@ def export_lesson_pptx(
|
|
|
475
496
|
p2.alignment = PP_ALIGN.CENTER
|
|
476
497
|
run2 = p2.add_run()
|
|
477
498
|
run2.text = (
|
|
478
|
-
f"Lesson {lesson.lesson_number} | "
|
|
479
499
|
f"{teacher_display_name} | "
|
|
480
500
|
f"{date.today().strftime('%B %d, %Y')}"
|
|
481
501
|
)
|
|
482
|
-
_set_text_props(run2,
|
|
502
|
+
_set_text_props(run2, 16, "BBBBBB")
|
|
483
503
|
|
|
484
504
|
# Bottom accent bar in subject color
|
|
485
505
|
_bar(slide, Emu(0), slide_h - Inches(0.15), slide_w, Inches(0.15), theme["secondary"])
|
|
@@ -535,7 +555,7 @@ def export_lesson_pptx(
|
|
|
535
555
|
run.text = "Standards Addressed"
|
|
536
556
|
_set_text_props(run, 16, "888888", bold=True)
|
|
537
557
|
|
|
538
|
-
for std in lesson.standards[:
|
|
558
|
+
for std in lesson.standards[:3]:
|
|
539
559
|
p = tf.add_paragraph()
|
|
540
560
|
p.space_before = Pt(6)
|
|
541
561
|
run = p.add_run()
|
|
@@ -577,9 +597,22 @@ def export_lesson_pptx(
|
|
|
577
597
|
p = tf.paragraphs[0]
|
|
578
598
|
p.line_spacing = Pt(38)
|
|
579
599
|
run = p.add_run()
|
|
580
|
-
|
|
600
|
+
# Brief prompt on slide face, full text in speaker notes
|
|
601
|
+
dn_text = lesson.do_now
|
|
602
|
+
if len(dn_text) > 250:
|
|
603
|
+
cutoff = dn_text[:250].rfind(". ")
|
|
604
|
+
dn_display = dn_text[:cutoff + 1] if cutoff > 80 else dn_text[:250].rsplit(" ", 1)[0] + "..."
|
|
605
|
+
else:
|
|
606
|
+
dn_display = dn_text
|
|
607
|
+
run.text = dn_display
|
|
581
608
|
_set_text_props(run, 28, theme["text_dark"])
|
|
582
609
|
|
|
610
|
+
# Full Do Now in speaker notes
|
|
611
|
+
if len(dn_text) > 250:
|
|
612
|
+
notes_slide = slide.notes_slide
|
|
613
|
+
notes_tf = notes_slide.notes_text_frame
|
|
614
|
+
notes_tf.text = dn_text
|
|
615
|
+
|
|
583
616
|
if do_now_img:
|
|
584
617
|
from clawed.slide_images import _extract_key_concepts
|
|
585
618
|
concepts = _extract_key_concepts(lesson.do_now)
|
|
@@ -663,41 +696,45 @@ def export_lesson_pptx(
|
|
|
663
696
|
|
|
664
697
|
_add_footer(slide, slide_num[0])
|
|
665
698
|
|
|
666
|
-
# ── Vocabulary slide
|
|
667
|
-
#
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
#
|
|
677
|
-
if not
|
|
699
|
+
# ── Vocabulary slide ───────────────────────────────────────
|
|
700
|
+
# Prefer structured vocabulary from v2.3 model fields
|
|
701
|
+
vocab_pairs: list[tuple[str, str]] = []
|
|
702
|
+
if hasattr(lesson, "vocabulary") and lesson.vocabulary:
|
|
703
|
+
for vt in lesson.vocabulary:
|
|
704
|
+
term = getattr(vt, "term", "") if hasattr(vt, "term") else vt.get("term", "")
|
|
705
|
+
defn = getattr(vt, "definition", "") if hasattr(vt, "definition") else vt.get("definition", "")
|
|
706
|
+
if term and defn:
|
|
707
|
+
vocab_pairs.append((term, defn))
|
|
708
|
+
|
|
709
|
+
# Fallback: regex extraction from DI text
|
|
710
|
+
if not vocab_pairs:
|
|
711
|
+
di_text_raw = lesson.direct_instruction or ""
|
|
678
712
|
vocab_patterns = re.findall(
|
|
679
|
-
r'(
|
|
680
|
-
r'([A-Za-z][^\n]{15,200})',
|
|
713
|
+
r'\*\*([A-Z][^*]{2,30})\*\*\s*[-—:]+\s*([^*\n]{15,200})',
|
|
681
714
|
di_text_raw,
|
|
682
715
|
)
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
716
|
+
if not vocab_patterns:
|
|
717
|
+
vocab_patterns = re.findall(
|
|
718
|
+
r'(?:^|\n)\s*\*?\*?([A-Z][a-z]+(?:\s+[A-Za-z]+){0,3})\*?\*?\s*[-—:]+\s+'
|
|
719
|
+
r'([A-Za-z][^\n]{15,200})',
|
|
720
|
+
di_text_raw,
|
|
721
|
+
)
|
|
722
|
+
INSTRUCTIONAL_WORDS = {
|
|
723
|
+
"check", "ask", "call", "facilitate", "transition", "minutes",
|
|
724
|
+
"discuss", "display", "distribute", "brief", "move", "moved",
|
|
725
|
+
"students", "responses", "excellent", "turn", "now", "let",
|
|
726
|
+
"today", "good", "morning", "scholars", "friends", "class",
|
|
727
|
+
"next", "first", "take", "look", "read", "write", "complete",
|
|
728
|
+
}
|
|
729
|
+
vocab_pairs = [
|
|
730
|
+
(term.strip(), defn.strip()) for term, defn in vocab_patterns
|
|
731
|
+
if 1 <= len(term.split()) <= 4
|
|
732
|
+
and len(defn.split()) >= 3
|
|
733
|
+
and not any(w in defn.lower().split()[:3] for w in INSTRUCTIONAL_WORDS)
|
|
734
|
+
and not any(w in term.lower().split() for w in INSTRUCTIONAL_WORDS)
|
|
735
|
+
]
|
|
736
|
+
|
|
737
|
+
if vocab_pairs:
|
|
701
738
|
slide = _next_slide()
|
|
702
739
|
_white_bg(slide)
|
|
703
740
|
|
|
@@ -724,7 +761,7 @@ def export_lesson_pptx(
|
|
|
724
761
|
tf = tb.text_frame
|
|
725
762
|
tf.word_wrap = True
|
|
726
763
|
|
|
727
|
-
for idx, (term, definition) in enumerate(
|
|
764
|
+
for idx, (term, definition) in enumerate(vocab_pairs[:8]):
|
|
728
765
|
p = tf.paragraphs[0] if idx == 0 else tf.add_paragraph()
|
|
729
766
|
p.space_before = Pt(10)
|
|
730
767
|
p.line_spacing = Pt(36)
|
|
@@ -808,7 +845,11 @@ def export_lesson_pptx(
|
|
|
808
845
|
# SECTION DIVIDER: "Let's Practice Together"
|
|
809
846
|
# ═══════════════════════════════════════════════════════════════════
|
|
810
847
|
if lesson.guided_practice:
|
|
811
|
-
|
|
848
|
+
gp_min = lesson.time_estimates.get("guided_practice", 15)
|
|
849
|
+
_section_divider(
|
|
850
|
+
prs, slide_num, f"Let's Practice Together\n({gp_min} minutes)",
|
|
851
|
+
theme, slide_w, slide_h,
|
|
852
|
+
)
|
|
812
853
|
|
|
813
854
|
# ═══════════════════════════════════════════════════════════════════
|
|
814
855
|
# GUIDED PRACTICE -- "Your Turn" header
|
|
@@ -832,7 +873,16 @@ def export_lesson_pptx(
|
|
|
832
873
|
|
|
833
874
|
# No image on Guided Practice -- keep clean for readability
|
|
834
875
|
|
|
835
|
-
#
|
|
876
|
+
# Brief student-facing instructions on slide face (first 2-3 sentences)
|
|
877
|
+
gp_text = lesson.guided_practice
|
|
878
|
+
gp_summary = gp_text
|
|
879
|
+
if len(gp_text) > 250:
|
|
880
|
+
cutoff = gp_text[:250].rfind(". ")
|
|
881
|
+
if cutoff > 80:
|
|
882
|
+
gp_summary = gp_text[:cutoff + 1]
|
|
883
|
+
else:
|
|
884
|
+
gp_summary = gp_text[:250].rsplit(" ", 1)[0] + "..."
|
|
885
|
+
|
|
836
886
|
tb = slide.shapes.add_textbox(
|
|
837
887
|
Inches(0.8), Inches(1.8), slide_w - Inches(2.0), Inches(4.5),
|
|
838
888
|
)
|
|
@@ -841,9 +891,14 @@ def export_lesson_pptx(
|
|
|
841
891
|
p = tf.paragraphs[0]
|
|
842
892
|
p.line_spacing = Pt(34)
|
|
843
893
|
run = p.add_run()
|
|
844
|
-
run.text =
|
|
894
|
+
run.text = gp_summary
|
|
845
895
|
_set_text_props(run, 24, theme["text_dark"])
|
|
846
896
|
|
|
897
|
+
# Full guided practice in speaker notes
|
|
898
|
+
notes_slide = slide.notes_slide
|
|
899
|
+
notes_tf = notes_slide.notes_text_frame
|
|
900
|
+
notes_tf.text = gp_text
|
|
901
|
+
|
|
847
902
|
# Time estimate
|
|
848
903
|
minutes = lesson.time_estimates.get("guided_practice", 15)
|
|
849
904
|
tb_time = slide.shapes.add_textbox(
|
|
@@ -883,7 +938,16 @@ def export_lesson_pptx(
|
|
|
883
938
|
|
|
884
939
|
# No image on Independent Work -- keep clean for readability
|
|
885
940
|
|
|
886
|
-
#
|
|
941
|
+
# Brief student-facing instructions on slide face
|
|
942
|
+
iw_text = lesson.independent_work
|
|
943
|
+
iw_summary = iw_text
|
|
944
|
+
if len(iw_text) > 250:
|
|
945
|
+
cutoff = iw_text[:250].rfind(". ")
|
|
946
|
+
if cutoff > 80:
|
|
947
|
+
iw_summary = iw_text[:cutoff + 1]
|
|
948
|
+
else:
|
|
949
|
+
iw_summary = iw_text[:250].rsplit(" ", 1)[0] + "..."
|
|
950
|
+
|
|
887
951
|
tb = slide.shapes.add_textbox(
|
|
888
952
|
Inches(1.0), Inches(1.8), slide_w - Inches(2.0), Inches(4.5),
|
|
889
953
|
)
|
|
@@ -892,9 +956,14 @@ def export_lesson_pptx(
|
|
|
892
956
|
p = tf.paragraphs[0]
|
|
893
957
|
p.line_spacing = Pt(34)
|
|
894
958
|
run = p.add_run()
|
|
895
|
-
run.text =
|
|
959
|
+
run.text = iw_summary
|
|
896
960
|
_set_text_props(run, 24, theme["text_dark"])
|
|
897
961
|
|
|
962
|
+
# Full independent work in speaker notes
|
|
963
|
+
notes_slide = slide.notes_slide
|
|
964
|
+
notes_tf = notes_slide.notes_text_frame
|
|
965
|
+
notes_tf.text = iw_text
|
|
966
|
+
|
|
898
967
|
# Time estimate in corner
|
|
899
968
|
minutes = lesson.time_estimates.get("independent_work", 10)
|
|
900
969
|
_rounded_card(
|
|
@@ -919,7 +988,7 @@ def export_lesson_pptx(
|
|
|
919
988
|
# SECTION DIVIDER: "Show What You Know"
|
|
920
989
|
# ═══════════════════════════════════════════════════════════════════
|
|
921
990
|
if lesson.exit_ticket:
|
|
922
|
-
_section_divider(prs, slide_num, "Show What You Know", theme, slide_w, slide_h)
|
|
991
|
+
_section_divider(prs, slide_num, "Show What You Know\n(Exit Ticket)", theme, slide_w, slide_h)
|
|
923
992
|
|
|
924
993
|
# ═══════════════════════════════════════════════════════════════════
|
|
925
994
|
# EXIT TICKET -- distinctive assessment design
|
|
@@ -972,7 +1041,11 @@ def export_lesson_pptx(
|
|
|
972
1041
|
tf = tb.text_frame
|
|
973
1042
|
tf.word_wrap = True
|
|
974
1043
|
run = tf.paragraphs[0].add_run()
|
|
975
|
-
|
|
1044
|
+
# Truncate long questions for slide readability
|
|
1045
|
+
q_text = q.question
|
|
1046
|
+
if len(q_text) > 120:
|
|
1047
|
+
q_text = q_text[:120].rsplit(" ", 1)[0] + "..."
|
|
1048
|
+
run.text = q_text
|
|
976
1049
|
_set_text_props(run, 20, theme["text_dark"])
|
|
977
1050
|
|
|
978
1051
|
q_top += Inches(1.3)
|
|
@@ -1025,8 +1098,19 @@ def export_lesson_pptx(
|
|
|
1025
1098
|
p = tf.paragraphs[0]
|
|
1026
1099
|
p.line_spacing = Pt(30)
|
|
1027
1100
|
run = p.add_run()
|
|
1028
|
-
|
|
1101
|
+
# Brief homework summary on slide, full in notes
|
|
1102
|
+
hw_text = lesson.homework
|
|
1103
|
+
if len(hw_text) > 200:
|
|
1104
|
+
cutoff = hw_text[:200].rfind(". ")
|
|
1105
|
+
hw_display = hw_text[:cutoff + 1] if cutoff > 60 else hw_text[:200].rsplit(" ", 1)[0] + "..."
|
|
1106
|
+
else:
|
|
1107
|
+
hw_display = hw_text
|
|
1108
|
+
run.text = hw_display
|
|
1029
1109
|
_set_text_props(run, 22, "DDDDDD")
|
|
1110
|
+
if len(hw_text) > 200:
|
|
1111
|
+
notes_slide = slide.notes_slide
|
|
1112
|
+
notes_tf = notes_slide.notes_text_frame
|
|
1113
|
+
notes_tf.text = f"HOMEWORK (full text):\n{hw_text}"
|
|
1030
1114
|
else:
|
|
1031
1115
|
# "Key Takeaway" or "Questions?"
|
|
1032
1116
|
tb = slide.shapes.add_textbox(
|
|
@@ -73,22 +73,35 @@ def _ask_provider() -> tuple[LLMProvider, str | None]:
|
|
|
73
73
|
table.add_column("Provider")
|
|
74
74
|
table.add_column("Cost")
|
|
75
75
|
table.add_column("Notes")
|
|
76
|
-
table.add_row("1", "
|
|
77
|
-
table.add_row("2", "
|
|
78
|
-
table.add_row("3", "
|
|
76
|
+
table.add_row("1", "Google Gemini", "Free tier available", "Best for getting started \u2014 generous free quota")
|
|
77
|
+
table.add_row("2", "Anthropic (Claude)", "Pay per token", "Highest quality")
|
|
78
|
+
table.add_row("3", "OpenAI (GPT-4o)", "Pay per token", "Widely used")
|
|
79
|
+
table.add_row("4", "Ollama (local)", "Free", "Runs on your machine \u2014 no internet needed")
|
|
79
80
|
console.print()
|
|
80
81
|
console.print(table)
|
|
81
82
|
|
|
82
83
|
while True:
|
|
83
|
-
choice = Prompt.ask(
|
|
84
|
+
choice = Prompt.ask(
|
|
85
|
+
"\n[bold]Pick a provider[/bold]", choices=["1", "2", "3", "4"], default="1",
|
|
86
|
+
)
|
|
84
87
|
if choice == "1":
|
|
88
|
+
provider = LLMProvider.GOOGLE
|
|
89
|
+
console.print(
|
|
90
|
+
"\n [dim]Get a free API key at: https://aistudio.google.com/apikey[/dim]",
|
|
91
|
+
)
|
|
92
|
+
key = Prompt.ask(" [bold]Google AI API key[/bold] [dim](AIza...)[/dim]")
|
|
93
|
+
if not key.strip():
|
|
94
|
+
console.print(" [red]API key cannot be empty.[/red]")
|
|
95
|
+
continue
|
|
96
|
+
return provider, key.strip()
|
|
97
|
+
elif choice == "2":
|
|
85
98
|
provider = LLMProvider.ANTHROPIC
|
|
86
99
|
key = Prompt.ask(" [bold]Anthropic API key[/bold] [dim](sk-ant-...)[/dim]")
|
|
87
100
|
if not key.strip():
|
|
88
101
|
console.print(" [red]API key cannot be empty.[/red]")
|
|
89
102
|
continue
|
|
90
103
|
return provider, key.strip()
|
|
91
|
-
elif choice == "
|
|
104
|
+
elif choice == "3":
|
|
92
105
|
provider = LLMProvider.OPENAI
|
|
93
106
|
key = Prompt.ask(" [bold]OpenAI API key[/bold] [dim](sk-...)[/dim]")
|
|
94
107
|
if not key.strip():
|
|
@@ -126,6 +139,10 @@ def _detect_available_models() -> tuple[LLMProvider | None, str]:
|
|
|
126
139
|
and Ollama running locally.
|
|
127
140
|
Returns (provider, description) or (None, message).
|
|
128
141
|
"""
|
|
142
|
+
# Check Google Gemini (free tier)
|
|
143
|
+
if os.environ.get("GOOGLE_API_KEY"):
|
|
144
|
+
return LLMProvider.GOOGLE, "Google Gemini API key found in environment"
|
|
145
|
+
|
|
129
146
|
# Check Anthropic
|
|
130
147
|
if os.environ.get("ANTHROPIC_API_KEY"):
|
|
131
148
|
return LLMProvider.ANTHROPIC, "Anthropic API key found in environment"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|