@brainpilot/skills 0.0.6 → 0.0.8

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.
Files changed (285) hide show
  1. package/package.json +2 -2
  2. package/skills/01_Meta-Skills/academic-research-hub/SKILL.md +108 -0
  3. package/skills/01_Meta-Skills/academic-research-hub/scripts/requirements.txt +17 -0
  4. package/skills/01_Meta-Skills/academic-research-hub/scripts/research.py +781 -0
  5. package/skills/01_Meta-Skills/beautiful-log/SKILL.md +64 -0
  6. package/skills/01_Meta-Skills/beautiful-log/scripts/beautiful_log.py +274 -0
  7. package/skills/01_Meta-Skills/ethoclaw-daily-paper/SKILL.md +130 -0
  8. package/skills/01_Meta-Skills/ethoclaw-daily-paper/assets/config.template.yaml +54 -0
  9. package/skills/01_Meta-Skills/ethoclaw-daily-paper/assets/top5_digest_template.md +5 -0
  10. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/build_top5_digest.py +300 -0
  11. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/common.py +137 -0
  12. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/merge_results.py +106 -0
  13. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/run_pipeline.py +177 -0
  14. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/search_arxiv.py +162 -0
  15. package/skills/01_Meta-Skills/ethoclaw-daily-paper/scripts/search_pubmed.py +202 -0
  16. package/skills/01_Meta-Skills/ethoclaw-normalize-tabular/SKILL.md +173 -0
  17. package/skills/01_Meta-Skills/ethoclaw-normalize-tabular/scripts/normalize_data.py +874 -0
  18. package/skills/01_Meta-Skills/ethoclaw-pdf-research/SKILL.md +134 -0
  19. package/skills/01_Meta-Skills/ethoclaw-pdf-research/references/confirmation-prompts.md +31 -0
  20. package/skills/01_Meta-Skills/ethoclaw-pdf-research/references/output-patterns.md +45 -0
  21. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_markdown_deliverables.py +41 -0
  22. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_research_log.py +84 -0
  23. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/build_summary_md.py +63 -0
  24. package/skills/01_Meta-Skills/ethoclaw-pdf-research/scripts/extract_pdf_bundle.py +140 -0
  25. package/skills/01_Meta-Skills/experiment-controller/SKILL.md +140 -0
  26. package/skills/01_Meta-Skills/knowledge-graph-builder/SKILL.md +366 -0
  27. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/entity_resolution.py +120 -0
  28. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/extraction_prompt_template.txt +19 -0
  29. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/graph_query.py +106 -0
  30. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/hypothesis_cli_reference.py +42 -0
  31. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/new_data_source_template.py +116 -0
  32. package/skills/01_Meta-Skills/knowledge-graph-builder/scripts/requirements.txt +15 -0
  33. package/skills/01_Meta-Skills/method-design/SKILL.md +61 -0
  34. package/skills/01_Meta-Skills/multi-search-engine/SKILL.md +119 -0
  35. package/skills/01_Meta-Skills/research-idea/SKILL.md +65 -0
  36. package/skills/05_EEG_ERP/eeg-skill/SKILL.md +197 -0
  37. package/skills/05_EEG_ERP/meg-skill/SKILL.md +188 -0
  38. package/skills/05_EEG_ERP/meg-skill/scripts/time_frequency.py +223 -0
  39. package/skills/05_EEG_ERP/mne-eeg-tool/SKILL.md +165 -0
  40. package/skills/05_EEG_ERP/mne-eeg-tool/scripts/eeg_pipeline_reference.py +231 -0
  41. package/skills/05_EEG_ERP/seed-iv-skill/SKILL.md +184 -0
  42. package/skills/05_EEG_ERP/seed-iv-skill/scripts/classify_seed_iv.py +154 -0
  43. package/skills/05_EEG_ERP/seed-iv-skill/scripts/extract_seed_iv_features.py +190 -0
  44. package/skills/05_EEG_ERP/seed-iv-skill/scripts/validate_seed_iv.py +102 -0
  45. package/skills/05_EEG_ERP/seed-vig-skill/SKILL.md +182 -0
  46. package/skills/05_EEG_ERP/seed-vig-skill/scripts/classify_seed_vig.py +165 -0
  47. package/skills/05_EEG_ERP/seed-vig-skill/scripts/extract_seed_vig_features.py +185 -0
  48. package/skills/05_EEG_ERP/seed-vig-skill/scripts/validate_seed_vig.py +88 -0
  49. package/skills/06_fMRI_Neuroimaging/abcd-skill/SKILL.md +308 -0
  50. package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/abcd_qc_summary.py +449 -0
  51. package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/extract_abcd_phenotype.py +292 -0
  52. package/skills/06_fMRI_Neuroimaging/abcd-skill/scripts/reorganize_abcd.py +387 -0
  53. package/skills/06_fMRI_Neuroimaging/abide-skill/SKILL.md +302 -0
  54. package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/abide_qc_summary.py +317 -0
  55. package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/extract_abide_phenotype.py +267 -0
  56. package/skills/06_fMRI_Neuroimaging/abide-skill/scripts/reorganize_abide.py +387 -0
  57. package/skills/06_fMRI_Neuroimaging/adhd200-skill/SKILL.md +244 -0
  58. package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/adhd200_qc_summary.py +98 -0
  59. package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/extract_adhd200_phenotype.py +134 -0
  60. package/skills/06_fMRI_Neuroimaging/adhd200-skill/scripts/reorganize_adhd200.py +206 -0
  61. package/skills/06_fMRI_Neuroimaging/adni-skill/SKILL.md +358 -0
  62. package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/generate_adni_task_files.py +1305 -0
  63. package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/generate_vqa_from_tasks.py +766 -0
  64. package/skills/06_fMRI_Neuroimaging/adni-skill/scripts/reorganize_adni.py +491 -0
  65. package/skills/06_fMRI_Neuroimaging/aibl-skill/SKILL.md +295 -0
  66. package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/aibl_qc_summary.py +260 -0
  67. package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/extract_aibl_phenotype.py +365 -0
  68. package/skills/06_fMRI_Neuroimaging/aibl-skill/scripts/reorganize_aibl.py +394 -0
  69. package/skills/06_fMRI_Neuroimaging/aomic-skill/SKILL.md +292 -0
  70. package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/aomic_qc_summary.py +258 -0
  71. package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/extract_aomic_phenotype.py +284 -0
  72. package/skills/06_fMRI_Neuroimaging/aomic-skill/scripts/reorganize_aomic.py +322 -0
  73. package/skills/06_fMRI_Neuroimaging/asl-skill/SKILL.md +168 -0
  74. package/skills/06_fMRI_Neuroimaging/asl-skill/scripts/compute_cbf.py +224 -0
  75. package/skills/06_fMRI_Neuroimaging/bids-organizer/SKILL.md +241 -0
  76. package/skills/06_fMRI_Neuroimaging/bold5000-skill/SKILL.md +186 -0
  77. package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/bold5000_qc_summary.py +96 -0
  78. package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/extract_bold5000_stimulus.py +125 -0
  79. package/skills/06_fMRI_Neuroimaging/bold5000-skill/scripts/reorganize_bold5000.py +102 -0
  80. package/skills/06_fMRI_Neuroimaging/camcan-skill/SKILL.md +213 -0
  81. package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/camcan_qc_summary.py +131 -0
  82. package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/extract_camcan_phenotype.py +145 -0
  83. package/skills/06_fMRI_Neuroimaging/camcan-skill/scripts/validate_camcan.py +141 -0
  84. package/skills/06_fMRI_Neuroimaging/cobre-skill/SKILL.md +201 -0
  85. package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/cobre_qc_summary.py +95 -0
  86. package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/extract_cobre_phenotype.py +104 -0
  87. package/skills/06_fMRI_Neuroimaging/cobre-skill/scripts/reorganize_cobre.py +140 -0
  88. package/skills/06_fMRI_Neuroimaging/conn-tool/SKILL.md +180 -0
  89. package/skills/06_fMRI_Neuroimaging/dcm2nii/SKILL.md +189 -0
  90. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/SKILL.md +183 -0
  91. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/dmt_har_med_qc_summary.py +96 -0
  92. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/extract_dmt_har_med_phenotype.py +121 -0
  93. package/skills/06_fMRI_Neuroimaging/dmt-har-med-skill/scripts/reorganize_dmt_har_med.py +125 -0
  94. package/skills/06_fMRI_Neuroimaging/dwi-skill/SKILL.md +359 -0
  95. package/skills/06_fMRI_Neuroimaging/fmri-skill/SKILL.md +371 -0
  96. package/skills/06_fMRI_Neuroimaging/fmriprep-tool/SKILL.md +228 -0
  97. package/skills/06_fMRI_Neuroimaging/freesurfer-tool/SKILL.md +286 -0
  98. package/skills/06_fMRI_Neuroimaging/freesurfer-tool/scripts/freesurfer_processor.py +145 -0
  99. package/skills/06_fMRI_Neuroimaging/fsl-tool/SKILL.md +208 -0
  100. package/skills/06_fMRI_Neuroimaging/hbn-skill/SKILL.md +271 -0
  101. package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/extract_hbn_phenotype.py +107 -0
  102. package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/hbn_qc_summary.py +96 -0
  103. package/skills/06_fMRI_Neuroimaging/hbn-skill/scripts/reorganize_hbn.py +150 -0
  104. package/skills/06_fMRI_Neuroimaging/hcpa-skill/SKILL.md +210 -0
  105. package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/extract_hcpa_phenotype.py +146 -0
  106. package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/hcpa_qc_summary.py +120 -0
  107. package/skills/06_fMRI_Neuroimaging/hcpa-skill/scripts/reorganize_hcpa.py +155 -0
  108. package/skills/06_fMRI_Neuroimaging/hcpd-skill/SKILL.md +210 -0
  109. package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/extract_hcpd_phenotype.py +148 -0
  110. package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/hcpd_qc_summary.py +125 -0
  111. package/skills/06_fMRI_Neuroimaging/hcpd-skill/scripts/reorganize_hcpd.py +146 -0
  112. package/skills/06_fMRI_Neuroimaging/hcpep-skill/SKILL.md +215 -0
  113. package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/extract_hcpep_phenotype.py +157 -0
  114. package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/hcpep_qc_summary.py +143 -0
  115. package/skills/06_fMRI_Neuroimaging/hcpep-skill/scripts/reorganize_hcpep.py +146 -0
  116. package/skills/06_fMRI_Neuroimaging/hcppipeline-tool/SKILL.md +217 -0
  117. package/skills/06_fMRI_Neuroimaging/hcpya-skill/SKILL.md +214 -0
  118. package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/extract_hcpya_phenotype.py +190 -0
  119. package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/hcpya_qc_summary.py +152 -0
  120. package/skills/06_fMRI_Neuroimaging/hcpya-skill/scripts/reorganize_hcpya.py +203 -0
  121. package/skills/06_fMRI_Neuroimaging/ixi-skill/SKILL.md +198 -0
  122. package/skills/06_fMRI_Neuroimaging/ixi-skill/scripts/ixi_qc_summary.py +137 -0
  123. package/skills/06_fMRI_Neuroimaging/ixi-skill/scripts/reorganize_ixi.py +190 -0
  124. package/skills/06_fMRI_Neuroimaging/mnd-skill/SKILL.md +191 -0
  125. package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/extract_mnd_phenotype.py +143 -0
  126. package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/mnd_qc_summary.py +120 -0
  127. package/skills/06_fMRI_Neuroimaging/mnd-skill/scripts/validate_mnd.py +107 -0
  128. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/SKILL.md +203 -0
  129. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/analyze_lesions.py +119 -0
  130. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/longitudinal_lesion.py +148 -0
  131. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/mschallenge_qc_summary.py +132 -0
  132. package/skills/06_fMRI_Neuroimaging/mschallenge-skill/scripts/validate_mschallenge.py +116 -0
  133. package/skills/06_fMRI_Neuroimaging/nibabel-skill/SKILL.md +184 -0
  134. package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/atlas_coordinate_reference.py +61 -0
  135. package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/freesurfer_io_reference.py +34 -0
  136. package/skills/06_fMRI_Neuroimaging/nibabel-skill/scripts/nifti_inspection_reference.py +35 -0
  137. package/skills/06_fMRI_Neuroimaging/nifd-skill/SKILL.md +205 -0
  138. package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/extract_nifd_phenotype.py +132 -0
  139. package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/nifd_qc_summary.py +111 -0
  140. package/skills/06_fMRI_Neuroimaging/nifd-skill/scripts/validate_nifd.py +111 -0
  141. package/skills/06_fMRI_Neuroimaging/nii2dcm/SKILL.md +143 -0
  142. package/skills/06_fMRI_Neuroimaging/nilearn-tool/SKILL.md +266 -0
  143. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/connectome_reference.py +65 -0
  144. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/denoise_timeseries_reference.py +58 -0
  145. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/hierarchical_parcellation_reference.py +53 -0
  146. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/kmeans_parcellation_reference.py +53 -0
  147. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/preprocess_bold_reference.py +76 -0
  148. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/rest_dictlearning_reference.py +56 -0
  149. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/rest_ica_reference.py +59 -0
  150. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/second_level_glm_reference.py +58 -0
  151. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/spacenet_classifier_reference.py +59 -0
  152. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/svm_classifier_reference.py +60 -0
  153. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/task_glm_reference.py +63 -0
  154. package/skills/06_fMRI_Neuroimaging/nilearn-tool/scripts/zalff_summary_reference.py +109 -0
  155. package/skills/06_fMRI_Neuroimaging/nsd-skill/SKILL.md +210 -0
  156. package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/extract_nsd_stimulus.py +171 -0
  157. package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/nsd_qc_summary.py +142 -0
  158. package/skills/06_fMRI_Neuroimaging/nsd-skill/scripts/validate_nsd.py +142 -0
  159. package/skills/06_fMRI_Neuroimaging/oasis-skill/SKILL.md +205 -0
  160. package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/extract_oasis_phenotype.py +126 -0
  161. package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/oasis_qc_summary.py +115 -0
  162. package/skills/06_fMRI_Neuroimaging/oasis-skill/scripts/validate_oasis.py +119 -0
  163. package/skills/06_fMRI_Neuroimaging/pet-skill/SKILL.md +173 -0
  164. package/skills/06_fMRI_Neuroimaging/pet-skill/scripts/compute_suvr.py +202 -0
  165. package/skills/06_fMRI_Neuroimaging/pnc-skill/SKILL.md +206 -0
  166. package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/extract_pnc_phenotype.py +136 -0
  167. package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/pnc_qc_summary.py +116 -0
  168. package/skills/06_fMRI_Neuroimaging/pnc-skill/scripts/validate_pnc.py +120 -0
  169. package/skills/06_fMRI_Neuroimaging/ppmi-skill/SKILL.md +209 -0
  170. package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/extract_ppmi_phenotype.py +138 -0
  171. package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/ppmi_qc_summary.py +111 -0
  172. package/skills/06_fMRI_Neuroimaging/ppmi-skill/scripts/validate_ppmi.py +117 -0
  173. package/skills/06_fMRI_Neuroimaging/qsiprep-tool/SKILL.md +320 -0
  174. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/SKILL.md +215 -0
  175. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/extract_rest_mdd_phenotype.py +132 -0
  176. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/harmonize_sites.py +152 -0
  177. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/rest_mdd_qc_summary.py +124 -0
  178. package/skills/06_fMRI_Neuroimaging/rest-mneta-mdd-skill/scripts/validate_rest_mdd.py +103 -0
  179. package/skills/06_fMRI_Neuroimaging/smri-skill/SKILL.md +302 -0
  180. package/skills/06_fMRI_Neuroimaging/tcp-skill/SKILL.md +204 -0
  181. package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/extract_tcp_phenotype.py +139 -0
  182. package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/tcp_qc_summary.py +111 -0
  183. package/skills/06_fMRI_Neuroimaging/tcp-skill/scripts/validate_tcp.py +99 -0
  184. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/SKILL.md +217 -0
  185. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/extract_ucla_cnp_phenotype.py +145 -0
  186. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/ucla_cnp_qc_summary.py +111 -0
  187. package/skills/06_fMRI_Neuroimaging/ucla-cnp-skill/scripts/validate_ucla_cnp.py +113 -0
  188. package/skills/06_fMRI_Neuroimaging/ukb-skill/SKILL.md +310 -0
  189. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/build_ukb_survival.py +210 -0
  190. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/extract_ukb_cases.py +308 -0
  191. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/extract_ukb_phenotype.py +232 -0
  192. package/skills/06_fMRI_Neuroimaging/ukb-skill/scripts/ukb_qc_summary.py +158 -0
  193. package/skills/06_fMRI_Neuroimaging/wmh-segmentation/SKILL.md +133 -0
  194. package/skills/07_Computational_Modeling/detrending/SKILL.md +118 -0
  195. package/skills/07_Computational_Modeling/dictlearning/SKILL.md +122 -0
  196. package/skills/07_Computational_Modeling/filtering/SKILL.md +121 -0
  197. package/skills/07_Computational_Modeling/glm/SKILL.md +153 -0
  198. package/skills/07_Computational_Modeling/hierarchical/SKILL.md +121 -0
  199. package/skills/07_Computational_Modeling/ica/SKILL.md +122 -0
  200. package/skills/07_Computational_Modeling/kmeans/SKILL.md +119 -0
  201. package/skills/07_Computational_Modeling/run_models/SKILL.md +427 -0
  202. package/skills/07_Computational_Modeling/spacenet/SKILL.md +122 -0
  203. package/skills/07_Computational_Modeling/svm/SKILL.md +120 -0
  204. package/skills/08_Computational_Neuroscience/brain_gnn/SKILL.md +183 -0
  205. package/skills/08_Computational_Neuroscience/dipy-tool/SKILL.md +239 -0
  206. package/skills/08_Computational_Neuroscience/dipy-tool/scripts/dti_metrics_reference.py +70 -0
  207. package/skills/08_Computational_Neuroscience/dipy-tool/scripts/load_and_mask_reference.py +76 -0
  208. package/skills/08_Computational_Neuroscience/dipy-tool/scripts/roi_stats_reference.py +59 -0
  209. package/skills/08_Computational_Neuroscience/fm_app/SKILL.md +195 -0
  210. package/skills/08_Computational_Neuroscience/neurostorm/SKILL.md +151 -0
  211. package/skills/13_Visualization/brain-visualization/SKILL.md +191 -0
  212. package/skills/13_Visualization/brain-visualization/scripts/connectome_reference.py +108 -0
  213. package/skills/13_Visualization/brain-visualization/scripts/freesurfer_ply_reference.py +54 -0
  214. package/skills/13_Visualization/brain-visualization/scripts/zalff_summary_reference.py +116 -0
  215. package/skills/13_Visualization/ethoclaw-paper-figure-layout/SKILL.md +78 -0
  216. package/skills/13_Visualization/ethoclaw-paper-figure-layout/assets/naturecomm_figures.tex +74 -0
  217. package/skills/13_Visualization/ethoclaw-paper-figure-layout/scripts/layout_results_foldered.py +579 -0
  218. package/skills/14_Writing/overleaf-skill/SKILL.md +184 -0
  219. package/skills/14_Writing/overleaf-skill/scripts/install.sh +30 -0
  220. package/skills/14_Writing/paper-writing/SKILL.md +146 -0
  221. package/skills/14_Writing/paper-writing/scripts/data_statement_templates.py +164 -0
  222. package/skills/14_Writing/paper-writing/scripts/figure_templates.py +315 -0
  223. package/skills/14_Writing/paper-writing/scripts/nature_figure_style.py +214 -0
  224. package/skills/14_Writing/paper-writing/scripts/section_phrasebank.py +246 -0
  225. package/skills/16_Animal_Behavior/deeplabcut/SKILL.md +154 -0
  226. package/skills/16_Animal_Behavior/deeplabcut/references/3d-pose.md +89 -0
  227. package/skills/16_Animal_Behavior/deeplabcut/references/maDLC.md +123 -0
  228. package/skills/16_Animal_Behavior/deeplabcut/references/modelzoo.md +98 -0
  229. package/skills/16_Animal_Behavior/deeplabcut/references/standard-pipeline.md +165 -0
  230. package/skills/16_Animal_Behavior/deeplabcut/references/utilities.md +146 -0
  231. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/SKILL.md +274 -0
  232. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/report_template_en.html +112 -0
  233. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/report_template_en.md +21 -0
  234. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/cluster-section.md +5 -0
  235. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/heatmap-section.md +5 -0
  236. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/integrated-interpretation.md +3 -0
  237. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/overview.md +3 -0
  238. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/project-summary.md +3 -0
  239. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/radar-section.md +5 -0
  240. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/raw-trajectory.md +3 -0
  241. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/sample-check.md +3 -0
  242. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/single-subject-section.md +3 -0
  243. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/assets/section_templates/stats-section.md +5 -0
  244. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/epm.md +52 -0
  245. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/fst.md +37 -0
  246. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/nor.md +39 -0
  247. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/oft.md +43 -0
  248. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/tcst.md +45 -0
  249. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/experiment-types/tst.md +36 -0
  250. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/input-types.md +59 -0
  251. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/interpretation-guardrails.md +45 -0
  252. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/metadata-schema.md +57 -0
  253. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/report-sections.md +86 -0
  254. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/references/section-selection-rules.md +169 -0
  255. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/build_report_manifest.py +27 -0
  256. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/render_report.py +34 -0
  257. package/skills/16_Animal_Behavior/ethoclaw-analysis-report/scripts/report_utils.py +1121 -0
  258. package/skills/16_Animal_Behavior/ethoclaw-animal-grounding/SKILL.md +390 -0
  259. package/skills/16_Animal_Behavior/ethoclaw-animal-grounding/reference_code.py +98 -0
  260. package/skills/16_Animal_Behavior/ethoclaw-animal-pose-estimation/SKILL.md +336 -0
  261. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/README.md +21 -0
  262. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/SKILL.md +41 -0
  263. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/batch_kinematic_generator.py +663 -0
  264. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/config.json +19 -0
  265. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/generate_kinematic_parameter.py +401 -0
  266. package/skills/16_Animal_Behavior/ethoclaw-kinematic-parameter-generator/kinematic_generator.py +265 -0
  267. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/SKILL.md +72 -0
  268. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/references/config.example.toml +56 -0
  269. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/scripts/cluster_all_params.py +232 -0
  270. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-clustermap-generate/scripts/cluster_all_params_from_config.py +236 -0
  271. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/SKILL.md +68 -0
  272. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/references/notes.md +5 -0
  273. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-radar-generate/scripts/plot_h5_radar.py +513 -0
  274. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/SKILL.md +52 -0
  275. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/config.toml +81 -0
  276. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/references/stats-rule.md +18 -0
  277. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_inspect.py +79 -0
  278. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_violin_batch.py +624 -0
  279. package/skills/16_Animal_Behavior/ethoclaw-multiparameter-violin-stats-generate/scripts/h5_violin_stats.py +438 -0
  280. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/SKILL.md +280 -0
  281. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/core_scripts/heatmap_trajectory.py +790 -0
  282. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/core_scripts/heatmap_velocity.py +855 -0
  283. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_2d.csv +101 -0
  284. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_2d.h5 +0 -0
  285. package/skills/16_Animal_Behavior/ethoclaw-trajectory-velocity-heatmap-generate/reference_data/reference_data_readme.md +126 -0
@@ -0,0 +1,663 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Batch process .h5 files to check for KinematicParameter and generate it if missing.
4
+ Also adds video information to VideoInfo if video is available.
5
+ If no .h5 files are found, processes .csv files and converts them to .h5 first.
6
+ """
7
+
8
+ import argparse
9
+ import subprocess
10
+ import sys
11
+ from pathlib import Path
12
+ import h5py
13
+ import json
14
+ import os
15
+
16
+
17
+ def get_fps_from_video(video_path):
18
+ """Extract FPS from video file using ffprobe."""
19
+ import subprocess
20
+ import json
21
+
22
+ cmd = [
23
+ 'ffprobe',
24
+ '-v', 'quiet',
25
+ '-print_format', 'json',
26
+ '-show_format',
27
+ '-show_streams',
28
+ str(video_path)
29
+ ]
30
+
31
+ try:
32
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
33
+ video_info = json.loads(result.stdout)
34
+
35
+ # Find video stream
36
+ for stream in video_info.get('streams', []):
37
+ if stream.get('codec_type') == 'video':
38
+ avg_frame_rate = stream.get('avg_frame_rate')
39
+ if avg_frame_rate:
40
+ # avg_frame_rate is often in form "num/den" like "30/1"
41
+ if '/' in avg_frame_rate:
42
+ num, den = avg_frame_rate.split('/')
43
+ fps = float(num) / float(den) if float(den) != 0 else 30.0
44
+ else:
45
+ fps = float(avg_frame_rate)
46
+ return fps
47
+
48
+ # Alternative: get from format if not in streams
49
+ format_info = video_info.get('format', {})
50
+ if 'avg_frame_rate' in format_info:
51
+ avg_frame_rate = format_info['avg_frame_rate']
52
+ if avg_frame_rate and avg_frame_rate != '0/0':
53
+ if '/' in avg_frame_rate:
54
+ num, den = avg_frame_rate.split('/')
55
+ fps = float(num) / float(den) if float(den) != 0 else 30.0
56
+ else:
57
+ fps = float(avg_frame_rate)
58
+ return fps
59
+
60
+ except Exception as e:
61
+ print(f" - Warning: Could not get FPS from video {video_path}: {e}")
62
+
63
+ # Fallback to OpenCV
64
+ try:
65
+ import cv2
66
+ cap = cv2.VideoCapture(str(video_path))
67
+ fps = cap.get(cv2.CAP_PROP_FPS)
68
+ cap.release()
69
+ if fps and fps > 0:
70
+ return fps
71
+ except Exception as cv_e:
72
+ print(f" - Warning: OpenCV fallback also failed: {cv_e}")
73
+
74
+ return 30.0 # Default FPS if all methods fail
75
+
76
+
77
+ def add_video_info_to_h5(h5_path, video_path, fps):
78
+ """Add video information to the HDF5 file under /VideoInfo."""
79
+ import subprocess
80
+ import json
81
+
82
+ # Get additional video info using ffprobe
83
+ cmd = [
84
+ 'ffprobe',
85
+ '-v', 'quiet',
86
+ '-print_format', 'json',
87
+ '-show_format',
88
+ '-show_streams',
89
+ str(video_path)
90
+ ]
91
+
92
+ try:
93
+ result = subprocess.run(cmd, capture_output=True, text=True, check=True)
94
+ video_info = json.loads(result.stdout)
95
+
96
+ # Extract video stream info
97
+ video_stream = None
98
+ for stream in video_info.get('streams', []):
99
+ if stream.get('codec_type') == 'video':
100
+ video_stream = stream
101
+ break
102
+
103
+ # Get format info
104
+ format_info = video_info.get('format', {})
105
+
106
+ # Add video info to HDF5
107
+ with h5py.File(str(h5_path), 'a') as f: # Open in append mode
108
+ # Create or get VideoInfo group
109
+ if 'VideoInfo' in f:
110
+ vid_group = f['VideoInfo']
111
+ else:
112
+ vid_group = f.create_group('VideoInfo')
113
+
114
+ # Add FPS
115
+ if 'fps' in vid_group:
116
+ del vid_group['fps']
117
+ vid_group.create_dataset('fps', data=float(fps))
118
+
119
+ # Add other video properties if available
120
+ if video_stream:
121
+ # Resolution
122
+ width = video_stream.get('width')
123
+ height = video_stream.get('height')
124
+
125
+ if width:
126
+ if 'width' in vid_group:
127
+ del vid_group['width']
128
+ vid_group.create_dataset('width', data=int(width))
129
+
130
+ if height:
131
+ if 'height' in vid_group:
132
+ del vid_group['height']
133
+ vid_group.create_dataset('height', data=int(height))
134
+
135
+ # Codec
136
+ codec_name = video_stream.get('codec_name')
137
+ if codec_name:
138
+ if 'codec' in vid_group:
139
+ del vid_group['codec']
140
+ vid_group.create_dataset('codec', data=codec_name.encode('utf-8'))
141
+
142
+ # Duration (from stream level)
143
+ duration = video_stream.get('duration')
144
+ if duration:
145
+ if 'duration' in vid_group:
146
+ del vid_group['duration']
147
+ vid_group.create_dataset('duration', data=float(duration))
148
+
149
+ # Add format-level info
150
+ if format_info:
151
+ # Duration (from format level)
152
+ if 'duration' not in (video_stream or {}) and 'duration' in format_info:
153
+ duration = float(format_info['duration'])
154
+ if 'duration' in vid_group:
155
+ del vid_group['duration']
156
+ vid_group.create_dataset('duration', data=duration)
157
+
158
+ # Bit rate
159
+ bit_rate = format_info.get('bit_rate')
160
+ if bit_rate:
161
+ if 'bit_rate' in vid_group:
162
+ del vid_group['bit_rate']
163
+ vid_group.create_dataset('bit_rate', data=int(bit_rate))
164
+
165
+ # File size
166
+ size = format_info.get('size')
167
+ if size:
168
+ if 'size' in vid_group:
169
+ del vid_group['size']
170
+ vid_group.create_dataset('size', data=int(size))
171
+ except Exception as e:
172
+ print(f" - Warning: Could not add detailed video info to {h5_path}: {e}")
173
+
174
+
175
+ def find_associated_video(h5_path):
176
+ """
177
+ Find an associated video file with the same stem as the .h5 file
178
+
179
+ Args:
180
+ h5_path (str or Path): Path to the .h5 file
181
+
182
+ Returns:
183
+ Path or None: Path to the video file if found, None otherwise
184
+ """
185
+ h5_path = Path(h5_path)
186
+ stem = h5_path.stem
187
+
188
+ # Common video extensions
189
+ video_extensions = ['.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.mpeg', '.mpg']
190
+
191
+ # Look in the same directory as the .h5 file
192
+ h5_dir = h5_path.parent
193
+
194
+ for ext in video_extensions:
195
+ video_path = h5_dir / (stem + ext)
196
+ if video_path.exists():
197
+ return video_path
198
+
199
+ # Look in the current working directory
200
+ for ext in video_extensions:
201
+ video_path = Path.cwd() / (stem + ext)
202
+ if video_path.exists():
203
+ return video_path
204
+
205
+ # Look in common subdirectories of the current directory
206
+ for subdir in ['videos', 'video', 'Videos', 'Video', 'data', 'Data']:
207
+ sub_dir = h5_dir / subdir
208
+ if sub_dir.exists() and sub_dir.is_dir():
209
+ for ext in video_extensions:
210
+ video_path = sub_dir / (stem + ext)
211
+ if video_path.exists():
212
+ return video_path
213
+
214
+ # For typical project structures, look for related directories
215
+ # E.g., if h5 is in 1_2Dskeleton, check for 0_videos
216
+ parent_dir = h5_dir.parent
217
+ if parent_dir.name.endswith('_2Dskeleton') or parent_dir.name.endswith('_2Dkeypoints'):
218
+ # Try to find a sibling directory with videos
219
+ project_dir = parent_dir.parent
220
+ for sibling_dir in project_dir.iterdir():
221
+ if sibling_dir.is_dir() and ('video' in sibling_dir.name.lower() or
222
+ '0_' in sibling_dir.name or
223
+ 'raw' in sibling_dir.name.lower()):
224
+ for ext in video_extensions:
225
+ video_path = sibling_dir / (stem + ext)
226
+ if video_path.exists():
227
+ return video_path
228
+
229
+ # Try parent directory and its subdirectories
230
+ for parent_level in range(1, 4): # Go up to 3 levels
231
+ cur_dir = h5_path
232
+ for _ in range(parent_level):
233
+ cur_dir = cur_dir.parent
234
+ if cur_dir == cur_dir.parent: # Reached root
235
+ break
236
+ else:
237
+ # Check in this parent directory
238
+ for ext in video_extensions:
239
+ video_path = cur_dir / (stem + ext)
240
+ if video_path.exists():
241
+ return video_path
242
+
243
+ # Check subdirectories of this parent
244
+ for subdir in cur_dir.iterdir():
245
+ if subdir.is_dir():
246
+ for ext in video_extensions:
247
+ video_path = subdir / (stem + ext)
248
+ if video_path.exists():
249
+ return video_path
250
+
251
+ return None
252
+
253
+
254
+ def csv_to_h5(csv_path, h5_output_path, fps=30.0):
255
+ """
256
+ Convert a CSV file containing 2D skeleton data to HDF5 format with 2Dskeleton group.
257
+
258
+ Args:
259
+ csv_path (str or Path): Path to the input CSV file
260
+ h5_output_path (str or Path): Path for the output HDF5 file
261
+ fps (float): Frames per second for the video
262
+ """
263
+ import pandas as pd
264
+ import numpy as np
265
+ import time
266
+ import os
267
+
268
+ # Read the CSV file
269
+ df = pd.read_csv(csv_path)
270
+
271
+ # Extract body parts from column names
272
+ # Expected format: {bodypart}_x, {bodypart}_y, {bodypart}_confidence
273
+ columns = df.columns.tolist()
274
+
275
+ # Identify unique body parts
276
+ body_parts = set()
277
+ for col in columns:
278
+ if '_' in col:
279
+ bp = '_'.join(col.split('_')[:-1]) # Get everything before the last underscore
280
+ if col.endswith(('_x', '_y', '_confidence')):
281
+ body_parts.add(bp)
282
+
283
+ body_parts = sorted(list(body_parts)) # Sort to ensure consistent order
284
+
285
+ # Prepare the skeleton data array
286
+ n_frames = len(df)
287
+ n_body_parts = len(body_parts)
288
+
289
+ # Create data in the format expected by the original script:
290
+ # data2D should be (n_frames, n_bodyparts*3) -> [x, y, likelihood] per bodypart
291
+ data2d = np.zeros((n_frames, n_body_parts * 3)) # x, y, confidence for each body part in flattened format
292
+
293
+ # Map body parts to indices
294
+ bp_to_idx = {bp: i for i, bp in enumerate(body_parts)}
295
+
296
+ # Fill the skeleton data in the expected format
297
+ for bp in body_parts:
298
+ bp_idx = bp_to_idx[bp]
299
+ x_col = f"{bp}_x"
300
+ y_col = f"{bp}_y"
301
+ conf_col = f"{bp}_confidence"
302
+
303
+ if x_col in df.columns and y_col in df.columns and conf_col in df.columns:
304
+ # Fill x, y, confidence in the flattened format
305
+ data2d[:, bp_idx * 3 + 0] = df[x_col].values # x coordinates
306
+ data2d[:, bp_idx * 3 + 1] = df[y_col].values # y coordinates
307
+ data2d[:, bp_idx * 3 + 2] = df[conf_col].values # confidence scores
308
+
309
+ # Create HDF5 file with retry mechanism for WSL file locking issues
310
+ max_retries = 5
311
+ retry_delay = 2 # seconds
312
+
313
+ for attempt in range(max_retries):
314
+ try:
315
+ # Ensure the output file doesn't exist to avoid locking issues
316
+ if os.path.exists(h5_output_path):
317
+ os.remove(h5_output_path)
318
+ time.sleep(0.5) # Brief pause after removal
319
+
320
+ # Create HDF5 file
321
+ with h5py.File(h5_output_path, 'w') as f:
322
+ # Create 2Dskeleton group
323
+ skel_group = f.create_group('2Dskeleton')
324
+
325
+ # Store body parts as a dataset (expected by original script)
326
+ skel_group.create_dataset('BodyParts', data=[bp.encode('utf-8') for bp in body_parts])
327
+
328
+ # Store the skeleton data in the expected format (data2D)
329
+ skel_group.create_dataset('data2D', data=data2d, compression='gzip')
330
+
331
+ # Also store in the original format as backup (some files seem to use this)
332
+ skeleton_data_backup = np.zeros((n_frames, n_body_parts, 3)) # x, y, confidence for each body part
333
+ for bp in body_parts:
334
+ bp_idx = bp_to_idx[bp]
335
+ x_col = f"{bp}_x"
336
+ y_col = f"{bp}_y"
337
+ conf_col = f"{bp}_confidence"
338
+
339
+ if x_col in df.columns and y_col in df.columns and conf_col in df.columns:
340
+ skeleton_data_backup[:, bp_idx, 0] = df[x_col].values # x coordinates
341
+ skeleton_data_backup[:, bp_idx, 1] = df[y_col].values # y coordinates
342
+ skeleton_data_backup[:, bp_idx, 2] = df[conf_col].values # confidence scores
343
+
344
+ skel_group.create_dataset('data', data=skeleton_data_backup, compression='gzip')
345
+
346
+ # Store frame count and fps as attributes
347
+ skel_group.attrs['frame_count'] = n_frames
348
+ skel_group.attrs['fps'] = fps
349
+
350
+ # Optionally add calibration info if available
351
+ cal_group = f.create_group('CalibrationInfo')
352
+ # Default to 1:1 pixel-to-mm ratio if not known
353
+ cal_group.create_dataset('px_mm_ratio_x', data=1.0)
354
+ cal_group.create_dataset('px_mm_ratio_y', data=1.0)
355
+
356
+ print(f" - Created HDF5 file from CSV: {h5_output_path}")
357
+ print(f" Body parts: {body_parts}")
358
+ print(f" Frames: {n_frames}")
359
+ print(f" FPS: {fps}")
360
+
361
+ # Verification: Try to read the file back to confirm it was written correctly
362
+ try:
363
+ with h5py.File(h5_output_path, 'r') as f:
364
+ if '2Dskeleton' not in f or 'data2D' not in f['2Dskeleton']:
365
+ raise Exception("File created but missing expected structure")
366
+ break # Success, exit retry loop
367
+ except Exception as verify_error:
368
+ print(f" - Verification failed, attempt {attempt + 1}: {verify_error}")
369
+ if attempt == max_retries - 1: # Last attempt
370
+ raise verify_error
371
+ time.sleep(retry_delay)
372
+
373
+ except Exception as e:
374
+ print(f" - Attempt {attempt + 1} failed: {e}")
375
+ if attempt == max_retries - 1: # Last attempt
376
+ raise e
377
+ time.sleep(retry_delay)
378
+
379
+
380
+ def run_generate_kinematic_parameter(h5_path, video_path=None, fps_default=30.0, ratio_default=1.0):
381
+ """
382
+ Run the generate_kinematic_parameter.py script on the .h5 file
383
+
384
+ Args:
385
+ h5_path (str or Path): Path to the .h5 file
386
+ video_path (str or Path, optional): Path to associated video file
387
+ fps_default (float): Default FPS to use if not found elsewhere
388
+ ratio_default (float): Default pixel-to-mm ratio for calibration
389
+ """
390
+ import subprocess
391
+ import os
392
+ import time
393
+
394
+ # Wait briefly before accessing the file to reduce locking conflicts
395
+ time.sleep(1)
396
+
397
+ # Get the path to the generate_kinematic_parameter.py script in the workspace
398
+ script_path = Path(__file__).parent / "generate_kinematic_parameter.py"
399
+
400
+ # If we have video info, we'll use the generate_kinematic_parameter script to add it,
401
+ # since that script already handles both video info and kinematic parameter generation
402
+ if video_path:
403
+ fps = get_fps_from_video(video_path)
404
+ # Use the actual FPS from video rather than default
405
+ fps_for_gen = fps
406
+ else:
407
+ fps_for_gen = fps_default
408
+
409
+ # Build the command
410
+ cmd = [
411
+ sys.executable, # Use the same Python interpreter
412
+ str(script_path),
413
+ "--h5", str(h5_path),
414
+ "--fps-default", str(fps_for_gen),
415
+ "--ratio-default", str(ratio_default),
416
+ "--overwrite" # Allow overwriting if needed
417
+ ]
418
+
419
+ # Add video path if provided (this allows the script to potentially get more accurate FPS)
420
+ # and enables video info extraction
421
+ if video_path:
422
+ cmd.extend(["--video", str(video_path)])
423
+ else:
424
+ # Disable video search if no video path provided
425
+ cmd.append("--no-search-video")
426
+
427
+ # Execute the command with retry mechanism
428
+ max_retries = 3
429
+ retry_delay = 2
430
+
431
+ for attempt in range(max_retries):
432
+ try:
433
+ result = subprocess.run(cmd, capture_output=True, text=True, timeout=300) # 5 minute timeout
434
+
435
+ if result.returncode != 0:
436
+ raise RuntimeError(f"Failed to run generate_kinematic_parameter.py:\nSTDOUT: {result.stdout}\nSTDERR: {result.stderr}")
437
+
438
+ print(result.stdout)
439
+ if result.stderr:
440
+ print("STDERR:", result.stderr)
441
+
442
+ # As a fallback, if VideoInfo wasn't added by the script but we have video info,
443
+ # try to add it directly
444
+ if video_path:
445
+ # Wait before accessing file again
446
+ time.sleep(1)
447
+
448
+ # Check if VideoInfo was added by the script
449
+ import h5py
450
+ with h5py.File(str(h5_path), 'r') as f:
451
+ has_video_info = 'VideoInfo' in f and 'fps' in f['VideoInfo']
452
+
453
+ if not has_video_info:
454
+ print(" - VideoInfo not found after processing, adding directly...")
455
+ fps = get_fps_from_video(video_path)
456
+ add_video_info_to_h5(h5_path, video_path, fps)
457
+
458
+ break # Success, exit retry loop
459
+
460
+ except subprocess.TimeoutExpired:
461
+ print(f" - Command timed out on attempt {attempt + 1}, retrying...")
462
+ if attempt == max_retries - 1:
463
+ raise RuntimeError(f"Command timed out after {max_retries} attempts")
464
+ time.sleep(retry_delay)
465
+ except Exception as e:
466
+ print(f" - Attempt {attempt + 1} failed: {e}")
467
+ if attempt == max_retries - 1: # Last attempt
468
+ raise e
469
+ time.sleep(retry_delay)
470
+
471
+
472
+ def process_single_file(h5_path, fps_default=30.0, ratio_default=1.0):
473
+ """
474
+ Process a single .h5 file to check for KinematicParameter and generate if missing.
475
+
476
+ Args:
477
+ h5_path (str or Path): Path to the .h5 file
478
+ fps_default (float): Default FPS to use if not found elsewhere
479
+ ratio_default (float): Default pixel-to-mm ratio for calibration
480
+
481
+ Returns:
482
+ bool: True if successful, False otherwise
483
+ """
484
+ h5_path = Path(h5_path)
485
+
486
+ print(f"Processing file: {h5_path}")
487
+
488
+ try:
489
+ # Check if KinematicParameter already exists
490
+ with h5py.File(h5_path, 'r') as f:
491
+ has_kinematic_param = 'KinematicParameter' in f
492
+ has_2dskeleton = '2Dskeleton' in f
493
+ has_video_info = 'VideoInfo' in f
494
+
495
+ if has_kinematic_param:
496
+ print(f" - KinematicParameter already exists in {h5_path}")
497
+ return True
498
+
499
+ if not has_2dskeleton:
500
+ print(f" - ERROR: No 2Dskeleton data found in {h5_path}")
501
+ return False
502
+
503
+ # Look for associated video to get FPS
504
+ video_path = find_associated_video(h5_path)
505
+ if video_path:
506
+ print(f" - Found associated video: {video_path}")
507
+ fps = get_fps_from_video(video_path)
508
+ print(f" - Determined FPS from video: {fps}")
509
+ else:
510
+ print(f" - No associated video found. Using default FPS: {fps_default}")
511
+ fps = fps_default
512
+
513
+ # Run the generate_kinematic_parameter script with ratio parameter
514
+ run_generate_kinematic_parameter(h5_path, video_path, fps_default, ratio_default)
515
+
516
+ print(f" - Processing completed for {h5_path}")
517
+ return True
518
+
519
+ except Exception as e:
520
+ print(f" - ERROR processing {h5_path}: {e}")
521
+ import traceback
522
+ traceback.print_exc()
523
+ return False
524
+
525
+
526
+ def process_csv_to_h5_and_then_kinematics(csv_path, fps_default=30.0, ratio_default=1.0):
527
+ """
528
+ Convert a CSV file to HDF5 and then process it for kinematic parameters.
529
+
530
+ Args:
531
+ csv_path (str or Path): Path to the CSV file
532
+ fps_default (float): Default FPS to use
533
+ ratio_default (float): Default pixel-to-mm ratio for calibration
534
+
535
+ Returns:
536
+ bool: True if successful, False otherwise
537
+ """
538
+ csv_path = Path(csv_path)
539
+ h5_path = csv_path.with_suffix('.h5')
540
+
541
+ print(f"Converting CSV to HDF5: {csv_path} -> {h5_path}")
542
+
543
+ try:
544
+ # Convert CSV to HDF5
545
+ csv_to_h5(csv_path, h5_path, fps_default)
546
+
547
+ # Wait briefly to allow file system to settle before accessing the new file
548
+ import time
549
+ time.sleep(2)
550
+
551
+ # Now process the newly created HDF5 file with ratio parameter
552
+ success = process_single_file(h5_path, fps_default, ratio_default)
553
+
554
+ return success
555
+ except Exception as e:
556
+ print(f" - ERROR converting {csv_path} to HDF5: {e}")
557
+ import traceback
558
+ traceback.print_exc()
559
+ return False
560
+
561
+
562
+ def main():
563
+ parser = argparse.ArgumentParser(description="Batch process .h5 files to check for KinematicParameter and generate if missing. If no .h5 files found, processes .csv files and converts them to .h5 first.")
564
+ parser.add_argument("--h5-path", type=str, help="Single .h5 file path to process")
565
+ parser.add_argument("--csv-path", type=str, help="Single .csv file path to convert and process")
566
+ parser.add_argument("--directory", type=str, help="Directory containing .h5 or .csv files to process")
567
+ parser.add_argument("--fps-default", type=float, default=30.0, help="Default FPS to use if not found elsewhere")
568
+ parser.add_argument("--ratio-default", type=float, default=1.0, help="Default pixel-to-mm ratio for calibration (default: 1.0)")
569
+
570
+ args = parser.parse_args()
571
+
572
+ if args.h5_path:
573
+ # Process single .h5 file
574
+ success = process_single_file(args.h5_path, args.fps_default, args.ratio_default)
575
+ if not success:
576
+ sys.exit(1)
577
+ elif args.csv_path:
578
+ # Process single .csv file
579
+ success = process_csv_to_h5_and_then_kinematics(args.csv_path, args.fps_default, args.ratio_default)
580
+ if not success:
581
+ sys.exit(1)
582
+ elif args.directory:
583
+ # Process directory - first check for .h5 files, then .csv files if no .h5 found
584
+ directory = Path(args.directory)
585
+ if not directory.exists():
586
+ print(f"Error: Directory {directory} does not exist")
587
+ sys.exit(1)
588
+
589
+ # Find all .h5 files in the directory
590
+ h5_files = list(directory.rglob('*.h5')) # Use rglob for recursive search
591
+ print(f"Found {len(h5_files)} .h5 files to process")
592
+
593
+ # If no .h5 files found, look for .csv files
594
+ if len(h5_files) == 0:
595
+ csv_files = list(directory.rglob('*.csv')) # Look for CSV files
596
+ print(f"No .h5 files found, found {len(csv_files)} .csv files to convert and process")
597
+
598
+ if len(csv_files) == 0:
599
+ print("No .h5 or .csv files found in the specified directory")
600
+ sys.exit(1)
601
+
602
+ # Process each CSV file
603
+ successful = 0
604
+ failed = 0
605
+ for i, csv_file in enumerate(csv_files):
606
+ print(f"\nProcessing CSV file {i+1}/{len(csv_files)}: {csv_file.name}")
607
+ success = process_csv_to_h5_and_then_kinematics(csv_file, args.fps_default, args.ratio_default)
608
+ if success:
609
+ successful += 1
610
+ else:
611
+ failed += 1
612
+
613
+ # Add delay between files to reduce file locking conflicts in WSL
614
+ if i < len(csv_files) - 1: # Don't sleep after the last file
615
+ import time
616
+ print(f"Waiting 3 seconds before processing next file...")
617
+ time.sleep(3)
618
+
619
+ print(f"\nCSV conversion and processing complete!")
620
+ print(f"Successful: {successful}")
621
+ print(f"Failed: {failed}")
622
+ print(f"Total: {len(csv_files)}")
623
+
624
+ if failed > 0:
625
+ print(f"Note: {failed} files failed due to WSL file locking issues. Consider re-running failed files individually.")
626
+ # Don't exit with error code if some files succeeded, as partial success is still valuable
627
+ if successful == 0:
628
+ sys.exit(1)
629
+ else:
630
+ # Process each .h5 file
631
+ successful = 0
632
+ failed = 0
633
+ for i, h5_file in enumerate(h5_files):
634
+ print(f"\nProcessing HDF5 file {i+1}/{len(h5_files)}: {h5_file.name}")
635
+ success = process_single_file(h5_file, args.fps_default, args.ratio_default)
636
+ if success:
637
+ successful += 1
638
+ else:
639
+ failed += 1
640
+
641
+ # Add delay between files to reduce file locking conflicts in WSL
642
+ if i < len(h5_files) - 1: # Don't sleep after the last file
643
+ import time
644
+ print(f"Waiting 2 seconds before processing next file...")
645
+ time.sleep(2)
646
+
647
+ print(f"\nProcessing complete!")
648
+ print(f"Successful: {successful}")
649
+ print(f"Failed: {failed}")
650
+ print(f"Total: {len(h5_files)}")
651
+
652
+ if failed > 0:
653
+ print(f"Note: {failed} files failed due to WSL file locking issues. Consider re-running failed files individually.")
654
+ # Don't exit with error code if some files succeeded, as partial success is still valuable
655
+ if successful == 0:
656
+ sys.exit(1)
657
+ else:
658
+ print("Error: Either --h5-path, --csv-path or --directory must be specified")
659
+ sys.exit(1)
660
+
661
+
662
+ if __name__ == "__main__":
663
+ main()
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "ethoclaw-kinematic-parameter-generator",
3
+ "description": "Checks if .h5 files contain KinematicParameter data, and if not, generates it from the 2Dskeleton data. Can process single files or batch process entire directories. Supports custom calibration parameters.",
4
+ "activation_keywords": ["kinematic", "h5", "parameter", "generate", "skeleton", "batch", "calibration", "ethoclaw"],
5
+ "files": [
6
+ "kinematic_generator.py",
7
+ "batch_kinematic_generator.py",
8
+ "generate_kinematic_parameter.py",
9
+ "SKILL.md",
10
+ "README.md"
11
+ ],
12
+ "requirements": [
13
+ "h5py",
14
+ "numpy",
15
+ "ffmpeg",
16
+ "opencv-python"
17
+ ],
18
+ "entry_point": "batch_kinematic_generator.py"
19
+ }