GameSentenceMiner 2.14.9__py3-none-any.whl → 2.14.10__py3-none-any.whl
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.
- GameSentenceMiner/ai/__init__.py +0 -0
- GameSentenceMiner/ai/ai_prompting.py +473 -0
- GameSentenceMiner/ocr/__init__.py +0 -0
- GameSentenceMiner/ocr/gsm_ocr_config.py +174 -0
- GameSentenceMiner/ocr/ocrconfig.py +129 -0
- GameSentenceMiner/ocr/owocr_area_selector.py +629 -0
- GameSentenceMiner/ocr/owocr_helper.py +638 -0
- GameSentenceMiner/ocr/ss_picker.py +140 -0
- GameSentenceMiner/owocr/owocr/__init__.py +1 -0
- GameSentenceMiner/owocr/owocr/__main__.py +9 -0
- GameSentenceMiner/owocr/owocr/config.py +148 -0
- GameSentenceMiner/owocr/owocr/lens_betterproto.py +1238 -0
- GameSentenceMiner/owocr/owocr/ocr.py +1690 -0
- GameSentenceMiner/owocr/owocr/run.py +1818 -0
- GameSentenceMiner/owocr/owocr/screen_coordinate_picker.py +109 -0
- GameSentenceMiner/tools/__init__.py +0 -0
- GameSentenceMiner/tools/audio_offset_selector.py +215 -0
- GameSentenceMiner/tools/ss_selector.py +135 -0
- GameSentenceMiner/tools/window_transparency.py +214 -0
- GameSentenceMiner/util/__init__.py +0 -0
- GameSentenceMiner/util/communication/__init__.py +22 -0
- GameSentenceMiner/util/communication/send.py +7 -0
- GameSentenceMiner/util/communication/websocket.py +94 -0
- GameSentenceMiner/util/configuration.py +1199 -0
- GameSentenceMiner/util/db.py +408 -0
- GameSentenceMiner/util/downloader/Untitled_json.py +472 -0
- GameSentenceMiner/util/downloader/__init__.py +0 -0
- GameSentenceMiner/util/downloader/download_tools.py +194 -0
- GameSentenceMiner/util/downloader/oneocr_dl.py +250 -0
- GameSentenceMiner/util/electron_config.py +259 -0
- GameSentenceMiner/util/ffmpeg.py +571 -0
- GameSentenceMiner/util/get_overlay_coords.py +366 -0
- GameSentenceMiner/util/gsm_utils.py +323 -0
- GameSentenceMiner/util/model.py +206 -0
- GameSentenceMiner/util/notification.py +157 -0
- GameSentenceMiner/util/text_log.py +214 -0
- GameSentenceMiner/util/win10toast/__init__.py +154 -0
- GameSentenceMiner/util/win10toast/__main__.py +22 -0
- GameSentenceMiner/web/__init__.py +0 -0
- GameSentenceMiner/web/service.py +132 -0
- GameSentenceMiner/web/static/__init__.py +0 -0
- GameSentenceMiner/web/static/apple-touch-icon.png +0 -0
- GameSentenceMiner/web/static/favicon-96x96.png +0 -0
- GameSentenceMiner/web/static/favicon.ico +0 -0
- GameSentenceMiner/web/static/favicon.svg +3 -0
- GameSentenceMiner/web/static/site.webmanifest +21 -0
- GameSentenceMiner/web/static/style.css +292 -0
- GameSentenceMiner/web/static/web-app-manifest-192x192.png +0 -0
- GameSentenceMiner/web/static/web-app-manifest-512x512.png +0 -0
- GameSentenceMiner/web/templates/__init__.py +0 -0
- GameSentenceMiner/web/templates/index.html +50 -0
- GameSentenceMiner/web/templates/text_replacements.html +238 -0
- GameSentenceMiner/web/templates/utility.html +483 -0
- GameSentenceMiner/web/texthooking_page.py +584 -0
- GameSentenceMiner/wip/__init___.py +0 -0
- {gamesentenceminer-2.14.9.dist-info → gamesentenceminer-2.14.10.dist-info}/METADATA +1 -1
- gamesentenceminer-2.14.10.dist-info/RECORD +79 -0
- gamesentenceminer-2.14.9.dist-info/RECORD +0 -24
- {gamesentenceminer-2.14.9.dist-info → gamesentenceminer-2.14.10.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.14.9.dist-info → gamesentenceminer-2.14.10.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.14.9.dist-info → gamesentenceminer-2.14.10.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.14.9.dist-info → gamesentenceminer-2.14.10.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,140 @@
|
|
1
|
+
import tkinter as tk
|
2
|
+
from tkinter import Canvas
|
3
|
+
from PIL import Image, ImageTk
|
4
|
+
import mss
|
5
|
+
import mss.tools
|
6
|
+
import io
|
7
|
+
|
8
|
+
class ScreenCropper:
|
9
|
+
def __init__(self):
|
10
|
+
self.main_monitor = None
|
11
|
+
self.root = None
|
12
|
+
self.canvas = None
|
13
|
+
self.captured_image = None
|
14
|
+
self.tk_image = None
|
15
|
+
self.start_x = None
|
16
|
+
self.start_y = None
|
17
|
+
self.end_x = None
|
18
|
+
self.end_y = None
|
19
|
+
self.rect_id = None
|
20
|
+
self.cropped_image = None
|
21
|
+
self.monitor_geometry = None
|
22
|
+
|
23
|
+
def grab_all_monitors(self):
|
24
|
+
try:
|
25
|
+
with mss.mss() as sct:
|
26
|
+
all_monitors_bbox = sct.monitors[0]
|
27
|
+
self.main_monitor = sct.monitors[1]
|
28
|
+
self.monitor_geometry = {
|
29
|
+
'left': all_monitors_bbox['left'],
|
30
|
+
'top': all_monitors_bbox['top'],
|
31
|
+
'width': all_monitors_bbox['width'],
|
32
|
+
'height': all_monitors_bbox['height']
|
33
|
+
}
|
34
|
+
sct_grab = sct.grab(all_monitors_bbox)
|
35
|
+
|
36
|
+
img_bytes = mss.tools.to_png(sct_grab.rgb, sct_grab.size)
|
37
|
+
self.captured_image = Image.open(io.BytesIO(img_bytes))
|
38
|
+
|
39
|
+
print("All monitors captured successfully.")
|
40
|
+
except Exception as e:
|
41
|
+
print(f"An error occurred during screen capture: {e}")
|
42
|
+
self.captured_image = None
|
43
|
+
self.monitor_geometry = None
|
44
|
+
|
45
|
+
def _on_button_press(self, event):
|
46
|
+
self.start_x = self.end_x = event.x
|
47
|
+
self.start_y = self.end_y = event.y
|
48
|
+
|
49
|
+
if self.rect_id:
|
50
|
+
self.canvas.delete(self.rect_id)
|
51
|
+
self.rect_id = self.canvas.create_rectangle(self.start_x, self.start_y,
|
52
|
+
self.end_x, self.end_y,
|
53
|
+
outline="red", width=2)
|
54
|
+
|
55
|
+
def _on_mouse_drag(self, event):
|
56
|
+
self.end_x = event.x
|
57
|
+
self.end_y = event.y
|
58
|
+
self.canvas.coords(self.rect_id, self.start_x, self.start_y,
|
59
|
+
self.end_x, self.end_y)
|
60
|
+
|
61
|
+
def _on_button_release(self, event):
|
62
|
+
self.end_x = event.x
|
63
|
+
self.end_y = event.y
|
64
|
+
|
65
|
+
x1 = min(self.start_x, self.end_x)
|
66
|
+
y1 = min(self.start_y, self.end_y)
|
67
|
+
x2 = max(self.start_x, self.end_x)
|
68
|
+
y2 = max(self.start_y, self.end_y)
|
69
|
+
|
70
|
+
if (x2 - x1) > 0 and (y2 - y1) > 0:
|
71
|
+
self.cropped_image = self.captured_image.crop((x1, y1, x2, y2))
|
72
|
+
print(f"Selection made: ({x1}, {y1}) to ({x2}, {y2})")
|
73
|
+
else:
|
74
|
+
print("No valid selection made (area was too small).")
|
75
|
+
self.cropped_image = None
|
76
|
+
|
77
|
+
self.root.destroy()
|
78
|
+
|
79
|
+
def _on_enter(self, event):
|
80
|
+
print(event)
|
81
|
+
print("Enter key pressed, grabbing main monitor area.")
|
82
|
+
self.cropped_image = self.captured_image.crop((self.main_monitor['left'], self.main_monitor['top'],
|
83
|
+
self.main_monitor['left'] + self.main_monitor['width'],
|
84
|
+
self.main_monitor['top'] + self.main_monitor['height']))
|
85
|
+
self.root.destroy()
|
86
|
+
|
87
|
+
|
88
|
+
def show_image_and_select_box(self):
|
89
|
+
if self.captured_image is None or self.monitor_geometry is None:
|
90
|
+
print("No image or monitor geometry to display. Capture all monitors first.")
|
91
|
+
return
|
92
|
+
|
93
|
+
self.root = tk.Tk()
|
94
|
+
self.root.attributes('-topmost', True)
|
95
|
+
self.root.overrideredirect(True)
|
96
|
+
|
97
|
+
window_width = self.monitor_geometry['width']
|
98
|
+
window_height = self.monitor_geometry['height']
|
99
|
+
window_x = self.monitor_geometry['left']
|
100
|
+
window_y = self.monitor_geometry['top']
|
101
|
+
|
102
|
+
self.root.geometry(f"{window_width}x{window_height}+{window_x}+{window_y}")
|
103
|
+
|
104
|
+
self.tk_image = ImageTk.PhotoImage(self.captured_image)
|
105
|
+
|
106
|
+
self.canvas = Canvas(self.root, cursor="cross", highlightthickness=0)
|
107
|
+
self.canvas.pack(fill=tk.BOTH, expand=True)
|
108
|
+
|
109
|
+
self.canvas.create_image(0, 0, anchor="nw", image=self.tk_image)
|
110
|
+
|
111
|
+
self.canvas.bind("<Button-1>", self._on_button_press)
|
112
|
+
self.canvas.bind("<B1-Motion>", self._on_mouse_drag)
|
113
|
+
self.canvas.bind("<ButtonRelease-1>", self._on_button_release)
|
114
|
+
|
115
|
+
|
116
|
+
self.root.mainloop()
|
117
|
+
|
118
|
+
def get_cropped_image(self):
|
119
|
+
return self.cropped_image
|
120
|
+
|
121
|
+
def run(self, return_main_monitor=False):
|
122
|
+
self.grab_all_monitors()
|
123
|
+
if return_main_monitor and self.captured_image:
|
124
|
+
return self.captured_image.crop((self.main_monitor['left'], self.main_monitor['top'],
|
125
|
+
self.main_monitor['left'] + self.main_monitor['width'],
|
126
|
+
self.main_monitor['top'] + self.main_monitor['height']))
|
127
|
+
if self.captured_image and self.monitor_geometry:
|
128
|
+
self.show_image_and_select_box()
|
129
|
+
return self.get_cropped_image()
|
130
|
+
return None
|
131
|
+
|
132
|
+
if __name__ == "__main__":
|
133
|
+
cropper = ScreenCropper()
|
134
|
+
cropped_img = cropper.run()
|
135
|
+
|
136
|
+
if cropped_img:
|
137
|
+
print("Image cropped successfully. Displaying cropped image...")
|
138
|
+
cropped_img.show()
|
139
|
+
else:
|
140
|
+
print("No image was cropped.")
|
@@ -0,0 +1 @@
|
|
1
|
+
from GameSentenceMiner.owocr.owocr.ocr import *
|
@@ -0,0 +1,148 @@
|
|
1
|
+
import os
|
2
|
+
import configparser
|
3
|
+
import argparse
|
4
|
+
import textwrap
|
5
|
+
import urllib.request
|
6
|
+
|
7
|
+
def str2bool(value):
|
8
|
+
if value.lower() == 'true':
|
9
|
+
return True
|
10
|
+
elif value.lower() == 'false':
|
11
|
+
return False
|
12
|
+
else:
|
13
|
+
raise argparse.ArgumentTypeError('Boolean value expected.')
|
14
|
+
|
15
|
+
parser = argparse.ArgumentParser(prog='owocr', description=textwrap.dedent('''\
|
16
|
+
Runs OCR in the background.
|
17
|
+
It can read images copied to the system clipboard or placed in a directory, images sent via a websocket or a Unix domain socket, or directly capture a screen (or a portion of it) or a window.
|
18
|
+
Recognized text can be either saved to system clipboard, appended to a text file or sent via a websocket.
|
19
|
+
'''))
|
20
|
+
|
21
|
+
parser.add_argument('-r', '--read_from', type=str, default=argparse.SUPPRESS,
|
22
|
+
help='Where to read input images from. Can be either "clipboard", "websocket", "unixsocket" (on macOS/Linux), "screencapture", or a path to a directory.')
|
23
|
+
parser.add_argument('-rs', '--read_from_secondary', type=str, default=argparse.SUPPRESS,
|
24
|
+
help="Optional secondary source to read input images from. Same options as read_from, but they can't both be directory paths.")
|
25
|
+
parser.add_argument('-w', '--write_to', type=str, default=argparse.SUPPRESS,
|
26
|
+
help='Where to save recognized texts to. Can be either "clipboard", "websocket", or a path to a text file.')
|
27
|
+
parser.add_argument('-e', '--engine', type=str, default=argparse.SUPPRESS,
|
28
|
+
help='OCR engine to use. Available: "mangaocr", "glens", "glensweb", "bing", "gvision", "avision", "alivetext", "azure", "winrtocr", "oneocr", "easyocr", "rapidocr", "ocrspace".')
|
29
|
+
parser.add_argument('-p', '--pause_at_startup', action='store_true', default=argparse.SUPPRESS,
|
30
|
+
help='Pause at startup.')
|
31
|
+
parser.add_argument('-i', '--ignore_flag', action='store_true', default=argparse.SUPPRESS,
|
32
|
+
help='Process flagged clipboard images (images that are copied to the clipboard with the *ocr_ignore* string).')
|
33
|
+
parser.add_argument('-d', '--delete_images', action='store_true', default=argparse.SUPPRESS,
|
34
|
+
help='Delete image files after processing when reading from a directory.')
|
35
|
+
parser.add_argument('-n', '--notifications', action='store_true', default=argparse.SUPPRESS,
|
36
|
+
help='Show an operating system notification with the detected text. Will be ignored when reading with screen capture, unless screen_capture_combo is set.')
|
37
|
+
parser.add_argument('-a', '--auto_pause', type=float, default=argparse.SUPPRESS,
|
38
|
+
help='Automatically pause the program after the specified amount of seconds since the last successful text recognition. Will be ignored when reading with screen capture, unless screen_capture_combo is set. 0 to disable.')
|
39
|
+
parser.add_argument('-cp', '--combo_pause', type=str, default=argparse.SUPPRESS,
|
40
|
+
help='Combo to wait on for pausing the program. As an example: "<ctrl>+<shift>+p". The list of keys can be found here: https://pynput.readthedocs.io/en/latest/keyboard.html#pynput.keyboard.Key')
|
41
|
+
parser.add_argument('-cs', '--combo_engine_switch', type=str, default=argparse.SUPPRESS,
|
42
|
+
help='Combo to wait on for switching the OCR engine. As an example: "<ctrl>+<shift>+a". To be used with combo_pause. The list of keys can be found here: https://pynput.readthedocs.io/en/latest/keyboard.html#pynput.keyboard.Key')
|
43
|
+
parser.add_argument('-sa', '--screen_capture_area', type=str, default=argparse.SUPPRESS,
|
44
|
+
help='Area to target when reading with screen capture. Can be either empty (automatic selector), a set of coordinates (x,y,width,height), "screen_N" (captures a whole screen, where N is the screen number starting from 1) or a window name (the first matching window title will be used).')
|
45
|
+
parser.add_argument('-sd', '--screen_capture_delay_secs', type=float, default=argparse.SUPPRESS,
|
46
|
+
help='Delay (in seconds) between screenshots when reading with screen capture.')
|
47
|
+
parser.add_argument('-sw', '--screen_capture_only_active_windows', type=str2bool, default=argparse.SUPPRESS,
|
48
|
+
help="When reading with screen capture and screen_capture_area is a window name, only target the window while it's active.")
|
49
|
+
parser.add_argument('-sc', '--screen_capture_combo', type=str, default=argparse.SUPPRESS,
|
50
|
+
help='When reading with screen capture, combo to wait on for taking a screenshot instead of using the delay. As an example: "<ctrl>+<shift>+s". The list of keys can be found here: https://pynput.readthedocs.io/en/latest/keyboard.html#pynput.keyboard.Key')
|
51
|
+
|
52
|
+
class Config:
|
53
|
+
has_config = False
|
54
|
+
downloaded_config = False
|
55
|
+
config_path = os.path.join(os.path.expanduser('~'),'.config','owocr_config.ini')
|
56
|
+
__general_config = {}
|
57
|
+
__engine_config = {}
|
58
|
+
__default_config = {
|
59
|
+
'read_from': 'clipboard',
|
60
|
+
'read_from_secondary': '',
|
61
|
+
'write_to': 'clipboard',
|
62
|
+
'engine': '',
|
63
|
+
'pause_at_startup': False,
|
64
|
+
'auto_pause' : 0,
|
65
|
+
'ignore_flag': False,
|
66
|
+
'delete_images': False,
|
67
|
+
'engines': [],
|
68
|
+
'logger_format': '<green>{time:HH:mm:ss.SSS}</green> | <level>{message}</level>',
|
69
|
+
'engine_color': 'cyan',
|
70
|
+
'delay_secs': 0.5,
|
71
|
+
'websocket_port': 7331,
|
72
|
+
'notifications': False,
|
73
|
+
'combo_pause': '',
|
74
|
+
'combo_engine_switch': '',
|
75
|
+
'screen_capture_area': '',
|
76
|
+
'screen_capture_delay_secs': 3,
|
77
|
+
'screen_capture_only_active_windows': True,
|
78
|
+
'screen_capture_combo': '',
|
79
|
+
'screen_capture_old_macos_api': False
|
80
|
+
}
|
81
|
+
|
82
|
+
def __parse(self, value):
|
83
|
+
value = value.strip()
|
84
|
+
if value.lower() == 'false':
|
85
|
+
return False
|
86
|
+
if value.lower() == 'true':
|
87
|
+
return True
|
88
|
+
try:
|
89
|
+
int(value)
|
90
|
+
return int(value)
|
91
|
+
except ValueError:
|
92
|
+
pass
|
93
|
+
try:
|
94
|
+
float(value)
|
95
|
+
return float(value)
|
96
|
+
except ValueError:
|
97
|
+
pass
|
98
|
+
return value
|
99
|
+
|
100
|
+
def __init__(self, parse_args=True):
|
101
|
+
if parse_args:
|
102
|
+
args = parser.parse_args()
|
103
|
+
self.__provided_cli_args = vars(args)
|
104
|
+
else:
|
105
|
+
self.__provided_cli_args = {}
|
106
|
+
config = configparser.ConfigParser()
|
107
|
+
res = config.read(self.config_path)
|
108
|
+
|
109
|
+
if len(res) == 0:
|
110
|
+
try:
|
111
|
+
config_folder = os.path.join(os.path.expanduser('~'),'.config')
|
112
|
+
if not os.path.isdir(config_folder):
|
113
|
+
os.makedirs(config_folder)
|
114
|
+
urllib.request.urlretrieve('https://github.com/AuroraWright/owocr/raw/master/owocr_config.ini', self.config_path)
|
115
|
+
self.downloaded_config = True
|
116
|
+
finally:
|
117
|
+
return
|
118
|
+
|
119
|
+
self.has_config = True
|
120
|
+
for key in config:
|
121
|
+
if key == 'general':
|
122
|
+
for sub_key in config[key]:
|
123
|
+
self.__general_config[sub_key.lower()] = self.__parse(config[key][sub_key])
|
124
|
+
elif key != 'DEFAULT':
|
125
|
+
self.__engine_config[key.lower()] = {}
|
126
|
+
for sub_key in config[key]:
|
127
|
+
self.__engine_config[key.lower()][sub_key.lower()] = self.__parse(config[key][sub_key])
|
128
|
+
|
129
|
+
def get_general(self, value, default_value=None):
|
130
|
+
if self.__provided_cli_args.get(value, None) is not None:
|
131
|
+
return self.__provided_cli_args[value]
|
132
|
+
try:
|
133
|
+
return self.__general_config[value]
|
134
|
+
except KeyError:
|
135
|
+
if default_value:
|
136
|
+
return default_value
|
137
|
+
if value in self.__default_config:
|
138
|
+
return self.__default_config[value]
|
139
|
+
else:
|
140
|
+
return None
|
141
|
+
|
142
|
+
def get_engine(self, value):
|
143
|
+
try:
|
144
|
+
return self.__engine_config[value]
|
145
|
+
except KeyError:
|
146
|
+
return None
|
147
|
+
|
148
|
+
config = Config(False)
|