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.
Files changed (24) hide show
  1. GameSentenceMiner/anki.py +31 -0
  2. GameSentenceMiner/ocr/owocr_helper.py +5 -5
  3. GameSentenceMiner/web/static/css/kanji-grid.css +107 -0
  4. GameSentenceMiner/web/static/css/search.css +14 -0
  5. GameSentenceMiner/web/static/css/shared.css +932 -0
  6. GameSentenceMiner/web/static/css/stats.css +499 -0
  7. GameSentenceMiner/web/static/js/anki_stats.js +84 -0
  8. GameSentenceMiner/web/static/js/database.js +541 -0
  9. GameSentenceMiner/web/static/js/kanji-grid.js +203 -0
  10. GameSentenceMiner/web/static/js/search.js +273 -0
  11. GameSentenceMiner/web/static/js/shared.js +506 -0
  12. GameSentenceMiner/web/static/js/stats.js +1427 -0
  13. GameSentenceMiner/web/templates/anki_stats.html +205 -0
  14. GameSentenceMiner/web/templates/components/navigation.html +16 -0
  15. GameSentenceMiner/web/templates/components/theme-styles.html +128 -0
  16. GameSentenceMiner/web/templates/stats.html +4 -0
  17. GameSentenceMiner/web/texthooking_page.py +50 -0
  18. {gamesentenceminer-2.15.10.dist-info → gamesentenceminer-2.15.12.dist-info}/METADATA +1 -1
  19. {gamesentenceminer-2.15.10.dist-info → gamesentenceminer-2.15.12.dist-info}/RECORD +23 -11
  20. GameSentenceMiner/web/templates/text_replacements.html +0 -449
  21. {gamesentenceminer-2.15.10.dist-info → gamesentenceminer-2.15.12.dist-info}/WHEEL +0 -0
  22. {gamesentenceminer-2.15.10.dist-info → gamesentenceminer-2.15.12.dist-info}/entry_points.txt +0 -0
  23. {gamesentenceminer-2.15.10.dist-info → gamesentenceminer-2.15.12.dist-info}/licenses/LICENSE +0 -0
  24. {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), img.width)
428
- y1 = min(max(0, y1), img.height)
429
- x2 = min(max(0, x2), img.width)
430
- y2 = min(max(0, y2), img.height)
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
+ }
@@ -0,0 +1,14 @@
1
+ /* Search Page Specific Styles */
2
+
3
+ /* Search-specific responsive styles */
4
+ @media (max-width: 768px) {
5
+ .navigation {
6
+ padding: 10px;
7
+ }
8
+
9
+ .nav-link {
10
+ display: block;
11
+ margin: 5px 0;
12
+ text-align: center;
13
+ }
14
+ }