batchalign 0.8.2.post9__tar.gz → 0.8.2.post11__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. {batchalign-0.8.2.post9/batchalign.egg-info → batchalign-0.8.2.post11}/PKG-INFO +1 -1
  2. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/analysis/compare.py +55 -7
  3. batchalign-0.8.2.post11/batchalign/version +3 -0
  4. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11/batchalign.egg-info}/PKG-INFO +1 -1
  5. batchalign-0.8.2.post9/batchalign/version +0 -3
  6. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/LICENSE +0 -0
  7. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/MANIFEST.in +0 -0
  8. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/README.md +0 -0
  9. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/__init__.py +0 -0
  10. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/__main__.py +0 -0
  11. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/cli/__init__.py +0 -0
  12. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/cli/bench.py +0 -0
  13. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/cli/cache.py +0 -0
  14. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/cli/cli.py +0 -0
  15. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/cli/dispatch.py +0 -0
  16. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/constants.py +0 -0
  17. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/document.py +0 -0
  18. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/errors.py +0 -0
  19. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/formats/__init__.py +0 -0
  20. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/formats/base.py +0 -0
  21. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/formats/chat/__init__.py +0 -0
  22. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/formats/chat/file.py +0 -0
  23. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/formats/chat/generator.py +0 -0
  24. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/formats/chat/lexer.py +0 -0
  25. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/formats/chat/parser.py +0 -0
  26. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/formats/chat/utils.py +0 -0
  27. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/formats/textgrid/__init__.py +0 -0
  28. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/formats/textgrid/file.py +0 -0
  29. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/formats/textgrid/generator.py +0 -0
  30. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/formats/textgrid/parser.py +0 -0
  31. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/__init__.py +0 -0
  32. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/audio_io.py +0 -0
  33. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/resolve.py +0 -0
  34. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/speaker/__init__.py +0 -0
  35. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/speaker/config.yaml +0 -0
  36. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/speaker/infer.py +0 -0
  37. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/speaker/utils.py +0 -0
  38. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/training/__init__.py +0 -0
  39. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/training/run.py +0 -0
  40. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/training/utils.py +0 -0
  41. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/utils.py +0 -0
  42. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/utterance/__init__.py +0 -0
  43. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/utterance/cantonese_infer.py +0 -0
  44. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/utterance/dataset.py +0 -0
  45. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/utterance/execute.py +0 -0
  46. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/utterance/infer.py +0 -0
  47. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/utterance/prep.py +0 -0
  48. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/utterance/train.py +0 -0
  49. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/wave2vec/__init__.py +0 -0
  50. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/wave2vec/infer_fa.py +0 -0
  51. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/whisper/__init__.py +0 -0
  52. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/whisper/infer_asr.py +0 -0
  53. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/models/whisper/infer_fa.py +0 -0
  54. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/__init__.py +0 -0
  55. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/analysis/__init__.py +0 -0
  56. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/analysis/eval.py +0 -0
  57. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/__init__.py +0 -0
  58. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/num2chinese.py +0 -0
  59. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/num2lang/__init__.py +0 -0
  60. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/num2lang/deu.py +0 -0
  61. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/num2lang/ell.py +0 -0
  62. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/num2lang/eng.py +0 -0
  63. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/num2lang/eus.py +0 -0
  64. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/num2lang/fra.py +0 -0
  65. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/num2lang/hrv.py +0 -0
  66. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/num2lang/ind.py +0 -0
  67. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/num2lang/jpn.py +0 -0
  68. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/num2lang/nld.py +0 -0
  69. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/num2lang/por.py +0 -0
  70. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/num2lang/spa.py +0 -0
  71. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/num2lang/tha.py +0 -0
  72. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/oai_whisper.py +0 -0
  73. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/rev.py +0 -0
  74. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/utils.py +0 -0
  75. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/whisper.py +0 -0
  76. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/asr/whisperx.py +0 -0
  77. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/avqi/__init__.py +0 -0
  78. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/avqi/engine.py +0 -0
  79. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/base.py +0 -0
  80. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/cache.py +0 -0
  81. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/cleanup/__init__.py +0 -0
  82. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/cleanup/cleanup.py +0 -0
  83. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/cleanup/disfluencies.py +0 -0
  84. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/cleanup/parse_support.py +0 -0
  85. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/cleanup/retrace.py +0 -0
  86. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/cleanup/support/filled_pauses.eng +0 -0
  87. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/cleanup/support/replacements.eng +0 -0
  88. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/cleanup/support/test.test +0 -0
  89. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/diarization/__init__.py +0 -0
  90. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/diarization/pyannote.py +0 -0
  91. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/dispatch.py +0 -0
  92. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/fa/__init__.py +0 -0
  93. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/fa/wave2vec_fa.py +0 -0
  94. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/fa/whisper_fa.py +0 -0
  95. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/morphosyntax/__init__.py +0 -0
  96. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/morphosyntax/coref.py +0 -0
  97. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/morphosyntax/en/irr.py +0 -0
  98. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/morphosyntax/fr/apm.py +0 -0
  99. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/morphosyntax/fr/apmn.py +0 -0
  100. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/morphosyntax/fr/case.py +0 -0
  101. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/morphosyntax/ja/verbforms.py +0 -0
  102. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/morphosyntax/ud.py +0 -0
  103. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/opensmile/__init__.py +0 -0
  104. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/opensmile/engine.py +0 -0
  105. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/pipeline.py +0 -0
  106. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/segmentation/__init__.py +0 -0
  107. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/segmentation/cantonese_seg.py +0 -0
  108. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/speaker/__init__.py +0 -0
  109. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/speaker/nemo_speaker.py +0 -0
  110. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/translate/__init__.py +0 -0
  111. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/translate/gtrans.py +0 -0
  112. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/translate/seamless.py +0 -0
  113. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/translate/utils.py +0 -0
  114. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/utr/__init__.py +0 -0
  115. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/utr/rev_utr.py +0 -0
  116. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/utr/utils.py +0 -0
  117. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/utr/whisper_utr.py +0 -0
  118. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/utterance/__init__.py +0 -0
  119. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/pipelines/utterance/ud_utterance.py +0 -0
  120. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/__init__.py +0 -0
  121. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/cli/test_dispatch_memory.py +0 -0
  122. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/conftest.py +0 -0
  123. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/formats/chat/test_chat_file.py +0 -0
  124. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/formats/chat/test_chat_generator.py +0 -0
  125. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/formats/chat/test_chat_lexer.py +0 -0
  126. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/formats/chat/test_chat_parser.py +0 -0
  127. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/formats/chat/test_chat_utils.py +0 -0
  128. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/formats/textgrid/test_textgrid.py +0 -0
  129. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/models/test_audio_io.py +0 -0
  130. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/models/test_audio_lazy.py +0 -0
  131. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/pipelines/analysis/test_eval.py +0 -0
  132. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/pipelines/asr/test_asr_pipeline.py +0 -0
  133. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/pipelines/asr/test_asr_utils.py +0 -0
  134. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/pipelines/cache/__init__.py +0 -0
  135. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/pipelines/cache/test_cache.py +0 -0
  136. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/pipelines/cleanup/test_disfluency.py +0 -0
  137. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/pipelines/cleanup/test_parse_support.py +0 -0
  138. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/pipelines/fa/test_fa_pipeline.py +0 -0
  139. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/pipelines/fa/test_fa_short_segments.py +0 -0
  140. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/pipelines/fixures.py +0 -0
  141. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/pipelines/test_pipeline.py +0 -0
  142. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/pipelines/test_pipeline_models.py +0 -0
  143. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/tests/test_document.py +0 -0
  144. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/utils/__init__.py +0 -0
  145. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/utils/abbrev.py +0 -0
  146. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/utils/compounds.py +0 -0
  147. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/utils/config.py +0 -0
  148. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/utils/device.py +0 -0
  149. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/utils/dp.py +0 -0
  150. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/utils/names.py +0 -0
  151. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign/utils/utils.py +0 -0
  152. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign.egg-info/SOURCES.txt +0 -0
  153. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign.egg-info/dependency_links.txt +0 -0
  154. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign.egg-info/entry_points.txt +0 -0
  155. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign.egg-info/requires.txt +0 -0
  156. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/batchalign.egg-info/top_level.txt +0 -0
  157. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/setup.cfg +0 -0
  158. {batchalign-0.8.2.post9 → batchalign-0.8.2.post11}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: batchalign
3
- Version: 0.8.2.post9
3
+ Version: 0.8.2.post11
4
4
  Summary: Python Speech Language Sample Analysis
5
5
  Author: Brian MacWhinney, Houjun Liu
6
6
  Author-email: macw@cmu.edu, houjun@cmu.edu
@@ -159,8 +159,10 @@ def _find_best_segment(gold_tokens, main_tokens, mfn):
159
159
  multiset overlap with the gold utterance, ignoring order. To keep common
160
160
  words from swallowing later transcript material, it only considers windows
161
161
  near the gold utterance length. Among equally good windows it prefers the
162
- latest one, not the earliest. The caller then runs the full Levenshtein
163
- aligner inside that window to produce token annotations.
162
+ one with the most positional (in-order) matches, then the latest one as a
163
+ final tiebreaker (so CHI repetitions / self-corrections beat earlier INV
164
+ tokens). The caller then runs the full Levenshtein aligner inside that
165
+ window to produce token annotations.
164
166
  """
165
167
  if not gold_tokens or not main_tokens:
166
168
  return 0, 0
@@ -175,6 +177,7 @@ def _find_best_segment(gold_tokens, main_tokens, mfn):
175
177
  best = (0, min(main_len, gold_len))
176
178
  best_score = -1.0
177
179
  best_len_delta = None
180
+ best_pos_matches = -1
178
181
 
179
182
  for span in range(min_window, max_window + 1):
180
183
  window_counts = Counter(main_tokens[:span])
@@ -197,16 +200,28 @@ def _find_best_segment(gold_tokens, main_tokens, mfn):
197
200
  len_delta = abs(span - gold_len)
198
201
  end = start + span
199
202
 
203
+ # Count how many tokens match the gold in the same position
204
+ pos_matches = sum(
205
+ 1 for k in range(min(span, gold_len))
206
+ if mfn(main_tokens[start + k], gold_tokens[k])
207
+ )
208
+
200
209
  if score > best_score:
201
210
  best = (start, end)
202
211
  best_score = score
203
212
  best_len_delta = len_delta
213
+ best_pos_matches = pos_matches
204
214
  elif score == best_score:
205
215
  if best_len_delta is None or len_delta < best_len_delta:
206
216
  best = (start, end)
207
217
  best_len_delta = len_delta
208
- elif len_delta == best_len_delta and end > best[1]:
209
- best = (start, end)
218
+ best_pos_matches = pos_matches
219
+ elif len_delta == best_len_delta:
220
+ if pos_matches > best_pos_matches:
221
+ best = (start, end)
222
+ best_pos_matches = pos_matches
223
+ elif pos_matches == best_pos_matches and end > best[1]:
224
+ best = (start, end)
210
225
 
211
226
  # If no tokens overlap at all, return an empty window so the caller
212
227
  # doesn't consume main tokens that belong to a later gold utterance.
@@ -216,6 +231,30 @@ def _find_best_segment(gold_tokens, main_tokens, mfn):
216
231
  return best
217
232
 
218
233
 
234
+ def _best_rotation(window_tokens, gold_tokens, mfn):
235
+ """Find the cyclic rotation of *window_tokens* that maximises matches.
236
+
237
+ Returns the rotation offset *r* such that
238
+ ``window_tokens[r:] + window_tokens[:r]`` best aligns to *gold_tokens*.
239
+ """
240
+ if len(window_tokens) <= 1:
241
+ return 0
242
+
243
+ best_r = 0
244
+ best_matches = -1
245
+ n = len(window_tokens)
246
+
247
+ for r in range(n):
248
+ rotated = window_tokens[r:] + window_tokens[:r]
249
+ alignment = align(rotated, gold_tokens, False, mfn)
250
+ matches = sum(1 for item in alignment if isinstance(item, Match))
251
+ if matches > best_matches:
252
+ best_matches = matches
253
+ best_r = r
254
+
255
+ return best_r
256
+
257
+
219
258
  def _get_pos(form):
220
259
  """Extract uppercased POS from a Form's morphology, or '?' if absent."""
221
260
  if form is not None and form.morphology:
@@ -362,8 +401,13 @@ class CompareEngine(BatchalignEngine):
362
401
  utt_main_forms[utt_idx].append(m_form)
363
402
  utt_main_speakers[utt_idx].append(m_utt_idx)
364
403
 
365
- # Align the chosen window against this gold utterance
404
+ # Align the chosen window against this gold utterance,
405
+ # trying cyclic rotations to avoid spurious del/ins pairs.
366
406
  window_main = conformed_main[abs_start:abs_end]
407
+ window_len = len(window_main)
408
+ rotation = _best_rotation(window_main, g_tokens, match_fn)
409
+ if rotation > 0:
410
+ window_main = window_main[rotation:] + window_main[:rotation]
367
411
  utt_alignment = align(window_main, g_tokens, False, match_fn)
368
412
 
369
413
  local_main_cursor = 0
@@ -372,7 +416,7 @@ class CompareEngine(BatchalignEngine):
372
416
 
373
417
  for item in utt_alignment:
374
418
  if isinstance(item, Match):
375
- global_main_idx = abs_start + local_main_cursor
419
+ global_main_idx = abs_start + (local_main_cursor + rotation) % window_len
376
420
  orig_main_idx = main_map[global_main_idx]
377
421
  main_form = main_info[orig_main_idx][2]
378
422
  orig_gold_idx = g_maps[local_gold_cursor]
@@ -403,7 +447,7 @@ class CompareEngine(BatchalignEngine):
403
447
  local_gold_cursor += 1
404
448
 
405
449
  else:
406
- global_main_idx = abs_start + local_main_cursor
450
+ global_main_idx = abs_start + (local_main_cursor + rotation) % window_len
407
451
  orig_main_idx = main_map[global_main_idx]
408
452
  main_form = main_info[orig_main_idx][2]
409
453
 
@@ -464,6 +508,10 @@ class CompareEngine(BatchalignEngine):
464
508
  utt.time = (timed_forms[0].time[0], timed_forms[-1].time[1])
465
509
  utt.text = None
466
510
 
511
+ # Copy @Media header from the main doc if it has one
512
+ if doc.media is not None:
513
+ gold.media = doc.media
514
+
467
515
  return gold
468
516
 
469
517
 
@@ -0,0 +1,3 @@
1
+ 0.8.2-post.11
2
+ April 08 2026
3
+ compare beter
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: batchalign
3
- Version: 0.8.2.post9
3
+ Version: 0.8.2.post11
4
4
  Summary: Python Speech Language Sample Analysis
5
5
  Author: Brian MacWhinney, Houjun Liu
6
6
  Author-email: macw@cmu.edu, houjun@cmu.edu
@@ -1,3 +0,0 @@
1
- 0.8.2-post.9
2
- April 02 2026
3
- segment