@synsci/cli-darwin-x64-baseline 1.1.71 → 1.1.73
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,807 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
AI-powered scientific schematic generation using Nano Banana Pro.
|
|
4
|
+
|
|
5
|
+
This script uses a smart iterative refinement approach:
|
|
6
|
+
1. Generate initial image with Nano Banana Pro
|
|
7
|
+
2. AI quality review using Gemini 3 Pro for scientific critique
|
|
8
|
+
3. Only regenerate if quality is below threshold for document type
|
|
9
|
+
4. Repeat until quality meets standards (max iterations)
|
|
10
|
+
|
|
11
|
+
Requirements:
|
|
12
|
+
- OPENROUTER_API_KEY environment variable
|
|
13
|
+
- requests library
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
python generate_schematic_ai.py "Create a flowchart showing CONSORT participant flow" -o flowchart.png
|
|
17
|
+
python generate_schematic_ai.py "Neural network architecture diagram" -o architecture.png --iterations 2
|
|
18
|
+
python generate_schematic_ai.py "Simple block diagram" -o diagram.png --doc-type poster
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import argparse
|
|
22
|
+
import base64
|
|
23
|
+
import json
|
|
24
|
+
import os
|
|
25
|
+
import sys
|
|
26
|
+
import time
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
import requests
|
|
33
|
+
except ImportError:
|
|
34
|
+
print("Error: requests library not found. Install with: pip install requests")
|
|
35
|
+
sys.exit(1)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# Try to load .env file from multiple potential locations
|
|
39
|
+
def _load_env_file():
|
|
40
|
+
"""Load .env file from current directory, parent directories, or package directory.
|
|
41
|
+
|
|
42
|
+
Returns True if a .env file was found and loaded, False otherwise.
|
|
43
|
+
Note: This does NOT override existing environment variables.
|
|
44
|
+
"""
|
|
45
|
+
try:
|
|
46
|
+
from dotenv import load_dotenv
|
|
47
|
+
except ImportError:
|
|
48
|
+
return False # python-dotenv not installed
|
|
49
|
+
|
|
50
|
+
# Try current working directory first
|
|
51
|
+
env_path = Path.cwd() / ".env"
|
|
52
|
+
if env_path.exists():
|
|
53
|
+
load_dotenv(dotenv_path=env_path, override=False)
|
|
54
|
+
return True
|
|
55
|
+
|
|
56
|
+
# Try parent directories (up to 5 levels)
|
|
57
|
+
cwd = Path.cwd()
|
|
58
|
+
for _ in range(5):
|
|
59
|
+
env_path = cwd / ".env"
|
|
60
|
+
if env_path.exists():
|
|
61
|
+
load_dotenv(dotenv_path=env_path, override=False)
|
|
62
|
+
return True
|
|
63
|
+
cwd = cwd.parent
|
|
64
|
+
if cwd == cwd.parent: # Reached root
|
|
65
|
+
break
|
|
66
|
+
|
|
67
|
+
# Try the package's parent directory (scientific-writer project root)
|
|
68
|
+
script_dir = Path(__file__).resolve().parent
|
|
69
|
+
for _ in range(5):
|
|
70
|
+
env_path = script_dir / ".env"
|
|
71
|
+
if env_path.exists():
|
|
72
|
+
load_dotenv(dotenv_path=env_path, override=False)
|
|
73
|
+
return True
|
|
74
|
+
script_dir = script_dir.parent
|
|
75
|
+
if script_dir == script_dir.parent:
|
|
76
|
+
break
|
|
77
|
+
|
|
78
|
+
return False
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class ScientificSchematicGenerator:
|
|
82
|
+
"""Generate scientific schematics using AI with smart iterative refinement.
|
|
83
|
+
|
|
84
|
+
Uses Gemini 3 Pro for quality review to determine if regeneration is needed.
|
|
85
|
+
Multiple passes only occur if the generated schematic doesn't meet the
|
|
86
|
+
quality threshold for the target document type.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
# Quality thresholds by document type (score out of 10)
|
|
90
|
+
# Higher thresholds for more formal publications
|
|
91
|
+
QUALITY_THRESHOLDS = {
|
|
92
|
+
"journal": 8.5, # Nature, Science, etc. - highest standards
|
|
93
|
+
"conference": 8.0, # Conference papers - high standards
|
|
94
|
+
"poster": 7.0, # Academic posters - good quality
|
|
95
|
+
"presentation": 6.5, # Slides/talks - clear but less formal
|
|
96
|
+
"report": 7.5, # Technical reports - professional
|
|
97
|
+
"grant": 8.0, # Grant proposals - must be compelling
|
|
98
|
+
"thesis": 8.0, # Dissertations - formal academic
|
|
99
|
+
"preprint": 7.5, # arXiv, etc. - good quality
|
|
100
|
+
"default": 7.5, # Default threshold
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
# Scientific diagram best practices prompt template
|
|
104
|
+
SCIENTIFIC_DIAGRAM_GUIDELINES = """
|
|
105
|
+
Create a high-quality scientific diagram with these requirements:
|
|
106
|
+
|
|
107
|
+
VISUAL QUALITY:
|
|
108
|
+
- Clean white or light background (no textures or gradients)
|
|
109
|
+
- High contrast for readability and printing
|
|
110
|
+
- Professional, publication-ready appearance
|
|
111
|
+
- Sharp, clear lines and text
|
|
112
|
+
- Adequate spacing between elements to prevent crowding
|
|
113
|
+
|
|
114
|
+
TYPOGRAPHY:
|
|
115
|
+
- Clear, readable sans-serif fonts (Arial, Helvetica style)
|
|
116
|
+
- Minimum 10pt font size for all labels
|
|
117
|
+
- Consistent font sizes throughout
|
|
118
|
+
- All text horizontal or clearly readable
|
|
119
|
+
- No overlapping text
|
|
120
|
+
|
|
121
|
+
SCIENTIFIC STANDARDS:
|
|
122
|
+
- Accurate representation of concepts
|
|
123
|
+
- Clear labels for all components
|
|
124
|
+
- Include scale bars, legends, or axes where appropriate
|
|
125
|
+
- Use standard scientific notation and symbols
|
|
126
|
+
- Include units where applicable
|
|
127
|
+
|
|
128
|
+
ACCESSIBILITY:
|
|
129
|
+
- Colorblind-friendly color palette (use Okabe-Ito colors if using color)
|
|
130
|
+
- High contrast between elements
|
|
131
|
+
- Redundant encoding (shapes + colors, not just colors)
|
|
132
|
+
- Works well in grayscale
|
|
133
|
+
|
|
134
|
+
LAYOUT:
|
|
135
|
+
- Logical flow (left-to-right or top-to-bottom)
|
|
136
|
+
- Clear visual hierarchy
|
|
137
|
+
- Balanced composition
|
|
138
|
+
- Appropriate use of whitespace
|
|
139
|
+
- No clutter or unnecessary decorative elements
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
def __init__(self, api_key: Optional[str] = None, verbose: bool = False):
|
|
143
|
+
"""
|
|
144
|
+
Initialize the generator.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
api_key: OpenRouter API key (or use OPENROUTER_API_KEY env var)
|
|
148
|
+
verbose: Print detailed progress information
|
|
149
|
+
"""
|
|
150
|
+
# Priority: 1) explicit api_key param, 2) environment variable, 3) .env file
|
|
151
|
+
self.api_key = api_key or os.getenv("OPENROUTER_API_KEY")
|
|
152
|
+
|
|
153
|
+
# If not found in environment, try loading from .env file
|
|
154
|
+
if not self.api_key:
|
|
155
|
+
_load_env_file()
|
|
156
|
+
self.api_key = os.getenv("OPENROUTER_API_KEY")
|
|
157
|
+
|
|
158
|
+
if not self.api_key:
|
|
159
|
+
raise ValueError(
|
|
160
|
+
"OPENROUTER_API_KEY not found. Please either:\n"
|
|
161
|
+
" 1. Set the OPENROUTER_API_KEY environment variable\n"
|
|
162
|
+
" 2. Add OPENROUTER_API_KEY to your .env file\n"
|
|
163
|
+
" 3. Pass api_key parameter to the constructor\n"
|
|
164
|
+
"Get your API key from: https://openrouter.ai/keys"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
self.verbose = verbose
|
|
168
|
+
self._last_error = None # Track last error for better reporting
|
|
169
|
+
self.base_url = "https://openrouter.ai/api/v1"
|
|
170
|
+
# Nano Banana Pro - Google's advanced image generation model
|
|
171
|
+
# https://openrouter.ai/google/gemini-3-pro-image-preview
|
|
172
|
+
self.image_model = "google/gemini-3-pro-image-preview"
|
|
173
|
+
# Gemini 3 Pro for quality review - excellent vision and reasoning
|
|
174
|
+
self.review_model = "google/gemini-3-pro"
|
|
175
|
+
|
|
176
|
+
def _log(self, message: str):
|
|
177
|
+
"""Log message if verbose mode is enabled."""
|
|
178
|
+
if self.verbose:
|
|
179
|
+
print(f"[{time.strftime('%H:%M:%S')}] {message}")
|
|
180
|
+
|
|
181
|
+
def _make_request(
|
|
182
|
+
self, model: str, messages: List[Dict[str, Any]], modalities: Optional[List[str]] = None
|
|
183
|
+
) -> Dict[str, Any]:
|
|
184
|
+
"""
|
|
185
|
+
Make a request to OpenRouter API.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
model: Model identifier
|
|
189
|
+
messages: List of message dictionaries
|
|
190
|
+
modalities: Optional list of modalities (e.g., ["image", "text"])
|
|
191
|
+
|
|
192
|
+
Returns:
|
|
193
|
+
API response as dictionary
|
|
194
|
+
"""
|
|
195
|
+
headers = {
|
|
196
|
+
"Authorization": f"Bearer {self.api_key}",
|
|
197
|
+
"Content-Type": "application/json",
|
|
198
|
+
"HTTP-Referer": "https://github.com/scientific-writer",
|
|
199
|
+
"X-Title": "Scientific Schematic Generator",
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
payload = {"model": model, "messages": messages}
|
|
203
|
+
|
|
204
|
+
if modalities:
|
|
205
|
+
payload["modalities"] = modalities
|
|
206
|
+
|
|
207
|
+
self._log(f"Making request to {model}...")
|
|
208
|
+
|
|
209
|
+
try:
|
|
210
|
+
response = requests.post(f"{self.base_url}/chat/completions", headers=headers, json=payload, timeout=120)
|
|
211
|
+
|
|
212
|
+
# Try to get response body even on error
|
|
213
|
+
try:
|
|
214
|
+
response_json = response.json()
|
|
215
|
+
except json.JSONDecodeError:
|
|
216
|
+
response_json = {"raw_text": response.text[:500]}
|
|
217
|
+
|
|
218
|
+
# Check for HTTP errors but include response body in error message
|
|
219
|
+
if response.status_code != 200:
|
|
220
|
+
error_detail = response_json.get("error", response_json)
|
|
221
|
+
self._log(f"HTTP {response.status_code}: {error_detail}")
|
|
222
|
+
raise RuntimeError(f"API request failed (HTTP {response.status_code}): {error_detail}")
|
|
223
|
+
|
|
224
|
+
return response_json
|
|
225
|
+
except requests.exceptions.Timeout:
|
|
226
|
+
raise RuntimeError("API request timed out after 120 seconds")
|
|
227
|
+
except requests.exceptions.RequestException as e:
|
|
228
|
+
raise RuntimeError(f"API request failed: {str(e)}")
|
|
229
|
+
|
|
230
|
+
def _extract_image_from_response(self, response: Dict[str, Any]) -> Optional[bytes]:
|
|
231
|
+
"""
|
|
232
|
+
Extract base64-encoded image from API response.
|
|
233
|
+
|
|
234
|
+
For Nano Banana Pro, images are returned in the 'images' field of the message,
|
|
235
|
+
not in the 'content' field.
|
|
236
|
+
|
|
237
|
+
Args:
|
|
238
|
+
response: API response dictionary
|
|
239
|
+
|
|
240
|
+
Returns:
|
|
241
|
+
Image bytes or None if not found
|
|
242
|
+
"""
|
|
243
|
+
try:
|
|
244
|
+
choices = response.get("choices", [])
|
|
245
|
+
if not choices:
|
|
246
|
+
self._log("No choices in response")
|
|
247
|
+
return None
|
|
248
|
+
|
|
249
|
+
message = choices[0].get("message", {})
|
|
250
|
+
|
|
251
|
+
# IMPORTANT: Nano Banana Pro returns images in the 'images' field
|
|
252
|
+
images = message.get("images", [])
|
|
253
|
+
if images and len(images) > 0:
|
|
254
|
+
self._log(f"Found {len(images)} image(s) in 'images' field")
|
|
255
|
+
|
|
256
|
+
# Get first image
|
|
257
|
+
first_image = images[0]
|
|
258
|
+
if isinstance(first_image, dict):
|
|
259
|
+
# Extract image_url
|
|
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
|
+
# Extract base64 data after comma
|
|
267
|
+
if "," in url:
|
|
268
|
+
base64_str = url.split(",", 1)[1]
|
|
269
|
+
# Clean whitespace
|
|
270
|
+
base64_str = base64_str.replace('\n', '').replace('\r', '').replace(' ', '')
|
|
271
|
+
self._log(f"Extracted base64 data (length: {len(base64_str)})")
|
|
272
|
+
return base64.b64decode(base64_str)
|
|
273
|
+
|
|
274
|
+
# Fallback: check content field (for other models or future changes)
|
|
275
|
+
content = message.get("content", "")
|
|
276
|
+
|
|
277
|
+
if self.verbose:
|
|
278
|
+
self._log(f"Content type: {type(content)}, length: {len(str(content))}")
|
|
279
|
+
|
|
280
|
+
# Handle string content
|
|
281
|
+
if isinstance(content, str) and "data:image" in content:
|
|
282
|
+
import re
|
|
283
|
+
|
|
284
|
+
match = re.search(r'data:image/[^;]+;base64,([A-Za-z0-9+/=\n\r]+)', content, re.DOTALL)
|
|
285
|
+
if match:
|
|
286
|
+
base64_str = match.group(1).replace('\n', '').replace('\r', '').replace(' ', '')
|
|
287
|
+
self._log(f"Found image in content field (length: {len(base64_str)})")
|
|
288
|
+
return base64.b64decode(base64_str)
|
|
289
|
+
|
|
290
|
+
# Handle list content
|
|
291
|
+
if isinstance(content, list):
|
|
292
|
+
for i, block in enumerate(content):
|
|
293
|
+
if isinstance(block, dict) and block.get("type") == "image_url":
|
|
294
|
+
url = block.get("image_url", {})
|
|
295
|
+
if isinstance(url, dict):
|
|
296
|
+
url = url.get("url", "")
|
|
297
|
+
if url and url.startswith("data:image") and "," in url:
|
|
298
|
+
base64_str = url.split(",", 1)[1].replace('\n', '').replace('\r', '').replace(' ', '')
|
|
299
|
+
self._log(f"Found image in content block {i}")
|
|
300
|
+
return base64.b64decode(base64_str)
|
|
301
|
+
|
|
302
|
+
self._log("No image data found in response")
|
|
303
|
+
return None
|
|
304
|
+
|
|
305
|
+
except Exception as e:
|
|
306
|
+
self._log(f"Error extracting image: {str(e)}")
|
|
307
|
+
import traceback
|
|
308
|
+
|
|
309
|
+
if self.verbose:
|
|
310
|
+
traceback.print_exc()
|
|
311
|
+
return None
|
|
312
|
+
|
|
313
|
+
def _image_to_base64(self, image_path: str) -> str:
|
|
314
|
+
"""
|
|
315
|
+
Convert image file to base64 data URL.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
image_path: Path to image file
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
Base64 data URL string
|
|
322
|
+
"""
|
|
323
|
+
with open(image_path, "rb") as f:
|
|
324
|
+
image_data = f.read()
|
|
325
|
+
|
|
326
|
+
# Determine image type from extension
|
|
327
|
+
ext = Path(image_path).suffix.lower()
|
|
328
|
+
mime_type = {
|
|
329
|
+
".png": "image/png",
|
|
330
|
+
".jpg": "image/jpeg",
|
|
331
|
+
".jpeg": "image/jpeg",
|
|
332
|
+
".gif": "image/gif",
|
|
333
|
+
".webp": "image/webp",
|
|
334
|
+
}.get(ext, "image/png")
|
|
335
|
+
|
|
336
|
+
base64_data = base64.b64encode(image_data).decode("utf-8")
|
|
337
|
+
return f"data:{mime_type};base64,{base64_data}"
|
|
338
|
+
|
|
339
|
+
def generate_image(self, prompt: str) -> Optional[bytes]:
|
|
340
|
+
"""
|
|
341
|
+
Generate an image using Nano Banana Pro.
|
|
342
|
+
|
|
343
|
+
Args:
|
|
344
|
+
prompt: Description of the diagram to generate
|
|
345
|
+
|
|
346
|
+
Returns:
|
|
347
|
+
Image bytes or None if generation failed
|
|
348
|
+
"""
|
|
349
|
+
self._last_error = None # Reset error
|
|
350
|
+
|
|
351
|
+
messages = [{"role": "user", "content": prompt}]
|
|
352
|
+
|
|
353
|
+
try:
|
|
354
|
+
response = self._make_request(model=self.image_model, messages=messages, modalities=["image", "text"])
|
|
355
|
+
|
|
356
|
+
# Debug: print response structure if verbose
|
|
357
|
+
if self.verbose:
|
|
358
|
+
self._log(f"Response keys: {response.keys()}")
|
|
359
|
+
if "error" in response:
|
|
360
|
+
self._log(f"API Error: {response['error']}")
|
|
361
|
+
if "choices" in response and response["choices"]:
|
|
362
|
+
msg = response["choices"][0].get("message", {})
|
|
363
|
+
self._log(f"Message keys: {msg.keys()}")
|
|
364
|
+
# Show content preview without printing huge base64 data
|
|
365
|
+
content = msg.get("content", "")
|
|
366
|
+
if isinstance(content, str):
|
|
367
|
+
preview = content[:200] + "..." if len(content) > 200 else content
|
|
368
|
+
self._log(f"Content preview: {preview}")
|
|
369
|
+
elif isinstance(content, list):
|
|
370
|
+
self._log(f"Content is list with {len(content)} items")
|
|
371
|
+
for i, item in enumerate(content[:3]):
|
|
372
|
+
if isinstance(item, dict):
|
|
373
|
+
self._log(f" Item {i}: type={item.get('type')}")
|
|
374
|
+
|
|
375
|
+
# Check for API errors in response
|
|
376
|
+
if "error" in response:
|
|
377
|
+
error_msg = response["error"]
|
|
378
|
+
if isinstance(error_msg, dict):
|
|
379
|
+
error_msg = error_msg.get("message", str(error_msg))
|
|
380
|
+
self._last_error = f"API Error: {error_msg}"
|
|
381
|
+
print(f"✗ {self._last_error}")
|
|
382
|
+
return None
|
|
383
|
+
|
|
384
|
+
image_data = self._extract_image_from_response(response)
|
|
385
|
+
if image_data:
|
|
386
|
+
self._log(f"✓ Generated image ({len(image_data)} bytes)")
|
|
387
|
+
else:
|
|
388
|
+
self._last_error = "No image data in API response - model may not support image generation"
|
|
389
|
+
self._log(f"✗ {self._last_error}")
|
|
390
|
+
# Additional debug info when image extraction fails
|
|
391
|
+
if self.verbose and "choices" in response:
|
|
392
|
+
msg = response["choices"][0].get("message", {})
|
|
393
|
+
self._log(f"Full message structure: {json.dumps({k: type(v).__name__ for k, v in msg.items()})}")
|
|
394
|
+
|
|
395
|
+
return image_data
|
|
396
|
+
except RuntimeError as e:
|
|
397
|
+
self._last_error = str(e)
|
|
398
|
+
self._log(f"✗ Generation failed: {self._last_error}")
|
|
399
|
+
return None
|
|
400
|
+
except Exception as e:
|
|
401
|
+
self._last_error = f"Unexpected error: {str(e)}"
|
|
402
|
+
self._log(f"✗ Generation failed: {self._last_error}")
|
|
403
|
+
import traceback
|
|
404
|
+
|
|
405
|
+
if self.verbose:
|
|
406
|
+
traceback.print_exc()
|
|
407
|
+
return None
|
|
408
|
+
|
|
409
|
+
def review_image(
|
|
410
|
+
self, image_path: str, original_prompt: str, iteration: int, doc_type: str = "default", max_iterations: int = 2
|
|
411
|
+
) -> Tuple[str, float, bool]:
|
|
412
|
+
"""
|
|
413
|
+
Review generated image using Gemini 3 Pro for quality analysis.
|
|
414
|
+
|
|
415
|
+
Uses Gemini 3 Pro's superior vision and reasoning capabilities to
|
|
416
|
+
evaluate the schematic quality and determine if regeneration is needed.
|
|
417
|
+
|
|
418
|
+
Args:
|
|
419
|
+
image_path: Path to the generated image
|
|
420
|
+
original_prompt: Original user prompt
|
|
421
|
+
iteration: Current iteration number
|
|
422
|
+
doc_type: Document type (journal, poster, presentation, etc.)
|
|
423
|
+
max_iterations: Maximum iterations allowed
|
|
424
|
+
|
|
425
|
+
Returns:
|
|
426
|
+
Tuple of (critique text, quality score 0-10, needs_improvement bool)
|
|
427
|
+
"""
|
|
428
|
+
# Use Gemini 3 Pro for review - excellent vision and analysis
|
|
429
|
+
image_data_url = self._image_to_base64(image_path)
|
|
430
|
+
|
|
431
|
+
# Get quality threshold for this document type
|
|
432
|
+
threshold = self.QUALITY_THRESHOLDS.get(doc_type.lower(), self.QUALITY_THRESHOLDS["default"])
|
|
433
|
+
|
|
434
|
+
review_prompt = f"""You are an expert reviewer evaluating a scientific diagram for publication quality.
|
|
435
|
+
|
|
436
|
+
ORIGINAL REQUEST: {original_prompt}
|
|
437
|
+
|
|
438
|
+
DOCUMENT TYPE: {doc_type} (quality threshold: {threshold}/10)
|
|
439
|
+
ITERATION: {iteration}/{max_iterations}
|
|
440
|
+
|
|
441
|
+
Carefully evaluate this diagram on these criteria:
|
|
442
|
+
|
|
443
|
+
1. **Scientific Accuracy** (0-2 points)
|
|
444
|
+
- Correct representation of concepts
|
|
445
|
+
- Proper notation and symbols
|
|
446
|
+
- Accurate relationships shown
|
|
447
|
+
|
|
448
|
+
2. **Clarity and Readability** (0-2 points)
|
|
449
|
+
- Easy to understand at a glance
|
|
450
|
+
- Clear visual hierarchy
|
|
451
|
+
- No ambiguous elements
|
|
452
|
+
|
|
453
|
+
3. **Label Quality** (0-2 points)
|
|
454
|
+
- All important elements labeled
|
|
455
|
+
- Labels are readable (appropriate font size)
|
|
456
|
+
- Consistent labeling style
|
|
457
|
+
|
|
458
|
+
4. **Layout and Composition** (0-2 points)
|
|
459
|
+
- Logical flow (top-to-bottom or left-to-right)
|
|
460
|
+
- Balanced use of space
|
|
461
|
+
- No overlapping elements
|
|
462
|
+
|
|
463
|
+
5. **Professional Appearance** (0-2 points)
|
|
464
|
+
- Publication-ready quality
|
|
465
|
+
- Clean, crisp lines and shapes
|
|
466
|
+
- Appropriate colors/contrast
|
|
467
|
+
|
|
468
|
+
RESPOND IN THIS EXACT FORMAT:
|
|
469
|
+
SCORE: [total score 0-10]
|
|
470
|
+
|
|
471
|
+
STRENGTHS:
|
|
472
|
+
- [strength 1]
|
|
473
|
+
- [strength 2]
|
|
474
|
+
|
|
475
|
+
ISSUES:
|
|
476
|
+
- [issue 1 if any]
|
|
477
|
+
- [issue 2 if any]
|
|
478
|
+
|
|
479
|
+
VERDICT: [ACCEPTABLE or NEEDS_IMPROVEMENT]
|
|
480
|
+
|
|
481
|
+
If score >= {threshold}, the diagram is ACCEPTABLE for {doc_type} publication.
|
|
482
|
+
If score < {threshold}, mark as NEEDS_IMPROVEMENT with specific suggestions."""
|
|
483
|
+
|
|
484
|
+
messages = [
|
|
485
|
+
{
|
|
486
|
+
"role": "user",
|
|
487
|
+
"content": [
|
|
488
|
+
{"type": "text", "text": review_prompt},
|
|
489
|
+
{"type": "image_url", "image_url": {"url": image_data_url}},
|
|
490
|
+
],
|
|
491
|
+
}
|
|
492
|
+
]
|
|
493
|
+
|
|
494
|
+
try:
|
|
495
|
+
# Use Gemini 3 Pro for high-quality review
|
|
496
|
+
response = self._make_request(model=self.review_model, messages=messages)
|
|
497
|
+
|
|
498
|
+
# Extract text response
|
|
499
|
+
choices = response.get("choices", [])
|
|
500
|
+
if not choices:
|
|
501
|
+
return "Image generated successfully", 8.0
|
|
502
|
+
|
|
503
|
+
message = choices[0].get("message", {})
|
|
504
|
+
content = message.get("content", "")
|
|
505
|
+
|
|
506
|
+
# Check reasoning field (Nano Banana Pro puts analysis here)
|
|
507
|
+
reasoning = message.get("reasoning", "")
|
|
508
|
+
if reasoning and not content:
|
|
509
|
+
content = reasoning
|
|
510
|
+
|
|
511
|
+
if isinstance(content, list):
|
|
512
|
+
# Extract text from content blocks
|
|
513
|
+
text_parts = []
|
|
514
|
+
for block in content:
|
|
515
|
+
if isinstance(block, dict) and block.get("type") == "text":
|
|
516
|
+
text_parts.append(block.get("text", ""))
|
|
517
|
+
content = "\n".join(text_parts)
|
|
518
|
+
|
|
519
|
+
# Try to extract score
|
|
520
|
+
score = 7.5 # Default score if extraction fails
|
|
521
|
+
import re
|
|
522
|
+
|
|
523
|
+
# Look for SCORE: X or SCORE: X/10 format
|
|
524
|
+
score_match = re.search(r'SCORE:\s*(\d+(?:\.\d+)?)', content, re.IGNORECASE)
|
|
525
|
+
if score_match:
|
|
526
|
+
score = float(score_match.group(1))
|
|
527
|
+
else:
|
|
528
|
+
# Fallback: look for any score pattern
|
|
529
|
+
score_match = re.search(
|
|
530
|
+
r'(?:score|rating|quality)[:\s]+(\d+(?:\.\d+)?)\s*(?:/\s*10)?', content, re.IGNORECASE
|
|
531
|
+
)
|
|
532
|
+
if score_match:
|
|
533
|
+
score = float(score_match.group(1))
|
|
534
|
+
|
|
535
|
+
# Determine if improvement is needed based on verdict or score
|
|
536
|
+
needs_improvement = False
|
|
537
|
+
if "NEEDS_IMPROVEMENT" in content.upper():
|
|
538
|
+
needs_improvement = True
|
|
539
|
+
elif score < threshold:
|
|
540
|
+
needs_improvement = True
|
|
541
|
+
|
|
542
|
+
self._log(f"✓ Review complete (Score: {score}/10, Threshold: {threshold}/10)")
|
|
543
|
+
self._log(f" Verdict: {'Needs improvement' if needs_improvement else 'Acceptable'}")
|
|
544
|
+
|
|
545
|
+
return (content if content else "Image generated successfully", score, needs_improvement)
|
|
546
|
+
except Exception as e:
|
|
547
|
+
self._log(f"Review skipped: {str(e)}")
|
|
548
|
+
# Don't fail the whole process if review fails - assume acceptable
|
|
549
|
+
return "Image generated successfully (review skipped)", 7.5, False
|
|
550
|
+
|
|
551
|
+
def improve_prompt(self, original_prompt: str, critique: str, iteration: int) -> str:
|
|
552
|
+
"""
|
|
553
|
+
Improve the generation prompt based on critique.
|
|
554
|
+
|
|
555
|
+
Args:
|
|
556
|
+
original_prompt: Original user prompt
|
|
557
|
+
critique: Review critique from previous iteration
|
|
558
|
+
iteration: Current iteration number
|
|
559
|
+
|
|
560
|
+
Returns:
|
|
561
|
+
Improved prompt for next generation
|
|
562
|
+
"""
|
|
563
|
+
improved_prompt = f"""{self.SCIENTIFIC_DIAGRAM_GUIDELINES}
|
|
564
|
+
|
|
565
|
+
USER REQUEST: {original_prompt}
|
|
566
|
+
|
|
567
|
+
ITERATION {iteration}: Based on previous feedback, address these specific improvements:
|
|
568
|
+
{critique}
|
|
569
|
+
|
|
570
|
+
Generate an improved version that addresses all the critique points while maintaining scientific accuracy and professional quality."""
|
|
571
|
+
|
|
572
|
+
return improved_prompt
|
|
573
|
+
|
|
574
|
+
def generate_iterative(
|
|
575
|
+
self, user_prompt: str, output_path: str, iterations: int = 2, doc_type: str = "default"
|
|
576
|
+
) -> Dict[str, Any]:
|
|
577
|
+
"""
|
|
578
|
+
Generate scientific schematic with smart iterative refinement.
|
|
579
|
+
|
|
580
|
+
Only regenerates if the quality score is below the threshold for the
|
|
581
|
+
specified document type. This saves API calls and time when the first
|
|
582
|
+
generation is already good enough.
|
|
583
|
+
|
|
584
|
+
Args:
|
|
585
|
+
user_prompt: User's description of desired diagram
|
|
586
|
+
output_path: Path to save final image
|
|
587
|
+
iterations: Maximum refinement iterations (default: 2, max: 2)
|
|
588
|
+
doc_type: Document type for quality threshold (journal, poster, etc.)
|
|
589
|
+
|
|
590
|
+
Returns:
|
|
591
|
+
Dictionary with generation results and metadata
|
|
592
|
+
"""
|
|
593
|
+
output_path = Path(output_path)
|
|
594
|
+
output_dir = output_path.parent
|
|
595
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
596
|
+
|
|
597
|
+
base_name = output_path.stem
|
|
598
|
+
extension = output_path.suffix or ".png"
|
|
599
|
+
|
|
600
|
+
# Get quality threshold for this document type
|
|
601
|
+
threshold = self.QUALITY_THRESHOLDS.get(doc_type.lower(), self.QUALITY_THRESHOLDS["default"])
|
|
602
|
+
|
|
603
|
+
results = {
|
|
604
|
+
"user_prompt": user_prompt,
|
|
605
|
+
"doc_type": doc_type,
|
|
606
|
+
"quality_threshold": threshold,
|
|
607
|
+
"iterations": [],
|
|
608
|
+
"final_image": None,
|
|
609
|
+
"final_score": 0.0,
|
|
610
|
+
"success": False,
|
|
611
|
+
"early_stop": False,
|
|
612
|
+
"early_stop_reason": None,
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
current_prompt = f"""{self.SCIENTIFIC_DIAGRAM_GUIDELINES}
|
|
616
|
+
|
|
617
|
+
USER REQUEST: {user_prompt}
|
|
618
|
+
|
|
619
|
+
Generate a publication-quality scientific diagram that meets all the guidelines above."""
|
|
620
|
+
|
|
621
|
+
print(f"\n{'=' * 60}")
|
|
622
|
+
print("Generating Scientific Schematic")
|
|
623
|
+
print(f"{'=' * 60}")
|
|
624
|
+
print(f"Description: {user_prompt}")
|
|
625
|
+
print(f"Document Type: {doc_type}")
|
|
626
|
+
print(f"Quality Threshold: {threshold}/10")
|
|
627
|
+
print(f"Max Iterations: {iterations}")
|
|
628
|
+
print(f"Output: {output_path}")
|
|
629
|
+
print(f"{'=' * 60}\n")
|
|
630
|
+
|
|
631
|
+
for i in range(1, iterations + 1):
|
|
632
|
+
print(f"\n[Iteration {i}/{iterations}]")
|
|
633
|
+
print("-" * 40)
|
|
634
|
+
|
|
635
|
+
# Generate image
|
|
636
|
+
print("Generating image...")
|
|
637
|
+
image_data = self.generate_image(current_prompt)
|
|
638
|
+
|
|
639
|
+
if not image_data:
|
|
640
|
+
error_msg = getattr(self, '_last_error', 'Image generation failed - no image data returned')
|
|
641
|
+
print(f"✗ Generation failed: {error_msg}")
|
|
642
|
+
results["iterations"].append({"iteration": i, "success": False, "error": error_msg})
|
|
643
|
+
continue
|
|
644
|
+
|
|
645
|
+
# Save iteration image
|
|
646
|
+
iter_path = output_dir / f"{base_name}_v{i}{extension}"
|
|
647
|
+
with open(iter_path, "wb") as f:
|
|
648
|
+
f.write(image_data)
|
|
649
|
+
print(f"✓ Saved: {iter_path}")
|
|
650
|
+
|
|
651
|
+
# Review image using Gemini 3 Pro
|
|
652
|
+
print("Reviewing image with Gemini 3 Pro...")
|
|
653
|
+
critique, score, needs_improvement = self.review_image(str(iter_path), user_prompt, i, doc_type, iterations)
|
|
654
|
+
print(f"✓ Score: {score}/10 (threshold: {threshold}/10)")
|
|
655
|
+
|
|
656
|
+
# Save iteration results
|
|
657
|
+
iteration_result = {
|
|
658
|
+
"iteration": i,
|
|
659
|
+
"image_path": str(iter_path),
|
|
660
|
+
"prompt": current_prompt,
|
|
661
|
+
"critique": critique,
|
|
662
|
+
"score": score,
|
|
663
|
+
"needs_improvement": needs_improvement,
|
|
664
|
+
"success": True,
|
|
665
|
+
}
|
|
666
|
+
results["iterations"].append(iteration_result)
|
|
667
|
+
|
|
668
|
+
# Check if quality is acceptable - STOP EARLY if so
|
|
669
|
+
if not needs_improvement:
|
|
670
|
+
print(f"\n✓ Quality meets {doc_type} threshold ({score} >= {threshold})")
|
|
671
|
+
print(" No further iterations needed!")
|
|
672
|
+
results["final_image"] = str(iter_path)
|
|
673
|
+
results["final_score"] = score
|
|
674
|
+
results["success"] = True
|
|
675
|
+
results["early_stop"] = True
|
|
676
|
+
results["early_stop_reason"] = f"Quality score {score} meets threshold {threshold} for {doc_type}"
|
|
677
|
+
break
|
|
678
|
+
|
|
679
|
+
# If this is the last iteration, we're done regardless
|
|
680
|
+
if i == iterations:
|
|
681
|
+
print("\n⚠ Maximum iterations reached")
|
|
682
|
+
results["final_image"] = str(iter_path)
|
|
683
|
+
results["final_score"] = score
|
|
684
|
+
results["success"] = True
|
|
685
|
+
break
|
|
686
|
+
|
|
687
|
+
# Quality below threshold - improve prompt for next iteration
|
|
688
|
+
print(f"\n⚠ Quality below threshold ({score} < {threshold})")
|
|
689
|
+
print("Improving prompt based on feedback...")
|
|
690
|
+
current_prompt = self.improve_prompt(user_prompt, critique, i + 1)
|
|
691
|
+
|
|
692
|
+
# Copy final version to output path
|
|
693
|
+
if results["success"] and results["final_image"]:
|
|
694
|
+
final_iter_path = Path(results["final_image"])
|
|
695
|
+
if final_iter_path != output_path:
|
|
696
|
+
import shutil
|
|
697
|
+
|
|
698
|
+
shutil.copy(final_iter_path, output_path)
|
|
699
|
+
print(f"\n✓ Final image: {output_path}")
|
|
700
|
+
|
|
701
|
+
# Save review log
|
|
702
|
+
log_path = output_dir / f"{base_name}_review_log.json"
|
|
703
|
+
with open(log_path, "w") as f:
|
|
704
|
+
json.dump(results, f, indent=2)
|
|
705
|
+
print(f"✓ Review log: {log_path}")
|
|
706
|
+
|
|
707
|
+
print(f"\n{'=' * 60}")
|
|
708
|
+
print("Generation Complete!")
|
|
709
|
+
print(f"Final Score: {results['final_score']}/10")
|
|
710
|
+
if results["early_stop"]:
|
|
711
|
+
print(
|
|
712
|
+
f"Iterations Used: {len([r for r in results['iterations'] if r.get('success')])}/{iterations} (early stop)"
|
|
713
|
+
)
|
|
714
|
+
print(f"{'=' * 60}\n")
|
|
715
|
+
|
|
716
|
+
return results
|
|
717
|
+
|
|
718
|
+
|
|
719
|
+
def main():
|
|
720
|
+
"""Command-line interface."""
|
|
721
|
+
parser = argparse.ArgumentParser(
|
|
722
|
+
description="Generate scientific schematics using AI with smart iterative refinement",
|
|
723
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
724
|
+
epilog="""
|
|
725
|
+
Examples:
|
|
726
|
+
# Generate a flowchart for a journal paper
|
|
727
|
+
python generate_schematic_ai.py "CONSORT participant flow diagram" -o flowchart.png --doc-type journal
|
|
728
|
+
|
|
729
|
+
# Generate neural network architecture for presentation (lower threshold)
|
|
730
|
+
python generate_schematic_ai.py "Transformer encoder-decoder architecture" -o transformer.png --doc-type presentation
|
|
731
|
+
|
|
732
|
+
# Generate with custom max iterations for poster
|
|
733
|
+
python generate_schematic_ai.py "Biological signaling pathway" -o pathway.png --iterations 2 --doc-type poster
|
|
734
|
+
|
|
735
|
+
# Verbose output
|
|
736
|
+
python generate_schematic_ai.py "Circuit diagram" -o circuit.png -v
|
|
737
|
+
|
|
738
|
+
Document Types (quality thresholds):
|
|
739
|
+
journal 8.5/10 - Nature, Science, peer-reviewed journals
|
|
740
|
+
conference 8.0/10 - Conference papers
|
|
741
|
+
thesis 8.0/10 - Dissertations, theses
|
|
742
|
+
grant 8.0/10 - Grant proposals
|
|
743
|
+
preprint 7.5/10 - arXiv, bioRxiv, etc.
|
|
744
|
+
report 7.5/10 - Technical reports
|
|
745
|
+
poster 7.0/10 - Academic posters
|
|
746
|
+
presentation 6.5/10 - Slides, talks
|
|
747
|
+
default 7.5/10 - General purpose
|
|
748
|
+
|
|
749
|
+
Note: Multiple iterations only occur if quality is BELOW the threshold.
|
|
750
|
+
If the first generation meets the threshold, no extra API calls are made.
|
|
751
|
+
|
|
752
|
+
Environment:
|
|
753
|
+
OPENROUTER_API_KEY OpenRouter API key (required)
|
|
754
|
+
""",
|
|
755
|
+
)
|
|
756
|
+
|
|
757
|
+
parser.add_argument("prompt", help="Description of the diagram to generate")
|
|
758
|
+
parser.add_argument("-o", "--output", required=True, help="Output image path (e.g., diagram.png)")
|
|
759
|
+
parser.add_argument("--iterations", type=int, default=2, help="Maximum refinement iterations (default: 2, max: 2)")
|
|
760
|
+
parser.add_argument(
|
|
761
|
+
"--doc-type",
|
|
762
|
+
default="default",
|
|
763
|
+
choices=["journal", "conference", "poster", "presentation", "report", "grant", "thesis", "preprint", "default"],
|
|
764
|
+
help="Document type for quality threshold (default: default)",
|
|
765
|
+
)
|
|
766
|
+
parser.add_argument("--api-key", help="OpenRouter API key (or set OPENROUTER_API_KEY)")
|
|
767
|
+
parser.add_argument("-v", "--verbose", action="store_true", help="Verbose output")
|
|
768
|
+
|
|
769
|
+
args = parser.parse_args()
|
|
770
|
+
|
|
771
|
+
# Check for API key
|
|
772
|
+
api_key = args.api_key or os.getenv("OPENROUTER_API_KEY")
|
|
773
|
+
if not api_key:
|
|
774
|
+
print("Error: OPENROUTER_API_KEY environment variable not set")
|
|
775
|
+
print("\nSet it with:")
|
|
776
|
+
print(" export OPENROUTER_API_KEY='your_api_key'")
|
|
777
|
+
print("\nOr provide via --api-key flag")
|
|
778
|
+
sys.exit(1)
|
|
779
|
+
|
|
780
|
+
# Validate iterations - enforce max of 2
|
|
781
|
+
if args.iterations < 1 or args.iterations > 2:
|
|
782
|
+
print("Error: Iterations must be between 1 and 2")
|
|
783
|
+
sys.exit(1)
|
|
784
|
+
|
|
785
|
+
try:
|
|
786
|
+
generator = ScientificSchematicGenerator(api_key=api_key, verbose=args.verbose)
|
|
787
|
+
results = generator.generate_iterative(
|
|
788
|
+
user_prompt=args.prompt, output_path=args.output, iterations=args.iterations, doc_type=args.doc_type
|
|
789
|
+
)
|
|
790
|
+
|
|
791
|
+
if results["success"]:
|
|
792
|
+
print(f"\n✓ Success! Image saved to: {args.output}")
|
|
793
|
+
if results.get("early_stop"):
|
|
794
|
+
print(
|
|
795
|
+
f" (Completed in {len([r for r in results['iterations'] if r.get('success')])} iteration(s) - quality threshold met)"
|
|
796
|
+
)
|
|
797
|
+
sys.exit(0)
|
|
798
|
+
else:
|
|
799
|
+
print("\n✗ Generation failed. Check review log for details.")
|
|
800
|
+
sys.exit(1)
|
|
801
|
+
except Exception as e:
|
|
802
|
+
print(f"\n✗ Error: {str(e)}")
|
|
803
|
+
sys.exit(1)
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
if __name__ == "__main__":
|
|
807
|
+
main()
|