import re import math import json import string import tempfile import os from collections import Counter from html.parser import HTMLParser from typing import Dict, List, Tuple, Any, Optional import xml.etree.ElementTree as ET import gradio as gr # ===================================================================== # CUSTOM CORE PARSERS & HELPERS (NO EXTERNAL NLP LIBRARIES) # ===================================================================== class SimpleHTMLInspector(HTMLParser): """ A lightweight, pure-Python HTML inspector utilizing standard HTMLParser. Fulfills educational HTML analysis without external BeautifulSoup or library dependencies. """ def __init__(self): super().__init__() self.tags: List[str] = [] self.content_map: List[Tuple[str, str]] = [] self.tag_stack: List[str] = [] def handle_starttag(self, tag: str, attrs: List[Tuple[str, Optional[str]]]): self.tags.append(tag) self.tag_stack.append(tag) def handle_data(self, data: str): cleaned = data.strip() if cleaned: current_tag = self.tag_stack[-1] if self.tag_stack else "text" # Ignore style/script data for clean text preview if current_tag not in ["script", "style"]: self.content_map.append((current_tag, cleaned)) def handle_endtag(self, tag: str): if self.tag_stack and self.tag_stack[-1] == tag: self.tag_stack.pop() def parse_csv_custom(text: str, delimiter: str = ",") -> Tuple[List[str], List[List[str]], int, int]: """ A custom state-machine CSV parser built from scratch. Complies with rules: No import csv, manages quote boundaries, escaped quotes, and newlines correctly. """ lines = text.splitlines() if not lines: return [], [], 0, 0 parsed_rows: List[List[str]] = [] for line in lines: if not line.strip(): continue row_fields = [] current_field = [] in_quotes = False i = 0 n = len(line) while i < n: char = line[i] if in_quotes: if char == '"': # Lookahead for escaped quote if i + 1 < n and line[i+1] == '"': current_field.append('"') i += 2 continue else: in_quotes = False else: current_field.append(char) else: if char == '"': in_quotes = True elif char == delimiter: row_fields.append("".join(current_field)) current_field = [] else: current_field.append(char) i += 1 row_fields.append("".join(current_field)) parsed_rows.append(row_fields) if not parsed_rows: return [], [], 0, 0 headers = parsed_rows[0] data_rows = parsed_rows[1:] if len(parsed_rows) > 1 else [] col_count = len(headers) row_count = len(parsed_rows) return headers, data_rows, row_count, col_count def detect_dominant_delimiter(text: str) -> str: """ Analyzes lines to guess if the delimiter is comma, semicolon, or tab. Looks for the highest count with consistency across initial lines. """ candidates = [",", ";", "\t"] sample_lines = [l for l in text.splitlines()[:5] if l.strip()] if not sample_lines: return "," best_delim = "," best_score = -1 for delim in candidates: counts = [line.count(delim) for line in sample_lines] avg_count = sum(counts) / len(counts) # Minimize standard deviation for structural consistency variance = sum((c - avg_count)**2 for c in counts) / len(counts) if avg_count > 0.5: score = avg_count / (1.0 + variance) # high frequency, low variation if score > best_score: best_score = score best_delim = delim return best_delim # ===================================================================== # TEXT ANALYZER CORE LOGIC # ===================================================================== class TextAnalyzer: """ The monolithic analysis processor wrapping all character, unicode, word, sentence, regex, and structured analyses. """ def __init__(self, text: str): self.text = text self.bytes_data = text.encode("utf-8") # Simple structural tokenizer self.lines = text.splitlines() # Word extraction without NLP: lowercase for counts, standard regex boundary matches self.words_raw = re.findall(r'\b[a-zA-Z0-9_\'-]+\b', text) self.words = [w.strip() for w in self.words_raw if w.strip()] # Sentence segmentation heuristic (split on . ! ? followed by space/line bounds) self.sentences = [s.strip() for s in re.split(r'[.!?]+(?=\s|$)', text) if s.strip()] def get_overview(self) -> Dict[str, Any]: """Module 1: General document measurements.""" char_count = len(self.text) word_count = len(self.words) sentence_count = max(1 if word_count > 0 and not self.sentences else 0, len(self.sentences)) line_count = len(self.lines) # Paragraphs: split by multiple empty lines paragraphs = [p for p in re.split(r'\n\s*\n', self.text) if p.strip()] paragraph_count = len(paragraphs) byte_count = len(self.bytes_data) avg_word_length = sum(len(w) for w in self.words) / word_count if word_count > 0 else 0.0 avg_sentence_length = word_count / sentence_count if sentence_count > 0 else 0.0 return { "char_count": char_count, "word_count": word_count, "sentence_count": sentence_count, "line_count": line_count, "paragraph_count": paragraph_count, "byte_count": byte_count, "avg_word_length": round(avg_word_length, 2), "avg_sentence_length": round(avg_sentence_length, 2), } def generate_encoding_table(self, max_chars: int = 150) -> List[List[str]]: """ Module 2: Technical character encodings mappings. Limits rows to avoid crashing browser windows with massive datasets. """ rows = [] for char in self.text[:max_chars]: dec = ord(char) hex_val = f"0x{dec:X}" bin_val = f"{dec:08b}" # ASCII validation ascii_repr = char if dec < 128 else "N/A" if dec < 32 or dec == 127: ascii_repr = "Control Char" if dec != 10 and dec != 9 else ("[LF]" if dec == 10 else "[TAB]") unicode_point = f"U+{dec:04X}" # UTF-8 details utf8_bytes = char.encode("utf-8") utf8_len = len(utf8_bytes) utf8_bytes_str = " ".join(f"{b:02X}" for b in utf8_bytes) rows.append([ char if dec >= 32 else " ", ascii_repr, unicode_point, str(dec), hex_val, bin_val, f"{utf8_len} byte(s)", utf8_bytes_str ]) return rows def generate_unicode_explorer(self, max_chars: int = 100) -> str: """ Module 3: Educational breakdown highlighting the prefix bit structure of UTF-8. Provides highly descriptive, interactive visual representation of multibyte UTF-8. """ html = ['
'] limit_text = self.text[:max_chars] for idx, char in enumerate(limit_text): dec_val = ord(char) cp = f"U+{dec_val:04X}" utf8_b = char.encode("utf-8") html.append('
') # Character Display Panel char_display = char if dec_val >= 32 else f"CTRL({dec_val})" html.append(f'
') html.append(f'
{char_display}
') html.append(f'
') html.append(f'
Character #{idx + 1}
') html.append(f'
{cp}
') html.append(f'
') html.append(f'
') # Binary byte representation detail html.append('
') html.append('
UTF-8 Bit Structure:
') for b in utf8_b: bin_str = f"{b:08b}" # Format markers with color spans according to UTF-8 rule if len(utf8_b) == 1: # Single Byte (ASCII): 0xxxxxxx formatted_bin = f"0{bin_str[1:]}" lbl = "ASCII Pattern" elif len(utf8_b) == 2: if b == utf8_b[0]: formatted_bin = f"110{bin_str[3:]}" lbl = "2-Byte Header" else: formatted_bin = f"10{bin_str[2:]}" lbl = "Data Byte" elif len(utf8_b) == 3: if b == utf8_b[0]: formatted_bin = f"1110{bin_str[4:]}" lbl = "3-Byte Header" else: formatted_bin = f"10{bin_str[2:]}" lbl = "Data Byte" else: # 4-byte sequences if b == utf8_b[0]: formatted_bin = f"11110{bin_str[5:]}" lbl = "4-Byte Header (Emoji/Rare)" else: formatted_bin = f"10{bin_str[2:]}" lbl = "Data Byte" html.append(f'
') html.append(f' ({lbl})') html.append(f' {formatted_bin}') html.append(f'
') html.append('
') # end byte display html.append('
') # end card html.append('
') if len(self.text) > max_chars: html.append(f'
Displaying first {max_chars} characters. Your input has {len(self.text)} total chars.
') return "\n".join(html) def get_char_frequencies(self) -> List[Tuple[str, int, float]]: """Module 4: Sort and measure character densities.""" total = len(self.text) if total == 0: return [] cnt = Counter(self.text) sorted_chars = cnt.most_common() return [(c, count, round((count / total) * 100, 2)) for c, count in sorted_chars] def get_word_frequencies(self) -> List[Tuple[str, int]]: """Module 5: Tokenize, clean and compute high vocabulary counts.""" if not self.words: return [] normalized_words = [w.lower() for w in self.words] cnt = Counter(normalized_words) return cnt.most_common() def get_string_statistics(self) -> Dict[str, Any]: """Module 6: Text measurements and distributions.""" unique_words = len(set(w.lower() for w in self.words)) unique_chars = len(set(self.text)) whitespace_count = sum(1 for c in self.text if c.isspace()) tab_count = self.text.count('\t') newline_count = self.text.count('\n') digit_count = sum(1 for c in self.text if c.isdigit()) uppercase_count = sum(1 for c in self.text if c.isupper()) lowercase_count = sum(1 for c in self.text if c.islower()) # Punctuation set (Standard English keys + Unicode counterparts) punct_set = set(string.punctuation) | {'“', '”', '‘', '’', '—', '–', '…', '¿', '¡'} punctuation_count = sum(1 for c in self.text if c in punct_set) longest_word = max(self.words, key=len) if self.words else "" shortest_word = min(self.words, key=len) if self.words else "" return { "longest_word": longest_word, "shortest_word": shortest_word, "unique_words": unique_words, "unique_characters": unique_chars, "whitespace_count": whitespace_count, "tab_count": tab_count, "newline_count": newline_count, "digit_count": digit_count, "uppercase_count": uppercase_count, "lowercase_count": lowercase_count, "punctuation_count": punctuation_count } def run_regex_explorer(self) -> Dict[str, List[str]]: """ Module 7: Matches semantic groups matching pre-defined structural regex rules. """ patterns = { "Emails": r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', "URLs": r'https?://(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&//=]*)', "Phone numbers": r'\+?[0-9]{1,4}?[-.\s]?(?:\([0-9]{1,3}\)|[0-9]{1,3})[-.\s]?[0-9]{1,4}[-.\s]?[0-9]{1,4}[-.\s]?[0-9]{1,9}', "Dates": r'\d{4}[-/.]\d{1,2}[-/.]\d{1,2}|\d{1,2}[-/.]\d{1,2}[-/.]\d{2,4}', "Times": r'\b(?:[01]?\d|2[0-3]):[0-5]\d(?::[0-5]\d)?\s?(?:AM|PM|am|pm)?\b', "Numbers": r'\b\d+(?:\.\d+)?\b', "Currency values": r'(?:\$|€|£|¥|₹)\s?\d+(?:,\d{3})*(?:\.\d+)?\b|\b\d+(?:\.\d+)?\s?(?:USD|EUR|GBP|JPY|INR)\b', "Hashtags": r'#[a-zA-Z0-9_]+', "Mentions": r'@[a-zA-Z0-9_]+', "IP addresses": r'\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b' } matches = {} for title, pattern in patterns.items(): found = re.findall(pattern, self.text) # Remove empty strings or simple fragments matches[title] = [f.strip() for f in found if f.strip()] return matches def detect_format(self) -> Tuple[str, str]: """ Module 8: Text Format Detection. Evaluates criteria and supplies natural explaining logic for findings. """ txt = self.text.strip() if not txt: return "Empty Input", "No text provided to detect structural formats." # JSON detection try: json.loads(txt) return "JSON (Valid)", "Parsed cleanly into key-value trees or arrays using standard python serialization (json.loads)." except json.JSONDecodeError: if (txt.startswith('{') and txt.endswith('}')) or (txt.startswith('[') and txt.endswith(']')): return "JSON (Malformed)", "Begins/ends with brackets ({}, []), but contains syntactic errors like misplaced commas or string literals." # XML detection try: ET.fromstring(txt) return "XML (Valid)", "Parsed successfully using standard ElementTree XML architecture." except ET.ParseError: if re.search(r'<\?xml', txt, re.I) or (txt.startswith('<') and txt.endswith('>')): return "XML (Malformed)", "Starts/ends with tags or contains XML headers, but fails parser schemas." # HTML detection html_sig_tags = r']*)*>', txt) if re.search(html_sig_tags, txt, re.I) or len(tags_found) > 4: return "HTML", f"Contains signature tags (matched {len(tags_found)} raw HTML elements) or document structures like ''." # Markdown detection md_points = 0 reasons = [] if re.search(r'^(?:#|##|###|####|#####|######)\s+.+', txt, re.M): md_points += 2 reasons.append("Contains structural section indicators (# Header)") if re.search(r'\[.+?\]\(https?://.+?\)', txt): md_points += 2 reasons.append("Identified Markdown link structures: [text](URL)") if re.search(r'^[*-]\s+\w+', txt, re.M): md_points += 1 reasons.append("Identified bullet lists (- or *)") if re.search(r'^```\w*\n', txt, re.M): md_points += 3 reasons.append("Identified structural code fencing tags (```)") if md_points >= 3: return "Markdown", f"Identified markdown layout markers: {', '.join(reasons)}." # CSV/TSV detection delim = detect_dominant_delimiter(self.text) lines_with_delim = [l for l in self.text.splitlines() if delim in l] if len(lines_with_delim) >= 2: # Check consistency of delimiter count counts = [l.count(delim) for l in lines_with_delim[:5]] avg_count = sum(counts) / len(counts) variance = sum((c - avg_count)**2 for c in counts) / len(counts) if avg_count > 0 and variance < 1.5: delim_name = "Comma" if delim == "," else ("Semicolon" if delim == ";" else "Tab") return f"CSV / Delimited Text", f"Structured grid properties detected using consistently spaced delimiter: '{delim_name}' (average spacing density: {avg_count:.1f} per line)." return "Plain Text (General)", "Default categorization. Contains no specialized programmatic structure, markup schemas, or clear delimiters." # ===================================================================== # UI GENERATION HELPER FUNCTIONS # ===================================================================== def analyze_all_inputs(text: str) -> List[Any]: """ Main callback updating all visual components in Gradio blocks concurrently. """ if not text or not text.strip(): # Fallback values empty_overview_html = "
Please supply valid text or load a sample.
" empty_tbl = [] return [ empty_overview_html, empty_tbl, empty_overview_html, empty_tbl, empty_tbl, empty_overview_html, empty_overview_html, empty_overview_html, empty_overview_html, "" ] analyzer = TextAnalyzer(text) # Overview ov = analyzer.get_overview() ov_html = f"""
Characters {ov['char_count']:,}
Words {ov['word_count']:,}
Sentences {ov['sentence_count']:,}
Bytes (UTF-8) {ov['byte_count']:,}
Lines {ov['line_count']:,}
Paragraphs {ov['paragraph_count']:,}
Avg Word Length {ov['avg_word_length']} chars
Avg Sentence Length {ov['avg_sentence_length']} words
""" # Visual Charts using Tailwind (Avoid high load graphics libraries) chars_stat = analyzer.get_string_statistics() total_measurable = max(1, chars_stat["uppercase_count"] + chars_stat["lowercase_count"] + chars_stat["digit_count"] + chars_stat["punctuation_count"] + chars_stat["whitespace_count"]) def pct(val): return (val / total_measurable) * 100 overview_chart_html = f"""

Character Class Distribution Ratio:

Lowercase ({chars_stat['lowercase_count']})
Uppercase ({chars_stat['uppercase_count']})
Digits ({chars_stat['digit_count']})
Punctuation ({chars_stat['punctuation_count']})
Whitespace ({chars_stat['whitespace_count']})
""" # Encodings Table encodings_data = analyzer.generate_encoding_table() # Unicode Inspector unicode_html = analyzer.generate_unicode_explorer() # Frequencies char_freqs = [[repr(c)[1:-1] if c != '\n' else '[LF]', count, f"{pct:.1f}%"] for c, count, pct in analyzer.get_char_frequencies()] word_freqs = [[word, count] for word, count in analyzer.get_word_frequencies()[:100]] # Detailed statistics mappings stats_data = [ ["Property Metric", "Value", "Educational Context"], ["Longest word length", f"{len(chars_stat['longest_word'])} chars ('{chars_stat['longest_word']}')" if chars_stat['longest_word'] else "N/A", "Useful for finding outlier anomalies or unspaced strings."], ["Shortest word length", f"{len(chars_stat['shortest_word'])} chars ('{chars_stat['shortest_word']}')" if chars_stat['shortest_word'] else "N/A", "Averages lower for basic grammar prepositions."], ["Unique vocabulary (Words)", str(chars_stat['unique_words']), "Vocabulary density indicator before lemmatization / stemming."], ["Unique character keys", str(chars_stat['unique_characters']), "Alphabet size of current document schema."], ["Whitespace instances", str(chars_stat['whitespace_count']), "Sum of space, newline, tab occurrences."], ["Tab character counts", str(chars_stat['tab_count']), "Important identifier for tab-separated grids or indent properties."], ["Line feeds (Newlines)", str(chars_stat['newline_count']), "Tells us structural grouping spacing parameters."], ["Number instances", str(chars_stat['digit_count']), "Shows the count of raw numerals."], ["Uppercase keys", str(chars_stat['uppercase_count']), "Casing properties indicating structural sentences or nouns."], ["Lowercase keys", str(chars_stat['lowercase_count']), "Standard core text body."], ["Punctuation marks", str(chars_stat['punctuation_count']), "Sentence partitions and code punctuation keys."] ] # Regex Matches HTML Builder regex_matches = analyzer.run_regex_explorer() regex_html = ['
'] for category, list_matches in regex_matches.items(): count = len(list_matches) color = "emerald" if count > 0 else "slate" badge_class = f"bg-{color}-100 text-{color}-800 dark:bg-{color}-950 dark:text-{color}-300" regex_html.append(f'
') regex_html.append(f'
') regex_html.append(f'

{category}

') regex_html.append(f' {count} matches') regex_html.append(f'
') if count > 0: # Highlight items in tags items_html = " ".join(f'{m}' for m in set(list_matches[:30])) if len(list_matches) > 30: items_html += f' ...and {len(list_matches)-30} more' regex_html.append(f'
{items_html}
') else: regex_html.append(f'

No matches detected in this pattern configuration.

') regex_html.append('
') regex_html.append('
') regex_html_str = "\n".join(regex_html) # Text Formats Detection format_type, format_desc = analyzer.detect_format() format_html_str = f"""
Identified Schema Format

{format_type}

{format_desc}

""" # Sub-Inspectors (CSV, HTML) csv_html_str = "

CSV structures not detected. This explorer will display formatting tables if text looks tabular.

" if "CSV" in format_type or "," in text or ";" in text or "\t" in text: delim = detect_dominant_delimiter(text) try: headers, data_rows, r_cnt, c_cnt = parse_csv_custom(text, delim) if r_cnt > 0: # Limit row views preview_rows = data_rows[:10] rows_html = "".join(f"" + "".join(f"{col}" for col in row) + "" for row in preview_rows) headers_html = "".join(f"{h}" for h in headers) csv_html_str = f"""
Parser Output: {r_cnt} Rows × {c_cnt} Columns Delimiter: '{delim}'
{headers_html}{rows_html}
{f'
Showing top 10 preview rows
' if len(data_rows) > 10 else ''}
""" except Exception as e: csv_html_str = f"

Failed standard CSV matrix processing: {str(e)}

" # HTML parsing extraction using SimpleHTMLInspector html_details_str = "

HTML markup pattern matches not found.

" if "HTML" in format_type or "<" in text: try: parser = SimpleHTMLInspector() parser.feed(text) tag_counts = Counter(parser.tags) tags_stat_html = " ".join(f"<{tag}> ({cnt})" for tag, cnt in tag_counts.items()) # Content mapping lists content_preview_html = "".join(f"
<{tag}>{data}
" for tag, data in parser.content_map[:15]) html_details_str = f"""
Tag Counts (Structure Streams)
{tags_stat_html if tags_stat_html else 'No tag keys found.'}
Tag Text Extraction Preview
{content_preview_html if content_preview_html else '
No clean text stream mapped inside tags.
'}
{f'
Displaying first 15 mapped nodes
' if len(parser.content_map) > 15 else ''}
""" except Exception as e: html_details_str = f"

HTML parser trace error: {str(e)}

" return [ ov_html, encodings_data, unicode_html, char_freqs, word_freqs, stats_data, regex_html_str, format_html_str, csv_html_str, html_details_str, overview_chart_html ] def handle_file_upload(file_obj) -> str: """ Reads the file path securely and returns decoded text. Handles decoding failures gracefully by falling back to errors or latin-1. """ if file_obj is None: return "" try: # File object passed is a tempfile wrapper path in Gradio with open(file_obj.name, "rb") as f: bytes_content = f.read() try: return bytes_content.decode("utf-8") except UnicodeDecodeError: # Fallback to Latin-1 encoding to preserve characters cleanly return bytes_content.decode("latin-1") except Exception as e: return f"File load error: {str(e)}" def generate_report(text: str) -> str: """ Fulfills Module 11: Export downloadable analysis reports. Formats analysis sections into a beautifully structured Markdown report file. """ if not text or not text.strip(): # Fallback empty path temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".md") temp_file.write("# No analysis data available\nPlease submit text first.".encode('utf-8')) temp_file.close() return temp_file.name analyzer = TextAnalyzer(text) ov = analyzer.get_overview() chars_stat = analyzer.get_string_statistics() fmt, desc = analyzer.detect_format() regex_matches = analyzer.run_regex_explorer() char_freqs = analyzer.get_char_frequencies()[:20] word_freqs = analyzer.get_word_frequencies()[:20] report = [] report.append("# Text Explorer Analysis Report") report.append(f"Generated on: 2026-07-05 (System Analysis)\n") report.append("---") report.append("## 1. Document Overview Statistics") report.append(f"- **Characters (Count)**: {ov['char_count']}") report.append(f"- **Words (Count)**: {ov['word_count']}") report.append(f"- **Sentences**: {ov['sentence_count']}") report.append(f"- **Line count**: {ov['line_count']}") report.append(f"- **Paragraphs**: {ov['paragraph_count']}") report.append(f"- **Bytes (Size)**: {ov['byte_count']} bytes") report.append(f"- **Average Word Length**: {ov['avg_word_length']} characters") report.append(f"- **Average Sentence Length**: {ov['avg_sentence_length']} words\n") report.append("## 2. Text Format Classification") report.append(f"- **Detected Structure Format**: {fmt}") report.append(f"- **Deduction Reason**: {desc}\n") report.append("## 3. String & Lexical Statistics") report.append(f"- **Longest word**: '{chars_stat['longest_word']}'") report.append(f"- **Shortest word**: '{chars_stat['shortest_word']}'") report.append(f"- **Unique words**: {chars_stat['unique_words']}") report.append(f"- **Unique characters**: {chars_stat['unique_characters']}") report.append(f"- **Whitespaces total**: {chars_stat['whitespace_count']}") report.append(f"- **Tabs**: {chars_stat['tab_count']}") report.append(f"- **Newlines**: {chars_stat['newline_count']}") report.append(f"- **Numerics (Digits)**: {chars_stat['digit_count']}") report.append(f"- **Uppercase characters**: {chars_stat['uppercase_count']}") report.append(f"- **Lowercase characters**: {chars_stat['lowercase_count']}") report.append(f"- **Punctuation keys**: {chars_stat['punctuation_count']}\n") report.append("## 4. Top 20 Character Frequencies") report.append("| Character | Count | Percentage |") report.append("| :--- | :--- | :--- |") for char, cnt, pct in char_freqs: c_repr = repr(char)[1:-1] if char != '\n' else '[LF]' report.append(f"| `{c_repr}` | {cnt} | {pct:.1f}% |") report.append("\n") report.append("## 5. Top 20 Vocabulary Word Frequencies") report.append("| Word | Count |") report.append("| :--- | :--- |") for word, cnt in word_freqs: report.append(f"| {word} | {cnt} |") report.append("\n") report.append("## 6. Regex Inspector Discoveries") for key, items in regex_matches.items(): if items: report.append(f"- **{key}** ({len(items)} found): {', '.join(set(items[:15]))}") else: report.append(f"- **{key}**: 0 instances detected.") report.append("\n---\n*Report generated by Text Explorer Space (Pure Python Educational Analyzer).*") # Write out to temporary local file path temp_dir = tempfile.gettempdir() file_path = os.path.join(temp_dir, "text_explorer_report.md") with open(file_path, "w", encoding="utf-8") as f: f.write("\n".join(report)) return file_path # ===================================================================== # CUSTOM CSS STYLE DEFINITIONS FOR THE GRADIO THEME # ===================================================================== CSS = """ body { background-color: #f8fafc; } .gradio-container { font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; } .header-hero { background: linear-gradient(135deg, #4f46e5 0%, #2563eb 100%); color: white !important; border-radius: 1rem; padding: 2.5rem 2rem; margin-bottom: 2rem; text-align: center; box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); } .header-hero h1 { color: white !important; font-weight: 900 !important; letter-spacing: -0.025em; font-size: 2.25rem !important; margin-bottom: 0.5rem; } .header-hero p { color: #e0e7ff !important; font-size: 1rem; } .educational-card { background-color: #f0fdfa; border: 1px solid #ccfbf1; border-radius: 0.75rem; padding: 1rem; margin-bottom: 1rem; } .educational-card h4 { color: #0f766e !important; margin-top: 0 !important; } .educational-card p, .educational-card li { color: #115e59 !important; font-size: 0.875rem !important; } """ # ===================================================================== # SAMPLE TEXTSETS FOR CONVENIENT USER EXPERIENCES # ===================================================================== SAMPLES = { "Simple English": "Hello World! Feel free to paste any text here to test the NLP Text Explorer system. It works immediately without external libraries.", "Multilingual & Emoji": "Multilingual test: Bonjour, こんにちは, 안녕하세요! Here is an emoji breakdown to inspect UTF-8 bytes: 😊 🚀 🍕. What is their representation in binary memory space?", "HTML document sample": '\n\n\n Sample Sandbox\n\n\n
\n

Welcome to Text Explorer!

\n

This is standard markup designed to verify our pure HTML-Parser extraction utilities.

\n Visit our project\n
\n\n', "Tabular CSV format": "username,email,role,joined_date\nsmith_john,john.smith@gmail.com,Administrator,2024-03-24\elizabeth_k,k.elizabeth@yahoo.com,Contributor,2025-05-15\ntech_support,support@domain.org,User,2026-01-10", "Markdown document": ( "# Markdown Document Guide\n\n" "Welcome to this structural text parsing review. Here are some key attributes:\n\n" "- Support lists\n- Supports link items: [Hugging Face Space](https://huggingface.co/spaces)\n\n" "## Sub-headers\n" "```python\n" "def test():\n" " return 'Hello, Markdown analyzer!'\n" "```" ) } # ===================================================================== # GRADIO BLOCKS APPLICATION VIEW # ===================================================================== with gr.Blocks(css=CSS, title="Text Explorer - Educational Pre-NLP Inspector") as demo: # Hero Title Banner gr.HTML("""

🔍 Text Explorer

Analyze and demystify raw character representation, encodings, byte streams, and structural text layouts before high-level NLP tokenization.

""") with gr.Row(): # Input column with gr.Column(scale=4): gr.Markdown("### 📥 Document Source Input") input_text = gr.Textbox( label="Source Text Area", placeholder="Paste your paragraphs, CSV structure, HTML content, or multilingual strings here...", lines=10, max_lines=25, elem_id="input-textbox" ) with gr.Row(): file_upload = gr.File( label="Or Upload Text File (.txt, .csv, .json, .html, .md)", file_types=[".txt", ".csv", ".json", ".html", ".md"], type="filepath", ) gr.Markdown("💡 **Educational Presets**") with gr.Row(): # Loop samples to create buttons for name, content in SAMPLES.items(): gr.Button(name, size="sm").click( fn=lambda val=content: val, outputs=input_text ) # Output / Analysis display tab matrix with gr.Column(scale=6): gr.Markdown("### ⚡ Real-Time Analytical Breakdown") with gr.Tabs(): # Overview with gr.TabItem("📊 Overview"): with gr.Accordion("📚 Educational Spotlight: The Lexical Units", open=True): gr.HTML("""

How Computers Partition Text

Before an NLP model can comprehend context, the document must be mathematically measured:

""") overview_html = gr.HTML("
Analyze text to generate document insights.
") overview_chart = gr.HTML() # Character Encodings with gr.TabItem("🔢 Encodings Table"): with gr.Accordion("🏫 Educational Spotlight: Encodings Simplified", open=False): gr.HTML("""

Encoding Architecture Explained

Every character is assigned a unique tracking coordinate:

""") encoding_table = gr.DataFrame( headers=["Char", "ASCII Representation", "Unicode Point", "Decimal", "Hexadecimal", "Binary Value", "UTF-8 Length", "UTF-8 Bytes"], datatype=["str", "str", "str", "str", "str", "str", "str", "str"], wrap=True ) # Unicode Explorer with gr.TabItem("🌌 Unicode Explorer"): with gr.Accordion("🎓 Educational Spotlight: Bit Patterns of UTF-8", open=False): gr.HTML("""

Deciphering the UTF-8 Multi-byte Rules

UTF-8 dynamically sizes bytes based on prefix triggers. Inspect the binary tags below:

""") unicode_explorer_html = gr.HTML("
Displaying individual unicode bit structures...
") # Frequencies with gr.TabItem("📈 Frequencies"): with gr.Row(): with gr.Column(): gr.Markdown("#### Character Frequency Analysis") char_freq_table = gr.DataFrame( headers=["Character Key", "Occurrence", "Ratio"], datatype=["str", "number", "str"] ) with gr.Column(): gr.Markdown("#### Word Frequency Analysis (Vocabulary)") word_freq_table = gr.DataFrame( headers=["Lowercased Token", "Occurrence"], datatype=["str", "number"] ) # Advanced Statistics with gr.TabItem("🧮 Detailed Statistics"): stats_table = gr.DataFrame( headers=["Property Metric", "Value", "Educational Context"], datatype=["str", "str", "str"], wrap=True ) # Regex Explorer with gr.TabItem("🔎 Regex Explorer"): with gr.Accordion("🧠 Educational Spotlight: Structured Pattern Matching", open=False): gr.HTML("""

Regex: The Structural Extraction Language

Regular expressions look for matching text layouts. They are extremely effective before models compile lexical vectors:

""") regex_explorer_html = gr.HTML("
Matches category analysis lists...
") # Format Detectors with gr.TabItem("🧱 Layout Formats"): with gr.Accordion("📦 Educational Spotlight: Layout Analysis Systems", open=False): gr.HTML("""

Markup and Matrix Structure Detection Rules

Computers parse document systems using distinctive delimiters and structural tags:

""") format_overview_html = gr.HTML() with gr.Accordion("CSV Preview Engine (Non-Library Machine)", open=True): csv_preview_html = gr.HTML("

No CSV parsed grid display loaded yet.

") with gr.Accordion("HTML Tree Parser Detail", open=True): html_preview_html = gr.HTML("

No HTML tag analysis details loaded yet.

") # Download Export with gr.TabItem("💾 Export Report"): gr.Markdown("### Create Inspection Summary File") gr.Markdown("Download a complete, beautifully structured Markdown text report mapping the calculations of the explorer for external study.") report_btn = gr.Button("🔨 Compile Markdown Analysis Report", variant="primary") report_file = gr.File(label="Downloadable Analysis Report", type="filepath") # ===================================================================== # CONTROLLER WIREFRAMES & ACTIONS # ===================================================================== # Upload handler updating input text file_upload.change( fn=handle_file_upload, inputs=file_upload, outputs=input_text ) # Core reactive interface processing all panels together ui_outputs = [ overview_html, encoding_table, unicode_explorer_html, char_freq_table, word_freq_table, stats_table, regex_explorer_html, format_overview_html, csv_preview_html, html_preview_html, overview_chart ] # Input changes trigger analytical updates instantly input_text.change( fn=analyze_all_inputs, inputs=input_text, outputs=ui_outputs ) # Export report trigger report_btn.click( fn=generate_report, inputs=input_text, outputs=report_file ) # Run the Gradio Space application if __name__ == "__main__": demo.launch()