@synsci/cli-darwin-x64 1.1.70 → 1.1.72
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.
- package/bin/skills/citation-management/SKILL.md +1109 -0
- package/bin/skills/citation-management/assets/bibtex_template.bib +264 -0
- package/bin/skills/citation-management/assets/citation_checklist.md +386 -0
- package/bin/skills/citation-management/references/bibtex_formatting.md +908 -0
- package/bin/skills/citation-management/references/citation_validation.md +794 -0
- package/bin/skills/citation-management/references/google_scholar_search.md +725 -0
- package/bin/skills/citation-management/references/metadata_extraction.md +870 -0
- package/bin/skills/citation-management/references/pubmed_search.md +839 -0
- package/bin/skills/citation-management/scripts/doi_to_bibtex.py +182 -0
- package/bin/skills/citation-management/scripts/extract_metadata.py +570 -0
- package/bin/skills/citation-management/scripts/format_bibtex.py +349 -0
- package/bin/skills/citation-management/scripts/search_google_scholar.py +251 -0
- package/bin/skills/citation-management/scripts/search_pubmed.py +348 -0
- package/bin/skills/citation-management/scripts/validate_citations.py +494 -0
- package/bin/skills/clinical-decision-support/README.md +129 -0
- package/bin/skills/clinical-decision-support/SKILL.md +506 -0
- package/bin/skills/clinical-decision-support/assets/biomarker_report_template.tex +380 -0
- package/bin/skills/clinical-decision-support/assets/clinical_pathway_template.tex +222 -0
- package/bin/skills/clinical-decision-support/assets/cohort_analysis_template.tex +359 -0
- package/bin/skills/clinical-decision-support/assets/color_schemes.tex +149 -0
- package/bin/skills/clinical-decision-support/assets/example_gbm_cohort.md +208 -0
- package/bin/skills/clinical-decision-support/assets/recommendation_strength_guide.md +328 -0
- package/bin/skills/clinical-decision-support/assets/treatment_recommendation_template.tex +529 -0
- package/bin/skills/clinical-decision-support/references/biomarker_classification.md +719 -0
- package/bin/skills/clinical-decision-support/references/clinical_decision_algorithms.md +604 -0
- package/bin/skills/clinical-decision-support/references/evidence_synthesis.md +840 -0
- package/bin/skills/clinical-decision-support/references/outcome_analysis.md +640 -0
- package/bin/skills/clinical-decision-support/references/patient_cohort_analysis.md +427 -0
- package/bin/skills/clinical-decision-support/references/treatment_recommendations.md +521 -0
- package/bin/skills/clinical-decision-support/scripts/biomarker_classifier.py +383 -0
- package/bin/skills/clinical-decision-support/scripts/build_decision_tree.py +417 -0
- package/bin/skills/clinical-decision-support/scripts/create_cohort_tables.py +509 -0
- package/bin/skills/clinical-decision-support/scripts/generate_survival_analysis.py +441 -0
- package/bin/skills/clinical-decision-support/scripts/validate_cds_document.py +326 -0
- package/bin/skills/clinical-reports/IMPLEMENTATION_SUMMARY.md +641 -0
- package/bin/skills/clinical-reports/README.md +236 -0
- package/bin/skills/clinical-reports/SKILL.md +1127 -0
- package/bin/skills/clinical-reports/assets/case_report_template.md +352 -0
- package/bin/skills/clinical-reports/assets/clinical_trial_csr_template.md +353 -0
- package/bin/skills/clinical-reports/assets/clinical_trial_sae_template.md +359 -0
- package/bin/skills/clinical-reports/assets/consult_note_template.md +305 -0
- package/bin/skills/clinical-reports/assets/discharge_summary_template.md +453 -0
- package/bin/skills/clinical-reports/assets/hipaa_compliance_checklist.md +395 -0
- package/bin/skills/clinical-reports/assets/history_physical_template.md +305 -0
- package/bin/skills/clinical-reports/assets/lab_report_template.md +309 -0
- package/bin/skills/clinical-reports/assets/pathology_report_template.md +249 -0
- package/bin/skills/clinical-reports/assets/quality_checklist.md +338 -0
- package/bin/skills/clinical-reports/assets/radiology_report_template.md +318 -0
- package/bin/skills/clinical-reports/assets/soap_note_template.md +253 -0
- package/bin/skills/clinical-reports/references/case_report_guidelines.md +570 -0
- package/bin/skills/clinical-reports/references/clinical_trial_reporting.md +693 -0
- package/bin/skills/clinical-reports/references/data_presentation.md +530 -0
- package/bin/skills/clinical-reports/references/diagnostic_reports_standards.md +629 -0
- package/bin/skills/clinical-reports/references/medical_terminology.md +588 -0
- package/bin/skills/clinical-reports/references/patient_documentation.md +744 -0
- package/bin/skills/clinical-reports/references/peer_review_standards.md +585 -0
- package/bin/skills/clinical-reports/references/regulatory_compliance.md +577 -0
- package/bin/skills/clinical-reports/scripts/check_deidentification.py +332 -0
- package/bin/skills/clinical-reports/scripts/compliance_checker.py +78 -0
- package/bin/skills/clinical-reports/scripts/extract_clinical_data.py +97 -0
- package/bin/skills/clinical-reports/scripts/format_adverse_events.py +97 -0
- package/bin/skills/clinical-reports/scripts/generate_report_template.py +149 -0
- package/bin/skills/clinical-reports/scripts/terminology_validator.py +126 -0
- package/bin/skills/clinical-reports/scripts/validate_case_report.py +323 -0
- package/bin/skills/clinical-reports/scripts/validate_trial_report.py +88 -0
- package/bin/skills/fireworks-ai/SKILL.md +665 -0
- package/bin/skills/generate-image/SKILL.md +178 -0
- package/bin/skills/generate-image/scripts/generate_image.py +254 -0
- package/bin/skills/groq/SKILL.md +347 -0
- package/bin/skills/hypothesis-generation/SKILL.md +293 -0
- package/bin/skills/hypothesis-generation/assets/FORMATTING_GUIDE.md +672 -0
- package/bin/skills/hypothesis-generation/assets/hypothesis_generation.sty +307 -0
- package/bin/skills/hypothesis-generation/assets/hypothesis_report_template.tex +572 -0
- package/bin/skills/hypothesis-generation/references/experimental_design_patterns.md +329 -0
- package/bin/skills/hypothesis-generation/references/hypothesis_quality_criteria.md +198 -0
- package/bin/skills/hypothesis-generation/references/literature_search_strategies.md +622 -0
- package/bin/skills/latex-posters/README.md +417 -0
- package/bin/skills/latex-posters/SKILL.md +1602 -0
- package/bin/skills/latex-posters/assets/baposter_template.tex +257 -0
- package/bin/skills/latex-posters/assets/beamerposter_template.tex +244 -0
- package/bin/skills/latex-posters/assets/poster_quality_checklist.md +358 -0
- package/bin/skills/latex-posters/assets/tikzposter_template.tex +251 -0
- package/bin/skills/latex-posters/references/latex_poster_packages.md +745 -0
- package/bin/skills/latex-posters/references/poster_content_guide.md +748 -0
- package/bin/skills/latex-posters/references/poster_design_principles.md +806 -0
- package/bin/skills/latex-posters/references/poster_layout_design.md +900 -0
- package/bin/skills/latex-posters/scripts/review_poster.sh +214 -0
- package/bin/skills/literature-review/SKILL.md +641 -0
- package/bin/skills/literature-review/assets/review_template.md +412 -0
- package/bin/skills/literature-review/references/citation_styles.md +166 -0
- package/bin/skills/literature-review/references/database_strategies.md +455 -0
- package/bin/skills/literature-review/scripts/generate_pdf.py +184 -0
- package/bin/skills/literature-review/scripts/search_databases.py +310 -0
- package/bin/skills/literature-review/scripts/verify_citations.py +218 -0
- package/bin/skills/market-research-reports/SKILL.md +904 -0
- package/bin/skills/market-research-reports/assets/FORMATTING_GUIDE.md +428 -0
- package/bin/skills/market-research-reports/assets/market_report_template.tex +1380 -0
- package/bin/skills/market-research-reports/assets/market_research.sty +564 -0
- package/bin/skills/market-research-reports/references/data_analysis_patterns.md +548 -0
- package/bin/skills/market-research-reports/references/report_structure_guide.md +999 -0
- package/bin/skills/market-research-reports/references/visual_generation_guide.md +1077 -0
- package/bin/skills/market-research-reports/scripts/generate_market_visuals.py +472 -0
- package/bin/skills/markitdown/INSTALLATION_GUIDE.md +318 -0
- package/bin/skills/markitdown/LICENSE.txt +22 -0
- package/bin/skills/markitdown/OPENROUTER_INTEGRATION.md +359 -0
- package/bin/skills/markitdown/QUICK_REFERENCE.md +309 -0
- package/bin/skills/markitdown/README.md +184 -0
- package/bin/skills/markitdown/SKILL.md +486 -0
- package/bin/skills/markitdown/SKILL_SUMMARY.md +307 -0
- package/bin/skills/markitdown/assets/example_usage.md +463 -0
- package/bin/skills/markitdown/references/api_reference.md +399 -0
- package/bin/skills/markitdown/references/file_formats.md +542 -0
- package/bin/skills/markitdown/scripts/batch_convert.py +195 -0
- package/bin/skills/markitdown/scripts/convert_literature.py +262 -0
- package/bin/skills/markitdown/scripts/convert_with_ai.py +224 -0
- package/bin/skills/ml-paper-writing/SKILL.md +937 -0
- package/bin/skills/ml-paper-writing/references/checklists.md +361 -0
- package/bin/skills/ml-paper-writing/references/citation-workflow.md +562 -0
- package/bin/skills/ml-paper-writing/references/reviewer-guidelines.md +367 -0
- package/bin/skills/ml-paper-writing/references/sources.md +159 -0
- package/bin/skills/ml-paper-writing/references/writing-guide.md +476 -0
- package/bin/skills/ml-paper-writing/templates/README.md +251 -0
- package/bin/skills/ml-paper-writing/templates/aaai2026/README.md +534 -0
- package/bin/skills/ml-paper-writing/templates/aaai2026/aaai2026-unified-supp.tex +144 -0
- package/bin/skills/ml-paper-writing/templates/aaai2026/aaai2026-unified-template.tex +952 -0
- package/bin/skills/ml-paper-writing/templates/aaai2026/aaai2026.bib +111 -0
- package/bin/skills/ml-paper-writing/templates/aaai2026/aaai2026.bst +1493 -0
- package/bin/skills/ml-paper-writing/templates/aaai2026/aaai2026.sty +315 -0
- package/bin/skills/ml-paper-writing/templates/acl/README.md +50 -0
- package/bin/skills/ml-paper-writing/templates/acl/acl.sty +312 -0
- package/bin/skills/ml-paper-writing/templates/acl/acl_latex.tex +377 -0
- package/bin/skills/ml-paper-writing/templates/acl/acl_lualatex.tex +101 -0
- package/bin/skills/ml-paper-writing/templates/acl/acl_natbib.bst +1940 -0
- package/bin/skills/ml-paper-writing/templates/acl/anthology.bib.txt +26 -0
- package/bin/skills/ml-paper-writing/templates/acl/custom.bib +70 -0
- package/bin/skills/ml-paper-writing/templates/acl/formatting.md +326 -0
- package/bin/skills/ml-paper-writing/templates/colm2025/README.md +3 -0
- package/bin/skills/ml-paper-writing/templates/colm2025/colm2025_conference.bib +11 -0
- package/bin/skills/ml-paper-writing/templates/colm2025/colm2025_conference.bst +1440 -0
- package/bin/skills/ml-paper-writing/templates/colm2025/colm2025_conference.pdf +0 -0
- package/bin/skills/ml-paper-writing/templates/colm2025/colm2025_conference.sty +218 -0
- package/bin/skills/ml-paper-writing/templates/colm2025/colm2025_conference.tex +305 -0
- package/bin/skills/ml-paper-writing/templates/colm2025/fancyhdr.sty +485 -0
- package/bin/skills/ml-paper-writing/templates/colm2025/math_commands.tex +508 -0
- package/bin/skills/ml-paper-writing/templates/colm2025/natbib.sty +1246 -0
- package/bin/skills/ml-paper-writing/templates/iclr2026/fancyhdr.sty +485 -0
- package/bin/skills/ml-paper-writing/templates/iclr2026/iclr2026_conference.bib +24 -0
- package/bin/skills/ml-paper-writing/templates/iclr2026/iclr2026_conference.bst +1440 -0
- package/bin/skills/ml-paper-writing/templates/iclr2026/iclr2026_conference.pdf +0 -0
- package/bin/skills/ml-paper-writing/templates/iclr2026/iclr2026_conference.sty +246 -0
- package/bin/skills/ml-paper-writing/templates/iclr2026/iclr2026_conference.tex +414 -0
- package/bin/skills/ml-paper-writing/templates/iclr2026/math_commands.tex +508 -0
- package/bin/skills/ml-paper-writing/templates/iclr2026/natbib.sty +1246 -0
- package/bin/skills/ml-paper-writing/templates/icml2026/algorithm.sty +79 -0
- package/bin/skills/ml-paper-writing/templates/icml2026/algorithmic.sty +201 -0
- package/bin/skills/ml-paper-writing/templates/icml2026/example_paper.bib +75 -0
- package/bin/skills/ml-paper-writing/templates/icml2026/example_paper.pdf +0 -0
- package/bin/skills/ml-paper-writing/templates/icml2026/example_paper.tex +662 -0
- package/bin/skills/ml-paper-writing/templates/icml2026/fancyhdr.sty +864 -0
- package/bin/skills/ml-paper-writing/templates/icml2026/icml2026.bst +1443 -0
- package/bin/skills/ml-paper-writing/templates/icml2026/icml2026.sty +767 -0
- package/bin/skills/ml-paper-writing/templates/icml2026/icml_numpapers.pdf +0 -0
- package/bin/skills/ml-paper-writing/templates/neurips2025/Makefile +36 -0
- package/bin/skills/ml-paper-writing/templates/neurips2025/extra_pkgs.tex +53 -0
- package/bin/skills/ml-paper-writing/templates/neurips2025/main.tex +38 -0
- package/bin/skills/ml-paper-writing/templates/neurips2025/neurips.sty +382 -0
- package/bin/skills/paper-2-web/SKILL.md +491 -0
- package/bin/skills/paper-2-web/references/installation.md +141 -0
- package/bin/skills/paper-2-web/references/paper2poster.md +346 -0
- package/bin/skills/paper-2-web/references/paper2video.md +305 -0
- package/bin/skills/paper-2-web/references/paper2web.md +187 -0
- package/bin/skills/paper-2-web/references/usage_examples.md +436 -0
- package/bin/skills/peer-review/SKILL.md +702 -0
- package/bin/skills/peer-review/references/calibration_guidelines.md +196 -0
- package/bin/skills/peer-review/references/common_issues.md +552 -0
- package/bin/skills/peer-review/references/paper_mechanics.md +269 -0
- package/bin/skills/peer-review/references/reporting_standards.md +290 -0
- package/bin/skills/peer-review/references/scoring_rubric.md +239 -0
- package/bin/skills/pptx-posters/SKILL.md +410 -0
- package/bin/skills/pptx-posters/assets/poster_html_template.html +257 -0
- package/bin/skills/pptx-posters/assets/poster_quality_checklist.md +358 -0
- package/bin/skills/pptx-posters/references/poster_content_guide.md +748 -0
- package/bin/skills/pptx-posters/references/poster_design_principles.md +806 -0
- package/bin/skills/pptx-posters/references/poster_layout_design.md +900 -0
- package/bin/skills/research-grants/README.md +285 -0
- package/bin/skills/research-grants/SKILL.md +938 -0
- package/bin/skills/research-grants/assets/budget_justification_template.md +453 -0
- package/bin/skills/research-grants/assets/nih_specific_aims_template.md +166 -0
- package/bin/skills/research-grants/assets/nsf_project_summary_template.md +92 -0
- package/bin/skills/research-grants/references/broader_impacts.md +392 -0
- package/bin/skills/research-grants/references/darpa_guidelines.md +636 -0
- package/bin/skills/research-grants/references/doe_guidelines.md +586 -0
- package/bin/skills/research-grants/references/nih_guidelines.md +851 -0
- package/bin/skills/research-grants/references/nsf_guidelines.md +570 -0
- package/bin/skills/research-grants/references/specific_aims_guide.md +458 -0
- package/bin/skills/research-lookup/README.md +156 -0
- package/bin/skills/research-lookup/SKILL.md +606 -0
- package/bin/skills/research-lookup/examples.py +174 -0
- package/bin/skills/research-lookup/lookup.py +187 -0
- package/bin/skills/research-lookup/research_lookup.py +483 -0
- package/bin/skills/research-lookup/scripts/research_lookup.py +483 -0
- package/bin/skills/scholar-evaluation/SKILL.md +289 -0
- package/bin/skills/scholar-evaluation/references/evaluation_framework.md +663 -0
- package/bin/skills/scholar-evaluation/scripts/calculate_scores.py +366 -0
- package/bin/skills/scientific-critical-thinking/SKILL.md +566 -0
- package/bin/skills/scientific-critical-thinking/references/common_biases.md +364 -0
- package/bin/skills/scientific-critical-thinking/references/evidence_hierarchy.md +484 -0
- package/bin/skills/scientific-critical-thinking/references/experimental_design.md +496 -0
- package/bin/skills/scientific-critical-thinking/references/logical_fallacies.md +478 -0
- package/bin/skills/scientific-critical-thinking/references/scientific_method.md +169 -0
- package/bin/skills/scientific-critical-thinking/references/statistical_pitfalls.md +506 -0
- package/bin/skills/scientific-schematics/QUICK_REFERENCE.md +207 -0
- package/bin/skills/scientific-schematics/README.md +327 -0
- package/bin/skills/scientific-schematics/SKILL.md +615 -0
- package/bin/skills/scientific-schematics/example_usage.sh +89 -0
- package/bin/skills/scientific-schematics/references/best_practices.md +559 -0
- package/bin/skills/scientific-schematics/scripts/generate_schematic.py +135 -0
- package/bin/skills/scientific-schematics/scripts/generate_schematic_ai.py +807 -0
- package/bin/skills/scientific-schematics/test_ai_generation.py +243 -0
- package/bin/skills/scientific-slides/SKILL.md +942 -0
- package/bin/skills/scientific-slides/assets/timing_guidelines.md +597 -0
- package/bin/skills/scientific-slides/references/data_visualization_slides.md +708 -0
- package/bin/skills/scientific-slides/references/presentation_structure.md +642 -0
- package/bin/skills/scientific-slides/references/slide_design_principles.md +849 -0
- package/bin/skills/scientific-slides/references/talk_types_guide.md +687 -0
- package/bin/skills/scientific-slides/references/visual_review_workflow.md +775 -0
- package/bin/skills/scientific-slides/scripts/generate_slide_image.py +143 -0
- package/bin/skills/scientific-slides/scripts/generate_slide_image_ai.py +748 -0
- package/bin/skills/scientific-slides/scripts/pdf_to_images.py +201 -0
- package/bin/skills/scientific-slides/scripts/slides_to_pdf.py +220 -0
- package/bin/skills/scientific-slides/scripts/validate_presentation.py +367 -0
- package/bin/skills/scientific-writing/SKILL.md +714 -0
- package/bin/skills/scientific-writing/assets/REPORT_FORMATTING_GUIDE.md +574 -0
- package/bin/skills/scientific-writing/assets/scientific_report.sty +606 -0
- package/bin/skills/scientific-writing/assets/scientific_report_template.tex +449 -0
- package/bin/skills/scientific-writing/references/citation_styles.md +720 -0
- package/bin/skills/scientific-writing/references/figures_tables.md +806 -0
- package/bin/skills/scientific-writing/references/imrad_structure.md +686 -0
- package/bin/skills/scientific-writing/references/professional_report_formatting.md +664 -0
- package/bin/skills/scientific-writing/references/reporting_guidelines.md +748 -0
- package/bin/skills/scientific-writing/references/writing_principles.md +824 -0
- package/bin/skills/tinker/SKILL.md +2 -3
- package/bin/skills/together-ai/SKILL.md +722 -0
- package/bin/skills/treatment-plans/README.md +488 -0
- package/bin/skills/treatment-plans/SKILL.md +1579 -0
- package/bin/skills/treatment-plans/assets/STYLING_QUICK_REFERENCE.md +185 -0
- package/bin/skills/treatment-plans/assets/chronic_disease_management_plan.tex +665 -0
- package/bin/skills/treatment-plans/assets/general_medical_treatment_plan.tex +547 -0
- package/bin/skills/treatment-plans/assets/medical_treatment_plan.sty +222 -0
- package/bin/skills/treatment-plans/assets/mental_health_treatment_plan.tex +774 -0
- package/bin/skills/treatment-plans/assets/one_page_treatment_plan.tex +193 -0
- package/bin/skills/treatment-plans/assets/pain_management_plan.tex +799 -0
- package/bin/skills/treatment-plans/assets/perioperative_care_plan.tex +753 -0
- package/bin/skills/treatment-plans/assets/quality_checklist.md +471 -0
- package/bin/skills/treatment-plans/assets/rehabilitation_treatment_plan.tex +756 -0
- package/bin/skills/treatment-plans/references/goal_setting_frameworks.md +411 -0
- package/bin/skills/treatment-plans/references/intervention_guidelines.md +507 -0
- package/bin/skills/treatment-plans/references/regulatory_compliance.md +476 -0
- package/bin/skills/treatment-plans/references/specialty_specific_guidelines.md +655 -0
- package/bin/skills/treatment-plans/references/treatment_plan_standards.md +485 -0
- package/bin/skills/treatment-plans/scripts/check_completeness.py +322 -0
- package/bin/skills/treatment-plans/scripts/generate_template.py +233 -0
- package/bin/skills/treatment-plans/scripts/timeline_generator.py +385 -0
- package/bin/skills/treatment-plans/scripts/validate_treatment_plan.py +369 -0
- package/bin/skills/unsloth/SKILL.md +565 -47
- package/bin/skills/unsloth/docs/advanced-rl.md +222 -0
- package/bin/skills/unsloth/docs/chat-templates.md +141 -0
- package/bin/skills/unsloth/docs/datasets.md +489 -0
- package/bin/skills/unsloth/docs/docker-extended.md +99 -0
- package/bin/skills/unsloth/docs/dynamic-ggufs-2.0.md +116 -0
- package/bin/skills/unsloth/docs/dynamic-ggufs-aider.md +118 -0
- package/bin/skills/unsloth/docs/faq.md +91 -0
- package/bin/skills/unsloth/docs/fp16-vs-bf16.md +61 -0
- package/bin/skills/unsloth/docs/fp8-rl.md +224 -0
- package/bin/skills/unsloth/docs/glm-4.7-flash.md +997 -0
- package/bin/skills/unsloth/docs/inference-deployment-overview.md +17 -0
- package/bin/skills/unsloth/docs/inference.md +27 -0
- package/bin/skills/unsloth/docs/installation-docker.md +155 -0
- package/bin/skills/unsloth/docs/installation-pip.md +148 -0
- package/bin/skills/unsloth/docs/kernels-packing.md +190 -0
- package/bin/skills/unsloth/docs/kimi-k2.5.md +634 -0
- package/bin/skills/unsloth/docs/lm-studio.md +235 -0
- package/bin/skills/unsloth/docs/lora-hot-swapping.md +75 -0
- package/bin/skills/unsloth/docs/lora-hyperparameters.md +363 -0
- package/bin/skills/unsloth/docs/memory-efficient-rl.md +267 -0
- package/bin/skills/unsloth/docs/model-selection.md +70 -0
- package/bin/skills/unsloth/docs/models.md +532 -0
- package/bin/skills/unsloth/docs/multi-gpu-ddp.md +90 -0
- package/bin/skills/unsloth/docs/notebooks.md +223 -0
- package/bin/skills/unsloth/docs/overview.md +110 -0
- package/bin/skills/unsloth/docs/qwen3-coder-next-extended.md +900 -0
- package/bin/skills/unsloth/docs/qwen3-coder-next.md +900 -0
- package/bin/skills/unsloth/docs/requirements.md +45 -0
- package/bin/skills/unsloth/docs/reward-hacking.md +25 -0
- package/bin/skills/unsloth/docs/saving-to-gguf.md +138 -0
- package/bin/skills/unsloth/docs/saving-to-ollama.md +46 -0
- package/bin/skills/unsloth/docs/sglang-guide.md +278 -0
- package/bin/skills/unsloth/docs/speculative-decoding.md +70 -0
- package/bin/skills/unsloth/docs/tool-calling.md +334 -0
- package/bin/skills/unsloth/docs/troubleshooting-faq.md +204 -0
- package/bin/skills/unsloth/docs/troubleshooting-inference.md +26 -0
- package/bin/skills/unsloth/docs/tts-fine-tuning.md +149 -0
- package/bin/skills/unsloth/docs/tutorial-grpo.md +273 -0
- package/bin/skills/unsloth/docs/tutorial-llama3-ollama.md +356 -0
- package/bin/skills/unsloth/docs/vision-fine-tuning.md +135 -0
- package/bin/skills/unsloth/docs/vision-rl.md +170 -0
- package/bin/skills/unsloth/docs/vllm-engine-arguments.md +43 -0
- package/bin/skills/unsloth/docs/vllm-guide.md +98 -0
- package/bin/skills/venue-templates/SKILL.md +686 -0
- package/bin/skills/venue-templates/assets/examples/cell_summary_example.md +247 -0
- package/bin/skills/venue-templates/assets/examples/medical_structured_abstract.md +313 -0
- package/bin/skills/venue-templates/assets/examples/nature_abstract_examples.md +213 -0
- package/bin/skills/venue-templates/assets/examples/neurips_introduction_example.md +245 -0
- package/bin/skills/venue-templates/assets/grants/nih_specific_aims.tex +235 -0
- package/bin/skills/venue-templates/assets/grants/nsf_proposal_template.tex +375 -0
- package/bin/skills/venue-templates/assets/journals/nature_article.tex +171 -0
- package/bin/skills/venue-templates/assets/journals/neurips_article.tex +283 -0
- package/bin/skills/venue-templates/assets/journals/plos_one.tex +317 -0
- package/bin/skills/venue-templates/assets/posters/beamerposter_academic.tex +311 -0
- package/bin/skills/venue-templates/references/cell_press_style.md +483 -0
- package/bin/skills/venue-templates/references/conferences_formatting.md +564 -0
- package/bin/skills/venue-templates/references/cs_conference_style.md +463 -0
- package/bin/skills/venue-templates/references/grants_requirements.md +787 -0
- package/bin/skills/venue-templates/references/journals_formatting.md +486 -0
- package/bin/skills/venue-templates/references/medical_journal_styles.md +535 -0
- package/bin/skills/venue-templates/references/ml_conference_style.md +556 -0
- package/bin/skills/venue-templates/references/nature_science_style.md +405 -0
- package/bin/skills/venue-templates/references/posters_guidelines.md +628 -0
- package/bin/skills/venue-templates/references/reviewer_expectations.md +417 -0
- package/bin/skills/venue-templates/references/venue_writing_styles.md +321 -0
- package/bin/skills/venue-templates/scripts/customize_template.py +195 -0
- package/bin/skills/venue-templates/scripts/query_template.py +266 -0
- package/bin/skills/venue-templates/scripts/validate_format.py +250 -0
- package/bin/synsc +0 -0
- package/package.json +1 -1
- package/bin/skills/unsloth/references/index.md +0 -7
- package/bin/skills/unsloth/references/llms-full.md +0 -16799
- package/bin/skills/unsloth/references/llms-txt.md +0 -12044
- package/bin/skills/unsloth/references/llms.md +0 -82
|
@@ -0,0 +1,748 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
AI-powered slide image generation using Nano Banana Pro.
|
|
4
|
+
|
|
5
|
+
This script generates presentation slides or slide visuals using AI:
|
|
6
|
+
- full_slide mode: Generate complete slides with title, content, and visuals (for PDF workflow)
|
|
7
|
+
- visual_only mode: Generate just images/figures to place on slides (for PPT workflow)
|
|
8
|
+
|
|
9
|
+
Supports attaching reference images for context (e.g., "create a slide about this chart").
|
|
10
|
+
|
|
11
|
+
Uses smart iterative refinement:
|
|
12
|
+
1. Generate initial image with Nano Banana Pro
|
|
13
|
+
2. Quality review using Gemini 3 Pro
|
|
14
|
+
3. Only regenerate if quality is below threshold
|
|
15
|
+
4. Repeat until quality meets standards (max iterations)
|
|
16
|
+
|
|
17
|
+
Requirements:
|
|
18
|
+
- OPENROUTER_API_KEY environment variable
|
|
19
|
+
- requests library
|
|
20
|
+
|
|
21
|
+
Usage:
|
|
22
|
+
# Full slide for PDF workflow
|
|
23
|
+
python generate_slide_image_ai.py "Title: Introduction to ML\nKey points: supervised learning, neural networks" -o slide_01.png
|
|
24
|
+
|
|
25
|
+
# Visual only for PPT workflow
|
|
26
|
+
python generate_slide_image_ai.py "Neural network architecture diagram" -o figure.png --visual-only
|
|
27
|
+
|
|
28
|
+
# With reference images attached
|
|
29
|
+
python generate_slide_image_ai.py "Create a slide explaining this chart" -o slide.png --attach chart.png --attach logo.png
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
import argparse
|
|
33
|
+
import base64
|
|
34
|
+
import json
|
|
35
|
+
import os
|
|
36
|
+
import sys
|
|
37
|
+
import time
|
|
38
|
+
from pathlib import Path
|
|
39
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
try:
|
|
43
|
+
import requests
|
|
44
|
+
except ImportError:
|
|
45
|
+
print("Error: requests library not found. Install with: pip install requests")
|
|
46
|
+
sys.exit(1)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _load_env_file():
|
|
50
|
+
"""Load .env file from current directory, parent directories, or package directory."""
|
|
51
|
+
try:
|
|
52
|
+
from dotenv import load_dotenv
|
|
53
|
+
except ImportError:
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
# Try current working directory first
|
|
57
|
+
env_path = Path.cwd() / ".env"
|
|
58
|
+
if env_path.exists():
|
|
59
|
+
load_dotenv(dotenv_path=env_path, override=False)
|
|
60
|
+
return True
|
|
61
|
+
|
|
62
|
+
# Try parent directories (up to 5 levels)
|
|
63
|
+
cwd = Path.cwd()
|
|
64
|
+
for _ in range(5):
|
|
65
|
+
env_path = cwd / ".env"
|
|
66
|
+
if env_path.exists():
|
|
67
|
+
load_dotenv(dotenv_path=env_path, override=False)
|
|
68
|
+
return True
|
|
69
|
+
cwd = cwd.parent
|
|
70
|
+
if cwd == cwd.parent:
|
|
71
|
+
break
|
|
72
|
+
|
|
73
|
+
# Try the package's parent directory
|
|
74
|
+
script_dir = Path(__file__).resolve().parent
|
|
75
|
+
for _ in range(5):
|
|
76
|
+
env_path = script_dir / ".env"
|
|
77
|
+
if env_path.exists():
|
|
78
|
+
load_dotenv(dotenv_path=env_path, override=False)
|
|
79
|
+
return True
|
|
80
|
+
script_dir = script_dir.parent
|
|
81
|
+
if script_dir == script_dir.parent:
|
|
82
|
+
break
|
|
83
|
+
|
|
84
|
+
return False
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class SlideImageGenerator:
|
|
88
|
+
"""Generate presentation slides or visuals using AI with iterative refinement.
|
|
89
|
+
|
|
90
|
+
Two modes:
|
|
91
|
+
- full_slide: Generate complete slide with title, content, visuals (for PDF workflow)
|
|
92
|
+
- visual_only: Generate just the image/figure for a slide (for PPT workflow)
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
# Quality threshold for presentations (lower than journal/conference papers)
|
|
96
|
+
QUALITY_THRESHOLD = 6.5
|
|
97
|
+
|
|
98
|
+
# Guidelines for generating full slides (complete slide images)
|
|
99
|
+
FULL_SLIDE_GUIDELINES = """
|
|
100
|
+
Create a professional presentation slide image with these requirements:
|
|
101
|
+
|
|
102
|
+
SLIDE LAYOUT (16:9 aspect ratio):
|
|
103
|
+
- Clean, modern slide design
|
|
104
|
+
- Clear visual hierarchy: title at top, content below
|
|
105
|
+
- Generous margins (at least 5% on all sides)
|
|
106
|
+
- Balanced composition with intentional white space
|
|
107
|
+
|
|
108
|
+
TYPOGRAPHY:
|
|
109
|
+
- LARGE, bold title text (easily readable from distance)
|
|
110
|
+
- Clear, sans-serif fonts throughout
|
|
111
|
+
- High contrast text (dark on light or light on dark)
|
|
112
|
+
- Bullet points or key phrases, NOT paragraphs
|
|
113
|
+
- Maximum 5-6 lines of text content
|
|
114
|
+
- Default author/presenter: "K-Dense" (use this unless another name is specified)
|
|
115
|
+
|
|
116
|
+
VISUAL ELEMENTS:
|
|
117
|
+
- Use GENERIC, simple images and icons - avoid overly specific or detailed imagery
|
|
118
|
+
- MINIMAL extra elements - no decorative borders, shadows, or flourishes
|
|
119
|
+
- Visuals should support and enhance the message, not distract
|
|
120
|
+
- Professional, clean aesthetic with restraint
|
|
121
|
+
- Consistent color scheme (2-3 main colors only)
|
|
122
|
+
- Prefer abstract/conceptual visuals over literal representations
|
|
123
|
+
|
|
124
|
+
PROFESSIONAL MINIMALISM:
|
|
125
|
+
- Less is more: favor empty space over additional elements
|
|
126
|
+
- No unnecessary decorations, gradients, or visual noise
|
|
127
|
+
- Clean lines and simple shapes
|
|
128
|
+
- Focused content without visual clutter
|
|
129
|
+
- Corporate/academic level of professionalism
|
|
130
|
+
|
|
131
|
+
PRESENTATION QUALITY:
|
|
132
|
+
- Designed for projection (high contrast)
|
|
133
|
+
- Bold, impactful design that commands attention
|
|
134
|
+
- Professional and polished appearance
|
|
135
|
+
- No cluttered or busy layouts
|
|
136
|
+
- Consistent styling throughout the deck
|
|
137
|
+
"""
|
|
138
|
+
|
|
139
|
+
# Guidelines for generating slide visuals only (figures/images for PPT)
|
|
140
|
+
VISUAL_ONLY_GUIDELINES = """
|
|
141
|
+
Create a high-quality visual/figure for a presentation slide:
|
|
142
|
+
|
|
143
|
+
IMAGE QUALITY:
|
|
144
|
+
- Clean, professional appearance
|
|
145
|
+
- High resolution and sharp details
|
|
146
|
+
- Suitable for embedding in a slide
|
|
147
|
+
|
|
148
|
+
DESIGN:
|
|
149
|
+
- Simple, clear composition with MINIMAL elements
|
|
150
|
+
- High contrast for projection readability
|
|
151
|
+
- No text unless essential to the visual
|
|
152
|
+
- Transparent or white background preferred
|
|
153
|
+
- GENERIC imagery - avoid overly specific or detailed visuals
|
|
154
|
+
|
|
155
|
+
PROFESSIONAL MINIMALISM:
|
|
156
|
+
- Favor simplicity over complexity
|
|
157
|
+
- No decorative elements, shadows, or flourishes
|
|
158
|
+
- Clean lines and simple shapes only
|
|
159
|
+
- Remove any unnecessary visual noise
|
|
160
|
+
- Abstract/conceptual rather than literal representations
|
|
161
|
+
|
|
162
|
+
STYLE:
|
|
163
|
+
- Modern, professional aesthetic
|
|
164
|
+
- Colorblind-friendly colors
|
|
165
|
+
- Bold but restrained imagery
|
|
166
|
+
- Suitable for scientific/professional presentations
|
|
167
|
+
- Corporate/academic level of polish
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
def __init__(self, api_key: Optional[str] = None, verbose: bool = False):
|
|
171
|
+
"""
|
|
172
|
+
Initialize the generator.
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
api_key: OpenRouter API key (or use OPENROUTER_API_KEY env var)
|
|
176
|
+
verbose: Print detailed progress information
|
|
177
|
+
"""
|
|
178
|
+
self.api_key = api_key or os.getenv("OPENROUTER_API_KEY")
|
|
179
|
+
|
|
180
|
+
if not self.api_key:
|
|
181
|
+
_load_env_file()
|
|
182
|
+
self.api_key = os.getenv("OPENROUTER_API_KEY")
|
|
183
|
+
|
|
184
|
+
if not self.api_key:
|
|
185
|
+
raise ValueError(
|
|
186
|
+
"OPENROUTER_API_KEY not found. Please either:\n"
|
|
187
|
+
" 1. Set the OPENROUTER_API_KEY environment variable\n"
|
|
188
|
+
" 2. Add OPENROUTER_API_KEY to your .env file\n"
|
|
189
|
+
" 3. Pass api_key parameter to the constructor\n"
|
|
190
|
+
"Get your API key from: https://openrouter.ai/keys"
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
self.verbose = verbose
|
|
194
|
+
self._last_error = None
|
|
195
|
+
self.base_url = "https://openrouter.ai/api/v1"
|
|
196
|
+
# Nano Banana Pro for image generation
|
|
197
|
+
self.image_model = "google/gemini-3-pro-image-preview"
|
|
198
|
+
# Gemini 3 Pro for quality review
|
|
199
|
+
self.review_model = "google/gemini-3-pro"
|
|
200
|
+
|
|
201
|
+
def _log(self, message: str):
|
|
202
|
+
"""Log message if verbose mode is enabled."""
|
|
203
|
+
if self.verbose:
|
|
204
|
+
print(f"[{time.strftime('%H:%M:%S')}] {message}")
|
|
205
|
+
|
|
206
|
+
def _make_request(
|
|
207
|
+
self, model: str, messages: List[Dict[str, Any]], modalities: Optional[List[str]] = None
|
|
208
|
+
) -> Dict[str, Any]:
|
|
209
|
+
"""Make a request to OpenRouter API."""
|
|
210
|
+
headers = {
|
|
211
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
212
|
+
"Content-Type": "application/json",
|
|
213
|
+
"HTTP-Referer": "https://github.com/scientific-writer",
|
|
214
|
+
"X-Title": "Scientific Slide Generator",
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
payload = {"model": model, "messages": messages}
|
|
218
|
+
|
|
219
|
+
if modalities:
|
|
220
|
+
payload["modalities"] = modalities
|
|
221
|
+
|
|
222
|
+
self._log(f"Making request to {model}...")
|
|
223
|
+
|
|
224
|
+
try:
|
|
225
|
+
response = requests.post(f"{self.base_url}/chat/completions", headers=headers, json=payload, timeout=120)
|
|
226
|
+
|
|
227
|
+
try:
|
|
228
|
+
response_json = response.json()
|
|
229
|
+
except json.JSONDecodeError:
|
|
230
|
+
response_json = {"raw_text": response.text[:500]}
|
|
231
|
+
|
|
232
|
+
if response.status_code != 200:
|
|
233
|
+
error_detail = response_json.get("error", response_json)
|
|
234
|
+
self._log(f"HTTP {response.status_code}: {error_detail}")
|
|
235
|
+
raise RuntimeError(f"API request failed (HTTP {response.status_code}): {error_detail}")
|
|
236
|
+
|
|
237
|
+
return response_json
|
|
238
|
+
except requests.exceptions.Timeout:
|
|
239
|
+
raise RuntimeError("API request timed out after 120 seconds")
|
|
240
|
+
except requests.exceptions.RequestException as e:
|
|
241
|
+
raise RuntimeError(f"API request failed: {str(e)}")
|
|
242
|
+
|
|
243
|
+
def _extract_image_from_response(self, response: Dict[str, Any]) -> Optional[bytes]:
|
|
244
|
+
"""Extract base64-encoded image from API response."""
|
|
245
|
+
try:
|
|
246
|
+
choices = response.get("choices", [])
|
|
247
|
+
if not choices:
|
|
248
|
+
self._log("No choices in response")
|
|
249
|
+
return None
|
|
250
|
+
|
|
251
|
+
message = choices[0].get("message", {})
|
|
252
|
+
|
|
253
|
+
# Nano Banana Pro returns images in the 'images' field
|
|
254
|
+
images = message.get("images", [])
|
|
255
|
+
if images and len(images) > 0:
|
|
256
|
+
self._log(f"Found {len(images)} image(s) in 'images' field")
|
|
257
|
+
|
|
258
|
+
first_image = images[0]
|
|
259
|
+
if isinstance(first_image, dict):
|
|
260
|
+
if first_image.get("type") == "image_url":
|
|
261
|
+
url = first_image.get("image_url", {})
|
|
262
|
+
if isinstance(url, dict):
|
|
263
|
+
url = url.get("url", "")
|
|
264
|
+
|
|
265
|
+
if url and url.startswith("data:image"):
|
|
266
|
+
if "," in url:
|
|
267
|
+
base64_str = url.split(",", 1)[1]
|
|
268
|
+
base64_str = base64_str.replace('\n', '').replace('\r', '').replace(' ', '')
|
|
269
|
+
self._log(f"Extracted base64 data (length: {len(base64_str)})")
|
|
270
|
+
return base64.b64decode(base64_str)
|
|
271
|
+
|
|
272
|
+
# Fallback: check content field
|
|
273
|
+
content = message.get("content", "")
|
|
274
|
+
|
|
275
|
+
if isinstance(content, str) and "data:image" in content:
|
|
276
|
+
import re
|
|
277
|
+
|
|
278
|
+
match = re.search(r'data:image/[^;]+;base64,([A-Za-z0-9+/=\n\r]+)', content, re.DOTALL)
|
|
279
|
+
if match:
|
|
280
|
+
base64_str = match.group(1).replace('\n', '').replace('\r', '').replace(' ', '')
|
|
281
|
+
self._log(f"Found image in content field (length: {len(base64_str)})")
|
|
282
|
+
return base64.b64decode(base64_str)
|
|
283
|
+
|
|
284
|
+
if isinstance(content, list):
|
|
285
|
+
for i, block in enumerate(content):
|
|
286
|
+
if isinstance(block, dict) and block.get("type") == "image_url":
|
|
287
|
+
url = block.get("image_url", {})
|
|
288
|
+
if isinstance(url, dict):
|
|
289
|
+
url = url.get("url", "")
|
|
290
|
+
if url and url.startswith("data:image") and "," in url:
|
|
291
|
+
base64_str = url.split(",", 1)[1].replace('\n', '').replace('\r', '').replace(' ', '')
|
|
292
|
+
self._log(f"Found image in content block {i}")
|
|
293
|
+
return base64.b64decode(base64_str)
|
|
294
|
+
|
|
295
|
+
self._log("No image data found in response")
|
|
296
|
+
return None
|
|
297
|
+
|
|
298
|
+
except Exception as e:
|
|
299
|
+
self._log(f"Error extracting image: {str(e)}")
|
|
300
|
+
return None
|
|
301
|
+
|
|
302
|
+
def _image_to_base64(self, image_path: str) -> str:
|
|
303
|
+
"""Convert image file to base64 data URL."""
|
|
304
|
+
with open(image_path, "rb") as f:
|
|
305
|
+
image_data = f.read()
|
|
306
|
+
|
|
307
|
+
ext = Path(image_path).suffix.lower()
|
|
308
|
+
mime_type = {
|
|
309
|
+
".png": "image/png",
|
|
310
|
+
".jpg": "image/jpeg",
|
|
311
|
+
".jpeg": "image/jpeg",
|
|
312
|
+
".gif": "image/gif",
|
|
313
|
+
".webp": "image/webp",
|
|
314
|
+
}.get(ext, "image/png")
|
|
315
|
+
|
|
316
|
+
base64_data = base64.b64encode(image_data).decode("utf-8")
|
|
317
|
+
return f"data:{mime_type};base64,{base64_data}"
|
|
318
|
+
|
|
319
|
+
def generate_image(self, prompt: str, attachments: Optional[List[str]] = None) -> Optional[bytes]:
|
|
320
|
+
"""
|
|
321
|
+
Generate an image using Nano Banana Pro.
|
|
322
|
+
|
|
323
|
+
Args:
|
|
324
|
+
prompt: Text description of the image to generate
|
|
325
|
+
attachments: Optional list of image file paths to attach as context
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
Image bytes or None if generation failed
|
|
329
|
+
"""
|
|
330
|
+
self._last_error = None
|
|
331
|
+
|
|
332
|
+
# Build content with text and optional image attachments
|
|
333
|
+
content = []
|
|
334
|
+
|
|
335
|
+
# Add text prompt
|
|
336
|
+
content.append({"type": "text", "text": prompt})
|
|
337
|
+
|
|
338
|
+
# Add attached images as context
|
|
339
|
+
if attachments:
|
|
340
|
+
for img_path in attachments:
|
|
341
|
+
try:
|
|
342
|
+
img_data_url = self._image_to_base64(img_path)
|
|
343
|
+
content.append({"type": "image_url", "image_url": {"url": img_data_url}})
|
|
344
|
+
self._log(f"Attached image: {img_path}")
|
|
345
|
+
except Exception as e:
|
|
346
|
+
self._log(f"Warning: Could not attach {img_path}: {e}")
|
|
347
|
+
|
|
348
|
+
messages = [{"role": "user", "content": content if attachments else prompt}]
|
|
349
|
+
|
|
350
|
+
try:
|
|
351
|
+
response = self._make_request(model=self.image_model, messages=messages, modalities=["image", "text"])
|
|
352
|
+
|
|
353
|
+
if self.verbose:
|
|
354
|
+
self._log(f"Response keys: {response.keys()}")
|
|
355
|
+
if "error" in response:
|
|
356
|
+
self._log(f"API Error: {response['error']}")
|
|
357
|
+
|
|
358
|
+
if "error" in response:
|
|
359
|
+
error_msg = response["error"]
|
|
360
|
+
if isinstance(error_msg, dict):
|
|
361
|
+
error_msg = error_msg.get("message", str(error_msg))
|
|
362
|
+
self._last_error = f"API Error: {error_msg}"
|
|
363
|
+
print(f"✗ {self._last_error}")
|
|
364
|
+
return None
|
|
365
|
+
|
|
366
|
+
image_data = self._extract_image_from_response(response)
|
|
367
|
+
if image_data:
|
|
368
|
+
self._log(f"✓ Generated image ({len(image_data)} bytes)")
|
|
369
|
+
else:
|
|
370
|
+
self._last_error = "No image data in API response"
|
|
371
|
+
self._log(f"✗ {self._last_error}")
|
|
372
|
+
|
|
373
|
+
return image_data
|
|
374
|
+
except RuntimeError as e:
|
|
375
|
+
self._last_error = str(e)
|
|
376
|
+
self._log(f"✗ Generation failed: {self._last_error}")
|
|
377
|
+
return None
|
|
378
|
+
except Exception as e:
|
|
379
|
+
self._last_error = f"Unexpected error: {str(e)}"
|
|
380
|
+
self._log(f"✗ Generation failed: {self._last_error}")
|
|
381
|
+
return None
|
|
382
|
+
|
|
383
|
+
def review_image(
|
|
384
|
+
self, image_path: str, original_prompt: str, iteration: int, visual_only: bool = False, max_iterations: int = 2
|
|
385
|
+
) -> Tuple[str, float, bool]:
|
|
386
|
+
"""Review generated image using Gemini 3 Pro."""
|
|
387
|
+
image_data_url = self._image_to_base64(image_path)
|
|
388
|
+
threshold = self.QUALITY_THRESHOLD
|
|
389
|
+
|
|
390
|
+
image_type = "slide visual/figure" if visual_only else "presentation slide"
|
|
391
|
+
|
|
392
|
+
review_prompt = f"""You are an expert reviewer evaluating a {image_type} for presentation quality.
|
|
393
|
+
|
|
394
|
+
ORIGINAL REQUEST: {original_prompt}
|
|
395
|
+
|
|
396
|
+
QUALITY THRESHOLD: {threshold}/10
|
|
397
|
+
ITERATION: {iteration}/{max_iterations}
|
|
398
|
+
|
|
399
|
+
Evaluate this {image_type} on these criteria:
|
|
400
|
+
|
|
401
|
+
1. **Visual Impact** (0-2 points)
|
|
402
|
+
- Bold, attention-grabbing design
|
|
403
|
+
- Professional appearance
|
|
404
|
+
- Suitable for projection
|
|
405
|
+
|
|
406
|
+
2. **Clarity** (0-2 points)
|
|
407
|
+
- Easy to understand at a glance
|
|
408
|
+
- Clear visual hierarchy
|
|
409
|
+
- Not cluttered or busy
|
|
410
|
+
|
|
411
|
+
3. **Readability** (0-2 points)
|
|
412
|
+
- Text is large and readable (if present)
|
|
413
|
+
- High contrast
|
|
414
|
+
- Clean typography
|
|
415
|
+
|
|
416
|
+
4. **Composition** (0-2 points)
|
|
417
|
+
- Balanced layout
|
|
418
|
+
- Good use of space
|
|
419
|
+
- Appropriate margins
|
|
420
|
+
|
|
421
|
+
5. **Relevance** (0-2 points)
|
|
422
|
+
- Matches the requested content
|
|
423
|
+
- Appropriate style for presentations
|
|
424
|
+
- Professional quality
|
|
425
|
+
|
|
426
|
+
RESPOND IN THIS EXACT FORMAT:
|
|
427
|
+
SCORE: [total score 0-10]
|
|
428
|
+
|
|
429
|
+
STRENGTHS:
|
|
430
|
+
- [strength 1]
|
|
431
|
+
- [strength 2]
|
|
432
|
+
|
|
433
|
+
ISSUES:
|
|
434
|
+
- [issue 1 if any]
|
|
435
|
+
- [issue 2 if any]
|
|
436
|
+
|
|
437
|
+
VERDICT: [ACCEPTABLE or NEEDS_IMPROVEMENT]
|
|
438
|
+
|
|
439
|
+
If score >= {threshold}, the image is ACCEPTABLE.
|
|
440
|
+
If score < {threshold}, mark as NEEDS_IMPROVEMENT with specific suggestions."""
|
|
441
|
+
|
|
442
|
+
messages = [
|
|
443
|
+
{
|
|
444
|
+
"role": "user",
|
|
445
|
+
"content": [
|
|
446
|
+
{"type": "text", "text": review_prompt},
|
|
447
|
+
{"type": "image_url", "image_url": {"url": image_data_url}},
|
|
448
|
+
],
|
|
449
|
+
}
|
|
450
|
+
]
|
|
451
|
+
|
|
452
|
+
try:
|
|
453
|
+
response = self._make_request(model=self.review_model, messages=messages)
|
|
454
|
+
|
|
455
|
+
choices = response.get("choices", [])
|
|
456
|
+
if not choices:
|
|
457
|
+
return "Image generated successfully", 7.0, False
|
|
458
|
+
|
|
459
|
+
message = choices[0].get("message", {})
|
|
460
|
+
content = message.get("content", "")
|
|
461
|
+
|
|
462
|
+
reasoning = message.get("reasoning", "")
|
|
463
|
+
if reasoning and not content:
|
|
464
|
+
content = reasoning
|
|
465
|
+
|
|
466
|
+
if isinstance(content, list):
|
|
467
|
+
text_parts = []
|
|
468
|
+
for block in content:
|
|
469
|
+
if isinstance(block, dict) and block.get("type") == "text":
|
|
470
|
+
text_parts.append(block.get("text", ""))
|
|
471
|
+
content = "\n".join(text_parts)
|
|
472
|
+
|
|
473
|
+
# Extract score
|
|
474
|
+
score = 7.0
|
|
475
|
+
import re
|
|
476
|
+
|
|
477
|
+
score_match = re.search(r'SCORE:\s*(\d+(?:\.\d+)?)', content, re.IGNORECASE)
|
|
478
|
+
if score_match:
|
|
479
|
+
score = float(score_match.group(1))
|
|
480
|
+
else:
|
|
481
|
+
score_match = re.search(r'(?:score|rating|quality)[:\s]+(\d+(?:\.\d+)?)', content, re.IGNORECASE)
|
|
482
|
+
if score_match:
|
|
483
|
+
score = float(score_match.group(1))
|
|
484
|
+
|
|
485
|
+
needs_improvement = False
|
|
486
|
+
if "NEEDS_IMPROVEMENT" in content.upper():
|
|
487
|
+
needs_improvement = True
|
|
488
|
+
elif score < threshold:
|
|
489
|
+
needs_improvement = True
|
|
490
|
+
|
|
491
|
+
self._log(f"✓ Review complete (Score: {score}/10, Threshold: {threshold}/10)")
|
|
492
|
+
|
|
493
|
+
return (content if content else "Image generated successfully", score, needs_improvement)
|
|
494
|
+
except Exception as e:
|
|
495
|
+
self._log(f"Review skipped: {str(e)}")
|
|
496
|
+
return "Image generated successfully (review skipped)", 7.0, False
|
|
497
|
+
|
|
498
|
+
def improve_prompt(self, original_prompt: str, critique: str, iteration: int, visual_only: bool = False) -> str:
|
|
499
|
+
"""Improve the generation prompt based on critique."""
|
|
500
|
+
guidelines = self.VISUAL_ONLY_GUIDELINES if visual_only else self.FULL_SLIDE_GUIDELINES
|
|
501
|
+
|
|
502
|
+
return f"""{guidelines}
|
|
503
|
+
|
|
504
|
+
USER REQUEST: {original_prompt}
|
|
505
|
+
|
|
506
|
+
ITERATION {iteration}: Based on previous feedback, address these specific improvements:
|
|
507
|
+
{critique}
|
|
508
|
+
|
|
509
|
+
Generate an improved version that addresses all the critique points."""
|
|
510
|
+
|
|
511
|
+
def generate_slide(
|
|
512
|
+
self,
|
|
513
|
+
user_prompt: str,
|
|
514
|
+
output_path: str,
|
|
515
|
+
visual_only: bool = False,
|
|
516
|
+
iterations: int = 2,
|
|
517
|
+
attachments: Optional[List[str]] = None,
|
|
518
|
+
) -> Dict[str, Any]:
|
|
519
|
+
"""
|
|
520
|
+
Generate a slide image or visual with iterative refinement.
|
|
521
|
+
|
|
522
|
+
Args:
|
|
523
|
+
user_prompt: Description of the slide/visual to generate
|
|
524
|
+
output_path: Path to save final image
|
|
525
|
+
visual_only: If True, generate just the visual (for PPT workflow)
|
|
526
|
+
iterations: Maximum refinement iterations (default: 2)
|
|
527
|
+
attachments: Optional list of image file paths to attach as context
|
|
528
|
+
|
|
529
|
+
Returns:
|
|
530
|
+
Dictionary with generation results and metadata
|
|
531
|
+
"""
|
|
532
|
+
output_path = Path(output_path)
|
|
533
|
+
output_dir = output_path.parent
|
|
534
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
535
|
+
|
|
536
|
+
base_name = output_path.stem
|
|
537
|
+
extension = output_path.suffix or ".png"
|
|
538
|
+
|
|
539
|
+
mode = "visual_only" if visual_only else "full_slide"
|
|
540
|
+
guidelines = self.VISUAL_ONLY_GUIDELINES if visual_only else self.FULL_SLIDE_GUIDELINES
|
|
541
|
+
|
|
542
|
+
results = {
|
|
543
|
+
"user_prompt": user_prompt,
|
|
544
|
+
"mode": mode,
|
|
545
|
+
"quality_threshold": self.QUALITY_THRESHOLD,
|
|
546
|
+
"attachments": attachments or [],
|
|
547
|
+
"iterations": [],
|
|
548
|
+
"final_image": None,
|
|
549
|
+
"final_score": 0.0,
|
|
550
|
+
"success": False,
|
|
551
|
+
"early_stop": False,
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
current_prompt = f"""{guidelines}
|
|
555
|
+
|
|
556
|
+
USER REQUEST: {user_prompt}
|
|
557
|
+
|
|
558
|
+
Generate a high-quality {'visual/figure' if visual_only else 'presentation slide'} that meets all the guidelines above."""
|
|
559
|
+
|
|
560
|
+
print(f"\n{'=' * 60}")
|
|
561
|
+
print(f"Generating Slide {'Visual' if visual_only else 'Image'}")
|
|
562
|
+
print(f"{'=' * 60}")
|
|
563
|
+
print(f"Description: {user_prompt[:100]}{'...' if len(user_prompt) > 100 else ''}")
|
|
564
|
+
print(f"Mode: {mode}")
|
|
565
|
+
if attachments:
|
|
566
|
+
print(f"Attachments: {len(attachments)} image(s)")
|
|
567
|
+
for att in attachments:
|
|
568
|
+
print(f" - {att}")
|
|
569
|
+
print(f"Quality Threshold: {self.QUALITY_THRESHOLD}/10")
|
|
570
|
+
print(f"Max Iterations: {iterations}")
|
|
571
|
+
print(f"Output: {output_path}")
|
|
572
|
+
print(f"{'=' * 60}\n")
|
|
573
|
+
|
|
574
|
+
# Track temporary files for cleanup
|
|
575
|
+
temp_files = []
|
|
576
|
+
final_image_data = None
|
|
577
|
+
|
|
578
|
+
for i in range(1, iterations + 1):
|
|
579
|
+
print(f"\n[Iteration {i}/{iterations}]")
|
|
580
|
+
print("-" * 40)
|
|
581
|
+
|
|
582
|
+
print("Generating image with Nano Banana Pro...")
|
|
583
|
+
image_data = self.generate_image(current_prompt, attachments=attachments)
|
|
584
|
+
|
|
585
|
+
if not image_data:
|
|
586
|
+
error_msg = self._last_error or 'Image generation failed'
|
|
587
|
+
print(f"✗ Generation failed: {error_msg}")
|
|
588
|
+
results["iterations"].append({"iteration": i, "success": False, "error": error_msg})
|
|
589
|
+
continue
|
|
590
|
+
|
|
591
|
+
# Save to temporary file for review (will be cleaned up)
|
|
592
|
+
import tempfile
|
|
593
|
+
|
|
594
|
+
temp_fd, temp_path = tempfile.mkstemp(suffix=extension)
|
|
595
|
+
os.close(temp_fd)
|
|
596
|
+
temp_path = Path(temp_path)
|
|
597
|
+
temp_files.append(temp_path)
|
|
598
|
+
|
|
599
|
+
with open(temp_path, "wb") as f:
|
|
600
|
+
f.write(image_data)
|
|
601
|
+
print(f"✓ Generated image (iteration {i})")
|
|
602
|
+
|
|
603
|
+
print("Reviewing image with Gemini 3 Pro...")
|
|
604
|
+
critique, score, needs_improvement = self.review_image(
|
|
605
|
+
str(temp_path), user_prompt, i, visual_only, iterations
|
|
606
|
+
)
|
|
607
|
+
print(f"✓ Score: {score}/10 (threshold: {self.QUALITY_THRESHOLD}/10)")
|
|
608
|
+
|
|
609
|
+
results["iterations"].append(
|
|
610
|
+
{
|
|
611
|
+
"iteration": i,
|
|
612
|
+
"critique": critique,
|
|
613
|
+
"score": score,
|
|
614
|
+
"needs_improvement": needs_improvement,
|
|
615
|
+
"success": True,
|
|
616
|
+
}
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
if not needs_improvement:
|
|
620
|
+
print(f"\n✓ Quality meets threshold ({score} >= {self.QUALITY_THRESHOLD})")
|
|
621
|
+
final_image_data = image_data
|
|
622
|
+
results["final_score"] = score
|
|
623
|
+
results["success"] = True
|
|
624
|
+
results["early_stop"] = True
|
|
625
|
+
break
|
|
626
|
+
|
|
627
|
+
if i == iterations:
|
|
628
|
+
print("\n⚠ Maximum iterations reached")
|
|
629
|
+
final_image_data = image_data
|
|
630
|
+
results["final_score"] = score
|
|
631
|
+
results["success"] = True
|
|
632
|
+
break
|
|
633
|
+
|
|
634
|
+
print(f"\n⚠ Quality below threshold ({score} < {self.QUALITY_THRESHOLD})")
|
|
635
|
+
print("Improving prompt...")
|
|
636
|
+
current_prompt = self.improve_prompt(user_prompt, critique, i + 1, visual_only)
|
|
637
|
+
|
|
638
|
+
# Clean up temporary files
|
|
639
|
+
for temp_file in temp_files:
|
|
640
|
+
try:
|
|
641
|
+
if temp_file.exists():
|
|
642
|
+
temp_file.unlink()
|
|
643
|
+
except Exception:
|
|
644
|
+
pass
|
|
645
|
+
|
|
646
|
+
# Save only the final image to output path
|
|
647
|
+
if results["success"] and final_image_data:
|
|
648
|
+
with open(output_path, "wb") as f:
|
|
649
|
+
f.write(final_image_data)
|
|
650
|
+
results["final_image"] = str(output_path)
|
|
651
|
+
print(f"\n✓ Final image: {output_path}")
|
|
652
|
+
|
|
653
|
+
print(f"\n{'=' * 60}")
|
|
654
|
+
print("Generation Complete!")
|
|
655
|
+
print(f"Final Score: {results['final_score']}/10")
|
|
656
|
+
if results["early_stop"]:
|
|
657
|
+
success_count = len([r for r in results['iterations'] if r.get('success')])
|
|
658
|
+
print(f"Iterations Used: {success_count}/{iterations} (early stop)")
|
|
659
|
+
print(f"{'=' * 60}\n")
|
|
660
|
+
|
|
661
|
+
return results
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
def main():
|
|
665
|
+
"""Command-line interface."""
|
|
666
|
+
parser = argparse.ArgumentParser(
|
|
667
|
+
description="Generate presentation slides or visuals using Nano Banana Pro AI",
|
|
668
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
669
|
+
epilog="""
|
|
670
|
+
Examples:
|
|
671
|
+
# Generate a full slide (for PDF workflow)
|
|
672
|
+
python generate_slide_image_ai.py "Title: Machine Learning Basics\\nKey points: supervised learning, neural networks, deep learning" -o slide_01.png
|
|
673
|
+
|
|
674
|
+
# Generate just a visual/figure (for PPT workflow)
|
|
675
|
+
python generate_slide_image_ai.py "Neural network architecture diagram with input, hidden, and output layers" -o figure.png --visual-only
|
|
676
|
+
|
|
677
|
+
# With reference images attached (Nano Banana Pro will see these)
|
|
678
|
+
python generate_slide_image_ai.py "Create a slide explaining this chart with key insights" -o slide.png --attach chart.png
|
|
679
|
+
python generate_slide_image_ai.py "Combine these images into a comparison slide" -o compare.png --attach before.png --attach after.png
|
|
680
|
+
|
|
681
|
+
# With custom iterations
|
|
682
|
+
python generate_slide_image_ai.py "Title slide for AI Conference 2025" -o title.png --iterations 2
|
|
683
|
+
|
|
684
|
+
# Verbose output
|
|
685
|
+
python generate_slide_image_ai.py "Data flow diagram" -o flow.png -v
|
|
686
|
+
|
|
687
|
+
Environment:
|
|
688
|
+
OPENROUTER_API_KEY OpenRouter API key (required)
|
|
689
|
+
""",
|
|
690
|
+
)
|
|
691
|
+
|
|
692
|
+
parser.add_argument("prompt", help="Description of the slide or visual to generate")
|
|
693
|
+
parser.add_argument("-o", "--output", required=True, help="Output image path")
|
|
694
|
+
parser.add_argument(
|
|
695
|
+
"--attach",
|
|
696
|
+
action="append",
|
|
697
|
+
dest="attachments",
|
|
698
|
+
metavar="IMAGE",
|
|
699
|
+
help="Attach image file(s) as context for generation (can use multiple times)",
|
|
700
|
+
)
|
|
701
|
+
parser.add_argument("--visual-only", action="store_true", help="Generate just the visual/figure (for PPT workflow)")
|
|
702
|
+
parser.add_argument("--iterations", type=int, default=2, help="Maximum refinement iterations (default: 2)")
|
|
703
|
+
parser.add_argument("--api-key", help="OpenRouter API key (or set OPENROUTER_API_KEY)")
|
|
704
|
+
parser.add_argument("-v", "--verbose", action="store_true", help="Verbose output")
|
|
705
|
+
|
|
706
|
+
args = parser.parse_args()
|
|
707
|
+
|
|
708
|
+
api_key = args.api_key or os.getenv("OPENROUTER_API_KEY")
|
|
709
|
+
if not api_key:
|
|
710
|
+
print("Error: OPENROUTER_API_KEY environment variable not set")
|
|
711
|
+
print("\nSet it with:")
|
|
712
|
+
print(" export OPENROUTER_API_KEY='your_api_key'")
|
|
713
|
+
sys.exit(1)
|
|
714
|
+
|
|
715
|
+
if args.iterations < 1 or args.iterations > 2:
|
|
716
|
+
print("Error: Iterations must be between 1 and 2")
|
|
717
|
+
sys.exit(1)
|
|
718
|
+
|
|
719
|
+
# Validate attachments exist
|
|
720
|
+
if args.attachments:
|
|
721
|
+
for att in args.attachments:
|
|
722
|
+
if not Path(att).exists():
|
|
723
|
+
print(f"Error: Attachment file not found: {att}")
|
|
724
|
+
sys.exit(1)
|
|
725
|
+
|
|
726
|
+
try:
|
|
727
|
+
generator = SlideImageGenerator(api_key=api_key, verbose=args.verbose)
|
|
728
|
+
results = generator.generate_slide(
|
|
729
|
+
user_prompt=args.prompt,
|
|
730
|
+
output_path=args.output,
|
|
731
|
+
visual_only=args.visual_only,
|
|
732
|
+
iterations=args.iterations,
|
|
733
|
+
attachments=args.attachments,
|
|
734
|
+
)
|
|
735
|
+
|
|
736
|
+
if results["success"]:
|
|
737
|
+
print(f"\n✓ Success! Image saved to: {args.output}")
|
|
738
|
+
sys.exit(0)
|
|
739
|
+
else:
|
|
740
|
+
print("\n✗ Generation failed. Check review log for details.")
|
|
741
|
+
sys.exit(1)
|
|
742
|
+
except Exception as e:
|
|
743
|
+
print(f"\n✗ Error: {str(e)}")
|
|
744
|
+
sys.exit(1)
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
if __name__ == "__main__":
|
|
748
|
+
main()
|