GameSentenceMiner 2.17.3__tar.gz → 2.17.4__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 (103) hide show
  1. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/ocr/owocr_helper.py +30 -24
  2. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/owocr/owocr/ocr.py +1 -1
  3. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner.egg-info/PKG-INFO +2 -2
  4. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner.egg-info/requires.txt +1 -1
  5. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/PKG-INFO +2 -2
  6. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/pyproject.toml +2 -2
  7. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/__init__.py +0 -0
  8. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/ai/__init__.py +0 -0
  9. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/ai/ai_prompting.py +0 -0
  10. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/anki.py +0 -0
  11. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/assets/__init__.py +0 -0
  12. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/assets/icon.png +0 -0
  13. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/assets/icon128.png +0 -0
  14. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/assets/icon256.png +0 -0
  15. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/assets/icon32.png +0 -0
  16. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/assets/icon512.png +0 -0
  17. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/assets/icon64.png +0 -0
  18. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/assets/pickaxe.png +0 -0
  19. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/config_gui.py +0 -0
  20. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/gametext.py +0 -0
  21. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/gsm.py +0 -0
  22. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/locales/en_us.json +0 -0
  23. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/locales/ja_jp.json +0 -0
  24. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/locales/zh_cn.json +0 -0
  25. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/obs.py +0 -0
  26. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/ocr/__init__.py +0 -0
  27. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/ocr/gsm_ocr_config.py +0 -0
  28. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/ocr/ocrconfig.py +0 -0
  29. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/ocr/owocr_area_selector.py +0 -0
  30. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/ocr/ss_picker.py +0 -0
  31. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/owocr/owocr/__init__.py +0 -0
  32. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/owocr/owocr/__main__.py +0 -0
  33. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/owocr/owocr/config.py +0 -0
  34. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/owocr/owocr/lens_betterproto.py +0 -0
  35. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/owocr/owocr/run.py +0 -0
  36. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py +0 -0
  37. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/tools/__init__.py +0 -0
  38. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/tools/audio_offset_selector.py +0 -0
  39. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/tools/furigana_filter_preview.py +0 -0
  40. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/tools/ss_selector.py +0 -0
  41. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/tools/window_transparency.py +0 -0
  42. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/__init__.py +0 -0
  43. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/communication/__init__.py +0 -0
  44. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/communication/send.py +0 -0
  45. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/communication/websocket.py +0 -0
  46. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/configuration.py +0 -0
  47. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/db.py +0 -0
  48. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/downloader/Untitled_json.py +0 -0
  49. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/downloader/__init__.py +0 -0
  50. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/downloader/download_tools.py +0 -0
  51. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/downloader/oneocr_dl.py +0 -0
  52. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/electron_config.py +0 -0
  53. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/ffmpeg.py +0 -0
  54. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/get_overlay_coords.py +0 -0
  55. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/gsm_utils.py +0 -0
  56. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/model.py +0 -0
  57. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/notification.py +0 -0
  58. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/text_log.py +0 -0
  59. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/win10toast/__init__.py +0 -0
  60. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/util/win10toast/__main__.py +0 -0
  61. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/vad.py +0 -0
  62. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/__init__.py +0 -0
  63. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/database_api.py +0 -0
  64. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/events.py +0 -0
  65. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/gsm_websocket.py +0 -0
  66. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/service.py +0 -0
  67. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/__init__.py +0 -0
  68. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/apple-touch-icon.png +0 -0
  69. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/css/kanji-grid.css +0 -0
  70. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/css/search.css +0 -0
  71. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/css/shared.css +0 -0
  72. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/css/stats.css +0 -0
  73. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/favicon-96x96.png +0 -0
  74. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/favicon.ico +0 -0
  75. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/favicon.svg +0 -0
  76. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/js/anki_stats.js +0 -0
  77. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/js/database.js +0 -0
  78. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/js/kanji-grid.js +0 -0
  79. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/js/search.js +0 -0
  80. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/js/shared.js +0 -0
  81. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/js/stats.js +0 -0
  82. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/site.webmanifest +0 -0
  83. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/style.css +0 -0
  84. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/web-app-manifest-192x192.png +0 -0
  85. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/static/web-app-manifest-512x512.png +0 -0
  86. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/stats.py +0 -0
  87. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/templates/anki_stats.html +0 -0
  88. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/templates/components/navigation.html +0 -0
  89. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/templates/components/theme-styles.html +0 -0
  90. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/templates/database.html +0 -0
  91. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/templates/index.html +0 -0
  92. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/templates/search.html +0 -0
  93. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/templates/stats.html +0 -0
  94. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/templates/utility.html +0 -0
  95. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/web/texthooking_page.py +0 -0
  96. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner/wip/__init___.py +0 -0
  97. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner.egg-info/SOURCES.txt +0 -0
  98. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner.egg-info/dependency_links.txt +0 -0
  99. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner.egg-info/entry_points.txt +0 -0
  100. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/GameSentenceMiner.egg-info/top_level.txt +0 -0
  101. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/LICENSE +0 -0
  102. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/README.md +0 -0
  103. {gamesentenceminer-2.17.3 → gamesentenceminer-2.17.4}/setup.cfg +0 -0
@@ -199,25 +199,30 @@ rectangles = None
199
199
  last_ocr2_result = []
200
200
  last_sent_result = ""
201
201
 
202
- def do_second_ocr(ocr1_text, time, img, filtering, pre_crop_image=None, ignore_furigana_filter=False, ignore_previous_result=False):
203
- global twopassocr, ocr2, last_ocr2_result, last_sent_result
204
- try:
205
- orig_text, text = run.process_and_write_results(img, None, last_ocr2_result if not ignore_previous_result else None, filtering, None,
206
- engine=get_ocr_ocr2(), furigana_filter_sensitivity=furigana_filter_sensitivity if not ignore_furigana_filter else 0)
207
-
208
- if compare_ocr_results(last_sent_result, text, threshold=80):
209
- if text:
210
- logger.info("Seems like Text we already sent, not doing anything.")
211
- return
212
- save_result_image(img, pre_crop_image=pre_crop_image)
213
- last_ocr2_result = orig_text
214
- last_sent_result = text
215
- asyncio.run(send_result(text, time))
216
- except json.JSONDecodeError:
217
- print("Invalid JSON received.")
218
- except Exception as e:
219
- logger.exception(e)
220
- print(f"Error processing message: {e}")
202
+ class OCRProcessor():
203
+ def __init__(self):
204
+ self.filtering = TextFiltering(lang=get_ocr_language())
205
+ pass
206
+
207
+ def do_second_ocr(self, ocr1_text, time, img, filtering, pre_crop_image=None, ignore_furigana_filter=False, ignore_previous_result=False):
208
+ global twopassocr, ocr2, last_ocr2_result, last_sent_result
209
+ try:
210
+ orig_text, text = run.process_and_write_results(img, None, last_ocr2_result if not ignore_previous_result else None, self.filtering, None,
211
+ engine=get_ocr_ocr2(), furigana_filter_sensitivity=furigana_filter_sensitivity if not ignore_furigana_filter else 0)
212
+
213
+ if compare_ocr_results(last_sent_result, text, threshold=80):
214
+ if text:
215
+ logger.info("Seems like Text we already sent, not doing anything.")
216
+ return
217
+ save_result_image(img, pre_crop_image=pre_crop_image)
218
+ last_ocr2_result = orig_text
219
+ last_sent_result = text
220
+ asyncio.run(send_result(text, time))
221
+ except json.JSONDecodeError:
222
+ print("Invalid JSON received.")
223
+ except Exception as e:
224
+ logger.exception(e)
225
+ print(f"Error processing message: {e}")
221
226
 
222
227
 
223
228
  def save_result_image(img, pre_crop_image=None):
@@ -249,6 +254,7 @@ previous_img = None
249
254
  previous_orig_text = "" # Store original text result
250
255
  TEXT_APPEARENCE_DELAY = get_ocr_scan_rate() * 1000 + 500 # Adjust as needed
251
256
  force_stable = False
257
+ second_ocr_processor = OCRProcessor()
252
258
 
253
259
  class ConfigChangeCheckThread(threading.Thread):
254
260
  def __init__(self):
@@ -461,7 +467,7 @@ def get_ocr2_image(crop_coords, og_image: Image.Image, ocr2_engine=None):
461
467
 
462
468
  # If no crop or optimization, just apply config and return
463
469
  if not crop_coords or not get_ocr_optimize_second_scan():
464
- img = run.apply_ocr_config_to_image(img, ocr_config_local, is_secondary=True)
470
+ img = run.apply_ocr_config_to_image(img, ocr_config_local, is_secondary=False)
465
471
  return img
466
472
 
467
473
  # Calculate scaling ratios
@@ -495,7 +501,7 @@ def process_task_queue():
495
501
  if task is None: # Exit signal
496
502
  break
497
503
  ocr1_text, stable_time, previous_img_local, filtering, pre_crop_image = task
498
- do_second_ocr(ocr1_text, stable_time, previous_img_local, filtering, pre_crop_image)
504
+ second_ocr_processor.do_second_ocr(ocr1_text, stable_time, previous_img_local, filtering, pre_crop_image)
499
505
  except Exception as e:
500
506
  logger.exception(f"Error processing task: {e}")
501
507
  finally:
@@ -550,21 +556,21 @@ def add_ss_hotkey(ss_hotkey="ctrl+shift+g"):
550
556
  ocr_config.scale_to_custom_size(img.width, img.height)
551
557
  for rectangle in [rectangle for rectangle in ocr_config.rectangles if rectangle.is_secondary]:
552
558
  new_img = run.apply_ocr_config_to_image(img, ocr_config, is_secondary=True, rectangles=[rectangle])
553
- do_second_ocr("", datetime.now(), new_img, TextFiltering(lang=get_ocr_language()), ignore_furigana_filter=True, ignore_previous_result=True)
559
+ second_ocr_processor.do_second_ocr("", datetime.now(), new_img, TextFiltering(lang=get_ocr_language()), ignore_furigana_filter=True, ignore_previous_result=True)
554
560
 
555
561
  filtering = TextFiltering(lang=get_ocr_language())
556
562
  cropper = ScreenCropper()
557
563
  def capture():
558
564
  print("Taking screenshot...")
559
565
  img = cropper.run()
560
- do_second_ocr("", datetime.now(), img, filtering, ignore_furigana_filter=True, ignore_previous_result=True)
566
+ second_ocr_processor.do_second_ocr("", datetime.now(), img, filtering, ignore_furigana_filter=True, ignore_previous_result=True)
561
567
  def capture_main_monitor():
562
568
  print("Taking screenshot of main monitor...")
563
569
  with mss.mss() as sct:
564
570
  main_monitor = sct.monitors[1] if len(sct.monitors) > 1 else sct.monitors[0]
565
571
  img = sct.grab(main_monitor)
566
572
  img_bytes = mss.tools.to_png(img.rgb, img.size)
567
- do_second_ocr("", datetime.now(), img_bytes, filtering, ignore_furigana_filter=True, ignore_previous_result=True)
573
+ second_ocr_processor.do_second_ocr("", datetime.now(), img_bytes, filtering, ignore_furigana_filter=True, ignore_previous_result=True)
568
574
  hotkey_reg = None
569
575
  secondary_hotkey_reg = None
570
576
  try:
@@ -375,7 +375,7 @@ class GoogleLens:
375
375
  # logger.info(f"Vertical space: {vertical_space}, Average height: {avg_height}")
376
376
  # logger.info(avg_height * 2)
377
377
  if vertical_space > avg_height * 2:
378
- res += 'BLANK_LINE'
378
+ res += 'BLANK_LINE\n'
379
379
  for line in paragraph['lines']:
380
380
  if furigana_filter_sensitivity:
381
381
  line_width = line['geometry']['bounding_box']['width'] * img.width
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GameSentenceMiner
3
- Version: 2.17.3
3
+ Version: 2.17.4
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
@@ -18,7 +18,7 @@ Requires-Dist: DateTime~=5.5
18
18
  Requires-Dist: pyperclip~=1.9.0
19
19
  Requires-Dist: soundfile~=0.12.1
20
20
  Requires-Dist: toml~=0.10.2
21
- Requires-Dist: psutil~=6.0.0
21
+ Requires-Dist: psutil~=7.1.0
22
22
  Requires-Dist: rapidfuzz~=3.9.7
23
23
  Requires-Dist: plyer~=2.1.0
24
24
  Requires-Dist: keyboard~=0.13.5
@@ -4,7 +4,7 @@ DateTime~=5.5
4
4
  pyperclip~=1.9.0
5
5
  soundfile~=0.12.1
6
6
  toml~=0.10.2
7
- psutil~=6.0.0
7
+ psutil~=7.1.0
8
8
  rapidfuzz~=3.9.7
9
9
  plyer~=2.1.0
10
10
  keyboard~=0.13.5
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GameSentenceMiner
3
- Version: 2.17.3
3
+ Version: 2.17.4
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
@@ -18,7 +18,7 @@ Requires-Dist: DateTime~=5.5
18
18
  Requires-Dist: pyperclip~=1.9.0
19
19
  Requires-Dist: soundfile~=0.12.1
20
20
  Requires-Dist: toml~=0.10.2
21
- Requires-Dist: psutil~=6.0.0
21
+ Requires-Dist: psutil~=7.1.0
22
22
  Requires-Dist: rapidfuzz~=3.9.7
23
23
  Requires-Dist: plyer~=2.1.0
24
24
  Requires-Dist: keyboard~=0.13.5
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "GameSentenceMiner"
10
- version = "2.17.3"
10
+ version = "2.17.4"
11
11
  description = "A tool for mining sentences from games. Update: Overlay?"
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.10"
@@ -28,7 +28,7 @@ dependencies = [
28
28
  "pyperclip~=1.9.0",
29
29
  "soundfile~=0.12.1",
30
30
  "toml~=0.10.2",
31
- "psutil~=6.0.0",
31
+ "psutil~=7.1.0",
32
32
  "rapidfuzz~=3.9.7",
33
33
  "plyer~=2.1.0",
34
34
  "keyboard~=0.13.5",