GameSentenceMiner 2.14.0rc1__tar.gz → 2.14.2__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 (81) hide show
  1. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/gametext.py +9 -4
  2. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/obs.py +6 -5
  3. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/owocr/owocr/ocr.py +17 -3
  4. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/get_overlay_coords.py +59 -35
  5. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner.egg-info/PKG-INFO +1 -1
  6. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/PKG-INFO +1 -1
  7. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/pyproject.toml +1 -1
  8. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/__init__.py +0 -0
  9. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/ai/__init__.py +0 -0
  10. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/ai/ai_prompting.py +0 -0
  11. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/anki.py +0 -0
  12. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/assets/__init__.py +0 -0
  13. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/assets/icon.png +0 -0
  14. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/assets/icon128.png +0 -0
  15. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/assets/icon256.png +0 -0
  16. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/assets/icon32.png +0 -0
  17. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/assets/icon512.png +0 -0
  18. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/assets/icon64.png +0 -0
  19. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/assets/pickaxe.png +0 -0
  20. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/config_gui.py +0 -0
  21. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/gsm.py +0 -0
  22. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/locales/en_us.json +0 -0
  23. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/locales/ja_jp.json +0 -0
  24. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/locales/zh_cn.json +0 -0
  25. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/ocr/__init__.py +0 -0
  26. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/ocr/gsm_ocr_config.py +0 -0
  27. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/ocr/ocrconfig.py +0 -0
  28. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/ocr/owocr_area_selector.py +0 -0
  29. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/ocr/owocr_helper.py +0 -0
  30. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/ocr/ss_picker.py +0 -0
  31. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/owocr/owocr/__init__.py +0 -0
  32. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/owocr/owocr/__main__.py +0 -0
  33. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/owocr/owocr/config.py +0 -0
  34. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/owocr/owocr/lens_betterproto.py +0 -0
  35. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/owocr/owocr/run.py +0 -0
  36. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py +0 -0
  37. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/tools/__init__.py +0 -0
  38. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/tools/audio_offset_selector.py +0 -0
  39. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/tools/ss_selector.py +0 -0
  40. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/tools/window_transparency.py +0 -0
  41. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/__init__.py +0 -0
  42. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/communication/__init__.py +0 -0
  43. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/communication/send.py +0 -0
  44. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/communication/websocket.py +0 -0
  45. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/configuration.py +0 -0
  46. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/db.py +0 -0
  47. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/downloader/Untitled_json.py +0 -0
  48. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/downloader/__init__.py +0 -0
  49. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/downloader/download_tools.py +0 -0
  50. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/downloader/oneocr_dl.py +0 -0
  51. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/electron_config.py +0 -0
  52. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/ffmpeg.py +0 -0
  53. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/gsm_utils.py +0 -0
  54. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/model.py +0 -0
  55. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/notification.py +0 -0
  56. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/util/text_log.py +0 -0
  57. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/vad.py +0 -0
  58. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/__init__.py +0 -0
  59. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/service.py +0 -0
  60. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/static/__init__.py +0 -0
  61. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/static/apple-touch-icon.png +0 -0
  62. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/static/favicon-96x96.png +0 -0
  63. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/static/favicon.ico +0 -0
  64. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/static/favicon.svg +0 -0
  65. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/static/site.webmanifest +0 -0
  66. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/static/style.css +0 -0
  67. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/static/web-app-manifest-192x192.png +0 -0
  68. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/static/web-app-manifest-512x512.png +0 -0
  69. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/templates/__init__.py +0 -0
  70. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/templates/index.html +0 -0
  71. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/templates/text_replacements.html +0 -0
  72. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/templates/utility.html +0 -0
  73. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/web/texthooking_page.py +0 -0
  74. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner/wip/__init___.py +0 -0
  75. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner.egg-info/SOURCES.txt +0 -0
  76. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner.egg-info/dependency_links.txt +0 -0
  77. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner.egg-info/entry_points.txt +0 -0
  78. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner.egg-info/requires.txt +0 -0
  79. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/GameSentenceMiner.egg-info/top_level.txt +0 -0
  80. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/LICENSE +0 -0
  81. {gamesentenceminer-2.14.0rc1 → gamesentenceminer-2.14.2}/setup.cfg +0 -0
@@ -7,12 +7,14 @@ import websockets
7
7
  from websockets import InvalidStatus
8
8
  from rapidfuzz import fuzz
9
9
 
10
+
10
11
  from GameSentenceMiner.util.db import GameLinesTable
11
12
  from GameSentenceMiner.util.gsm_utils import do_text_replacements, TEXT_REPLACEMENTS_FILE, run_new_thread
12
13
  from GameSentenceMiner.util.configuration import *
13
14
  from GameSentenceMiner.util.text_log import *
14
15
  from GameSentenceMiner import obs
15
- from GameSentenceMiner.web.texthooking_page import add_event_to_texthooker, send_word_coordinates_to_overlay, overlay_server_thread
16
+ from GameSentenceMiner.web.texthooking_page import add_event_to_texthooker, overlay_server_thread
17
+
16
18
  from GameSentenceMiner.util.get_overlay_coords import OverlayProcessor
17
19
 
18
20
 
@@ -29,8 +31,7 @@ last_clipboard = ''
29
31
 
30
32
  reconnecting = False
31
33
  websocket_connected = {}
32
-
33
- overlay_processor = OverlayProcessor()
34
+ overlay_processor = None
34
35
 
35
36
  async def monitor_clipboard():
36
37
  global current_line, last_clipboard
@@ -179,6 +180,7 @@ async def handle_new_text_event(current_clipboard, line_time=None):
179
180
 
180
181
 
181
182
  async def add_line_to_text_log(line, line_time=None):
183
+ global overlay_processor
182
184
  if get_config().general.texthook_replacement_regex:
183
185
  current_line_after_regex = re.sub(get_config().general.texthook_replacement_regex, '', line)
184
186
  else:
@@ -191,7 +193,10 @@ async def add_line_to_text_log(line, line_time=None):
191
193
  if len(get_text_log().values) > 0:
192
194
  await add_event_to_texthooker(get_text_log()[-1])
193
195
  if get_config().overlay.websocket_port and overlay_server_thread.has_clients():
194
- await overlay_processor.find_box_and_send_to_overlay(current_line_after_regex)
196
+ if not overlay_processor:
197
+ overlay_processor = OverlayProcessor()
198
+ if overlay_processor.ready:
199
+ await overlay_processor.find_box_and_send_to_overlay(current_line_after_regex)
195
200
  GameLinesTable.add_line(get_text_log()[-1])
196
201
 
197
202
 
@@ -461,11 +461,12 @@ if __name__ == '__main__':
461
461
  from mss import mss
462
462
  logging.basicConfig(level=logging.INFO)
463
463
  # main()
464
- connect_to_obs_sync()
465
-
466
- while True:
467
- print(get_active_source())
468
- time.sleep(3)
464
+ # connect_to_obs_sync()
465
+ # img = get_screenshot_PIL(source_name="Display Capture 2", compression=75, img_format='png', width=1280, height=720)
466
+ # img.show()
467
+ # while True:
468
+ # print(get_active_source())
469
+ # time.sleep(3)
469
470
  # i = 100
470
471
  # for i in range(1, 100):
471
472
  # print(f"Getting screenshot {i}")
@@ -71,7 +71,12 @@ except ImportError:
71
71
  pass
72
72
 
73
73
  try:
74
- import oneocr
74
+ try:
75
+ if os.path.exists(os.path.expanduser('~/.config/oneocr/oneocr.dll')):
76
+ import oneocr
77
+ except Exception as e:
78
+ oneocr = None
79
+ logger.warning(f'Failed to import OneOCR: {e}', exc_info=True)
75
80
  except ImportError:
76
81
  pass
77
82
 
@@ -280,7 +285,10 @@ class GoogleLens:
280
285
  logger.info('Google Lens ready')
281
286
 
282
287
  def __call__(self, img, furigana_filter_sensitivity=0, return_coords=False):
283
- furigana_filter_sensitivity = get_furigana_filter_sensitivity()
288
+ if furigana_filter_sensitivity != None:
289
+ furigana_filter_sensitivity = get_furigana_filter_sensitivity()
290
+ else:
291
+ furigana_filter_sensitivity = 0
284
292
  lang = get_ocr_language()
285
293
  img, is_path = input_to_pil_image(img)
286
294
  if lang != self.initial_lang:
@@ -863,8 +871,11 @@ class OneOCR:
863
871
  logger.warning('OneOCR is not supported on Windows older than 10!')
864
872
  elif 'oneocr' not in sys.modules:
865
873
  logger.warning('oneocr not available, OneOCR will not work!')
874
+ elif not os.path.exists(os.path.expanduser('~/.config/oneocr/oneocr.dll')):
875
+ logger.warning('OneOCR DLLs not found, please install OwOCR Dependencies via OCR Tab in GSM.')
866
876
  else:
867
877
  try:
878
+ logger.info(f'Loading OneOCR model')
868
879
  self.model = oneocr.OcrEngine()
869
880
  except RuntimeError as e:
870
881
  logger.warning(e + ', OneOCR will not work!')
@@ -902,7 +913,10 @@ class OneOCR:
902
913
 
903
914
  def __call__(self, img, furigana_filter_sensitivity=0, return_coords=False, multiple_crop_coords=False, return_one_box=True):
904
915
  lang = get_ocr_language()
905
- furigana_filter_sensitivity = get_furigana_filter_sensitivity()
916
+ if furigana_filter_sensitivity != None:
917
+ furigana_filter_sensitivity = get_furigana_filter_sensitivity()
918
+ else:
919
+ furigana_filter_sensitivity = 0
906
920
  if lang != self.initial_lang:
907
921
  self.initial_lang = lang
908
922
  self.regex = get_regex(lang)
@@ -15,9 +15,16 @@ from GameSentenceMiner.web.texthooking_page import send_word_coordinates_to_over
15
15
 
16
16
  # Conditionally import OCR engines
17
17
  try:
18
- from GameSentenceMiner.owocr.owocr.ocr import GoogleLens, OneOCR, get_regex
19
- except ImportError:
18
+ if os.path.exists(os.path.expanduser('~/.config/oneocr/oneocr.dll')):
19
+ from GameSentenceMiner.owocr.owocr.ocr import OneOCR
20
+ else:
21
+ OneOCR = None
22
+ from GameSentenceMiner.owocr.owocr.ocr import GoogleLens, get_regex
23
+ except ImportError as import_err:
24
+ GoogleLens, OneOCR, get_regex = None, None, None
25
+ except Exception as e:
20
26
  GoogleLens, OneOCR, get_regex = None, None, None
27
+ logger.error(f"Error importing OCR engines: {e}", exc_info=True)
21
28
 
22
29
  # Conditionally import screenshot library
23
30
  try:
@@ -40,19 +47,28 @@ class OverlayProcessor:
40
47
  self.oneocr = None
41
48
  self.lens = None
42
49
  self.regex = None
50
+ self.ready = False
43
51
 
44
- if self.config.overlay.websocket_port and all([GoogleLens, OneOCR, get_regex]):
45
- logger.info("Initializing OCR engines...")
46
- self.oneocr = OneOCR(lang=get_ocr_language())
47
- self.lens = GoogleLens(lang=get_ocr_language())
48
- self.ocr_language = get_ocr_language()
49
- self.regex = get_regex(self.ocr_language)
50
- logger.info("OCR engines initialized.")
51
- else:
52
- logger.warning("OCR dependencies not found or websocket port not configured. OCR functionality will be disabled.")
53
-
54
- if not mss:
55
- logger.warning("MSS library not found. Screenshot functionality may be limited.")
52
+ try:
53
+ if self.config.overlay.websocket_port and all([GoogleLens, get_regex]):
54
+ logger.info("Initializing OCR engines...")
55
+ if OneOCR:
56
+ self.oneocr = OneOCR(lang=get_ocr_language())
57
+ self.lens = GoogleLens(lang=get_ocr_language())
58
+ self.ocr_language = get_ocr_language()
59
+ self.regex = get_regex(self.ocr_language)
60
+ logger.info("OCR engines initialized.")
61
+ self.ready = True
62
+ else:
63
+ logger.warning("OCR dependencies not found or websocket port not configured. OCR functionality will be disabled.")
64
+
65
+ if not mss:
66
+ logger.warning("MSS library not found. Screenshot functionality may be limited.")
67
+ except Exception as e:
68
+ logger.error(f"Error initializing OCR engines for overlay, try installing owocr in OCR tab of GSM: {e}", exc_info=True)
69
+ self.oneocr = None
70
+ self.lens = None
71
+ self.regex = None
56
72
 
57
73
  async def find_box_and_send_to_overlay(self, sentence_to_check: str = None):
58
74
  """
@@ -124,41 +140,49 @@ class OverlayProcessor:
124
140
 
125
141
  async def _do_work(self, sentence_to_check: str = None) -> Tuple[List[Dict[str, Any]], int]:
126
142
  """The main OCR workflow."""
127
- if not self.oneocr or not self.lens:
128
- raise RuntimeError("OCR engines are not initialized. Cannot perform OCR.")
143
+ if not self.lens:
144
+ logger.error("OCR engines are not initialized. Cannot perform OCR for Overlay.")
145
+ return []
129
146
 
130
147
  # 1. Get screenshot
131
148
  full_screenshot, monitor_width, monitor_height = self._get_full_screenshot()
132
149
  if not full_screenshot:
133
150
  logger.warning("Failed to get a screenshot.")
134
151
  return []
152
+ if self.oneocr:
153
+ # 2. Use OneOCR to find general text areas (fast)
154
+ _, _, oneocr_results, crop_coords_list = self.oneocr(
155
+ full_screenshot,
156
+ return_coords=True,
157
+ multiple_crop_coords=True,
158
+ return_one_box=False,
159
+ furigana_filter_sensitivity=None # Disable furigana filtering
160
+ )
135
161
 
136
- # 2. Use OneOCR to find general text areas (fast)
137
- _, _, _, crop_coords_list = self.oneocr(
138
- full_screenshot,
139
- return_coords=True,
140
- multiple_crop_coords=True,
141
- return_one_box=False,
142
- furigana_filter_sensitivity=0
143
- )
144
-
145
- # 3. Create a composite image with only the detected text regions
146
- composite_image = self._create_composite_image(
147
- full_screenshot,
148
- crop_coords_list,
149
- monitor_width,
150
- monitor_height
151
- )
162
+ # 3. Create a composite image with only the detected text regions
163
+ composite_image = self._create_composite_image(
164
+ full_screenshot,
165
+ crop_coords_list,
166
+ monitor_width,
167
+ monitor_height
168
+ )
169
+ else:
170
+ composite_image = full_screenshot
152
171
 
153
172
  # 4. Use Google Lens on the cleaner composite image for higher accuracy
154
- res, text, coords = self.lens(
173
+ res = self.lens(
155
174
  composite_image,
156
175
  return_coords=True,
157
- furigana_filter_sensitivity=0
176
+ furigana_filter_sensitivity=None # Disable furigana filtering
158
177
  )
159
178
 
179
+ if len(res) != 3:
180
+ return oneocr_results
181
+
182
+ _, _, coords = res
183
+
160
184
  if not res or not coords:
161
- return []
185
+ return oneocr_results
162
186
 
163
187
  # 5. Process the high-accuracy results into the desired format
164
188
  extracted_data = self._extract_text_with_pixel_boxes(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GameSentenceMiner
3
- Version: 2.14.0rc1
3
+ Version: 2.14.2
4
4
  Summary: A tool for mining sentences from games. Update: Overlay?
5
5
  Author-email: Beangate <bpwhelan95@gmail.com>
6
6
  License: MIT License
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GameSentenceMiner
3
- Version: 2.14.0rc1
3
+ Version: 2.14.2
4
4
  Summary: A tool for mining sentences from games. Update: Overlay?
5
5
  Author-email: Beangate <bpwhelan95@gmail.com>
6
6
  License: MIT License
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "GameSentenceMiner"
10
- version = "2.14.0.pre1"
10
+ version = "2.14.2"
11
11
  description = "A tool for mining sentences from games. Update: Overlay?"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.10"