GameSentenceMiner 0.0.0.dev0__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 (348) hide show
  1. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/__init__.py +39 -0
  2. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/__init__.py +0 -0
  3. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/ai_prompting.py +121 -0
  4. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/contracts.py +33 -0
  5. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/features/__init__.py +1 -0
  6. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/features/character_context.py +50 -0
  7. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/features/character_summary.py +25 -0
  8. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/parsing/__init__.py +1 -0
  9. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/parsing/output_parser.py +29 -0
  10. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/prompts/__init__.py +1 -0
  11. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/prompts/builder.py +118 -0
  12. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/prompts/templates.py +74 -0
  13. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/providers/__init__.py +1 -0
  14. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/providers/base.py +10 -0
  15. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/providers/gemini_client.py +107 -0
  16. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/providers/groq_client.py +51 -0
  17. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/providers/ollama_client.py +58 -0
  18. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/providers/openai_client.py +91 -0
  19. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/registry.py +119 -0
  20. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ai/service.py +230 -0
  21. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/anki.py +1769 -0
  22. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/assets/__init__.py +0 -0
  23. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/assets/anki_confirmation_example.png +0 -0
  24. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/assets/icon.png +0 -0
  25. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/assets/icon128.png +0 -0
  26. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/assets/icon256.png +0 -0
  27. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/assets/icon32.png +0 -0
  28. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/assets/icon512.png +0 -0
  29. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/assets/icon64.png +0 -0
  30. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/assets/pickaxe.png +0 -0
  31. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/gametext.py +478 -0
  32. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/gsm.py +849 -0
  33. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/locales/en_us.json +806 -0
  34. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/locales/es_es.json +793 -0
  35. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/locales/ja_jp.json +761 -0
  36. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/locales/zh_cn.json +750 -0
  37. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/longplay_handler.py +311 -0
  38. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/LICENSE +661 -0
  39. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/README.md +29 -0
  40. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/__init__.py +9 -0
  41. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/__main__.py +15 -0
  42. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/basic_mecab_controller.py +148 -0
  43. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/basic_types.py +128 -0
  44. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/compound_furigana.py +93 -0
  45. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/format.py +70 -0
  46. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/kana_conv.py +80 -0
  47. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/lru_cache.py +46 -0
  48. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/mecab_controller.py +182 -0
  49. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/mecab_exe_finder.py +45 -0
  50. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/replace_mistakes.py +284 -0
  51. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/LICENSE +5 -0
  52. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/LICENSE.MECAB-IPADIC +70 -0
  53. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/char.bin +0 -0
  54. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/dicrc +29 -0
  55. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/itaijidict +564 -0
  56. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/kanwadict +0 -0
  57. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/libmecab.2.dylib +0 -0
  58. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/libmecab.dll +0 -0
  59. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/libmecab.so.1 +0 -0
  60. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/matrix.bin +0 -0
  61. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/mecab.exe +0 -0
  62. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/mecab.lin +0 -0
  63. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/mecab.mac +0 -0
  64. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/mecabrc +0 -0
  65. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/sys.dic +0 -0
  66. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/unk.dic +0 -0
  67. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/support/user_dic.dic +0 -0
  68. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/mecab/unify_readings.py +136 -0
  69. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/obs.py +2313 -0
  70. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ocr/__init__.py +96 -0
  71. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ocr/compare.py +199 -0
  72. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ocr/coordinate_math.py +91 -0
  73. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ocr/gsm_ocr.py +2401 -0
  74. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ocr/gsm_ocr_config.py +283 -0
  75. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ocr/image_scaling.py +363 -0
  76. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ocr/ocr_format_converter.py +337 -0
  77. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ocr/ocrconfig.py +136 -0
  78. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ocr/owocr_area_selector_qt.py +1501 -0
  79. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ocr/owocr_helper.py +5 -0
  80. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ocr/ss_picker_qt.py +598 -0
  81. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ocr/two_pass_ocr.py +28 -0
  82. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/__init__.py +1 -0
  83. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/__main__.py +9 -0
  84. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/config.py +149 -0
  85. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_betterproto.py +1237 -0
  86. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/aim_communication_pb2.py +48 -0
  87. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/aim_query_pb2.py +44 -0
  88. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_client_context_pb2.py +48 -0
  89. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_client_logs_pb2.py +40 -0
  90. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_client_platform_pb2.py +37 -0
  91. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_cluster_info_pb2.py +38 -0
  92. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_contextual_inputs_pb2.py +40 -0
  93. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_deep_gleam_data_pb2.py +54 -0
  94. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_document_pb2.py +39 -0
  95. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_filters_pb2.py +43 -0
  96. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_geometry_pb2.py +42 -0
  97. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_image_crop_pb2.py +39 -0
  98. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_image_data_pb2.py +42 -0
  99. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_interaction_request_metadata_pb2.py +51 -0
  100. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_knowledge_intent_query_pb2.py +46 -0
  101. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_knowledge_query_pb2.py +38 -0
  102. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_math_solver_query_pb2.py +37 -0
  103. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_message_set_pb2.py +38 -0
  104. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_overlay_object_pb2.py +44 -0
  105. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_payload_pb2.py +37 -0
  106. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_phase_latencies_metadata_pb2.py +45 -0
  107. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_platform_pb2.py +37 -0
  108. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_polygon_pb2.py +43 -0
  109. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_request_id_pb2.py +40 -0
  110. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_request_type_pb2.py +37 -0
  111. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_routing_info_pb2.py +37 -0
  112. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_selection_type_pb2.py +37 -0
  113. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_server_pb2.py +55 -0
  114. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_service_deps_pb2.py +78 -0
  115. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_stickiness_signals_pb2.py +43 -0
  116. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_surface_pb2.py +37 -0
  117. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_text_pb2.py +56 -0
  118. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_text_query_pb2.py +37 -0
  119. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_translate_stickiness_signals_pb2.py +37 -0
  120. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_video_context_input_params_pb2.py +37 -0
  121. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_video_params_pb2.py +38 -0
  122. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_visual_input_type_pb2.py +37 -0
  123. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_visual_search_interaction_data_pb2.py +42 -0
  124. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/lens_protos/lens_overlay_visual_search_interaction_log_data_pb2.py +44 -0
  125. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/ocr.py +5402 -0
  126. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/ocr_upstream.py +2530 -0
  127. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/run.py +3407 -0
  128. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/owocr/owocr/screen_ai_downloader.py +219 -0
  129. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/replay_handler.py +450 -0
  130. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/tools/__init__.py +0 -0
  131. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/tools/window_transparency.py +214 -0
  132. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/__init__.py +230 -0
  133. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/anki_confirmation_qt.py +1051 -0
  134. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/audio_waveform_widget.py +309 -0
  135. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/__init__.py +3 -0
  136. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/binding.py +127 -0
  137. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/editor.py +70 -0
  138. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/i18n.py +21 -0
  139. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/labels.py +53 -0
  140. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/prompt_help.py +114 -0
  141. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/services/__init__.py +3 -0
  142. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/services/ai_models.py +135 -0
  143. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/styles.py +87 -0
  144. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/__init__.py +3 -0
  145. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/advanced.py +50 -0
  146. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/ai.py +289 -0
  147. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/anki.py +307 -0
  148. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/audio.py +62 -0
  149. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/experimental.py +147 -0
  150. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/features.py +25 -0
  151. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/general.py +281 -0
  152. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/gsm_cloud.py +29 -0
  153. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/obs.py +72 -0
  154. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/overlay.py +80 -0
  155. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/paths.py +47 -0
  156. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/port_widget.py +91 -0
  157. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/profiles.py +58 -0
  158. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/required.py +309 -0
  159. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/screenshot.py +66 -0
  160. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/text_processing.py +281 -0
  161. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/vad.py +67 -0
  162. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config/tabs/websocket_sources.py +159 -0
  163. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/config_gui_qt.py +3240 -0
  164. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/furigana_filter_preview_qt.py +828 -0
  165. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/qt_main.py +480 -0
  166. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/ui/screenshot_selector_qt.py +393 -0
  167. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/__init__.py +0 -0
  168. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/clients/__init__.py +4 -0
  169. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/clients/anilist_api_client.py +896 -0
  170. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/clients/discord_rpc.py +230 -0
  171. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/clients/jiten_api_client.py +369 -0
  172. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/clients/vndb_api_client.py +840 -0
  173. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/cloud_sync/__init__.py +3 -0
  174. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/cloud_sync/service.py +616 -0
  175. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/communication/__init__.py +21 -0
  176. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/communication/electron_ipc.py +124 -0
  177. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/communication/ocr_ipc.py +200 -0
  178. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/communication/send.py +19 -0
  179. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/config/__init__.py +3 -0
  180. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/config/configuration.py +2269 -0
  181. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/config/electron_config.py +482 -0
  182. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/config/feature_flags.py +40 -0
  183. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/cron/__init__.py +12 -0
  184. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/cron/daily_rollup.py +781 -0
  185. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/cron/jiten_update.py +843 -0
  186. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/cron/jiten_upgrader.py +341 -0
  187. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/cron/jiten_upgrader_cron.py +178 -0
  188. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/cron/populate_games.py +154 -0
  189. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/cron/run_crons.py +314 -0
  190. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/cron/setup_populate_games_cron.py +119 -0
  191. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/cron/setup_user_plugins_cron.py +107 -0
  192. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/cron/user_plugins.py +97 -0
  193. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/database/cron_table.py +371 -0
  194. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/database/db.py +1757 -0
  195. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/database/games_table.py +643 -0
  196. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/database/stats_rollup_table.py +227 -0
  197. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/docs.py +7 -0
  198. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/downloader/Untitled_json.py +585 -0
  199. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/downloader/__init__.py +0 -0
  200. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/downloader/download_tools.py +418 -0
  201. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/downloader/oneocr_dl.py +300 -0
  202. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/gsm_cloud_auth_cache.py +109 -0
  203. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/gsm_utils.py +731 -0
  204. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/logging_config.py +403 -0
  205. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/media/__init__.py +2 -0
  206. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/media/audio_player.py +322 -0
  207. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/media/ffmpeg.py +1159 -0
  208. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/models/__init__.py +1 -0
  209. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/models/model.py +232 -0
  210. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/overlay/__init__.py +2 -0
  211. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/overlay/get_overlay_coords.py +1809 -0
  212. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/platform/__init__.py +8 -0
  213. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/platform/hotkey.py +215 -0
  214. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/platform/magpie_compat.py +91 -0
  215. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/platform/notification.py +194 -0
  216. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/platform/window_state_monitor.py +1854 -0
  217. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/port_diagnostics.py +178 -0
  218. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/shared/__init__.py +50 -0
  219. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/shared/base_api_client.py +260 -0
  220. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/shared/game_update_service.py +346 -0
  221. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/shared/image_utils.py +265 -0
  222. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/shared/spoiler_utils.py +204 -0
  223. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/stats/__init__.py +3 -0
  224. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/stats/live_stats.py +77 -0
  225. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/stats/stats_rollup_table.py +227 -0
  226. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/stats/stats_util.py +37 -0
  227. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/text_log.py +247 -0
  228. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/text_processing.py +67 -0
  229. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/yomitan_dict/__init__.py +24 -0
  230. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/yomitan_dict/content_builder.py +419 -0
  231. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/yomitan_dict/dict_builder.py +379 -0
  232. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/yomitan_dict/image_handler.py +94 -0
  233. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/util/yomitan_dict/name_parser.py +318 -0
  234. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/vad.py +488 -0
  235. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/__init__.py +21 -0
  236. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/anki_api_endpoints.py +923 -0
  237. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/cloud_sync_api.py +147 -0
  238. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/database_api.py +2660 -0
  239. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/events.py +95 -0
  240. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/goals_api.py +2261 -0
  241. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/gsm_websocket.py +718 -0
  242. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/jiten_database_api.py +28 -0
  243. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/overlay_handler.py +260 -0
  244. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/read_only_stats.py +7 -0
  245. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/rollup_stats.py +953 -0
  246. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/routes/__init__.py +40 -0
  247. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/routes/cron_routes.py +79 -0
  248. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/routes/debug_routes.py +68 -0
  249. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/routes/game_management_routes.py +579 -0
  250. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/routes/jiten_linking_routes.py +610 -0
  251. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/routes/search_routes.py +383 -0
  252. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/service.py +350 -0
  253. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/__init__.py +0 -0
  254. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/apple-touch-icon.png +0 -0
  255. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/css/dashboard-shared.css +349 -0
  256. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/css/goals.css +373 -0
  257. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/css/kanji-grid.css +202 -0
  258. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/css/loading-skeleton.css +41 -0
  259. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/css/overview.css +1514 -0
  260. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/css/popups-shared.css +126 -0
  261. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/css/search.css +614 -0
  262. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/css/shared.css +1854 -0
  263. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/css/stats.css +1366 -0
  264. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/favicon-96x96.png +0 -0
  265. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/favicon.ico +0 -0
  266. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/favicon.svg +4 -0
  267. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/anki_stats.js +478 -0
  268. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/components/bar-chart.js +339 -0
  269. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/database-bulk-operations.js +320 -0
  270. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/database-game-data.js +390 -0
  271. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/database-game-operations.js +213 -0
  272. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/database-helpers.js +44 -0
  273. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/database-jiten-integration.js +1123 -0
  274. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/database-popups.js +89 -0
  275. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/database-tabs.js +64 -0
  276. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/database-text-management.js +371 -0
  277. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/database.js +315 -0
  278. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/goals.js +2506 -0
  279. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/heatmap.js +489 -0
  280. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/kanji-grid.js +466 -0
  281. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/overview.js +2298 -0
  282. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/regex-patterns.js +100 -0
  283. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/search.js +780 -0
  284. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/shared.js +770 -0
  285. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/stats.js +2999 -0
  286. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/js/unified-search.js +446 -0
  287. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/site.webmanifest +21 -0
  288. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/style.css +292 -0
  289. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/web-app-manifest-192x192.png +0 -0
  290. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/static/web-app-manifest-512x512.png +0 -0
  291. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/stats.py +1644 -0
  292. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/stats_api.py +2344 -0
  293. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/anki_stats.html +378 -0
  294. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/date-range.html +144 -0
  295. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/html-head.html +79 -0
  296. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/js-config.html +37 -0
  297. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/basic_kanji_book_bkb_v1_v2.json +17 -0
  298. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/duolingo_kanji.json +29 -0
  299. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/grade.json +17 -0
  300. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/hk_primary_learning.json +17 -0
  301. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/hkscs2016.json +13 -0
  302. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/hsk_levels.json +33 -0
  303. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/humanum_frequency_list.json +41 -0
  304. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/jis_levels.json +25 -0
  305. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/jlpt_level.json +29 -0
  306. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/jpdb_kanji_frequency_list.json +37 -0
  307. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/jpdbv2_kanji_frequency_list.json +161 -0
  308. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/jun_das_modern_chinese_character_frequency_list.json +13 -0
  309. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/kanji_in_context_revised_edition.json +37 -0
  310. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/kanji_kentei_level.json +61 -0
  311. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/mainland_china_elementary_textbook_characters.json +33 -0
  312. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/moe_way_quiz.json +47 -0
  313. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/official_kanji.json +25 -0
  314. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/remembering_the_kanji.json +25 -0
  315. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/standard_form_of_national_characters.json +25 -0
  316. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/table_of_general_standard_chinese_characters.json +21 -0
  317. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/the_kodansha_kanji_learners_course_klc.json +45 -0
  318. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/thousand_character_classic.json +13 -0
  319. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/wanikani_levels.json +249 -0
  320. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/kanji_grid/words_hk_frequency_list.json +33 -0
  321. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/navigation.html +21 -0
  322. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/popups.html +15 -0
  323. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/regex-input.html +160 -0
  324. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/settings-modal.html +146 -0
  325. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/components/theme-styles.html +128 -0
  326. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/database.html +927 -0
  327. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/goals.html +518 -0
  328. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/index.html +51 -0
  329. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/overview.html +286 -0
  330. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/search.html +264 -0
  331. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/stats.html +373 -0
  332. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/templates/utility.html +483 -0
  333. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/texthooking_page.py +1359 -0
  334. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/web/yomitan_api.py +339 -0
  335. gamesentenceminer-0.0.0.dev0/GameSentenceMiner/wip/__init___.py +0 -0
  336. gamesentenceminer-0.0.0.dev0/GameSentenceMiner.egg-info/PKG-INFO +211 -0
  337. gamesentenceminer-0.0.0.dev0/GameSentenceMiner.egg-info/SOURCES.txt +346 -0
  338. gamesentenceminer-0.0.0.dev0/GameSentenceMiner.egg-info/dependency_links.txt +1 -0
  339. gamesentenceminer-0.0.0.dev0/GameSentenceMiner.egg-info/entry_points.txt +2 -0
  340. gamesentenceminer-0.0.0.dev0/GameSentenceMiner.egg-info/requires.txt +72 -0
  341. gamesentenceminer-0.0.0.dev0/GameSentenceMiner.egg-info/top_level.txt +1 -0
  342. gamesentenceminer-0.0.0.dev0/LICENSE +674 -0
  343. gamesentenceminer-0.0.0.dev0/PKG-INFO +211 -0
  344. gamesentenceminer-0.0.0.dev0/README.md +130 -0
  345. gamesentenceminer-0.0.0.dev0/pyproject.toml +116 -0
  346. gamesentenceminer-0.0.0.dev0/setup.cfg +4 -0
  347. gamesentenceminer-0.0.0.dev0/tests/test_anki.py +667 -0
  348. gamesentenceminer-0.0.0.dev0/tests/test_port_diagnostics.py +114 -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,121 @@
1
+ import logging
2
+ from typing import List, Optional
3
+
4
+ from GameSentenceMiner.ai.features.character_summary import CharacterSummaryService
5
+ from GameSentenceMiner.ai.service import AIService, snapshot_config
6
+ from GameSentenceMiner.util.config.configuration import (
7
+ AI_GEMINI,
8
+ AI_GROQ,
9
+ AI_GSM_CLOUD,
10
+ AI_LM_STUDIO,
11
+ AI_OLLAMA,
12
+ AI_OPENAI,
13
+ Ai,
14
+ get_config,
15
+ logger,
16
+ )
17
+ from GameSentenceMiner.util.text_log import GameLine
18
+
19
+ # Suppress debug logs from httpcore
20
+ logging.getLogger("httpcore").setLevel(logging.WARNING)
21
+ logging.getLogger("httpx").setLevel(logging.WARNING)
22
+ logging.getLogger("groq._base_client").setLevel(logging.WARNING)
23
+
24
+
25
+ def get_ai_prompt_result(
26
+ lines: List[GameLine],
27
+ sentence: str,
28
+ current_line: GameLine,
29
+ game_title: str = "",
30
+ force_refresh: bool = False,
31
+ custom_prompt=None,
32
+ ) -> str:
33
+ try:
34
+ config = get_config()
35
+ snapshot = snapshot_config(config.ai, config.general)
36
+ service = AIService(config_snapshot=snapshot, logger=logger)
37
+ return service.translate(
38
+ lines=lines,
39
+ sentence=sentence,
40
+ current_line=current_line,
41
+ game_title=game_title,
42
+ custom_prompt=custom_prompt,
43
+ )
44
+ except Exception as e:
45
+ logger.error(
46
+ "Error caught while trying to get AI prompt result. Check logs for more details.",
47
+ exc_info=True,
48
+ )
49
+ logger.debug(e, exc_info=True)
50
+ return ""
51
+
52
+
53
+ def ai_config_changed(config: Ai, current: Optional[Ai]) -> bool:
54
+ if not current:
55
+ return True
56
+ if config.provider != current.provider:
57
+ return True
58
+ if config.provider == AI_GEMINI and (
59
+ config.gemini_api_key != current.gemini_api_key
60
+ or config.gemini_model != current.gemini_model
61
+ or config.gemini_backup_model != current.gemini_backup_model
62
+ ):
63
+ return True
64
+ if config.provider == AI_GROQ and (
65
+ config.groq_api_key != current.groq_api_key
66
+ or config.groq_model != current.groq_model
67
+ or config.groq_backup_model != current.groq_backup_model
68
+ ):
69
+ return True
70
+ if config.provider == AI_OPENAI and (
71
+ config.open_ai_api_key != current.open_ai_api_key
72
+ or config.open_ai_model != current.open_ai_model
73
+ or config.open_ai_backup_model != current.open_ai_backup_model
74
+ or config.open_ai_url != current.open_ai_url
75
+ ):
76
+ return True
77
+ if config.provider == AI_GSM_CLOUD and (
78
+ config.gsm_cloud_access_token != current.gsm_cloud_access_token
79
+ or config.gsm_cloud_models != current.gsm_cloud_models
80
+ or config.gsm_cloud_api_url != current.gsm_cloud_api_url
81
+ ):
82
+ return True
83
+ if config.provider == AI_OLLAMA and (
84
+ config.ollama_url != current.ollama_url
85
+ or config.ollama_model != current.ollama_model
86
+ or config.ollama_backup_model != current.ollama_backup_model
87
+ ):
88
+ return True
89
+ if config.provider == AI_LM_STUDIO and (
90
+ config.lm_studio_url != current.lm_studio_url
91
+ or config.lm_studio_model != current.lm_studio_model
92
+ or config.lm_studio_backup_model != current.lm_studio_backup_model
93
+ or config.lm_studio_api_key != current.lm_studio_api_key
94
+ ):
95
+ return True
96
+ if config.custom_prompt != current.custom_prompt:
97
+ return True
98
+ if config.custom_full_prompt != current.custom_full_prompt:
99
+ return True
100
+ if config.use_canned_translation_prompt != current.use_canned_translation_prompt:
101
+ return True
102
+ if config.use_canned_context_prompt != current.use_canned_context_prompt:
103
+ return True
104
+ if config.temperature != current.temperature:
105
+ return True
106
+ if config.max_output_tokens != current.max_output_tokens:
107
+ return True
108
+ if config.top_p != current.top_p:
109
+ return True
110
+ return False
111
+
112
+
113
+ def generate_character_summary(character_data: dict) -> Optional[str]:
114
+ if not character_data:
115
+ return None
116
+
117
+ config = get_config()
118
+ snapshot = snapshot_config(config.ai, config.general)
119
+ service = AIService(config_snapshot=snapshot, logger=logger)
120
+ summary_service = CharacterSummaryService(logger=logger)
121
+ return summary_service.generate_from_vndb(character_data, service)
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import Optional, Dict, Any
5
+
6
+
7
+ @dataclass(frozen=True)
8
+ class AIRequest:
9
+ provider: str
10
+ model: str
11
+ prompt: str
12
+ temperature: float
13
+ top_p: float
14
+ max_tokens: int
15
+ game_title: str = ""
16
+ request_kind: str = "translation"
17
+ metadata: Optional[Dict[str, Any]] = None
18
+
19
+
20
+ @dataclass(frozen=True)
21
+ class AIResponse:
22
+ provider: str
23
+ model: str
24
+ text: str
25
+ raw_text: str
26
+ latency_ms: int
27
+ usage: Optional[Dict[str, Any]] = None
28
+
29
+
30
+ class AIError(Exception):
31
+ def __init__(self, message: str, transient: bool = False):
32
+ super().__init__(message)
33
+ self.transient = transient
@@ -0,0 +1 @@
1
+ from __future__ import annotations
@@ -0,0 +1,50 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+
5
+
6
+ class CharacterContextProvider:
7
+ def __init__(self, summary_service, logger):
8
+ self.summary_service = summary_service
9
+ self.logger = logger
10
+
11
+ def get_character_context(self, game_title: str, ai_service) -> str:
12
+ if not game_title:
13
+ return ""
14
+
15
+ try:
16
+ from GameSentenceMiner.util.database.games_table import GamesTable
17
+
18
+ game = GamesTable.get_by_obs_scene_name(game_title)
19
+ if not game:
20
+ game = GamesTable.get_by_title(game_title)
21
+
22
+ if not game:
23
+ return ""
24
+
25
+ self.logger.debug(
26
+ f"Found game '{game.title_original}' (id={game.id}) for scene '{game_title}'"
27
+ )
28
+ if game.character_summary:
29
+ return game.character_summary
30
+
31
+ if game.vndb_character_data:
32
+ try:
33
+ if isinstance(game.vndb_character_data, dict):
34
+ vndb_data = game.vndb_character_data
35
+ else:
36
+ vndb_data = json.loads(game.vndb_character_data)
37
+ summary = self.summary_service.generate_from_vndb(vndb_data, ai_service)
38
+ if summary:
39
+ game.character_summary = summary
40
+ game.save()
41
+ self.logger.info(f"Generated and stored character summary for {game_title}")
42
+ return summary
43
+ except json.JSONDecodeError:
44
+ self.logger.warning(f"Failed to parse VNDB data for {game_title}")
45
+ except Exception as e:
46
+ self.logger.error(f"Failed to generate character summary for {game_title}: {e}")
47
+ except Exception as e:
48
+ self.logger.error(f"Error fetching character context: {e}")
49
+
50
+ return ""
@@ -0,0 +1,25 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from typing import Optional
5
+
6
+ from GameSentenceMiner.ai.prompts.templates import CHARACTER_SUMMARY_PROMPT
7
+
8
+
9
+ class CharacterSummaryService:
10
+ def __init__(self, logger):
11
+ self.logger = logger
12
+
13
+ def generate_from_vndb(self, character_data: dict, ai_service) -> Optional[str]:
14
+ if not character_data:
15
+ return None
16
+
17
+ character_json = json.dumps(character_data, ensure_ascii=False, indent=2)
18
+ prompt = CHARACTER_SUMMARY_PROMPT.format(character_json=character_json)
19
+ try:
20
+ result = ai_service.generate_raw_prompt(prompt, request_kind="character_summary")
21
+ if result:
22
+ return result.strip()
23
+ except Exception as e:
24
+ self.logger.error(f"Failed to generate character summary: {e}")
25
+ return None
@@ -0,0 +1 @@
1
+ from __future__ import annotations
@@ -0,0 +1,29 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from dataclasses import dataclass
5
+ from typing import Optional
6
+
7
+
8
+ @dataclass
9
+ class OutputParser:
10
+ compat_mode: bool = True
11
+
12
+ def parse(self, raw_text: str) -> str:
13
+ if not raw_text:
14
+ return raw_text
15
+
16
+ if not self.compat_mode:
17
+ return raw_text
18
+
19
+ if "{" in raw_text and "}" in raw_text:
20
+ try:
21
+ json_output = raw_text[raw_text.find("{"):raw_text.rfind("}") + 1]
22
+ json_output = json_output.replace("{output:", '{"output":')
23
+ parsed = json.loads(json_output)
24
+ if isinstance(parsed, dict) and "output" in parsed:
25
+ return parsed["output"]
26
+ except Exception:
27
+ return raw_text
28
+
29
+ return raw_text
@@ -0,0 +1 @@
1
+ from __future__ import annotations
@@ -0,0 +1,118 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import List, Optional
5
+
6
+ from GameSentenceMiner.ai.prompts.templates import (
7
+ DIALOGUE_CONTEXT_TEMPLATE,
8
+ FULL_PROMPT_TEMPLATE,
9
+ build_context_prompt,
10
+ build_translation_prompt,
11
+ )
12
+ from GameSentenceMiner.util.text_log import GameLine
13
+
14
+
15
+ @dataclass(frozen=True)
16
+ class PromptSelection:
17
+ prompt_text: str
18
+ prompt_kind: str
19
+
20
+
21
+ class DialogueContextBuilder:
22
+ @staticmethod
23
+ def build(lines: List[GameLine], current_line: GameLine, context_length: int) -> str:
24
+ if context_length == 0:
25
+ return "No dialogue context available."
26
+
27
+ if context_length == -1:
28
+ start_index = 0
29
+ end_index = len(lines)
30
+ else:
31
+ start_index = max(0, current_line.index - context_length)
32
+ end_index = min(len(lines), current_line.index + 1 + context_length)
33
+
34
+ context_lines_text = []
35
+ for i in range(start_index, end_index):
36
+ if i < len(lines):
37
+ context_lines_text.append(lines[i].text)
38
+
39
+ return DIALOGUE_CONTEXT_TEMPLATE.format("\n".join(context_lines_text))
40
+
41
+
42
+ class PromptSelector:
43
+ @staticmethod
44
+ def select(
45
+ use_canned_translation_prompt: bool,
46
+ use_canned_context_prompt: bool,
47
+ custom_prompt: str,
48
+ native_language_name: str,
49
+ custom_prompt_override: Optional[str] = None,
50
+ ) -> PromptSelection:
51
+ if custom_prompt_override:
52
+ return PromptSelection(prompt_text=custom_prompt_override, prompt_kind="custom")
53
+ if use_canned_translation_prompt:
54
+ return PromptSelection(
55
+ prompt_text=build_translation_prompt(native_language_name),
56
+ prompt_kind="translation",
57
+ )
58
+ if use_canned_context_prompt:
59
+ return PromptSelection(
60
+ prompt_text=build_context_prompt(native_language_name),
61
+ prompt_kind="context",
62
+ )
63
+ return PromptSelection(prompt_text=custom_prompt, prompt_kind="custom")
64
+
65
+
66
+ class FullPromptRenderer:
67
+ @staticmethod
68
+ def render(
69
+ game_title: str,
70
+ character_context: str,
71
+ dialogue_context: str,
72
+ prompt_to_use: str,
73
+ sentence: str,
74
+ ) -> str:
75
+ return FULL_PROMPT_TEMPLATE.format(
76
+ game_title=game_title or "Unknown",
77
+ character_context=character_context,
78
+ dialogue_context=dialogue_context,
79
+ prompt_to_use=prompt_to_use,
80
+ sentence=sentence,
81
+ )
82
+
83
+
84
+ class PromptBuilder:
85
+ def __init__(self, native_language_name: str):
86
+ self.native_language_name = native_language_name
87
+
88
+ def build(
89
+ self,
90
+ lines: List[GameLine],
91
+ sentence: str,
92
+ current_line: GameLine,
93
+ game_title: str,
94
+ dialogue_context_length: int,
95
+ use_canned_translation_prompt: bool,
96
+ use_canned_context_prompt: bool,
97
+ custom_prompt: str,
98
+ custom_prompt_override: Optional[str] = None,
99
+ character_context: str = "",
100
+ ) -> tuple[str, str]:
101
+ dialogue_context = DialogueContextBuilder.build(
102
+ lines, current_line, dialogue_context_length
103
+ )
104
+ selection = PromptSelector.select(
105
+ use_canned_translation_prompt=use_canned_translation_prompt,
106
+ use_canned_context_prompt=use_canned_context_prompt,
107
+ custom_prompt=custom_prompt,
108
+ native_language_name=self.native_language_name,
109
+ custom_prompt_override=custom_prompt_override,
110
+ )
111
+ full_prompt = FullPromptRenderer.render(
112
+ game_title=game_title,
113
+ character_context=character_context,
114
+ dialogue_context=dialogue_context,
115
+ prompt_to_use=selection.prompt_text,
116
+ sentence=sentence,
117
+ )
118
+ return full_prompt, selection.prompt_kind
@@ -0,0 +1,74 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ def build_translation_prompt(native_language_name: str) -> str:
5
+ return f"""
6
+ **Professional Game Localization Task**
7
+
8
+ **Task Directive:**
9
+ Translate ONLY the provided line(s) of game dialogue specified below into natural-sounding, context-aware {native_language_name}. The translation must preserve the original tone and intent of the source.
10
+
11
+ **Output Requirements:**
12
+ - Provide only the single, best {native_language_name} translation.
13
+ - Expletives are okay, only if they absolutely 100% fit the context and tone of the original line, and are commonly used in {native_language_name} localizations of similar games.
14
+ - 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.
15
+ - If there are no HTML tags present in the original text, do not add any in the translation whatsoever.
16
+ - Do not include notes, alternatives, explanations, or any other surrounding text. Absolutely nothing but the translated line(s).
17
+
18
+ **Line(s) to Translate:**
19
+ """
20
+
21
+
22
+ def build_context_prompt(native_language_name: str) -> str:
23
+ return f"""
24
+
25
+ **Task Directive:**
26
+ Provide a very brief summary of the scene in {native_language_name} based on the provided dialogue and context. Focus on the characters' actions and the immediate situation being described.
27
+
28
+ Current Line(s):
29
+ """
30
+
31
+
32
+ DIALOGUE_CONTEXT_TEMPLATE = """
33
+ Dialogue Context:
34
+
35
+ {0}
36
+ """
37
+
38
+
39
+ FULL_PROMPT_TEMPLATE = """
40
+ **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.
41
+
42
+ Character Context:
43
+ {character_context}
44
+
45
+ {dialogue_context}
46
+
47
+ {prompt_to_use}
48
+
49
+ {sentence}
50
+ """
51
+
52
+
53
+ CHARACTER_SUMMARY_PROMPT = """
54
+ You are a helpful assistant that creates concise character summaries for game localization.
55
+
56
+ Given the following character data from a visual novel, create a CHARACTER LIST in this exact format:
57
+
58
+ **CHARACTER LIST**:
59
+ [Japanese Name] -> [Romanized Name] (brief one-line description)
60
+
61
+ Rules:
62
+ - Include age if available (e.g., "17yo")
63
+ - Include gender (male/female)
64
+ - Include 2-3 key personality traits that will aid in translation.
65
+ - Keep each line under 120 characters
66
+ - Use Format Japanese name (romanization name): tags
67
+ - Mention what pronoun they use and mark it as their pronoun if they have one listed
68
+ - Example: 陽見 恵凪 (Harumi Ena): Clumsy, Dandere, Hotblooded 19yo girl atashi pronoun
69
+
70
+ Character Data:
71
+ {character_json}
72
+
73
+ Generate the CHARACTER LIST now:
74
+ """
@@ -0,0 +1 @@
1
+ from __future__ import annotations
@@ -0,0 +1,10 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Protocol
4
+
5
+ from GameSentenceMiner.ai.contracts import AIRequest, AIResponse
6
+
7
+
8
+ class ProviderClient(Protocol):
9
+ def generate(self, request: AIRequest) -> AIResponse:
10
+ ...
@@ -0,0 +1,107 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ from google import genai
5
+ from google.genai import types
6
+ from typing import Optional, Any, Dict
7
+
8
+ from GameSentenceMiner.ai.contracts import AIRequest, AIResponse, AIError
9
+ from GameSentenceMiner.util.config.configuration import normalize_gemini_model_name
10
+
11
+
12
+ class GeminiClient:
13
+ def __init__(self, api_key: str, model_name: str, logger):
14
+ self.api_key = api_key
15
+ self.model_name = model_name
16
+ self.logger = logger
17
+ self.client = None
18
+ self._safety_settings = [
19
+ types.SafetySetting(
20
+ category=types.HarmCategory.HARM_CATEGORY_HARASSMENT,
21
+ threshold=types.HarmBlockThreshold.BLOCK_NONE,
22
+ ),
23
+ types.SafetySetting(
24
+ category=types.HarmCategory.HARM_CATEGORY_HATE_SPEECH,
25
+ threshold=types.HarmBlockThreshold.BLOCK_NONE,
26
+ ),
27
+ types.SafetySetting(
28
+ category=types.HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT,
29
+ threshold=types.HarmBlockThreshold.BLOCK_NONE,
30
+ ),
31
+ types.SafetySetting(
32
+ category=types.HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT,
33
+ threshold=types.HarmBlockThreshold.BLOCK_NONE,
34
+ ),
35
+ ]
36
+ try:
37
+ self.client = genai.Client(api_key=self.api_key)
38
+ except Exception as e:
39
+ self.logger.error(f"Failed to initialize Gemini API: {e}")
40
+
41
+ @staticmethod
42
+ def _get_thinking_budget(model_name: str) -> Optional[int]:
43
+ model = (model_name or "").lower()
44
+ if "gemini-2.5" in model or "gemini-3" in model:
45
+ return -1 if "-pro" in model else 0
46
+ return None
47
+
48
+ def _build_generation_config(self, request: AIRequest, model_name: str) -> types.GenerateContentConfig:
49
+ config = types.GenerateContentConfig(
50
+ temperature=request.temperature,
51
+ max_output_tokens=request.max_tokens,
52
+ top_p=request.top_p,
53
+ stop_sequences=None,
54
+ safety_settings=self._safety_settings,
55
+ )
56
+ thinking_budget = self._get_thinking_budget(model_name)
57
+ if thinking_budget is not None:
58
+ config.thinking_config = types.ThinkingConfig(thinking_budget=thinking_budget)
59
+ return config
60
+
61
+ def generate(self, request: AIRequest) -> AIResponse:
62
+ if self.client is None:
63
+ raise AIError("Gemini model not initialized.", transient=False)
64
+
65
+ start_time = time.time()
66
+ try:
67
+ model_name = normalize_gemini_model_name(request.model)
68
+ generation_config = self._build_generation_config(request, model_name)
69
+ contents = [
70
+ types.Content(
71
+ role="user",
72
+ parts=[types.Part.from_text(text=request.prompt)],
73
+ ),
74
+ ]
75
+ response = self.client.models.generate_content(
76
+ model=model_name,
77
+ contents=contents,
78
+ config=generation_config,
79
+ )
80
+
81
+ self.logger.debug(f"Gemini raw response: {response}")
82
+
83
+ result = ""
84
+ if response.candidates:
85
+ for candidate in response.candidates:
86
+ if candidate.content and candidate.content.parts:
87
+ for part in candidate.content.parts:
88
+ if hasattr(part, "text") and part.text:
89
+ result += part.text
90
+
91
+ raw_text = result.strip()
92
+ usage: Optional[Dict[str, Any]] = None
93
+ if hasattr(response, "usage_metadata") and response.usage_metadata:
94
+ usage = response.usage_metadata.model_dump() if hasattr(response.usage_metadata, "model_dump") else dict(response.usage_metadata)
95
+
96
+ latency_ms = int((time.time() - start_time) * 1000)
97
+ return AIResponse(
98
+ provider=request.provider,
99
+ model=model_name,
100
+ text=raw_text,
101
+ raw_text=raw_text,
102
+ latency_ms=latency_ms,
103
+ usage=usage,
104
+ )
105
+ except Exception as e:
106
+ self.logger.error(f"Gemini processing failed: {e}")
107
+ raise AIError(f"Processing failed: {e}", transient=True)
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ from groq import Groq
5
+ from typing import Optional, Any, Dict
6
+
7
+ from GameSentenceMiner.ai.contracts import AIRequest, AIResponse, AIError
8
+
9
+
10
+ class GroqClient:
11
+ def __init__(self, api_key: str, logger):
12
+ self.api_key = api_key
13
+ self.logger = logger
14
+ self.client = None
15
+ try:
16
+ self.client = Groq(api_key=self.api_key)
17
+ except Exception as e:
18
+ self.logger.error(f"Failed to initialize Groq client: {e}")
19
+
20
+ def generate(self, request: AIRequest) -> AIResponse:
21
+ if self.client is None:
22
+ raise AIError("Groq client not initialized.", transient=False)
23
+
24
+ start_time = time.time()
25
+ try:
26
+ completion = self.client.chat.completions.create(
27
+ model=request.model,
28
+ messages=[{"role": "user", "content": request.prompt}],
29
+ temperature=request.temperature,
30
+ max_completion_tokens=request.max_tokens,
31
+ top_p=request.top_p,
32
+ stream=False,
33
+ stop=None,
34
+ )
35
+ raw_text = completion.choices[0].message.content.strip()
36
+ usage: Optional[Dict[str, Any]] = None
37
+ if hasattr(completion, "usage") and completion.usage:
38
+ usage = completion.usage.model_dump() if hasattr(completion.usage, "model_dump") else dict(completion.usage)
39
+
40
+ latency_ms = int((time.time() - start_time) * 1000)
41
+ return AIResponse(
42
+ provider=request.provider,
43
+ model=request.model,
44
+ text=raw_text,
45
+ raw_text=raw_text,
46
+ latency_ms=latency_ms,
47
+ usage=usage,
48
+ )
49
+ except Exception as e:
50
+ self.logger.error(f"Groq processing failed: {e}")
51
+ raise AIError(f"Processing failed: {e}", transient=True)