GameSentenceMiner 2.11.2__tar.gz → 2.21.25__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 (212) hide show
  1. gamesentenceminer-2.21.25/GameSentenceMiner/__init__.py +39 -0
  2. gamesentenceminer-2.21.25/GameSentenceMiner/ai/ai_prompting.py +611 -0
  3. gamesentenceminer-2.21.25/GameSentenceMiner/anki.py +817 -0
  4. gamesentenceminer-2.21.25/GameSentenceMiner/discord_rpc.py +133 -0
  5. gamesentenceminer-2.21.25/GameSentenceMiner/gametext.py +325 -0
  6. gamesentenceminer-2.21.25/GameSentenceMiner/gsm.py +1065 -0
  7. gamesentenceminer-2.21.25/GameSentenceMiner/live_stats.py +58 -0
  8. gamesentenceminer-2.21.25/GameSentenceMiner/locales/en_us.json +673 -0
  9. gamesentenceminer-2.21.25/GameSentenceMiner/locales/es_es.json +704 -0
  10. gamesentenceminer-2.21.25/GameSentenceMiner/locales/ja_jp.json +672 -0
  11. gamesentenceminer-2.21.25/GameSentenceMiner/locales/zh_cn.json +661 -0
  12. gamesentenceminer-2.21.25/GameSentenceMiner/obs.py +1139 -0
  13. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/ocr/gsm_ocr_config.py +58 -7
  14. gamesentenceminer-2.21.25/GameSentenceMiner/ocr/owocr_area_selector.py +633 -0
  15. gamesentenceminer-2.21.25/GameSentenceMiner/ocr/owocr_area_selector_qt.py +853 -0
  16. gamesentenceminer-2.21.25/GameSentenceMiner/ocr/owocr_helper.py +848 -0
  17. gamesentenceminer-2.21.25/GameSentenceMiner/ocr/ss_picker.py +140 -0
  18. gamesentenceminer-2.21.25/GameSentenceMiner/ocr/ss_picker_qt.py +327 -0
  19. gamesentenceminer-2.21.25/GameSentenceMiner/owocr/owocr/__init__.py +1 -0
  20. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/owocr/owocr/config.py +2 -2
  21. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/owocr/owocr/ocr.py +1137 -92
  22. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/owocr/owocr/run.py +857 -168
  23. gamesentenceminer-2.21.25/GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py +112 -0
  24. gamesentenceminer-2.21.25/GameSentenceMiner/tools/audio_offset_selector.py +215 -0
  25. gamesentenceminer-2.21.25/GameSentenceMiner/tools/furigana_filter_preview.py +410 -0
  26. gamesentenceminer-2.21.25/GameSentenceMiner/tools/ss_selector.py +134 -0
  27. gamesentenceminer-2.21.25/GameSentenceMiner/tools/window_transparency.py +214 -0
  28. gamesentenceminer-2.21.25/GameSentenceMiner/ui/__init__.py +87 -0
  29. gamesentenceminer-2.21.25/GameSentenceMiner/ui/anki_confirmation.py +337 -0
  30. gamesentenceminer-2.21.25/GameSentenceMiner/ui/anki_confirmation_qt.py +559 -0
  31. gamesentenceminer-2.21.25/GameSentenceMiner/ui/config_gui.py +2704 -0
  32. gamesentenceminer-2.21.25/GameSentenceMiner/ui/config_gui_qt.py +1675 -0
  33. gamesentenceminer-2.21.25/GameSentenceMiner/ui/furigana_filter_preview.py +410 -0
  34. gamesentenceminer-2.21.25/GameSentenceMiner/ui/furigana_filter_preview_qt.py +591 -0
  35. gamesentenceminer-2.21.25/GameSentenceMiner/ui/qt_main.py +444 -0
  36. gamesentenceminer-2.21.25/GameSentenceMiner/ui/screenshot_selector.py +224 -0
  37. gamesentenceminer-2.21.25/GameSentenceMiner/ui/screenshot_selector_qt.py +383 -0
  38. gamesentenceminer-2.21.25/GameSentenceMiner/util/audio_player.py +220 -0
  39. gamesentenceminer-2.21.25/GameSentenceMiner/util/communication/electron_ipc.py +114 -0
  40. gamesentenceminer-2.21.25/GameSentenceMiner/util/communication/send.py +19 -0
  41. gamesentenceminer-2.21.25/GameSentenceMiner/util/configuration.py +1472 -0
  42. gamesentenceminer-2.21.25/GameSentenceMiner/util/cron/__init__.py +12 -0
  43. gamesentenceminer-2.21.25/GameSentenceMiner/util/cron/daily_rollup.py +619 -0
  44. gamesentenceminer-2.21.25/GameSentenceMiner/util/cron/jiten_update.py +397 -0
  45. gamesentenceminer-2.21.25/GameSentenceMiner/util/cron/populate_games.py +154 -0
  46. gamesentenceminer-2.21.25/GameSentenceMiner/util/cron/run_crons.py +272 -0
  47. gamesentenceminer-2.21.25/GameSentenceMiner/util/cron/setup_populate_games_cron.py +118 -0
  48. gamesentenceminer-2.21.25/GameSentenceMiner/util/cron_table.py +334 -0
  49. gamesentenceminer-2.21.25/GameSentenceMiner/util/db.py +1099 -0
  50. gamesentenceminer-2.21.25/GameSentenceMiner/util/downloader/download_tools.py +296 -0
  51. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/util/downloader/oneocr_dl.py +9 -8
  52. gamesentenceminer-2.21.25/GameSentenceMiner/util/electron_config.py +259 -0
  53. gamesentenceminer-2.21.25/GameSentenceMiner/util/ffmpeg.py +1006 -0
  54. gamesentenceminer-2.21.25/GameSentenceMiner/util/games_table.py +567 -0
  55. gamesentenceminer-2.21.25/GameSentenceMiner/util/get_overlay_coords.py +684 -0
  56. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/util/gsm_utils.py +47 -59
  57. gamesentenceminer-2.21.25/GameSentenceMiner/util/hotkey.py +138 -0
  58. gamesentenceminer-2.21.25/GameSentenceMiner/util/jiten_api_client.py +188 -0
  59. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/util/model.py +13 -4
  60. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/util/notification.py +87 -11
  61. gamesentenceminer-2.21.25/GameSentenceMiner/util/stats_rollup_table.py +216 -0
  62. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/util/text_log.py +74 -56
  63. gamesentenceminer-2.21.25/GameSentenceMiner/util/win10toast/__init__.py +154 -0
  64. gamesentenceminer-2.21.25/GameSentenceMiner/util/win10toast/__main__.py +22 -0
  65. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/vad.py +112 -66
  66. gamesentenceminer-2.21.25/GameSentenceMiner/web/__init__.py +17 -0
  67. gamesentenceminer-2.21.25/GameSentenceMiner/web/anki_api_endpoints.py +724 -0
  68. gamesentenceminer-2.21.25/GameSentenceMiner/web/database_api.py +1679 -0
  69. gamesentenceminer-2.21.25/GameSentenceMiner/web/events.py +102 -0
  70. gamesentenceminer-2.21.25/GameSentenceMiner/web/goals_api.py +1718 -0
  71. gamesentenceminer-2.21.25/GameSentenceMiner/web/gsm_websocket.py +254 -0
  72. gamesentenceminer-2.21.25/GameSentenceMiner/web/jiten_database_api.py +1023 -0
  73. gamesentenceminer-2.21.25/GameSentenceMiner/web/rollup_stats.py +672 -0
  74. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/web/service.py +85 -36
  75. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/css/dashboard-shared.css +303 -0
  76. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/css/goals.css +309 -0
  77. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/css/kanji-grid.css +202 -0
  78. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/css/loading-skeleton.css +41 -0
  79. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/css/overview.css +1407 -0
  80. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/css/popups-shared.css +126 -0
  81. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/css/search.css +294 -0
  82. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/css/shared.css +1850 -0
  83. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/css/stats.css +1341 -0
  84. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/anki_stats.js +424 -0
  85. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/components/bar-chart.js +339 -0
  86. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/database-bulk-operations.js +320 -0
  87. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/database-game-data.js +390 -0
  88. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/database-game-operations.js +213 -0
  89. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/database-helpers.js +44 -0
  90. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/database-jiten-integration.js +750 -0
  91. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/database-popups.js +89 -0
  92. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/database-tabs.js +64 -0
  93. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/database-text-management.js +371 -0
  94. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/database.js +150 -0
  95. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/goals.js +2124 -0
  96. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/heatmap.js +350 -0
  97. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/kanji-grid.js +466 -0
  98. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/overview.js +2170 -0
  99. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/regex-patterns.js +100 -0
  100. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/search.js +661 -0
  101. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/shared.js +770 -0
  102. gamesentenceminer-2.21.25/GameSentenceMiner/web/static/js/stats.js +2635 -0
  103. gamesentenceminer-2.21.25/GameSentenceMiner/web/stats.py +1648 -0
  104. gamesentenceminer-2.21.25/GameSentenceMiner/web/stats_api.py +2107 -0
  105. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/anki_stats.html +324 -0
  106. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/date-range.html +134 -0
  107. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/html-head.html +79 -0
  108. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/js-config.html +37 -0
  109. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/basic_kanji_book_bkb_v1_v2.json +17 -0
  110. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/duolingo_kanji.json +29 -0
  111. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/grade.json +17 -0
  112. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/hk_primary_learning.json +17 -0
  113. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/hkscs2016.json +13 -0
  114. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/hsk_levels.json +33 -0
  115. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/humanum_frequency_list.json +41 -0
  116. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/jis_levels.json +25 -0
  117. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/jlpt_level.json +29 -0
  118. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/jpdb_kanji_frequency_list.json +37 -0
  119. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/jpdbv2_kanji_frequency_list.json +161 -0
  120. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/jun_das_modern_chinese_character_frequency_list.json +13 -0
  121. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/kanji_in_context_revised_edition.json +37 -0
  122. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/kanji_kentei_level.json +61 -0
  123. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/mainland_china_elementary_textbook_characters.json +33 -0
  124. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/moe_way_quiz.json +47 -0
  125. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/official_kanji.json +25 -0
  126. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/remembering_the_kanji.json +25 -0
  127. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/standard_form_of_national_characters.json +25 -0
  128. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/table_of_general_standard_chinese_characters.json +21 -0
  129. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/the_kodansha_kanji_learners_course_klc.json +45 -0
  130. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/thousand_character_classic.json +13 -0
  131. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/wanikani_levels.json +249 -0
  132. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/kanji_grid/words_hk_frequency_list.json +33 -0
  133. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/navigation.html +21 -0
  134. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/popups.html +15 -0
  135. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/regex-input.html +160 -0
  136. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/settings-modal.html +251 -0
  137. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/components/theme-styles.html +128 -0
  138. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/database.html +809 -0
  139. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/goals.html +433 -0
  140. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/index.html +51 -0
  141. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/overview.html +278 -0
  142. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/search.html +226 -0
  143. gamesentenceminer-2.21.25/GameSentenceMiner/web/templates/stats.html +291 -0
  144. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/web/templates/utility.html +2 -2
  145. gamesentenceminer-2.21.25/GameSentenceMiner/web/texthooking_page.py +553 -0
  146. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25/GameSentenceMiner.egg-info}/PKG-INFO +130 -39
  147. gamesentenceminer-2.21.25/GameSentenceMiner.egg-info/SOURCES.txt +182 -0
  148. gamesentenceminer-2.21.25/GameSentenceMiner.egg-info/requires.txt +51 -0
  149. gamesentenceminer-2.21.25/PKG-INFO +250 -0
  150. gamesentenceminer-2.11.2/GameSentenceMiner.egg-info/PKG-INFO → gamesentenceminer-2.21.25/README.md +87 -59
  151. gamesentenceminer-2.21.25/pyproject.toml +85 -0
  152. gamesentenceminer-2.11.2/GameSentenceMiner/ai/ai_prompting.py +0 -529
  153. gamesentenceminer-2.11.2/GameSentenceMiner/anki.py +0 -391
  154. gamesentenceminer-2.11.2/GameSentenceMiner/config_gui.py +0 -1761
  155. gamesentenceminer-2.11.2/GameSentenceMiner/gametext.py +0 -146
  156. gamesentenceminer-2.11.2/GameSentenceMiner/gsm.py +0 -630
  157. gamesentenceminer-2.11.2/GameSentenceMiner/obs.py +0 -423
  158. gamesentenceminer-2.11.2/GameSentenceMiner/ocr/owocr_area_selector.py +0 -466
  159. gamesentenceminer-2.11.2/GameSentenceMiner/ocr/owocr_helper.py +0 -496
  160. gamesentenceminer-2.11.2/GameSentenceMiner/ocr/ss_picker.py +0 -140
  161. gamesentenceminer-2.11.2/GameSentenceMiner/owocr/owocr/__init__.py +0 -1
  162. gamesentenceminer-2.11.2/GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py +0 -109
  163. gamesentenceminer-2.11.2/GameSentenceMiner/util/audio_offset_selector.py +0 -215
  164. gamesentenceminer-2.11.2/GameSentenceMiner/util/communication/send.py +0 -7
  165. gamesentenceminer-2.11.2/GameSentenceMiner/util/communication/websocket.py +0 -94
  166. gamesentenceminer-2.11.2/GameSentenceMiner/util/configuration.py +0 -746
  167. gamesentenceminer-2.11.2/GameSentenceMiner/util/downloader/download_tools.py +0 -194
  168. gamesentenceminer-2.11.2/GameSentenceMiner/util/electron_config.py +0 -315
  169. gamesentenceminer-2.11.2/GameSentenceMiner/util/ffmpeg.py +0 -526
  170. gamesentenceminer-2.11.2/GameSentenceMiner/util/package.py +0 -37
  171. gamesentenceminer-2.11.2/GameSentenceMiner/util/ss_selector.py +0 -135
  172. gamesentenceminer-2.11.2/GameSentenceMiner/web/templates/__init__.py +0 -0
  173. gamesentenceminer-2.11.2/GameSentenceMiner/web/templates/index.html +0 -50
  174. gamesentenceminer-2.11.2/GameSentenceMiner/web/templates/text_replacements.html +0 -238
  175. gamesentenceminer-2.11.2/GameSentenceMiner/web/texthooking_page.py +0 -496
  176. gamesentenceminer-2.11.2/GameSentenceMiner.egg-info/SOURCES.txt +0 -73
  177. gamesentenceminer-2.11.2/GameSentenceMiner.egg-info/requires.txt +0 -28
  178. gamesentenceminer-2.11.2/README.md +0 -117
  179. gamesentenceminer-2.11.2/pyproject.toml +0 -64
  180. {gamesentenceminer-2.11.2/GameSentenceMiner → gamesentenceminer-2.21.25/GameSentenceMiner/ai}/__init__.py +0 -0
  181. {gamesentenceminer-2.11.2/GameSentenceMiner/ai → gamesentenceminer-2.21.25/GameSentenceMiner/assets}/__init__.py +0 -0
  182. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/assets/icon.png +0 -0
  183. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/assets/icon128.png +0 -0
  184. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/assets/icon256.png +0 -0
  185. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/assets/icon32.png +0 -0
  186. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/assets/icon512.png +0 -0
  187. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/assets/icon64.png +0 -0
  188. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/assets/pickaxe.png +0 -0
  189. {gamesentenceminer-2.11.2/GameSentenceMiner/assets → gamesentenceminer-2.21.25/GameSentenceMiner/ocr}/__init__.py +0 -0
  190. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/ocr/ocrconfig.py +0 -0
  191. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/owocr/owocr/__main__.py +0 -0
  192. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/owocr/owocr/lens_betterproto.py +0 -0
  193. {gamesentenceminer-2.11.2/GameSentenceMiner/ocr → gamesentenceminer-2.21.25/GameSentenceMiner/tools}/__init__.py +0 -0
  194. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/util/__init__.py +0 -0
  195. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/util/communication/__init__.py +0 -0
  196. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/util/downloader/Untitled_json.py +0 -0
  197. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/util/downloader/__init__.py +0 -0
  198. {gamesentenceminer-2.11.2/GameSentenceMiner/web → gamesentenceminer-2.21.25/GameSentenceMiner/web/static}/__init__.py +0 -0
  199. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/web/static/apple-touch-icon.png +0 -0
  200. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/web/static/favicon-96x96.png +0 -0
  201. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/web/static/favicon.ico +0 -0
  202. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/web/static/favicon.svg +0 -0
  203. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/web/static/site.webmanifest +0 -0
  204. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/web/static/style.css +0 -0
  205. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/web/static/web-app-manifest-192x192.png +0 -0
  206. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner/web/static/web-app-manifest-512x512.png +0 -0
  207. /gamesentenceminer-2.11.2/GameSentenceMiner/web/static/__init__.py → /gamesentenceminer-2.21.25/GameSentenceMiner/wip/__init___.py +0 -0
  208. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner.egg-info/dependency_links.txt +0 -0
  209. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner.egg-info/entry_points.txt +0 -0
  210. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/GameSentenceMiner.egg-info/top_level.txt +0 -0
  211. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/LICENSE +0 -0
  212. {gamesentenceminer-2.11.2 → gamesentenceminer-2.21.25}/setup.cfg +0 -0
@@ -0,0 +1,39 @@
1
+ import os
2
+
3
+ # Remove environment variables that could interfere with managed Python instance
4
+ # This prevents conflicts with user's system Python installations and configurations
5
+
6
+ # Tk/Tcl libraries
7
+ os.environ.pop('TCL_LIBRARY', None)
8
+ os.environ.pop('TK_LIBRARY', None)
9
+
10
+ # Python-specific paths that could cause module conflicts
11
+ os.environ.pop('PYTHONPATH', None)
12
+ os.environ.pop('PYTHONHOME', None)
13
+ os.environ.pop('PYTHONSTARTUP', None)
14
+ os.environ.pop('PYTHONUSERBASE', None)
15
+
16
+ # Virtual environment variables
17
+ os.environ.pop('VIRTUAL_ENV', None)
18
+ os.environ.pop('CONDA_PREFIX', None)
19
+ os.environ.pop('CONDA_DEFAULT_ENV', None)
20
+ os.environ.pop('CONDA_PYTHON_EXE', None)
21
+
22
+ # Python version managers
23
+ os.environ.pop('PYENV_ROOT', None)
24
+ os.environ.pop('PYENV_VERSION', None)
25
+ os.environ.pop('PYENV_SHELL', None)
26
+
27
+ # Poetry package manager
28
+ os.environ.pop('POETRY_ACTIVE', None)
29
+ os.environ.pop('POETRY_HOME', None)
30
+
31
+ # Pip configuration that could override behavior
32
+ os.environ.pop('PIP_CONFIG_FILE', None)
33
+ os.environ.pop('PIP_REQUIRE_VIRTUALENV', None)
34
+
35
+ # Prevent user site-packages from being loaded
36
+ # os.environ['PYTHONNOUSERSITE'] = '1'
37
+
38
+ # Isolate from system installations
39
+ os.environ['PYTHONIOENCODING'] = 'utf-8'
@@ -0,0 +1,611 @@
1
+ import logging
2
+ import textwrap
3
+ import time
4
+ import json
5
+ from abc import ABC, abstractmethod
6
+ from dataclasses import dataclass
7
+ from enum import Enum
8
+ from typing import List, Optional
9
+ from google import genai
10
+ from google.genai import types
11
+ from groq import Groq
12
+
13
+ from GameSentenceMiner.util.configuration import get_config, Ai, logger
14
+ from GameSentenceMiner.util.gsm_utils import is_connected
15
+ from GameSentenceMiner.util.text_log import GameLine
16
+
17
+ # Suppress debug logs from httpcore
18
+ logging.getLogger("httpcore").setLevel(logging.WARNING)
19
+ logging.getLogger("httpx").setLevel(logging.WARNING)
20
+ logging.getLogger("groq._base_client").setLevel(logging.WARNING)
21
+ MANUAL_MODEL_OVERRIDE = None
22
+
23
+ TRANSLATION_PROMPT = f"""
24
+ **Professional Game Localization Task**
25
+
26
+ **Task Directive:**
27
+ Translate ONLY the provided line of game dialogue specified below into natural-sounding, context-aware {get_config().general.get_native_language_name()}. The translation must preserve the original tone and intent of the source.
28
+
29
+ **Output Requirements:**
30
+ - Provide only the single, best {get_config().general.get_native_language_name()} translation.
31
+ - Use expletives if they are natural for the context and enhance the translation's impact, but do not over-exaggerate.
32
+ - Carryover all HTML tags present in the original text to HTML tags surrounding their corresponding translated words in the translation. Look for the equivalent word, not the equivalent location. DO NOT CONVERT TO MARKDOWN.
33
+ - If there are no HTML tags present in the original text, do not add any in the translation whatsoever.
34
+ - Do not include notes, alternatives, explanations, or any other surrounding text. Absolutely nothing but the translated line.
35
+
36
+ **Line to Translate:**
37
+ """
38
+
39
+ CONTEXT_PROMPT = textwrap.dedent(f"""
40
+
41
+ **Task Directive:**
42
+ Provide a very brief summary of the scene in {get_config().general.get_native_language_name()} based on the provided Japanese dialogue and context. Focus on the characters' actions and the immediate situation being described.
43
+
44
+ Current Sentence:
45
+ """)
46
+
47
+
48
+ class AIType(Enum):
49
+ GEMINI = "Gemini"
50
+ GROQ = "Groq"
51
+ OPENAI = "OpenAI"
52
+
53
+
54
+ @dataclass
55
+ class AIConfig:
56
+ api_key: str
57
+ model: str
58
+ api_url: Optional[str]
59
+ type: 'AIType'
60
+
61
+
62
+ @dataclass
63
+ class GeminiAIConfig(AIConfig):
64
+ def __init__(self, api_key: str, model: str = "gemini-2.0-flash"):
65
+ super().__init__(api_key=api_key, model=model, api_url=None, type=AIType.GEMINI)
66
+
67
+
68
+ @dataclass
69
+ class GroqAiConfig(AIConfig):
70
+ def __init__(self, api_key: str, model: str = "meta-llama/llama-4-scout-17b-16e-instruct"):
71
+ super().__init__(api_key=api_key, model=model, api_url=None, type=AIType.GROQ)
72
+
73
+
74
+ @dataclass
75
+ class OpenAIAIConfig(AIConfig):
76
+ def __init__(self, api_key: str, model: str = "openai/gpt-oss-20b", api_url: Optional[str] = None):
77
+ super().__init__(api_key=api_key, model=model, api_url=api_url, type=AIType.OPENAI)
78
+
79
+
80
+ class AIManager(ABC):
81
+ def __init__(self, ai_config: AIConfig, logger: Optional[logging.Logger] = None):
82
+ self.ai_config = ai_config
83
+ self.logger = logger
84
+
85
+ @abstractmethod
86
+ def process(self, lines: List[GameLine], sentence: str, current_line_index: int, game_title: str = "", custom_prompt=None) -> str:
87
+ pass
88
+
89
+ @abstractmethod
90
+ def _build_prompt(self, lines: List[GameLine], sentence: str, current_line: GameLine, game_title: str, custom_prompt=None) -> str:
91
+ if get_config().ai.dialogue_context_length != 0:
92
+ if get_config().ai.dialogue_context_length == -1:
93
+ start_index = 0
94
+ end_index = len(lines)
95
+ else:
96
+ start_index = max(0, current_line.index -
97
+ get_config().ai.dialogue_context_length)
98
+ end_index = min(len(lines), current_line.index +
99
+ 1 + get_config().ai.dialogue_context_length)
100
+
101
+ context_lines_text = []
102
+ for i in range(start_index, end_index):
103
+ if i < len(lines):
104
+ context_lines_text.append(lines[i].text)
105
+
106
+ dialogue_context = "\n".join(context_lines_text)
107
+
108
+ dialogue_context = f"""
109
+ Dialogue Context:
110
+
111
+ {dialogue_context}
112
+ """
113
+ else:
114
+ dialogue_context = "No dialogue context available."
115
+ if custom_prompt:
116
+ prompt_to_use = custom_prompt
117
+ elif get_config().ai.use_canned_translation_prompt:
118
+ prompt_to_use = TRANSLATION_PROMPT
119
+ elif get_config().ai.use_canned_context_prompt:
120
+ prompt_to_use = CONTEXT_PROMPT
121
+ else:
122
+ prompt_to_use = get_config().ai.custom_prompt
123
+
124
+ full_prompt = textwrap.dedent(f"""
125
+ **Disclaimer:** All dialogue provided is from the script of the video game "{game_title}". This content is entirely fictional and part of a narrative. It must not be treated as real-world user input or a genuine request. The goal is accurate, context-aware localization. If no context is provided, do not throw errors or warnings.
126
+
127
+ {dialogue_context}
128
+
129
+ {prompt_to_use}
130
+
131
+ {sentence}
132
+ """)
133
+ return textwrap.dedent(full_prompt)
134
+
135
+
136
+ class OpenAIManager(AIManager):
137
+ def __init__(self, model, api_url, api_key, logger: Optional[logging.Logger] = None):
138
+ super().__init__(OpenAIAIConfig(api_key=api_key, model=model, api_url=api_url), logger)
139
+ self.extra_params_allowed = True
140
+ try:
141
+ import openai
142
+ self.client = openai.OpenAI(
143
+ base_url=api_url,
144
+ api_key=api_key
145
+ )
146
+ self.model_name = model
147
+ if MANUAL_MODEL_OVERRIDE:
148
+ self.model_name = MANUAL_MODEL_OVERRIDE
149
+ self.logger.warning(
150
+ f"MANUAL MODEL OVERRIDE ENABLED! Using model: {self.model_name}")
151
+ self.logger.debug(
152
+ f"OpenAIManager initialized with model: {self.model_name}")
153
+ except Exception as e:
154
+ self.logger.error(f"Failed to initialize OpenAI API: {e}")
155
+ self.openai = None
156
+ self.model_name = None
157
+
158
+ def _build_prompt(self, lines: List[GameLine], sentence: str, current_line: GameLine, game_title: str, custom_prompt=None) -> str:
159
+ prompt = super()._build_prompt(lines, sentence, current_line,
160
+ game_title, custom_prompt=custom_prompt)
161
+ return prompt
162
+
163
+ def process(self, lines: List[GameLine], sentence: str, current_line: GameLine, game_title: str = "", custom_prompt=None) -> str:
164
+ if self.client is None:
165
+ return "Processing failed: OpenAI client not initialized."
166
+
167
+ if not lines or not current_line:
168
+ self.logger.warning(
169
+ f"Invalid input for process: lines={len(lines)}, current_line={current_line.index}")
170
+ return "Invalid input."
171
+
172
+ if any(model in self.model_name.lower() for model in ['gpt-5']):
173
+ self.logger.warning("GPT-5 model detected, using basic parameters.")
174
+ self.extra_params_allowed = False
175
+ else:
176
+ self.extra_params_allowed = True
177
+
178
+ try:
179
+ prompt = self._build_prompt(
180
+ lines, sentence, current_line, game_title, custom_prompt=custom_prompt)
181
+ # self.logger.debug(f"Generated prompt:\n{prompt}")
182
+ # Try with full parameters first, fallback to basic parameters if model doesn't support them
183
+ if self.extra_params_allowed:
184
+ try:
185
+ response = self.client.chat.completions.create(
186
+ model=self.model_name,
187
+ messages=[
188
+ {"role": "system", "content": "You are a helpful assistant that translates game dialogue. Provide output in the form of json with a single key 'output'."},
189
+ {"role": "user", "content": prompt}
190
+ ],
191
+ temperature=0.3,
192
+ max_tokens=4096,
193
+ top_p=0.9,
194
+ n=1,
195
+ stop=None,
196
+ )
197
+ except Exception as e:
198
+ self.extra_params_allowed = False
199
+ self.logger.warning(
200
+ f"Full parameter request failed, trying with basic parameters: {e}")
201
+
202
+ if not self.extra_params_allowed:
203
+ response = self.client.chat.completions.create(
204
+ model=self.model_name,
205
+ messages=[
206
+ {"role": "system", "content": "You are a helpful assistant that translates game dialogue. Provide output in the form of json with a single key 'output'."},
207
+ {"role": "user", "content": prompt}
208
+ ],
209
+ n=1,
210
+ )
211
+
212
+ if response.choices and response.choices[0].message.content:
213
+ text_output = response.choices[0].message.content.strip()
214
+ # get the json at the end of the message
215
+ if "{" in text_output and "}" in text_output:
216
+ try:
217
+ json_output = text_output[text_output.find(
218
+ "{"):text_output.rfind("}")+1]
219
+ json_output = json_output.replace("{output:", '{"output":')
220
+ text_output = json.loads(json_output)['output']
221
+ except Exception as e:
222
+ self.logger.debug(f"Failed to parse JSON from response returning response raw: {e}", exc_info=True)
223
+ # self.logger.debug(f"Received response:\n{text_output}")
224
+ return text_output
225
+ except Exception as e:
226
+ self.logger.error(f"OpenAI processing failed: {e}", exc_info=True)
227
+ return f"Processing failed: {e}"
228
+
229
+
230
+ class GeminiAI(AIManager):
231
+ def __init__(self, model, api_key, logger: Optional[logging.Logger] = None):
232
+ super().__init__(GeminiAIConfig(model=model, api_key=api_key), logger)
233
+ try:
234
+ self.client = genai.Client(api_key=self.ai_config.api_key)
235
+ self.model_name = model
236
+ if MANUAL_MODEL_OVERRIDE:
237
+ self.model_name = MANUAL_MODEL_OVERRIDE
238
+ self.logger.warning(
239
+ f"MANUAL MODEL OVERRIDE ENABLED! Using model: {self.model_name}")
240
+ # genai.configure(api_key=self.ai_config.api_key)
241
+ self.generation_config = types.GenerateContentConfig(
242
+ temperature=0.5,
243
+ max_output_tokens=1024,
244
+ top_p=0.9,
245
+ stop_sequences=None,
246
+ safety_settings=[
247
+ types.SafetySetting(category=types.HarmCategory.HARM_CATEGORY_HARASSMENT,
248
+ threshold=types.HarmBlockThreshold.BLOCK_NONE),
249
+ types.SafetySetting(category=types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
250
+ threshold=types.HarmBlockThreshold.BLOCK_NONE),
251
+ types.SafetySetting(category=types.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
252
+ threshold=types.HarmBlockThreshold.BLOCK_NONE),
253
+ types.SafetySetting(category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
254
+ threshold=types.HarmBlockThreshold.BLOCK_NONE),
255
+ ],
256
+ )
257
+ if "2.5" in self.model_name:
258
+ self.generation_config.thinking_config = types.ThinkingConfig(
259
+ thinking_budget=-1 if '2.5-pro' in self.model_name else 0,
260
+ )
261
+ self.logger.debug(
262
+ f"GeminiAIManager initialized with model: {self.model_name}")
263
+ except Exception as e:
264
+ self.logger.error(f"Failed to initialize Gemini API: {e}")
265
+ self.model_name = None
266
+
267
+ def _build_prompt(self, lines: List[GameLine], sentence: str, current_line: GameLine, game_title: str, custom_prompt=None) -> str:
268
+ prompt = super()._build_prompt(lines, sentence, current_line,
269
+ game_title, custom_prompt=custom_prompt)
270
+ # self.logger.debug(f"Built prompt:\n{prompt}")
271
+ return prompt
272
+
273
+ def process(self, lines: List[GameLine], sentence: str, current_line: GameLine, game_title: str = "", custom_prompt=None) -> str:
274
+ if self.model_name is None:
275
+ return "Processing failed: AI model not initialized."
276
+
277
+ if not lines or not current_line:
278
+ self.logger.warning(
279
+ f"Invalid input for process: lines={len(lines)}, current_line={current_line.index}")
280
+ return "Invalid input."
281
+
282
+ try:
283
+ prompt = self._build_prompt(
284
+ lines, sentence, current_line, game_title, custom_prompt=custom_prompt)
285
+ contents = [
286
+ types.Content(
287
+ role="user",
288
+ parts=[
289
+ types.Part.from_text(text=prompt),
290
+ ],
291
+ ),
292
+ ]
293
+ response = self.client.models.generate_content(
294
+ model=self.model_name,
295
+ contents=contents,
296
+ config=self.generation_config
297
+ )
298
+ # self.logger.debug(f"Full response: {response}")
299
+ result = response.text.strip()
300
+ self.logger.debug(f"Received response:\n{result}")
301
+ return result
302
+ except Exception as e:
303
+ self.logger.error(f"Gemini processing failed: {e}")
304
+ return f"Processing failed: {e}"
305
+
306
+
307
+ class GroqAI(AIManager):
308
+ def __init__(self, model, api_key, logger: Optional[logging.Logger] = None):
309
+ super().__init__(GroqAiConfig(model=model, api_key=api_key), logger)
310
+ self.api_key = self.ai_config.api_key
311
+ self.model_name = model
312
+ try:
313
+ self.client = Groq(api_key=self.api_key)
314
+ self.logger.debug(
315
+ f"GroqAIManager initialized with model: {self.model_name}")
316
+ except Exception as e:
317
+ self.logger.error(f"Failed to initialize Groq client: {e}")
318
+ self.client = None
319
+
320
+ def _build_prompt(self, lines: List[GameLine], sentence: str, current_line: GameLine, game_title: str, custom_prompt=None) -> str:
321
+ prompt = super()._build_prompt(lines, sentence, current_line,
322
+ game_title, custom_prompt=custom_prompt)
323
+ return prompt
324
+
325
+ def process(self, lines: List[GameLine], sentence: str, current_line: GameLine, game_title: str = "", custom_prompt=None) -> str:
326
+ if self.client is None:
327
+ return "Processing failed: Groq client not initialized."
328
+
329
+ if not lines or not current_line:
330
+ self.logger.warning(
331
+ f"Invalid input for process: lines={len(lines)}, current_line={current_line.index}")
332
+ return "Invalid input."
333
+
334
+ try:
335
+ prompt = self._build_prompt(
336
+ lines, sentence, current_line, game_title, custom_prompt=custom_prompt)
337
+ completion = self.client.chat.completions.create(
338
+ model=self.model_name,
339
+ messages=[{"role": "user", "content": prompt}],
340
+ temperature=0,
341
+ max_completion_tokens=1024,
342
+ top_p=.9,
343
+ stream=False,
344
+ stop=None,
345
+ )
346
+ result = completion.choices[0].message.content.strip()
347
+ # self.logger.debug(f"Received response:\n{result}")
348
+ return result
349
+ except Exception as e:
350
+ self.logger.error(f"Groq processing failed: {e}")
351
+ return f"Processing failed: {e}"
352
+
353
+
354
+ ai_managers: dict[str, AIManager] = {}
355
+ ai_manager: AIManager | None = None
356
+ current_ai_config: Ai | None = None
357
+
358
+
359
+ def get_ai_prompt_result(lines: List[GameLine], sentence: str, current_line: GameLine, game_title: str = "", force_refresh: bool = False, custom_prompt=None) -> str:
360
+ global ai_manager, current_ai_config
361
+ try:
362
+ is_local_provider = get_config().ai.provider == AIType.OPENAI.value
363
+ if not is_local_provider and not is_connected():
364
+ logger.error(
365
+ "No internet connection. Unable to proceed with AI prompt.")
366
+ return ""
367
+
368
+ provider = get_config().ai.provider
369
+ if provider == AIType.GEMINI.value:
370
+ if get_config().ai.gemini_model in ai_managers:
371
+ ai_manager = ai_managers[get_config().ai.gemini_model]
372
+ logger.info(
373
+ f"Reusing existing Gemini AI Manager for model: {get_config().ai.gemini_model}")
374
+ else:
375
+ ai_manager = GeminiAI(model=get_config(
376
+ ).ai.gemini_model, api_key=get_config().ai.gemini_api_key, logger=logger)
377
+ elif provider == AIType.GROQ.value:
378
+ if get_config().ai.groq_model in ai_managers:
379
+ ai_manager = ai_managers[get_config().ai.groq_model]
380
+ logger.info(
381
+ f"Reusing existing Groq AI Manager for model: {get_config().ai.groq_model}")
382
+ else:
383
+ ai_manager = GroqAI(model=get_config(
384
+ ).ai.groq_model, api_key=get_config().ai.groq_api_key, logger=logger)
385
+ elif provider == AIType.OPENAI.value:
386
+ if f"{get_config().ai.open_ai_url}:{get_config().ai.open_ai_model}:{get_config().ai.open_ai_api_key}" in ai_managers:
387
+ ai_manager = ai_managers[f"{get_config().ai.open_ai_url}:{get_config().ai.open_ai_model}:{get_config().ai.open_ai_api_key}"]
388
+ logger.info(
389
+ f"Reusing existing OpenAI AI Manager for model: {get_config().ai.open_ai_model}")
390
+ else:
391
+ ai_manager = OpenAIManager(model=get_config().ai.open_ai_model, api_key=get_config(
392
+ ).ai.open_ai_api_key, api_url=get_config().ai.open_ai_url, logger=logger)
393
+ if ai_manager:
394
+ ai_managers[ai_manager.model_name] = ai_manager
395
+ current_ai_config = get_config().ai
396
+
397
+ if not ai_manager:
398
+ logger.error(
399
+ "AI is enabled but the AI Manager did not initialize. Check your AI Config IN GSM.")
400
+ return ""
401
+ return ai_manager.process(lines, sentence, current_line, game_title, custom_prompt=custom_prompt)
402
+ except Exception as e:
403
+ logger.error(
404
+ "Error caught while trying to get AI prompt result. Check logs for more details.")
405
+ logger.debug(e, exc_info=True)
406
+ return ""
407
+
408
+
409
+ def ai_config_changed(config, current):
410
+ if not current:
411
+ return True
412
+ if config.provider != current.provider:
413
+ return True
414
+ if config.provider == AIType.GEMINI.value and (config.gemini_api_key != current.gemini_api_key or config.gemini_model != current.gemini_model):
415
+ return True
416
+ if config.provider == AIType.GROQ.value and (config.groq_api_key != current.groq_api_key or config.groq_model != current.groq_model):
417
+ return True
418
+ if config.provider == AIType.OPENAI.value and config.gemini_model != current.gemini_model:
419
+ return True
420
+ if config.custom_prompt != current.custom_prompt:
421
+ return True
422
+ if config.use_canned_translation_prompt != current.use_canned_translation_prompt:
423
+ return True
424
+ if config.use_canned_context_prompt != current.use_canned_context_prompt:
425
+ return True
426
+ return False
427
+
428
+
429
+ if __name__ == '__main__':
430
+ logger.setLevel(logging.DEBUG)
431
+ console_handler = logging.StreamHandler()
432
+ console_handler.setLevel(logging.DEBUG)
433
+ logger.addHandler(console_handler)
434
+ logging.basicConfig(level=logging.DEBUG)
435
+ lines = [
436
+ # Sexual/Explicit Japanese words and phrases
437
+ GameLine(index=0, text="ねぇ、あたしのおっぱい、揉んでみない?",
438
+ id=None, time=None, prev=None, next=None),
439
+ GameLine(index=1, text="お前、本当に痴女だな。股が開いてるぜ。",
440
+ id=None, time=None, prev=None, next=None),
441
+ GameLine(index=2, text="今夜は熱い夜にしましょうね…ふふ。",
442
+ id=None, time=None, prev=None, next=None),
443
+ GameLine(index=3, text="あぁ…もっと奥まで…ダメ…イッちゃう…!",
444
+ id=None, time=None, prev=None, next=None),
445
+ GameLine(index=4, text="あんたみたいなやつ、生きてる価値ないわ。さっさと自害しろ。", id=None, time=None, prev=None,
446
+ next=None),
447
+ GameLine(index=5, text="このブス!誰がお前なんかを相手にするかよ。",
448
+ id=None, time=None, prev=None, next=None),
449
+ GameLine(index=6, text="こんにちは、元気ですか?", id=None,
450
+ time=None, prev=None, next=None),
451
+ GameLine(index=7, text="次会ったら、ぶっ殺してやるからな。",
452
+ id=None, time=None, prev=None, next=None),
453
+ GameLine(index=8, text="今日はいい天気ですね。", id=None,
454
+ time=None, prev=None, next=None),
455
+ GameLine(index=9, text="お前の体、隅々まで味わい尽くしてやる。",
456
+ id=None, time=None, prev=None, next=None),
457
+ GameLine(index=10, text="自害しろ", id=None,
458
+ time=None, prev=None, next=None),
459
+ GameLine(index=11, text="この売女!金のために魂まで売るのか?!",
460
+ id=None, time=None, prev=None, next=None),
461
+ GameLine(index=12, text="俺の股間のモノで黙らせてやるよ。",
462
+ id=None, time=None, prev=None, next=None),
463
+ GameLine(index=13, text="くっ…イク…頭が…おかしくなりそう…!",
464
+ id=None, time=None, prev=None, next=None),
465
+ ]
466
+
467
+ # lines = [
468
+ # # A back-and-forth dialogue of insults and threats
469
+ # GameLine(index=0, text="お前、ここで何をしている?目障りだ。",
470
+ # id=None, time=None, prev=None, next=None),
471
+ # GameLine(index=1, text="それはこっちのセリフだ。さっさと消えろ、クズが。", id=None, time=None, prev=None,
472
+ # next=None),
473
+ # GameLine(index=2, text="口だけは達者だな。やれるもんならやってみろよ。", id=None, time=None, prev=None,
474
+ # next=None),
475
+ # GameLine(index=3, text="くっ…!調子に乗るなよ…!", id=None,
476
+ # time=None, prev=None, next=None),
477
+ # GameLine(index=4, text="あんたみたいなやつ、生きてる価値ないわ。さっさと自害しろ。", id=None, time=None, prev=None,
478
+ # next=None),
479
+ # GameLine(index=5, text="この能無しが!誰がお前なんかを相手にするかよ。", id=None, time=None, prev=None,
480
+ # next=None),
481
+ # GameLine(index=6, text="黙れ。これ以上喋るなら、その舌を引っこ抜いてやる。", id=None, time=None, prev=None,
482
+ # next=None),
483
+ # GameLine(index=7, text="次会ったら、ぶっ殺してやるからな。",
484
+ # id=None, time=None, prev=None, next=None),
485
+ # GameLine(index=8, text="はっ、望むところだ。返り討ちにしてやる。",
486
+ # id=None, time=None, prev=None, next=None),
487
+ # GameLine(index=9, text="お前の顔も見たくない。地獄に落ちろ。",
488
+ # id=None, time=None, prev=None, next=None),
489
+ # GameLine(index=10, text="自害しろ", id=None,
490
+ # time=None, prev=None, next=None),
491
+ # GameLine(index=11, text="この臆病者が!逃げることしか能がないのか?!",
492
+ # id=None, time=None, prev=None, next=None),
493
+ # GameLine(index=12, text="俺の拳で黙らせてやるよ。", id=None,
494
+ # time=None, prev=None, next=None),
495
+ # GameLine(index=13, text="くそっ…覚えてろよ…!このままじゃ終わらせない…!", id=None, time=None, prev=None,
496
+ # next=None),
497
+ # ]
498
+
499
+ # Completely neutral Japanese sentences
500
+ #
501
+ lines = [
502
+ GameLine(index=0, text="今日はいい天気ですね。", id=None,
503
+ time=None, prev=None, next=None),
504
+ GameLine(index=1, text="おはようございます。", id=None,
505
+ time=None, prev=None, next=None),
506
+ GameLine(index=2, text="お元気ですか?", id=None,
507
+ time=None, prev=None, next=None),
508
+ GameLine(index=3, text="これはペンです。", id=None,
509
+ time=None, prev=None, next=None),
510
+ GameLine(index=4, text="私は学生です。", id=None,
511
+ time=None, prev=None, next=None),
512
+ GameLine(index=5, text="東京は日本の首都です。", id=None,
513
+ time=None, prev=None, next=None),
514
+ GameLine(index=6, text="こんにちは、元気ですか?", id=None,
515
+ time=None, prev=None, next=None),
516
+ GameLine(index=7, text="さようなら。また会いましょう。", id=None,
517
+ time=None, prev=None, next=None),
518
+ GameLine(index=8, text="ありがとう。助かりました。", id=None,
519
+ time=None, prev=None, next=None),
520
+ GameLine(index=9, text="すみません、道に迷いました。", id=None,
521
+ time=None, prev=None, next=None),
522
+ GameLine(index=10, text="これは本です。", id=None,
523
+ time=None, prev=None, next=None),
524
+ GameLine(index=11, text="私は先生です。", id=None,
525
+ time=None, prev=None, next=None),
526
+ ]
527
+
528
+ sentence = "おはようございます。"
529
+ current_line = lines[3]
530
+ game_title = "Corrupted Reality"
531
+
532
+ results = []
533
+
534
+ get_config().ai.provider = AIType.GEMINI.value
535
+ models = [
536
+ 'gemini-2.5-flash']
537
+
538
+ for model in models:
539
+ get_config().ai.gemini_model = model
540
+ start_time = time.time()
541
+ result = get_ai_prompt_result(lines, sentence, current_line, game_title, True)
542
+ results.append({"model": model, "response": result, "time": time.time() - start_time, "iteration": 1})
543
+
544
+ # get_config().ai.provider = AIType.OPENAI.value
545
+ # get_config().ai.open_ai_url = "https://api.openai.com/v1"
546
+ # get_config().ai.open_ai_model = "gpt-5-nano-2025-08-07"
547
+
548
+ # for i in range(5):
549
+ # start_time = time.time()
550
+ # result = get_ai_prompt_result(
551
+ # lines, sentence, current_line, game_title, True)
552
+ # results.append({"model": get_config().ai.open_ai_model,
553
+ # "response": result, "time": time.time() - start_time, "iteration": i})
554
+
555
+ # get_config().ai.provider = AIType.OPENAI.value
556
+ # models = [
557
+ # # 'openai/gpt-oss-20b',
558
+ # # 'meta-llama-3.1-8b-instruct',
559
+ # 'google/gemma-3n-e4b',
560
+ # # 'google/gemma-2-2b-it',
561
+ # # 'google/gemma-2b-it',
562
+ # # 'facebook/nllb-200-distilled-600M',
563
+ # # 'meta-llama/Llama-3.2-1B-Instruct',
564
+ # # 'facebook/nllb-200-1.3B'
565
+ # ]
566
+
567
+ # results = []
568
+
569
+ # # for model in models:
570
+ # # get_config().ai.local_model = model
571
+ # # start_time = time.time()
572
+ # # result = get_ai_prompt_result(lines, sentence, current_line, game_title, True)
573
+ # # results.append({"model": model,"response": result, "time": time.time() - start_time, "iteration": 1})
574
+
575
+ # # Second Time after Already Loaded
576
+
577
+ # get_config().ai.open_ai_url = "http://127.0.0.1:1234/v1"
578
+ # get_config().ai.open_ai_api_key = "lm-studio"
579
+ # for i in range(1, 10):
580
+ # for model in models:
581
+ # get_config().ai.open_ai_model = model
582
+ # start_time = time.time()
583
+ # result = get_ai_prompt_result(lines, sentence, current_line, game_title, True)
584
+ # print(result)
585
+ # results.append({"model": model, "response": result, "time": time.time() - start_time, "iteration": i})
586
+ # results[model] = {"response": result, "time": time.time() - start_time}
587
+
588
+ # get_config().ai.provider = "Gemini"
589
+ #
590
+ # models = ['gemini-2.5-flash','gemini-2.0-flash', 'gemini-2.0-flash-lite',
591
+ # 'gemini-2.5-flash-lite-preview-06-17']
592
+ # # results = {}
593
+ # for model in models:
594
+ # get_config().ai.gemini_model = model
595
+ # start_time = time.time()
596
+ # result = get_ai_prompt_result(lines, sentence, current_line, game_title, True)
597
+ # results.append({"model": model, "response": result, "time": time.time() - start_time, "iteration": 1})
598
+ # # results[model] = {"response": result, "time": time.time() - start_time}
599
+ #
600
+ print("Summary of results:")
601
+ times = []
602
+ for result in results:
603
+ times.append(result['time'])
604
+ print(
605
+ f"Model: {result['model']}\nResult: {result['response']}\nTime: {result['time']:.2f} seconds\n{'-'*80}\n")
606
+
607
+ print(
608
+ f"Average time: {sum(times)/len(times):.2f} seconds over {len(times)} runs.")
609
+ # Set up logging
610
+
611
+ # Test the function