GameSentenceMiner 2.15.10__py3-none-any.whl → 2.15.12__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/anki.py +31 -0
- GameSentenceMiner/ocr/owocr_helper.py +5 -5
- GameSentenceMiner/web/static/css/kanji-grid.css +107 -0
- GameSentenceMiner/web/static/css/search.css +14 -0
- GameSentenceMiner/web/static/css/shared.css +932 -0
- GameSentenceMiner/web/static/css/stats.css +499 -0
- GameSentenceMiner/web/static/js/anki_stats.js +84 -0
- GameSentenceMiner/web/static/js/database.js +541 -0
- GameSentenceMiner/web/static/js/kanji-grid.js +203 -0
- GameSentenceMiner/web/static/js/search.js +273 -0
- GameSentenceMiner/web/static/js/shared.js +506 -0
- GameSentenceMiner/web/static/js/stats.js +1427 -0
- GameSentenceMiner/web/templates/anki_stats.html +205 -0
- GameSentenceMiner/web/templates/components/navigation.html +16 -0
- GameSentenceMiner/web/templates/components/theme-styles.html +128 -0
- GameSentenceMiner/web/templates/stats.html +4 -0
- GameSentenceMiner/web/texthooking_page.py +50 -0
- {gamesentenceminer-2.15.10.dist-info → gamesentenceminer-2.15.12.dist-info}/METADATA +1 -1
- {gamesentenceminer-2.15.10.dist-info → gamesentenceminer-2.15.12.dist-info}/RECORD +23 -11
- GameSentenceMiner/web/templates/text_replacements.html +0 -449
- {gamesentenceminer-2.15.10.dist-info → gamesentenceminer-2.15.12.dist-info}/WHEEL +0 -0
- {gamesentenceminer-2.15.10.dist-info → gamesentenceminer-2.15.12.dist-info}/entry_points.txt +0 -0
- {gamesentenceminer-2.15.10.dist-info → gamesentenceminer-2.15.12.dist-info}/licenses/LICENSE +0 -0
- {gamesentenceminer-2.15.10.dist-info → gamesentenceminer-2.15.12.dist-info}/top_level.txt +0 -0
GameSentenceMiner/anki.py
CHANGED
@@ -546,5 +546,36 @@ def start_monitoring_anki():
|
|
546
546
|
obs_thread.start()
|
547
547
|
|
548
548
|
|
549
|
+
# --- Anki Stats Kanji Extraction Utilities ---
|
550
|
+
|
551
|
+
def get_all_anki_first_field_kanji():
|
552
|
+
"""
|
553
|
+
Fetch all notes from Anki and extract unique kanji from the first field of each note.
|
554
|
+
Returns a set of kanji characters.
|
555
|
+
"""
|
556
|
+
from GameSentenceMiner.web.stats import is_kanji
|
557
|
+
try:
|
558
|
+
note_ids = invoke("findNotes", query="")
|
559
|
+
if not note_ids:
|
560
|
+
return set()
|
561
|
+
kanji_set = set()
|
562
|
+
batch_size = 1000
|
563
|
+
for i in range(0, len(note_ids), batch_size):
|
564
|
+
batch_ids = note_ids[i:i+batch_size]
|
565
|
+
notes_info = invoke("notesInfo", notes=batch_ids)
|
566
|
+
for note in notes_info:
|
567
|
+
fields = note.get("fields", {})
|
568
|
+
first_field = next(iter(fields.values()), None)
|
569
|
+
if first_field and "value" in first_field:
|
570
|
+
first_field_value = first_field["value"]
|
571
|
+
for char in first_field_value:
|
572
|
+
if is_kanji(char):
|
573
|
+
kanji_set.add(char)
|
574
|
+
return kanji_set
|
575
|
+
except Exception as e:
|
576
|
+
logger.error(f"Failed to fetch kanji from Anki: {e}")
|
577
|
+
return set()
|
578
|
+
|
579
|
+
|
549
580
|
if __name__ == "__main__":
|
550
581
|
print(invoke("getIntervals", cards=["1754694986036"]))
|
@@ -414,7 +414,7 @@ done = False
|
|
414
414
|
# Create a queue for tasks
|
415
415
|
second_ocr_queue = queue.Queue()
|
416
416
|
|
417
|
-
def get_ocr2_image(crop_coords, og_image, ocr2_engine=None):
|
417
|
+
def get_ocr2_image(crop_coords, og_image: Image.Image, ocr2_engine=None):
|
418
418
|
"""
|
419
419
|
Returns the image to use for the second OCR pass, cropping and scaling as needed.
|
420
420
|
Logic is unchanged, but code is refactored for clarity and maintainability.
|
@@ -424,10 +424,10 @@ def get_ocr2_image(crop_coords, og_image, ocr2_engine=None):
|
|
424
424
|
if not crop_coords or not get_ocr_optimize_second_scan():
|
425
425
|
return og_image
|
426
426
|
x1, y1, x2, y2 = crop_coords
|
427
|
-
x1 = min(max(0, x1),
|
428
|
-
y1 = min(max(0, y1),
|
429
|
-
x2 = min(max(0, x2),
|
430
|
-
y2 = min(max(0, y2),
|
427
|
+
x1 = min(max(0, x1), og_image.width)
|
428
|
+
y1 = min(max(0, y1), og_image.height)
|
429
|
+
x2 = min(max(0, x2), og_image.width)
|
430
|
+
y2 = min(max(0, y2), og_image.height)
|
431
431
|
og_image.save(os.path.join(get_temporary_directory(), "pre_oneocrcrop.png"))
|
432
432
|
return og_image.crop((x1, y1, x2, y2))
|
433
433
|
|
@@ -0,0 +1,107 @@
|
|
1
|
+
/* Shared Kanji Grid Component Styles */
|
2
|
+
|
3
|
+
/* Kanji Grid Container */
|
4
|
+
.kanji-counter {
|
5
|
+
text-align: center;
|
6
|
+
font-size: 18px;
|
7
|
+
font-weight: bold;
|
8
|
+
color: #495057;
|
9
|
+
margin-bottom: 20px;
|
10
|
+
}
|
11
|
+
|
12
|
+
.kanji-grid {
|
13
|
+
display: grid;
|
14
|
+
grid-template-columns: repeat(auto-fill, minmax(30px, 1fr));
|
15
|
+
gap: 3px;
|
16
|
+
margin-bottom: 20px;
|
17
|
+
max-width: 100%;
|
18
|
+
}
|
19
|
+
|
20
|
+
/* Individual Kanji Cell */
|
21
|
+
.kanji-cell {
|
22
|
+
width: 30px;
|
23
|
+
height: 30px;
|
24
|
+
background-color: #ebedf0;
|
25
|
+
border-radius: 3px;
|
26
|
+
display: flex;
|
27
|
+
align-items: center;
|
28
|
+
justify-content: center;
|
29
|
+
font-size: 16px;
|
30
|
+
font-weight: bold;
|
31
|
+
color: #333;
|
32
|
+
cursor: pointer;
|
33
|
+
position: relative;
|
34
|
+
transition: all 0.2s ease;
|
35
|
+
font-family: "Noto Sans CJK JP", "Hiragino Sans", "Yu Gothic", "Meiryo", "Takao", "IPAexGothic", "IPAPGothic", "VL PGothic", "Koruri", sans-serif;
|
36
|
+
line-height: 1;
|
37
|
+
text-align: center;
|
38
|
+
}
|
39
|
+
|
40
|
+
.kanji-cell:hover {
|
41
|
+
transform: scale(1.1);
|
42
|
+
z-index: 10;
|
43
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
44
|
+
}
|
45
|
+
|
46
|
+
/* Frequency-based color levels (for backward compatibility) */
|
47
|
+
.kanji-cell.level-1 { background-color: #c6e48b; }
|
48
|
+
.kanji-cell.level-2 { background-color: #7bc96f; }
|
49
|
+
.kanji-cell.level-3 { background-color: #239a3b; color: white; }
|
50
|
+
.kanji-cell.level-4 { background-color: #196127; color: white; }
|
51
|
+
|
52
|
+
/* Legend */
|
53
|
+
.kanji-legend {
|
54
|
+
display: flex;
|
55
|
+
align-items: center;
|
56
|
+
justify-content: center;
|
57
|
+
margin-top: 10px;
|
58
|
+
font-size: 12px;
|
59
|
+
color: #586069;
|
60
|
+
}
|
61
|
+
|
62
|
+
.kanji-legend-item {
|
63
|
+
width: 12px;
|
64
|
+
height: 12px;
|
65
|
+
margin: 0 2px;
|
66
|
+
border-radius: 2px;
|
67
|
+
}
|
68
|
+
|
69
|
+
/* Grid Container Wrapper */
|
70
|
+
.kanji-grid-container {
|
71
|
+
background: var(--bg-secondary);
|
72
|
+
padding: 20px;
|
73
|
+
border-radius: 8px;
|
74
|
+
box-shadow: 0 4px 12px var(--shadow-color);
|
75
|
+
border: 1px solid var(--border-color);
|
76
|
+
}
|
77
|
+
|
78
|
+
/* Responsive Design */
|
79
|
+
@media (max-width: 768px) {
|
80
|
+
.kanji-grid {
|
81
|
+
grid-template-columns: repeat(auto-fill, minmax(25px, 1fr));
|
82
|
+
gap: 2px;
|
83
|
+
}
|
84
|
+
|
85
|
+
.kanji-cell {
|
86
|
+
width: 25px;
|
87
|
+
height: 25px;
|
88
|
+
font-size: 14px;
|
89
|
+
}
|
90
|
+
|
91
|
+
.kanji-counter {
|
92
|
+
font-size: 16px;
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
@media (max-width: 480px) {
|
97
|
+
.kanji-grid {
|
98
|
+
grid-template-columns: repeat(auto-fill, minmax(22px, 1fr));
|
99
|
+
gap: 1px;
|
100
|
+
}
|
101
|
+
|
102
|
+
.kanji-cell {
|
103
|
+
width: 22px;
|
104
|
+
height: 22px;
|
105
|
+
font-size: 12px;
|
106
|
+
}
|
107
|
+
}
|