pomera-ai-commander 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +680 -0
- package/bin/pomera-ai-commander.js +62 -0
- package/core/__init__.py +66 -0
- package/core/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/__pycache__/app_context.cpython-313.pyc +0 -0
- package/core/__pycache__/async_text_processor.cpython-313.pyc +0 -0
- package/core/__pycache__/backup_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/backup_recovery_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/content_hash_cache.cpython-313.pyc +0 -0
- package/core/__pycache__/context_menu.cpython-313.pyc +0 -0
- package/core/__pycache__/data_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/database_connection_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_curl_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_promera_ai_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_schema.cpython-313.pyc +0 -0
- package/core/__pycache__/database_schema_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_settings_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/database_settings_manager_interface.cpython-313.pyc +0 -0
- package/core/__pycache__/dialog_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/efficient_line_numbers.cpython-313.pyc +0 -0
- package/core/__pycache__/error_handler.cpython-313.pyc +0 -0
- package/core/__pycache__/error_service.cpython-313.pyc +0 -0
- package/core/__pycache__/event_consolidator.cpython-313.pyc +0 -0
- package/core/__pycache__/memory_efficient_text_widget.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_test_suite.cpython-313.pyc +0 -0
- package/core/__pycache__/migration_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_find_replace.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_pattern_engine.cpython-313.pyc +0 -0
- package/core/__pycache__/optimized_search_highlighter.cpython-313.pyc +0 -0
- package/core/__pycache__/performance_monitor.cpython-313.pyc +0 -0
- package/core/__pycache__/persistence_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/progressive_stats_calculator.cpython-313.pyc +0 -0
- package/core/__pycache__/regex_pattern_cache.cpython-313.pyc +0 -0
- package/core/__pycache__/regex_pattern_library.cpython-313.pyc +0 -0
- package/core/__pycache__/search_operation_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_defaults_registry.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_integrity_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_serializer.cpython-313.pyc +0 -0
- package/core/__pycache__/settings_validator.cpython-313.pyc +0 -0
- package/core/__pycache__/smart_stats_calculator.cpython-313.pyc +0 -0
- package/core/__pycache__/statistics_update_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/stats_config_manager.cpython-313.pyc +0 -0
- package/core/__pycache__/streaming_text_handler.cpython-313.pyc +0 -0
- package/core/__pycache__/task_scheduler.cpython-313.pyc +0 -0
- package/core/__pycache__/visibility_monitor.cpython-313.pyc +0 -0
- package/core/__pycache__/widget_cache.cpython-313.pyc +0 -0
- package/core/app_context.py +482 -0
- package/core/async_text_processor.py +422 -0
- package/core/backup_manager.py +656 -0
- package/core/backup_recovery_manager.py +1034 -0
- package/core/content_hash_cache.py +509 -0
- package/core/context_menu.py +313 -0
- package/core/data_validator.py +1067 -0
- package/core/database_connection_manager.py +745 -0
- package/core/database_curl_settings_manager.py +609 -0
- package/core/database_promera_ai_settings_manager.py +447 -0
- package/core/database_schema.py +412 -0
- package/core/database_schema_manager.py +396 -0
- package/core/database_settings_manager.py +1508 -0
- package/core/database_settings_manager_interface.py +457 -0
- package/core/dialog_manager.py +735 -0
- package/core/efficient_line_numbers.py +511 -0
- package/core/error_handler.py +747 -0
- package/core/error_service.py +431 -0
- package/core/event_consolidator.py +512 -0
- package/core/mcp/__init__.py +43 -0
- package/core/mcp/__pycache__/__init__.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/protocol.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/schema.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/server_stdio.cpython-313.pyc +0 -0
- package/core/mcp/__pycache__/tool_registry.cpython-313.pyc +0 -0
- package/core/mcp/protocol.py +288 -0
- package/core/mcp/schema.py +251 -0
- package/core/mcp/server_stdio.py +299 -0
- package/core/mcp/tool_registry.py +2345 -0
- package/core/memory_efficient_text_widget.py +712 -0
- package/core/migration_manager.py +915 -0
- package/core/migration_test_suite.py +1086 -0
- package/core/migration_validator.py +1144 -0
- package/core/optimized_find_replace.py +715 -0
- package/core/optimized_pattern_engine.py +424 -0
- package/core/optimized_search_highlighter.py +553 -0
- package/core/performance_monitor.py +675 -0
- package/core/persistence_manager.py +713 -0
- package/core/progressive_stats_calculator.py +632 -0
- package/core/regex_pattern_cache.py +530 -0
- package/core/regex_pattern_library.py +351 -0
- package/core/search_operation_manager.py +435 -0
- package/core/settings_defaults_registry.py +1087 -0
- package/core/settings_integrity_validator.py +1112 -0
- package/core/settings_serializer.py +558 -0
- package/core/settings_validator.py +1824 -0
- package/core/smart_stats_calculator.py +710 -0
- package/core/statistics_update_manager.py +619 -0
- package/core/stats_config_manager.py +858 -0
- package/core/streaming_text_handler.py +723 -0
- package/core/task_scheduler.py +596 -0
- package/core/update_pattern_library.py +169 -0
- package/core/visibility_monitor.py +596 -0
- package/core/widget_cache.py +498 -0
- package/mcp.json +61 -0
- package/package.json +57 -0
- package/pomera.py +7483 -0
- package/pomera_mcp_server.py +144 -0
- package/tools/__init__.py +5 -0
- package/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- package/tools/__pycache__/ai_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/ascii_art_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/base64_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/base_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/case_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/column_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/cron_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_history.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_processor.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_settings.cpython-313.pyc +0 -0
- package/tools/__pycache__/curl_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/diff_viewer.cpython-313.pyc +0 -0
- package/tools/__pycache__/email_extraction_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/email_header_analyzer.cpython-313.pyc +0 -0
- package/tools/__pycache__/extraction_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/find_replace.cpython-313.pyc +0 -0
- package/tools/__pycache__/folder_file_reporter.cpython-313.pyc +0 -0
- package/tools/__pycache__/folder_file_reporter_adapter.cpython-313.pyc +0 -0
- package/tools/__pycache__/generator_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/hash_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/html_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/huggingface_helper.cpython-313.pyc +0 -0
- package/tools/__pycache__/jsonxml_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/line_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/list_comparator.cpython-313.pyc +0 -0
- package/tools/__pycache__/markdown_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/mcp_widget.cpython-313.pyc +0 -0
- package/tools/__pycache__/notes_widget.cpython-313.pyc +0 -0
- package/tools/__pycache__/number_base_converter.cpython-313.pyc +0 -0
- package/tools/__pycache__/regex_extractor.cpython-313.pyc +0 -0
- package/tools/__pycache__/slug_generator.cpython-313.pyc +0 -0
- package/tools/__pycache__/sorter_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/string_escape_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/text_statistics_tool.cpython-313.pyc +0 -0
- package/tools/__pycache__/text_wrapper.cpython-313.pyc +0 -0
- package/tools/__pycache__/timestamp_converter.cpython-313.pyc +0 -0
- package/tools/__pycache__/tool_loader.cpython-313.pyc +0 -0
- package/tools/__pycache__/translator_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/url_link_extractor.cpython-313.pyc +0 -0
- package/tools/__pycache__/url_parser.cpython-313.pyc +0 -0
- package/tools/__pycache__/whitespace_tools.cpython-313.pyc +0 -0
- package/tools/__pycache__/word_frequency_counter.cpython-313.pyc +0 -0
- package/tools/ai_tools.py +2892 -0
- package/tools/ascii_art_generator.py +353 -0
- package/tools/base64_tools.py +184 -0
- package/tools/base_tool.py +511 -0
- package/tools/case_tool.py +309 -0
- package/tools/column_tools.py +396 -0
- package/tools/cron_tool.py +885 -0
- package/tools/curl_history.py +601 -0
- package/tools/curl_processor.py +1208 -0
- package/tools/curl_settings.py +503 -0
- package/tools/curl_tool.py +5467 -0
- package/tools/diff_viewer.py +1072 -0
- package/tools/email_extraction_tool.py +249 -0
- package/tools/email_header_analyzer.py +426 -0
- package/tools/extraction_tools.py +250 -0
- package/tools/find_replace.py +1751 -0
- package/tools/folder_file_reporter.py +1463 -0
- package/tools/folder_file_reporter_adapter.py +480 -0
- package/tools/generator_tools.py +1217 -0
- package/tools/hash_generator.py +256 -0
- package/tools/html_tool.py +657 -0
- package/tools/huggingface_helper.py +449 -0
- package/tools/jsonxml_tool.py +730 -0
- package/tools/line_tools.py +419 -0
- package/tools/list_comparator.py +720 -0
- package/tools/markdown_tools.py +562 -0
- package/tools/mcp_widget.py +1417 -0
- package/tools/notes_widget.py +973 -0
- package/tools/number_base_converter.py +373 -0
- package/tools/regex_extractor.py +572 -0
- package/tools/slug_generator.py +311 -0
- package/tools/sorter_tools.py +459 -0
- package/tools/string_escape_tool.py +393 -0
- package/tools/text_statistics_tool.py +366 -0
- package/tools/text_wrapper.py +431 -0
- package/tools/timestamp_converter.py +422 -0
- package/tools/tool_loader.py +710 -0
- package/tools/translator_tools.py +523 -0
- package/tools/url_link_extractor.py +262 -0
- package/tools/url_parser.py +205 -0
- package/tools/whitespace_tools.py +356 -0
- package/tools/word_frequency_counter.py +147 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Text Statistics Tool Module - Comprehensive text analysis
|
|
3
|
+
|
|
4
|
+
This module provides detailed text statistics and analysis functionality
|
|
5
|
+
for the Pomera AI Commander application.
|
|
6
|
+
|
|
7
|
+
Features:
|
|
8
|
+
- Character count (with/without spaces)
|
|
9
|
+
- Word count
|
|
10
|
+
- Line count
|
|
11
|
+
- Sentence count
|
|
12
|
+
- Paragraph count
|
|
13
|
+
- Average word length
|
|
14
|
+
- Reading time estimate
|
|
15
|
+
- Most frequent words
|
|
16
|
+
- Unique word count
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import tkinter as tk
|
|
20
|
+
from tkinter import ttk
|
|
21
|
+
import re
|
|
22
|
+
from collections import Counter
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class TextStatisticsProcessor:
|
|
26
|
+
"""Text statistics processor with comprehensive analysis capabilities."""
|
|
27
|
+
|
|
28
|
+
@staticmethod
|
|
29
|
+
def analyze_text(text, words_per_minute=200, frequency_count=10):
|
|
30
|
+
"""Perform comprehensive text analysis."""
|
|
31
|
+
if not text.strip():
|
|
32
|
+
return {
|
|
33
|
+
"char_count": 0,
|
|
34
|
+
"char_count_no_spaces": 0,
|
|
35
|
+
"word_count": 0,
|
|
36
|
+
"line_count": 0,
|
|
37
|
+
"sentence_count": 0,
|
|
38
|
+
"paragraph_count": 0,
|
|
39
|
+
"avg_word_length": 0,
|
|
40
|
+
"reading_time_seconds": 0,
|
|
41
|
+
"unique_words": 0,
|
|
42
|
+
"top_words": []
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# Character counts
|
|
46
|
+
char_count = len(text)
|
|
47
|
+
char_count_no_spaces = len(text.replace(' ', '').replace('\t', '').replace('\n', '').replace('\r', ''))
|
|
48
|
+
|
|
49
|
+
# Word count
|
|
50
|
+
words = re.findall(r'\b\w+\b', text.lower())
|
|
51
|
+
word_count = len(words)
|
|
52
|
+
|
|
53
|
+
# Line count
|
|
54
|
+
lines = text.splitlines()
|
|
55
|
+
line_count = len(lines)
|
|
56
|
+
non_empty_lines = len([l for l in lines if l.strip()])
|
|
57
|
+
|
|
58
|
+
# Sentence count (approximate)
|
|
59
|
+
sentences = re.split(r'[.!?]+', text)
|
|
60
|
+
sentence_count = len([s for s in sentences if s.strip()])
|
|
61
|
+
|
|
62
|
+
# Paragraph count
|
|
63
|
+
paragraphs = re.split(r'\n\s*\n', text)
|
|
64
|
+
paragraph_count = len([p for p in paragraphs if p.strip()])
|
|
65
|
+
|
|
66
|
+
# Average word length
|
|
67
|
+
if words:
|
|
68
|
+
avg_word_length = sum(len(w) for w in words) / len(words)
|
|
69
|
+
else:
|
|
70
|
+
avg_word_length = 0
|
|
71
|
+
|
|
72
|
+
# Reading time
|
|
73
|
+
reading_time_seconds = (word_count / words_per_minute) * 60 if words_per_minute > 0 else 0
|
|
74
|
+
|
|
75
|
+
# Unique words
|
|
76
|
+
unique_words = len(set(words))
|
|
77
|
+
|
|
78
|
+
# Top words (excluding common stop words)
|
|
79
|
+
stop_words = {'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for',
|
|
80
|
+
'of', 'with', 'by', 'from', 'is', 'are', 'was', 'were', 'be', 'been',
|
|
81
|
+
'being', 'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would',
|
|
82
|
+
'could', 'should', 'may', 'might', 'must', 'shall', 'can', 'it', 'its',
|
|
83
|
+
'this', 'that', 'these', 'those', 'i', 'you', 'he', 'she', 'we', 'they'}
|
|
84
|
+
|
|
85
|
+
filtered_words = [w for w in words if w not in stop_words and len(w) > 1]
|
|
86
|
+
word_freq = Counter(filtered_words)
|
|
87
|
+
top_words = word_freq.most_common(frequency_count)
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
"char_count": char_count,
|
|
91
|
+
"char_count_no_spaces": char_count_no_spaces,
|
|
92
|
+
"word_count": word_count,
|
|
93
|
+
"line_count": line_count,
|
|
94
|
+
"non_empty_lines": non_empty_lines,
|
|
95
|
+
"sentence_count": sentence_count,
|
|
96
|
+
"paragraph_count": paragraph_count,
|
|
97
|
+
"avg_word_length": round(avg_word_length, 2),
|
|
98
|
+
"reading_time_seconds": round(reading_time_seconds),
|
|
99
|
+
"unique_words": unique_words,
|
|
100
|
+
"top_words": top_words
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@staticmethod
|
|
104
|
+
def format_reading_time(seconds):
|
|
105
|
+
"""Format reading time in human-readable format."""
|
|
106
|
+
if seconds < 60:
|
|
107
|
+
return f"{seconds} seconds"
|
|
108
|
+
elif seconds < 3600:
|
|
109
|
+
minutes = seconds // 60
|
|
110
|
+
secs = seconds % 60
|
|
111
|
+
if secs:
|
|
112
|
+
return f"{minutes} min {secs} sec"
|
|
113
|
+
return f"{minutes} min"
|
|
114
|
+
else:
|
|
115
|
+
hours = seconds // 3600
|
|
116
|
+
minutes = (seconds % 3600) // 60
|
|
117
|
+
return f"{hours} hr {minutes} min"
|
|
118
|
+
|
|
119
|
+
@staticmethod
|
|
120
|
+
def format_statistics(stats, show_frequency=True):
|
|
121
|
+
"""Format statistics as readable text output."""
|
|
122
|
+
output = []
|
|
123
|
+
output.append("=" * 50)
|
|
124
|
+
output.append("TEXT STATISTICS")
|
|
125
|
+
output.append("=" * 50)
|
|
126
|
+
output.append("")
|
|
127
|
+
output.append(f"Characters (total): {stats['char_count']:,}")
|
|
128
|
+
output.append(f"Characters (no spaces): {stats['char_count_no_spaces']:,}")
|
|
129
|
+
output.append(f"Words: {stats['word_count']:,}")
|
|
130
|
+
output.append(f"Unique Words: {stats['unique_words']:,}")
|
|
131
|
+
output.append(f"Lines (total): {stats['line_count']:,}")
|
|
132
|
+
output.append(f"Lines (non-empty): {stats['non_empty_lines']:,}")
|
|
133
|
+
output.append(f"Sentences: {stats['sentence_count']:,}")
|
|
134
|
+
output.append(f"Paragraphs: {stats['paragraph_count']:,}")
|
|
135
|
+
output.append(f"Average Word Length: {stats['avg_word_length']} characters")
|
|
136
|
+
output.append(f"Reading Time: {TextStatisticsProcessor.format_reading_time(stats['reading_time_seconds'])}")
|
|
137
|
+
|
|
138
|
+
if show_frequency and stats['top_words']:
|
|
139
|
+
output.append("")
|
|
140
|
+
output.append("-" * 50)
|
|
141
|
+
output.append("MOST FREQUENT WORDS")
|
|
142
|
+
output.append("-" * 50)
|
|
143
|
+
for i, (word, count) in enumerate(stats['top_words'], 1):
|
|
144
|
+
output.append(f" {i:2}. {word:<20} ({count:,} occurrences)")
|
|
145
|
+
|
|
146
|
+
output.append("")
|
|
147
|
+
output.append("=" * 50)
|
|
148
|
+
|
|
149
|
+
return '\n'.join(output)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class TextStatisticsWidget(ttk.Frame):
|
|
153
|
+
"""Widget for text statistics tool."""
|
|
154
|
+
|
|
155
|
+
def __init__(self, parent, app):
|
|
156
|
+
super().__init__(parent)
|
|
157
|
+
self.app = app
|
|
158
|
+
self.processor = TextStatisticsProcessor()
|
|
159
|
+
|
|
160
|
+
self.words_per_minute = tk.IntVar(value=200)
|
|
161
|
+
self.show_frequency = tk.BooleanVar(value=True)
|
|
162
|
+
self.frequency_count = tk.IntVar(value=10)
|
|
163
|
+
|
|
164
|
+
self.create_widgets()
|
|
165
|
+
self.load_settings()
|
|
166
|
+
|
|
167
|
+
def create_widgets(self):
|
|
168
|
+
"""Creates the widget interface."""
|
|
169
|
+
# Settings frame
|
|
170
|
+
settings_frame = ttk.LabelFrame(self, text="Settings", padding=10)
|
|
171
|
+
settings_frame.pack(fill=tk.X, padx=5, pady=5)
|
|
172
|
+
|
|
173
|
+
# Reading speed
|
|
174
|
+
speed_frame = ttk.Frame(settings_frame)
|
|
175
|
+
speed_frame.pack(fill=tk.X, pady=2)
|
|
176
|
+
ttk.Label(speed_frame, text="Reading Speed (WPM):").pack(side=tk.LEFT)
|
|
177
|
+
ttk.Spinbox(speed_frame, from_=100, to=500, width=5,
|
|
178
|
+
textvariable=self.words_per_minute,
|
|
179
|
+
command=self.on_setting_change).pack(side=tk.LEFT, padx=5)
|
|
180
|
+
|
|
181
|
+
# Show frequency
|
|
182
|
+
ttk.Checkbutton(settings_frame, text="Show Word Frequency",
|
|
183
|
+
variable=self.show_frequency,
|
|
184
|
+
command=self.on_setting_change).pack(anchor=tk.W, pady=2)
|
|
185
|
+
|
|
186
|
+
# Frequency count
|
|
187
|
+
freq_frame = ttk.Frame(settings_frame)
|
|
188
|
+
freq_frame.pack(fill=tk.X, pady=2)
|
|
189
|
+
ttk.Label(freq_frame, text="Top Words to Show:").pack(side=tk.LEFT)
|
|
190
|
+
ttk.Spinbox(freq_frame, from_=5, to=50, width=4,
|
|
191
|
+
textvariable=self.frequency_count,
|
|
192
|
+
command=self.on_setting_change).pack(side=tk.LEFT, padx=5)
|
|
193
|
+
|
|
194
|
+
# Buttons frame
|
|
195
|
+
buttons_frame = ttk.Frame(self)
|
|
196
|
+
buttons_frame.pack(pady=10)
|
|
197
|
+
|
|
198
|
+
ttk.Button(buttons_frame, text="Analyze Text",
|
|
199
|
+
command=self.analyze).pack(side=tk.LEFT, padx=5)
|
|
200
|
+
ttk.Button(buttons_frame, text="Word Frequency Counter",
|
|
201
|
+
command=self.word_frequency).pack(side=tk.LEFT, padx=5)
|
|
202
|
+
|
|
203
|
+
def load_settings(self):
|
|
204
|
+
"""Load settings from the application."""
|
|
205
|
+
settings = self.app.settings.get("tool_settings", {}).get("Text Statistics", {})
|
|
206
|
+
|
|
207
|
+
self.words_per_minute.set(settings.get("words_per_minute", 200))
|
|
208
|
+
self.show_frequency.set(settings.get("show_frequency", True))
|
|
209
|
+
self.frequency_count.set(settings.get("frequency_count", 10))
|
|
210
|
+
|
|
211
|
+
def save_settings(self):
|
|
212
|
+
"""Save current settings to the application."""
|
|
213
|
+
if "Text Statistics" not in self.app.settings["tool_settings"]:
|
|
214
|
+
self.app.settings["tool_settings"]["Text Statistics"] = {}
|
|
215
|
+
|
|
216
|
+
self.app.settings["tool_settings"]["Text Statistics"].update({
|
|
217
|
+
"words_per_minute": self.words_per_minute.get(),
|
|
218
|
+
"show_frequency": self.show_frequency.get(),
|
|
219
|
+
"frequency_count": self.frequency_count.get()
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
self.app.save_settings()
|
|
223
|
+
|
|
224
|
+
def on_setting_change(self, *args):
|
|
225
|
+
"""Handle setting changes."""
|
|
226
|
+
self.save_settings()
|
|
227
|
+
|
|
228
|
+
def analyze(self):
|
|
229
|
+
"""Analyze the input text."""
|
|
230
|
+
active_input_tab = self.app.input_tabs[self.app.input_notebook.index(self.app.input_notebook.select())]
|
|
231
|
+
input_text = active_input_tab.text.get("1.0", tk.END).rstrip('\n')
|
|
232
|
+
|
|
233
|
+
stats = TextStatisticsProcessor.analyze_text(
|
|
234
|
+
input_text,
|
|
235
|
+
self.words_per_minute.get(),
|
|
236
|
+
self.frequency_count.get()
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
result = TextStatisticsProcessor.format_statistics(
|
|
240
|
+
stats,
|
|
241
|
+
self.show_frequency.get()
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
active_output_tab = self.app.output_tabs[self.app.output_notebook.index(self.app.output_notebook.select())]
|
|
245
|
+
active_output_tab.text.config(state="normal")
|
|
246
|
+
active_output_tab.text.delete("1.0", tk.END)
|
|
247
|
+
active_output_tab.text.insert("1.0", result)
|
|
248
|
+
active_output_tab.text.config(state="disabled")
|
|
249
|
+
|
|
250
|
+
self.app.update_all_stats()
|
|
251
|
+
|
|
252
|
+
def word_frequency(self):
|
|
253
|
+
"""Generate word frequency report."""
|
|
254
|
+
active_input_tab = self.app.input_tabs[self.app.input_notebook.index(self.app.input_notebook.select())]
|
|
255
|
+
input_text = active_input_tab.text.get("1.0", tk.END).rstrip('\n')
|
|
256
|
+
|
|
257
|
+
if not input_text.strip():
|
|
258
|
+
return
|
|
259
|
+
|
|
260
|
+
# Use the same word extraction logic as analyze_text
|
|
261
|
+
words = re.findall(r'\b\w+\b', input_text.lower())
|
|
262
|
+
if not words:
|
|
263
|
+
result = "No words found."
|
|
264
|
+
else:
|
|
265
|
+
word_counts = Counter(words)
|
|
266
|
+
total_words = len(words)
|
|
267
|
+
|
|
268
|
+
report = []
|
|
269
|
+
report.append("=" * 50)
|
|
270
|
+
report.append("WORD FREQUENCY COUNTER")
|
|
271
|
+
report.append("=" * 50)
|
|
272
|
+
report.append("")
|
|
273
|
+
for word, count in word_counts.most_common():
|
|
274
|
+
percentage = (count / total_words) * 100
|
|
275
|
+
report.append(f"{word:<20} {count:>6} ({percentage:>6.2f}%)")
|
|
276
|
+
report.append("")
|
|
277
|
+
report.append(f"Total words: {total_words}")
|
|
278
|
+
report.append("=" * 50)
|
|
279
|
+
result = '\n'.join(report)
|
|
280
|
+
|
|
281
|
+
active_output_tab = self.app.output_tabs[self.app.output_notebook.index(self.app.output_notebook.select())]
|
|
282
|
+
active_output_tab.text.config(state="normal")
|
|
283
|
+
active_output_tab.text.delete("1.0", tk.END)
|
|
284
|
+
active_output_tab.text.insert("1.0", result)
|
|
285
|
+
active_output_tab.text.config(state="disabled")
|
|
286
|
+
|
|
287
|
+
self.app.update_all_stats()
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
class TextStatistics:
|
|
291
|
+
"""Main class for Text Statistics integration."""
|
|
292
|
+
|
|
293
|
+
def __init__(self):
|
|
294
|
+
self.processor = TextStatisticsProcessor()
|
|
295
|
+
|
|
296
|
+
def create_widget(self, parent, app):
|
|
297
|
+
"""Create and return the Text Statistics widget."""
|
|
298
|
+
return TextStatisticsWidget(parent, app)
|
|
299
|
+
|
|
300
|
+
def get_default_settings(self):
|
|
301
|
+
"""Return default settings for Text Statistics."""
|
|
302
|
+
return {
|
|
303
|
+
"words_per_minute": 200,
|
|
304
|
+
"show_frequency": True,
|
|
305
|
+
"frequency_count": 10
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
def process_text(self, input_text, settings):
|
|
309
|
+
"""Process text and return statistics."""
|
|
310
|
+
stats = TextStatisticsProcessor.analyze_text(
|
|
311
|
+
input_text,
|
|
312
|
+
settings.get("words_per_minute", 200),
|
|
313
|
+
settings.get("frequency_count", 10)
|
|
314
|
+
)
|
|
315
|
+
return TextStatisticsProcessor.format_statistics(
|
|
316
|
+
stats,
|
|
317
|
+
settings.get("show_frequency", True)
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
# BaseTool-compatible wrapper
|
|
322
|
+
try:
|
|
323
|
+
from tools.base_tool import BaseTool
|
|
324
|
+
from typing import Dict, Any
|
|
325
|
+
import tkinter as tk
|
|
326
|
+
from tkinter import ttk
|
|
327
|
+
|
|
328
|
+
class TextStatisticsV2(BaseTool):
|
|
329
|
+
"""
|
|
330
|
+
BaseTool-compatible version of TextStatistics.
|
|
331
|
+
"""
|
|
332
|
+
|
|
333
|
+
TOOL_NAME = "Text Statistics"
|
|
334
|
+
TOOL_DESCRIPTION = "Analyze text and show character, word, line counts, etc."
|
|
335
|
+
TOOL_VERSION = "2.0.0"
|
|
336
|
+
|
|
337
|
+
def process_text(self, input_text: str, settings: Dict[str, Any]) -> str:
|
|
338
|
+
"""Process text and return statistics."""
|
|
339
|
+
stats = TextStatisticsProcessor.analyze_text(
|
|
340
|
+
input_text,
|
|
341
|
+
settings.get("words_per_minute", 200),
|
|
342
|
+
settings.get("frequency_count", 10)
|
|
343
|
+
)
|
|
344
|
+
return TextStatisticsProcessor.format_statistics(
|
|
345
|
+
stats,
|
|
346
|
+
settings.get("show_frequency", True)
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
def get_default_settings(self) -> Dict[str, Any]:
|
|
350
|
+
return {
|
|
351
|
+
"words_per_minute": 200,
|
|
352
|
+
"show_frequency": True,
|
|
353
|
+
"frequency_count": 10
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
def create_ui(self, parent: tk.Widget, settings: Dict[str, Any],
|
|
357
|
+
on_change=None, on_apply=None) -> tk.Widget:
|
|
358
|
+
"""Create a simple UI for Text Statistics."""
|
|
359
|
+
frame = ttk.Frame(parent)
|
|
360
|
+
ttk.Label(frame, text="Analyze text statistics").pack(side=tk.LEFT, padx=5)
|
|
361
|
+
if on_apply:
|
|
362
|
+
ttk.Button(frame, text="Analyze", command=on_apply).pack(side=tk.LEFT, padx=5)
|
|
363
|
+
return frame
|
|
364
|
+
|
|
365
|
+
except ImportError:
|
|
366
|
+
pass
|