GameSentenceMiner 2.15.9__py3-none-any.whl → 2.15.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/ocr/gsm_ocr_config.py +1 -1
- GameSentenceMiner/ocr/owocr_helper.py +21 -12
- GameSentenceMiner/owocr/owocr/run.py +2 -2
- GameSentenceMiner/util/configuration.py +3 -0
- GameSentenceMiner/util/text_log.py +2 -2
- GameSentenceMiner/web/database_api.py +783 -0
- GameSentenceMiner/web/events.py +178 -0
- GameSentenceMiner/web/stats.py +582 -0
- GameSentenceMiner/web/templates/database.html +277 -0
- GameSentenceMiner/web/templates/search.html +103 -0
- GameSentenceMiner/web/templates/stats.html +330 -0
- GameSentenceMiner/web/templates/text_replacements.html +211 -0
- GameSentenceMiner/web/templates/utility.html +2 -2
- GameSentenceMiner/web/texthooking_page.py +58 -316
- GameSentenceMiner/web/websockets.py +120 -0
- {gamesentenceminer-2.15.9.dist-info → gamesentenceminer-2.15.10.dist-info}/METADATA +1 -1
- {gamesentenceminer-2.15.9.dist-info → gamesentenceminer-2.15.10.dist-info}/RECORD +21 -15
- GameSentenceMiner/web/templates/__init__.py +0 -0
- {gamesentenceminer-2.15.9.dist-info → gamesentenceminer-2.15.10.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.15.9.dist-info → gamesentenceminer-2.15.10.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.15.9.dist-info → gamesentenceminer-2.15.10.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.15.9.dist-info → gamesentenceminer-2.15.10.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,178 @@
|
|
1
|
+
import asyncio
|
2
|
+
from collections import defaultdict
|
3
|
+
import datetime
|
4
|
+
import json
|
5
|
+
import os
|
6
|
+
import queue
|
7
|
+
import sqlite3
|
8
|
+
import threading
|
9
|
+
from dataclasses import dataclass
|
10
|
+
|
11
|
+
from GameSentenceMiner.util.db import GameLinesTable
|
12
|
+
from GameSentenceMiner.util.text_log import GameLine, initial_time
|
13
|
+
from GameSentenceMiner.util.configuration import logger, DB_PATH
|
14
|
+
|
15
|
+
|
16
|
+
@dataclass
|
17
|
+
class EventItem:
|
18
|
+
line: 'GameLine'
|
19
|
+
id: str
|
20
|
+
text: str
|
21
|
+
time: datetime.datetime
|
22
|
+
checked: bool = False
|
23
|
+
history: bool = False
|
24
|
+
|
25
|
+
def to_dict(self):
|
26
|
+
return {
|
27
|
+
'id': self.id,
|
28
|
+
'text': self.text,
|
29
|
+
'time': self.time,
|
30
|
+
'checked': self.checked,
|
31
|
+
'history': self.history,
|
32
|
+
}
|
33
|
+
|
34
|
+
def to_serializable(self):
|
35
|
+
return {
|
36
|
+
'id': self.id,
|
37
|
+
'text': self.text,
|
38
|
+
'time': self.time.isoformat(),
|
39
|
+
'checked': self.checked,
|
40
|
+
'history': self.history,
|
41
|
+
}
|
42
|
+
|
43
|
+
|
44
|
+
class EventManager:
|
45
|
+
events: list[EventItem]
|
46
|
+
events_dict: dict[str, EventItem] = {}
|
47
|
+
|
48
|
+
def __init__(self):
|
49
|
+
self.events = []
|
50
|
+
self.ids = []
|
51
|
+
self.events_dict = {}
|
52
|
+
self._connect()
|
53
|
+
self._create_table()
|
54
|
+
self._load_events_from_db()
|
55
|
+
# self.close_connection()
|
56
|
+
|
57
|
+
def _connect(self):
|
58
|
+
self.conn = sqlite3.connect(DB_PATH)
|
59
|
+
self.cursor = self.conn.cursor()
|
60
|
+
|
61
|
+
def _create_table(self):
|
62
|
+
self.cursor.execute("""
|
63
|
+
CREATE TABLE IF NOT EXISTS events (
|
64
|
+
event_id TEXT PRIMARY KEY,
|
65
|
+
line_id TEXT,
|
66
|
+
text TEXT,
|
67
|
+
time TEXT
|
68
|
+
)
|
69
|
+
""")
|
70
|
+
self.conn.commit()
|
71
|
+
|
72
|
+
def _load_events_from_db(self):
|
73
|
+
self.cursor.execute("SELECT * FROM events")
|
74
|
+
rows = self.cursor.fetchall()
|
75
|
+
for row in rows:
|
76
|
+
event_id, line_id, text, timestamp = row
|
77
|
+
timestamp = datetime.datetime.fromisoformat(timestamp)
|
78
|
+
line = GameLine(line_id, text, timestamp, None, None, 0)
|
79
|
+
event = EventItem(line, event_id, text, timestamp,
|
80
|
+
False, timestamp < initial_time)
|
81
|
+
self.events.append(event)
|
82
|
+
self.ids.append(event_id)
|
83
|
+
self.events_dict[event_id] = event
|
84
|
+
|
85
|
+
def __iter__(self):
|
86
|
+
return iter(self.events)
|
87
|
+
|
88
|
+
def replace_events(self, new_events: list[EventItem]):
|
89
|
+
self.events = new_events
|
90
|
+
|
91
|
+
def add_gameline(self, line: GameLine):
|
92
|
+
new_event = EventItem(line, line.id, line.text,
|
93
|
+
line.time, False, False)
|
94
|
+
self.events_dict[line.id] = new_event
|
95
|
+
self.ids.append(line.id)
|
96
|
+
self.events.append(new_event)
|
97
|
+
# self.store_to_db(new_event)
|
98
|
+
# event_queue.put(new_event)
|
99
|
+
return new_event
|
100
|
+
|
101
|
+
def reset_checked_lines(self):
|
102
|
+
for event in self.events:
|
103
|
+
event.checked = False
|
104
|
+
|
105
|
+
def get_events(self):
|
106
|
+
return self.events
|
107
|
+
|
108
|
+
def add_event(self, event):
|
109
|
+
self.events.append(event)
|
110
|
+
self.ids.append(event.id)
|
111
|
+
event_queue.put(event)
|
112
|
+
|
113
|
+
def get(self, event_id):
|
114
|
+
return self.events_dict.get(event_id)
|
115
|
+
|
116
|
+
def get_ids(self):
|
117
|
+
return self.ids
|
118
|
+
|
119
|
+
def close_connection(self):
|
120
|
+
if self.conn:
|
121
|
+
self.conn.close()
|
122
|
+
|
123
|
+
def clear_history(self):
|
124
|
+
self.cursor.execute("DELETE FROM events WHERE time < ?",
|
125
|
+
(initial_time.isoformat(),))
|
126
|
+
logger.info(f"Cleared history before {initial_time.isoformat()}")
|
127
|
+
self.conn.commit()
|
128
|
+
# Clear the in-memory events as well
|
129
|
+
event_manager.events = [
|
130
|
+
event for event in event_manager if not event.history]
|
131
|
+
event_manager.events_dict = {
|
132
|
+
event.id: event for event in event_manager.events}
|
133
|
+
|
134
|
+
|
135
|
+
class EventProcessor(threading.Thread):
|
136
|
+
def __init__(self, event_queue, db_path):
|
137
|
+
super().__init__()
|
138
|
+
self.event_queue = event_queue
|
139
|
+
self.db_path = db_path
|
140
|
+
self.conn = None
|
141
|
+
self.cursor = None
|
142
|
+
self.daemon = True
|
143
|
+
|
144
|
+
def _connect(self):
|
145
|
+
self.conn = sqlite3.connect(self.db_path)
|
146
|
+
self.cursor = self.conn.cursor()
|
147
|
+
|
148
|
+
def run(self):
|
149
|
+
self._connect()
|
150
|
+
while True:
|
151
|
+
try:
|
152
|
+
event = self.event_queue.get()
|
153
|
+
if event is None: # Exit signal
|
154
|
+
break
|
155
|
+
self._store_to_db(event)
|
156
|
+
except Exception as e:
|
157
|
+
logger.error(f"Error processing event: {e}")
|
158
|
+
self._close_connection()
|
159
|
+
|
160
|
+
def _store_to_db(self, event):
|
161
|
+
self.cursor.execute("""
|
162
|
+
INSERT INTO events (event_id, line_id, text, time)
|
163
|
+
VALUES (?, ?, ?, ?)
|
164
|
+
""", (event.id, event.line.id, event.text, event.time.isoformat()))
|
165
|
+
self.conn.commit()
|
166
|
+
|
167
|
+
def _close_connection(self):
|
168
|
+
if self.conn:
|
169
|
+
self.conn.close()
|
170
|
+
|
171
|
+
|
172
|
+
# Global instances
|
173
|
+
event_manager = EventManager()
|
174
|
+
event_queue = queue.Queue()
|
175
|
+
|
176
|
+
# Initialize the EventProcessor with the queue and event manager
|
177
|
+
event_processor = EventProcessor(event_queue, DB_PATH)
|
178
|
+
event_processor.start()
|