import streamlit as st import requests from PIL import Image, ImageDraw, ImageFont import io import time import json import base64 import uuid import hashlib import urllib.parse import random import datetime import re from collections import Counter from bs4 import BeautifulSoup from fpdf import FPDF import os from io import BytesIO import streamlit as st import html import string # --- BATCH 1: MEDIA & FILE FUNCTIONS --- def lexical_replacer_tool(): """ The Master Function for the Lexical Space Replacer Tool. Contains 100+ text manipulation features split into Normal and Dev modes. """ st.markdown("## ๐Ÿ› ๏ธ Lexical Replacer Toolkit") st.markdown("---") # --- STATE MANAGEMENT --- # We use session state to hold the text so it persists when switching tabs if 'replacer_input' not in st.session_state: st.session_state.replacer_input = "Paste your text or HTML here..." if 'replacer_output' not in st.session_state: st.session_state.replacer_output = "" # --- THE LOGIC ENGINE (100+ Features Mapped) --- # We map "Human Readable Names" to "Lambda Functions" for efficiency. ops = { # --- GROUP 1: BASIC CLEANUP (Normal Mode) --- "Remove Double Spaces": lambda t: re.sub(r'\s+', ' ', t), "Trim Whitespace": lambda t: t.strip(), "Remove Empty Lines": lambda t: "\n".join([line for line in t.splitlines() if line.strip()]), "Remove Duplicate Lines": lambda t: "\n".join(list(dict.fromkeys(t.splitlines()))), # Preserves order "Sentence Case": lambda t: ". ".join([s.capitalize() for s in t.split(". ")]), "Title Case": lambda t: t.title(), "UPPERCASE": lambda t: t.upper(), "lowercase": lambda t: t.lower(), "tOGGLE cASE": lambda t: t.swapcase(), "Smart Quotes to Straight": lambda t: t.replace('โ€œ', '"').replace('โ€', '"').replace("โ€˜", "'").replace("โ€™", "'"), "Remove Special Characters": lambda t: re.sub(r'[^a-zA-Z0-9\s]', '', t), "Remove Emojis": lambda t: t.encode('ascii', 'ignore').decode('ascii'), "Remove Numbers": lambda t: re.sub(r'\d+', '', t), "Remove Non-ASCII": lambda t: re.sub(r'[^\x00-\x7F]+', '', t), "Unescape HTML": lambda t: html.unescape(t), "Text Reverse": lambda t: t[::-1], "Word Reverse": lambda t: " ".join(t.split()[::-1]), "Sort Lines A-Z": lambda t: "\n".join(sorted(t.splitlines())), "Sort Lines Z-A": lambda t: "\n".join(sorted(t.splitlines(), reverse=True)), "Shuffle Lines": lambda t: "\n".join(random.sample(t.splitlines(), len(t.splitlines()))), # --- GROUP 2: FORMATTING (Normal Mode) --- "Add Line Breaks (
)": lambda t: t.replace("\n", "
\n"), "Wrap in

Tags": lambda t: "\n".join([f"

{line}

" for line in t.splitlines() if line.strip()]), "List Maker (Bullets)": lambda t: "", "List Maker (Numbered)": lambda t: "
    \n" + "\n".join([f"
  1. {line}
  2. " for line in t.splitlines() if line.strip()]) + "\n
", "Markdown to HTML Bold": lambda t: re.sub(r'\*\*(.*?)\*\*', r'\1', t), "HTML to Markdown Bold": lambda t: re.sub(r'(.*?)', r'**\1**', t), "Strip All HTML Tags": lambda t: re.sub(r'<[^>]+>', '', t), "Obfuscate Emails": lambda t: re.sub(r'([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})', r'[email protected]', t), "Format Date (DD/MM/YYYY)": lambda t: t, # Placeholder for complex regex "Tab to 4 Spaces": lambda t: t.replace("\t", " "), "Slugify (URL Friendly)": lambda t: re.sub(r'[^a-z0-9]+', '-', t.lower()).strip('-'), "Add Target='_blank'": lambda t: t.replace('.*?', '', t, flags=re.DOTALL), "Remove Comments": lambda t: re.sub(r'', '', t, flags=re.DOTALL), } # --- LAYOUT --- col1, col2 = st.columns([1, 1]) with col1: st.subheader("Input") text_input = st.text_area("Paste text here", value=st.session_state.replacer_input, height=350, key="input_widget") # Update session state on change if text_input != st.session_state.replacer_input: st.session_state.replacer_input = text_input with col2: st.subheader("Control Panel") mode = st.radio("Select Mode:", ["๐ŸŸข Normal Mode", "๐Ÿ”ด Developer Mode"], horizontal=True) selected_ops = [] if mode == "๐ŸŸข Normal Mode": st.info("Tools for Writing, SEO, and Formatting") with st.expander("โœจ Cleaning Tools", expanded=True): if st.button("Remove Double Spaces"): selected_ops.append("Remove Double Spaces") if st.button("Trim Whitespace"): selected_ops.append("Trim Whitespace") if st.button("Remove Empty Lines"): selected_ops.append("Remove Empty Lines") if st.button("Remove Duplicate Lines"): selected_ops.append("Remove Duplicate Lines") if st.button("Remove Special Chars"): selected_ops.append("Remove Special Characters") with st.expander("๐Ÿ”  Casing Tools"): c1, c2, c3 = st.columns(3) with c1: if st.button("UPPERCASE"): selected_ops.append("UPPERCASE") if st.button("Sentence Case"): selected_ops.append("Sentence Case") with c2: if st.button("lowercase"): selected_ops.append("lowercase") if st.button("Title Case"): selected_ops.append("Title Case") with c3: if st.button("Toggle Case"): selected_ops.append("tOGGLE cASE") with st.expander("๐Ÿ“„ Formatting"): if st.button("Make HTML List (Bullet)"): selected_ops.append("List Maker (Bullets)") if st.button("Make HTML List (Number)"): selected_ops.append("List Maker (Numbered)") if st.button("Smart Quotes -> Straight"): selected_ops.append("Smart Quotes to Straight") if st.button("Slugify Text"): selected_ops.append("Slugify (URL Friendly)") else: # Developer Mode st.error("Tools for Code, Regex, and Backend") # Regex Section with st.expander("๐Ÿ” Regex Find & Replace", expanded=True): regex_find = st.text_input("Find Pattern (Regex)", value="") regex_repl = st.text_input("Replace With", value="") if st.button("Run Regex Replace"): try: st.session_state.replacer_input = re.sub(regex_find, regex_repl, st.session_state.replacer_input) st.success("Regex Applied!") st.rerun() except Exception as e: st.error(f"Regex Error: {e}") with st.expander("๐Ÿ’ป Encoders / Decoders"): c1, c2 = st.columns(2) with c1: if st.button("Base64 Encode"): selected_ops.append("Base64 Encode") if st.button("URL Encode"): selected_ops.append("URL Encode") with c2: if st.button("Base64 Decode"): selected_ops.append("Base64 Decode") if st.button("URL Decode"): selected_ops.append("URL Decode") with st.expander("๐Ÿงน Code Cleaning"): if st.button("Minify JSON"): selected_ops.append("Minify JSON") if st.button("Beautify JSON"): selected_ops.append("Beautify JSON") if st.button("Escape HTML"): selected_ops.append("Escape HTML Entities") with st.expander("๐Ÿ…ฑ๏ธ Blogger Specific"): if st.button("Clean MS Word Junk"): selected_ops.append("Clean MS Word Junk") if st.button("Force HTTPS"): selected_ops.append("Blogger: HTTPS Force") if st.button("Remove Inline Styles"): selected_ops.append("Remove Inline Styles") if st.button("Remove Scripts"): selected_ops.append("Remove Script Tags") # --- ANALYSIS (Always Visible) --- st.write("---") st.caption("๐Ÿ“Š Live Analysis") char_count = len(st.session_state.replacer_input) word_count = len(st.session_state.replacer_input.split()) st.write(f"**Chars:** {char_count} | **Words:** {word_count}") # --- EXECUTION ENGINE --- # If a button added an op to the list, run it against the input text if selected_ops: current_text = st.session_state.replacer_input for op_name in selected_ops: try: # Apply the function from our dictionary current_text = ops[op_name](current_text) st.toast(f"Applied: {op_name}") except Exception as e: st.error(f"Error in {op_name}: {e}") # Update State st.session_state.replacer_input = current_text st.rerun() # Refresh to show changes in the text area # --- RESULT DOWNLOAD --- if st.session_state.replacer_input: st.download_button( label="Download Result", data=st.session_state.replacer_input, file_name="lexical_cleaned.txt", mime="text/plain" ) def run_ultimate_pdf_converter(): """ The Ultimate Text-to-PDF Converter (Stable Version). Features: - Auto-Healing Font Loader (Fixes TTLibError) - Smart Symbols & Typography - Markdown Engine (Headers, Tables, Code Blocks) - LMS Junk Cleaner """ # --- CONSTANTS --- SMART_SYMBOLS = { r'<->': 'โ†”', r'->': 'โ†’', r'<-': 'โ†', r'=>': 'โ‡’', r'<=': 'โ‰ค', r'>=': 'โ‰ฅ', r'!=': 'โ‰ ', r'\.\.\.': 'โ€ฆ', r'\(c\)': 'ยฉ', r'\(r\)': 'ยฎ', r'\(tm\)': 'โ„ข', r'\+-': 'ยฑ', r'\~=': 'โ‰ˆ', r'--': 'โ€”', r'alpha': 'ฮฑ', r'beta': 'ฮฒ', r'theta': 'ฮธ', r'pi': 'ฯ€', r'sigma': 'ฮฃ', r'delta': 'ฮ”', r'gamma': 'ฮ“', r'omega': 'ฮฉ', r'mu': 'ฮผ', r'lambda': 'ฮป', r'deg': 'ยฐ', r'infinity': 'โˆž', r'sqrt': 'โˆš' } # --- INTERNAL PDF CLASS --- class UltimatePDF(FPDF): def __init__(self, orientation='P', unit='mm', format='A4'): super().__init__(orientation=orientation, unit=unit, format=format) self.set_auto_page_break(auto=True, margin=15) self.main_font = 'Arial' # Default fallback self.ensure_fonts() def ensure_fonts(self): font_filename = "DejaVuSans.ttf" font_url = "https://github.com/dejavu-fonts/dejavu-fonts/raw/master/ttf/DejaVuSans.ttf" # 1. Check if file exists and is valid size (HTML error pages are small) if os.path.exists(font_filename): if os.path.getsize(font_filename) < 1000: # Less than 1KB is definitely garbage os.remove(font_filename) # 2. Download if missing if not os.path.exists(font_filename): try: # Fake user-agent to avoid GitHub blocking scripts headers = {'User-Agent': 'Mozilla/5.0'} r = requests.get(font_url, headers=headers, timeout=10) if r.status_code == 200: with open(font_filename, "wb") as f: f.write(r.content) except Exception as e: print(f"Font download failed: {e}") # 3. Try Loading the Font try: if os.path.exists(font_filename): self.add_font('DejaVu', '', font_filename, uni=True) self.main_font = 'DejaVu' except Exception: # If loading fails (corrupt file), delete it to retry next time try: os.remove(font_filename) except: pass self.main_font = 'Arial' # Fallback to standard st.toast("โš ๏ธ Font failed to load. Using standard font (some symbols may be missing).", icon="โš ๏ธ") def header(self): if getattr(self, 'show_header', False): self.set_font(self.main_font, '', 8) self.set_text_color(128) self.cell(0, 10, f'Generated by Ultimate PDF | {getattr(self, "title_meta", "Doc")}', 0, 0, 'R') self.ln(10) def footer(self): self.set_y(-15) self.set_font(self.main_font, '', 8) self.set_text_color(128) self.cell(0, 10, f'Page {self.page_no()}', 0, 0, 'C') # --- MARKDOWN RENDERING HELPERS --- def add_markdown_header(self, text, level): sizes = {1: 20, 2: 16, 3: 14} self.set_font(self.main_font, '', sizes.get(level, 12)) self.set_text_color(0, 50, 100) self.cell(0, 10, text, ln=True) self.set_text_color(0) self.set_font(self.main_font, '', 12) def add_code_block(self, code_lines): self.set_font("Courier", size=10) self.set_fill_color(245, 245, 245) for line in code_lines: # Replace tabs with spaces to prevent alignment issues safe_line = line.replace('\t', ' ') self.cell(0, 5, safe_line, ln=True, fill=True, border=0) self.set_font(self.main_font, '', 12) self.ln(3) def add_table(self, table_lines): self.set_font(self.main_font, '', 10) cell_h = 7 for row in table_lines: cols = [c.strip() for c in row.split('|') if c.strip()] if not cols: continue col_w = (self.w - 30) // len(cols) for col in cols: self.cell(col_w, cell_h, col, border=1) self.ln() self.set_font(self.main_font, '', 12) self.ln(5) def add_blockquote(self, text): self.set_text_color(80) self.set_x(self.l_margin + 8) self.multi_cell(0, 6, f"โ€œ {text}") self.set_x(self.l_margin) self.set_text_color(0) self.ln(2) def add_image_from_url(self, url): try: r = requests.get(url, timeout=5) if r.status_code == 200: img_data = BytesIO(r.content) self.image(img_data, w=100) self.ln(5) except: self.set_text_color(200, 0, 0) self.cell(0, 10, f"[Image load failed: {url}]", ln=True) self.set_text_color(0) # --- TEXT PROCESSOR --- def clean_and_parse(raw_text, use_smart_symbols=True, clean_lms=True): processed_lines = [] # 1. LMS Regex Cleaning if clean_lms: # Common LMS patterns patterns = [ r'\[ID:?\s*\w+\]', # [ID: 123] r'Question\s+ID\s*[:\-]\s*\w+', # Question ID: 123 r'\(\d+\s*pts?\)', # (1 pts) r'Select one:', # Moodle/Blackboard prompt r'\[\d{1,2}:\d{2}\s*(AM|PM)?\]' # Timestamps ] for p in patterns: raw_text = re.sub(p, '', raw_text, flags=re.IGNORECASE) raw_text = re.sub(r'\n{3,}', '\n\n', raw_text) # Fix spacing # 2. Smart Symbols if use_smart_symbols: for pattern, symbol in SMART_SYMBOLS.items(): if pattern.isalpha(): raw_text = re.sub(r'\b' + pattern + r'\b', symbol, raw_text, flags=re.IGNORECASE) else: raw_text = re.sub(pattern, symbol, raw_text) lines = raw_text.split('\n') # 3. Block Parser buffer_type = None buffer_content = [] for line in lines: line_stripped = line.strip() # Detect Code Block if line_stripped.startswith('```'): if buffer_type == 'code': # Close code processed_lines.append({'type': 'code', 'content': buffer_content}) buffer_content = [] buffer_type = None else: # Open code if buffer_type == 'table': # Close table if open processed_lines.append({'type': 'table', 'content': buffer_content}) buffer_content = [] buffer_type = 'code' continue if buffer_type == 'code': buffer_content.append(line) # Preserve whitespace in code continue # Detect Table if '|' in line_stripped and len(line_stripped) > 3: if buffer_type != 'table': buffer_type = 'table' buffer_content.append(line_stripped) continue elif buffer_type == 'table': # Close table processed_lines.append({'type': 'table', 'content': buffer_content}) buffer_content = [] buffer_type = None # Detect Headers if line_stripped.startswith('#'): level = line_stripped.count('#') text = line_stripped.replace('#', '').strip() processed_lines.append({'type': 'header', 'level': min(level, 3), 'content': text}) continue # Detect Quotes if line_stripped.startswith('> '): processed_lines.append({'type': 'quote', 'content': line_stripped[2:]}) continue # Detect Images if line_stripped.startswith('http') and line_stripped.lower().endswith(('.png', '.jpg', '.jpeg', '.webp')): processed_lines.append({'type': 'image', 'url': line_stripped}) continue # Detect Lists if line_stripped.startswith(('* ', '- ')): processed_lines.append({'type': 'list', 'content': line_stripped[2:]}) continue # Detect HR if line_stripped == '---': processed_lines.append({'type': 'hr'}) continue if line_stripped: processed_lines.append({'type': 'text', 'content': line_stripped}) else: processed_lines.append({'type': 'empty'}) if buffer_type == 'table': processed_lines.append({'type': 'table', 'content': buffer_content}) return processed_lines # --- UI RENDER --- st.title("โšก Ultimate PDF Engine") with st.expander("โ„น๏ธ Help & Features", expanded=False): st.write("- **Smart Symbols:** Writes 'alpha' as ฮฑ, '->' as โ†’") st.write("- **Tables:** Use `| Name | Score |` format") st.write("- **Code:** Use ` ``` ` for code blocks") st.write("- **Images:** Paste URL on new line") # Settings Sidebar with st.sidebar: st.header("โš™๏ธ PDF Config") filename = st.text_input("Filename", "My_Notes.pdf") orientation = st.radio("Orientation", ["Portrait", "Landscape"]) st.subheader("Filters") enable_lms = st.checkbox("Clean LMS Junk", True) enable_smart = st.checkbox("Smart Symbols", True) enable_header = st.checkbox("Show Header", True) font_size = st.slider("Font Size", 8, 24, 12) # Input raw_input = st.text_area("Paste text here...", height=350) # Action if st.button("๐Ÿš€ Generate PDF", type="primary"): if not raw_input.strip(): st.warning("Input is empty.") return with st.spinner("Processing..."): # Setup PDF orient_code = 'P' if orientation == "Portrait" else 'L' pdf = UltimatePDF(orientation=orient_code) pdf.title_meta = filename.replace('.pdf', '') pdf.show_header = enable_header pdf.add_page() pdf.set_font(pdf.main_font, '', font_size) # Process blocks = clean_and_parse(raw_input, use_smart_symbols=enable_smart, clean_lms=enable_lms) # Render for block in blocks: if block['type'] == 'header': pdf.add_markdown_header(block['content'], block['level']) elif block['type'] == 'code': pdf.add_code_block(block['content']) elif block['type'] == 'table': pdf.add_table(block['content']) elif block['type'] == 'quote': pdf.add_blockquote(block['content']) elif block['type'] == 'image': pdf.add_image_from_url(block['url']) elif block['type'] == 'list': pdf.set_x(pdf.l_margin + 5) pdf.write(8, f"โ€ข {block['content']}") pdf.ln() pdf.set_x(pdf.l_margin) elif block['type'] == 'hr': pdf.ln(2) pdf.line(pdf.l_margin, pdf.get_y(), pdf.w - pdf.r_margin, pdf.get_y()) pdf.ln(5) elif block['type'] == 'text': pdf.write(8, block['content']) pdf.ln() elif block['type'] == 'empty': pdf.ln(4) # Download try: pdf_bytes = pdf.output(dest='S').encode('latin-1', 'replace') st.success("PDF Generated Successfully!") st.download_button( "โฌ‡๏ธ Download PDF", data=pdf_bytes, file_name=filename if filename.endswith('.pdf') else f"{filename}.pdf", mime="application/pdf" ) except Exception as e: st.error(f"Error creating PDF file: {e}") import streamlit as st from huggingface_hub import InferenceClient import os # --- 1. The Logic Function (Backend) --- # We use @st.cache_data so if the user clicks other buttons, we don't re-run the expensive API call. @st.cache_data(show_spinner="Analyzing code with Qwen AI...") def get_seo_data(code_snippet, file_type, api_key): """ Sends code to Hugging Face Inference API and returns SEO/JSON-LD strategy. """ if not code_snippet: return None, "โš ๏ธ Please paste some code first." if not api_key: return None, "โŒ Error: HF_TOKEN not found in secrets." try: client = InferenceClient(api_key=api_key) # Strict Prompt for Qwen 2.5 Coder system_instruction = f""" You are an expert Technical SEO Specialist. Analyze the user's {file_type} code. Task: Generate Google-compliant JSON-LD structured data and SEO meta tags. Output Format (Strict Markdown): ## SEO Metadata **Title:** [Engaging Title, max 60 chars] **Description:** [Summary including keywords, max 160 chars] **Keywords:** [5-8 comma-separated keywords] ## JSON-LD Structured Data ```json [Insert VALID JSON-LD here. - If Python: Use schema.org/SoftwareSourceCode - If HTML: Use schema.org/WebPage or schema.org/TechArticle] ``` """ user_message = f"Analyze this {file_type} code:\n\n{code_snippet}" response = client.chat_completion( model="Qwen/Qwen2.5-Coder-32B-Instruct", messages=[ {"role": "system", "content": system_instruction}, {"role": "user", "content": user_message} ], max_tokens=1500, temperature=0.2 ) return response.choices[0].message.content, None except Exception as e: return None, f"Error: {str(e)}" # --- 2. The UI Function (Frontend) --- def render_seo_ui(): """ Call this function in your main app.py where you want the SEO tool to show up. """ st.header("๐Ÿš€ AI Code-to-SEO Generator") st.markdown("Generate **JSON-LD** and **Meta Tags** for your Python/HTML files using Qwen 2.5 Coder.") # Get Token (Try secrets first, then env var) try: hf_token = st.secrets["HF_TOKEN"] except: hf_token = os.getenv("HF_TOKEN") with st.form("seo_form"): col1, col2 = st.columns([1, 3]) with col1: file_type = st.radio("File Type", ["Python", "HTML"]) with col2: code_input = st.text_area("Paste Code Here", height=300, placeholder="import os...") submitted = st.form_submit_button("โœจ Generate SEO Data") if submitted: if not hf_token: st.error("Authentication Error: Please add `HF_TOKEN` to your Streamlit secrets.") else: result, error = get_seo_data(code_input, file_type, hf_token) if error: st.error(error) else: st.success("SEO Data Generated Successfully!") st.markdown("---") st.markdown(result) # Optional: Add a copy button for the raw result st.download_button( label="๐Ÿ“ฅ Download Result", data=result, file_name="seo_strategy.md", mime="text/markdown" ) def tool_youtube_downloader(): st.header("๐ŸŽฅ YouTube Media Extractor") url = st.text_input("Paste YouTube URL", placeholder="https://youtube.com/...") format_type = st.radio("Format", ["Video (MP4)", "Audio Only (MP3)"], horizontal=True) if url and st.button("๐Ÿš€ Process Media"): with st.spinner("Contacting server..."): try: headers = {"Accept": "application/json", "Content-Type": "application/json"} payload = { "url": url, "vQuality": "1080", "isAudioOnly": True if "Audio" in format_type else False } # Using Cobalt API response = requests.post("https://api.cobalt.tools/api/json", headers=headers, json=payload) data = response.json() if "url" in data: st.success("โœ… Ready!") st.link_button(f"โฌ‡๏ธ Download {format_type}", data["url"]) if "Audio" not in format_type: st.video(data["url"]) else: st.audio(data["url"]) else: st.error(f"Error: {data.get('text', 'Unknown error')}") except Exception as e: st.error(f"Connection failed: {str(e)}") def tool_smart_converter(): with st.spinner("Starting File Engine..."): time.sleep(0.3) import pandas as pd st.header("๐Ÿ”„ Smart File Converter") st.info("Supports: Images (PNG/JPG/WEBP) and Data (CSV/JSON/Excel)") uploaded_file = st.file_uploader("Upload File", type=['png', 'jpg', 'jpeg', 'webp', 'csv', 'json', 'xlsx'],key="smart_conv_upload") if uploaded_file: file_type = uploaded_file.name.split('.')[-1].lower() # LOGIC: IMAGE CONVERSION if file_type in ['png', 'jpg', 'jpeg', 'webp']: image = Image.open(uploaded_file) st.image(image, caption="Preview", width=300) target_format = st.selectbox("Convert to:", ["PNG", "JPEG", "WEBP", "PDF"]) if st.button("Convert Image"): buf = io.BytesIO() # RGB required for JPEG/PDF if image.mode in ("RGBA", "P") and target_format in ["JPEG", "PDF"]: image = image.convert("RGB") image.save(buf, format=target_format) st.download_button(f"Download {target_format}", data=buf.getvalue(), file_name=f"converted.{target_format.lower()}") # LOGIC: DATA CONVERSION elif file_type in ['csv', 'json', 'xlsx']: df = None try: if file_type == 'csv': df = pd.read_csv(uploaded_file) elif file_type == 'json': df = pd.read_json(uploaded_file) elif file_type == 'xlsx': df = pd.read_excel(uploaded_file) st.write("Data Preview:", df.head()) target_data = st.selectbox("Convert to:", ["CSV", "JSON", "Excel"]) if st.button("Convert Data"): buf = io.BytesIO() if target_data == "CSV": df.to_csv(buf, index=False) ext = "csv" elif target_data == "JSON": df.to_json(buf, orient='records') ext = "json" elif target_data == "Excel": df.to_excel(buf, index=False) ext = "xlsx" st.download_button(f"Download {target_data}", data=buf.getvalue(), file_name=f"converted.{ext}") except Exception as e: st.error(f"Error reading file: {e}") def tool_image_compressor(): st.header("๐Ÿ“‰ Image Compressor") # ADD key="compressor" uploaded_file = st.file_uploader("Upload Image", type=['png', 'jpg', 'jpeg'], key="compressor") if uploaded_file: image = Image.open(uploaded_file) st.write(f"Original Size: {uploaded_file.size / 1024:.2f} KB") quality = st.slider("Quality (Lower = Smaller file)", 10, 95, 60) if st.button("Compress"): buf = io.BytesIO() if image.mode in ("RGBA", "P"): image = image.convert("RGB") image.save(buf, format="JPEG", quality=quality, optimize=True) size_kb = len(buf.getvalue()) / 1024 st.success(f"Compressed Size: {size_kb:.2f} KB") st.download_button("Download Compressed Image", data=buf.getvalue(), file_name="compressed.jpg") def tool_image_resizer(): st.header("๐Ÿ“ Image Resizer") # ADD key="resizer" uploaded_file = st.file_uploader("Upload Image", type=['png', 'jpg', 'jpeg', 'webp'], key="resizer") if uploaded_file: image = Image.open(uploaded_file) st.write(f"Current Dimensions: {image.size}") col1, col2 = st.columns(2) w = col1.number_input("Width", value=image.width) h = col2.number_input("Height", value=image.height) if st.button("Resize"): new_img = image.resize((int(w), int(h))) buf = io.BytesIO() new_img.save(buf, format=image.format) st.image(new_img, caption="Resized Preview") st.download_button("Download Resized Image", data=buf.getvalue(), file_name=f"resized.{image.format.lower()}") def tool_thumbnail_generator(): st.header("๐Ÿš€ Ultimate Thumbnail Studio") # --- DEPENDENCIES --- from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageEnhance, ImageOps, ImageColor import io # --- LAYOUT FIX FOR PC/MOBILE --- # We use a container for the controls to keep them tidy on PC # and "use_column_width" to fix the crash. # Top row: All Controls (Split into 2 columns for better PC spacing) with st.expander("๐ŸŽจ Thumbnail Settings & Controls", expanded=True): col_c1, col_c2 = st.columns(2) # --- LEFT CONTROL COLUMN --- with col_c1: st.subheader("1. Background & Filters") bg_mode = st.radio("Background Type", ["Upload Image", "Solid Color", "Gradient"], horizontal=True) bg_image = None if bg_mode == "Upload Image": bg_file = st.file_uploader("Upload BG", type=['png', 'jpg', 'jpeg', 'webp'], key="max_bg") if bg_file: bg_image = Image.open(bg_file).convert("RGBA") elif bg_mode == "Solid Color": hex_bg = st.color_picker("Pick Color", "#1E1E1E") st.session_state.thumb_bg_color = hex_bg else: # Gradient c1_col, c2_col = st.columns(2) grad_c1 = c1_col.color_picker("Start", "#12c2e9") grad_c2 = c2_col.color_picker("End", "#c471ed") grad_dir = st.selectbox("Direction", ["Horizontal", "Vertical"]) st.markdown("---") st.write("**Filters**") f1, f2 = st.columns(2) blur_amt = f1.slider("Blur", 0, 20, 0) brightness = f2.slider("Brightness", 0.5, 1.5, 1.0) # --- RIGHT CONTROL COLUMN --- with col_c2: st.subheader("2. Text & Branding") main_text = st.text_area("Main Title", "THE ULTIMATE\nGUIDE TO PYTHON", height=100) t1, t2 = st.columns(2) font_size = t1.slider("Size", 20, 200, 80) font_color = t2.color_picker("Text Color", "#FFFFFF") st.write("**Styling**") s1, s2 = st.columns(2) stroke_width = s1.slider("Outline", 0, 10, 2) stroke_color = s2.color_picker("Outline Color", "#000000") st.markdown("---") logo_file = st.file_uploader("Upload Logo (PNG)", type=['png', 'webp'], key="max_logo") if logo_file: l1, l2 = st.columns(2) logo_size = l1.slider("Logo Size", 50, 300, 150) logo_pos = l2.selectbox("Position", ["Top-Right", "Top-Left", "Bottom-Right", "Bottom-Left"]) else: logo_size = 150 logo_pos = "Top-Right" # --- PREVIEW SECTION (Full Width for PC clarity) --- st.subheader("๐Ÿ‘๏ธ Preview & Download") # GENERATION LOGIC CANVAS_W, CANVAS_H = 1280, 720 canvas = Image.new("RGBA", (CANVAS_W, CANVAS_H), (0,0,0,0)) # 1. Background if bg_mode == "Upload Image" and bg_image: bg_ratio = bg_image.width / bg_image.height target_ratio = CANVAS_W / CANVAS_H if bg_ratio > target_ratio: new_h = CANVAS_H new_w = int(new_h * bg_ratio) else: new_w = CANVAS_W new_h = int(new_w / bg_ratio) bg_image = bg_image.resize((new_w, new_h), Image.Resampling.LANCZOS) left = (new_w - CANVAS_W)/2 top = (new_h - CANVAS_H)/2 bg_image = bg_image.crop((left, top, left+CANVAS_W, top+CANVAS_H)) canvas.paste(bg_image, (0,0)) elif bg_mode == "Gradient": base = Image.new('RGB', (CANVAS_W, CANVAS_H), grad_c1) top_img = Image.new('RGB', (CANVAS_W, CANVAS_H), grad_c2) mask = Image.new("L", (CANVAS_W, CANVAS_H)) mask_data = [] for y in range(CANVAS_H): for x in range(CANVAS_W): if grad_dir == "Vertical": mask_data.append(int(255 * (y / CANVAS_H))) else: mask_data.append(int(255 * (x / CANVAS_W))) mask.putdata(mask_data) canvas = Image.composite(top_img, base, mask).convert("RGBA") else: if 'thumb_bg_color' not in st.session_state: st.session_state.thumb_bg_color = "#1E1E1E" canvas = Image.new("RGBA", (CANVAS_W, CANVAS_H), st.session_state.thumb_bg_color) # 2. Filters if blur_amt > 0: canvas = canvas.filter(ImageFilter.GaussianBlur(blur_amt)) if brightness != 1.0: enhancer = ImageEnhance.Brightness(canvas) canvas = enhancer.enhance(brightness) # 3. Text txt_layer = Image.new("RGBA", canvas.size, (255,255,255,0)) draw = ImageDraw.Draw(txt_layer) try: font = ImageFont.truetype("arialbd.ttf", font_size) except: try: font = ImageFont.truetype("arial.ttf", font_size) except: font = ImageFont.load_default() # Center Text Calculation # Using basic textsize for compatibility if textbbox fails in older Pillow try: bbox = draw.multiline_textbbox((0,0), main_text, font=font, align="center") text_w = bbox[2] - bbox[0] text_h = bbox[3] - bbox[1] except: # Fallback for very old Pillow versions text_w, text_h = draw.textsize(main_text, font=font) cx, cy = CANVAS_W // 2, CANVAS_H // 2 text_x = cx - (text_w // 2) text_y = cy - (text_h // 2) # Shadow draw.multiline_text((text_x + 8, text_y + 8), main_text, font=font, align="center", fill="black") # Main Text draw.multiline_text((text_x, text_y), main_text, font=font, align="center", fill=font_color, stroke_width=stroke_width, stroke_fill=stroke_color) # 4. Logo if logo_file: logo = Image.open(logo_file).convert("RGBA") logo.thumbnail((logo_size, logo_size), Image.Resampling.LANCZOS) pad = 30 if "Top" in logo_pos: ly = pad elif "Bottom" in logo_pos: ly = CANVAS_H - logo.height - pad if "Left" in logo_pos: lx = pad elif "Right" in logo_pos: lx = CANVAS_W - logo.width - pad txt_layer.paste(logo, (lx, ly), logo) # Final Composite final_comp = Image.alpha_composite(canvas, txt_layer) # --- DISPLAY & DOWNLOAD --- # Centered layout for PC look col_show, col_down = st.columns([3, 1]) with col_show: # FIX: Changed use_container_width to use_column_width st.image(final_comp, caption="Result", use_column_width=True) with col_down: st.write("### Ready?") buf = io.BytesIO() final_comp.convert("RGB").save(buf, format="PNG") st.download_button("๐Ÿ’พ Download PNG", data=buf.getvalue(), file_name="thumbnail.png", mime="image/png") # --- MAIN ROUTER (Paste this at the VERY END of app.py) --- # This checks the URL params and decides which function to run if __name__ == "__main__": st.set_page_config(page_title="Lexical Space Tools", layout="centered") # Get the 'mode' from the URL (e.g. ?mode=youtube) params = st.query_params mode = params.get("mode", "home") # --- BATCH 2: WEBMASTER & SEO FUNCTIONS --- def tool_meta_tag_generator(): st.header("๐Ÿท๏ธ Meta Tag Generator") title = st.text_input("Site Title", "My Awesome Blog") desc = st.text_area("Description", "A blog about technology and coding.") keywords = st.text_input("Keywords (comma separated)", "tech, coding, python") author = st.text_input("Author", "Lexical Space") if st.button("Generate Tags"): code = f""" {title} """ st.code(code, language="html") def tool_slug_generator(): st.header("๐ŸŒ URL Slug Generator") text = st.text_input("Enter Post Title", "How to Install Python on Windows 10!") if text: # Lowercase, strip whitespace, replace spaces with dashes, remove non-alphanumeric slug = text.lower().strip() slug = re.sub(r'[^a-z0-9\s-]', '', slug) slug = re.sub(r'[\s-]+', '-', slug) st.success(f"Slug: {slug}") st.code(slug, language="text") def tool_robots_generator(): st.header("๐Ÿค– Robots.txt Generator") st.write("Control which crawlers can access your site.") all_agents = st.checkbox("Apply to all robots (*)", value=True) disallow_admin = st.checkbox("Disallow /admin", value=True) disallow_private = st.checkbox("Disallow /private", value=False) sitemap_url = st.text_input("Sitemap URL (Optional)", "https://yoursite.com/sitemap.xml") if st.button("Generate Robots.txt"): agent = "*" if all_agents else "Googlebot" txt = f"User-agent: {agent}\n" if disallow_admin: txt += "Disallow: /admin/\n" if disallow_private: txt += "Disallow: /private/\n" if sitemap_url: txt += f"\nSitemap: {sitemap_url}" st.text_area("Result", txt, height=150) def tool_sitemap_builder(): st.header("๐Ÿ—บ๏ธ XML Sitemap Builder") urls = st.text_area("Paste URLs (one per line)", "https://site.com\nhttps://site.com/about") if st.button("Build XML"): xml = '\n' xml += '\n' for url in urls.split('\n'): if url.strip(): xml += f' \n {url.strip()}\n monthly\n \n' xml += '' st.text_area("Sitemap.xml", xml, height=200) def tool_keyword_density(): with st.spinner("Loading Analytics..."): import pandas as pd from collections import Counter st.header("๐Ÿ“Š Keyword Density Checker") text = st.text_area("Paste Article Text", height=200,key="density_text") if st.button("Analyze"): # Simple stopword list to ignore stopwords = set(['the', 'and', 'is', 'in', 'it', 'of', 'to', 'a', 'for', 'on', 'that', 'with', 'as']) words = re.findall(r'\w+', text.lower()) filtered = [w for w in words if w not in stopwords and len(w) > 2] counts = Counter(filtered).most_common(10) df = pd.DataFrame(counts, columns=["Keyword", "Count"]) df['Density %'] = (df['Count'] / len(words) * 100).round(2) st.table(df) def tool_plagiarism_check(): st.header("๐Ÿ•ต๏ธ Plagiarism Scanner (Google Check)") st.info("Splits text into sentences and searches Google for exact matches.") text = st.text_area("Paste Text to Check", height=150,key="plag_text") if st.button("Check Text"): sentences = re.split(r'[.!?]', text) clean_sentences = [s.strip() for s in sentences if len(s.strip()) > 20] for i, s in enumerate(clean_sentences[:5]): # Limit to first 5 for demo query = f'"{s}"' url = f"https://www.google.com/search?q={query}" st.markdown(f"**Sentence {i+1}:** {s[:50]}...") st.link_button(f"๐Ÿ” Check Google for Match", url) def tool_code_minifier(): st.header("๐Ÿงน Code Minifier") mode = st.radio("Type", ["HTML", "CSS"]) raw_code = st.text_area("Input Code", height=200) if st.button("Minify"): minified = "" if mode == "HTML": # Basic whitespace removal between tags lines = raw_code.split('\n') minified = "".join([line.strip() for line in lines]) elif mode == "CSS": # Remove comments and whitespace # 1. Remove comments minified = re.sub(r'/\*[\s\S]*?\*/', '', raw_code) # 2. Remove whitespace around braces/colons minified = re.sub(r'\s*([{:;,])\s*', r'\1', minified) # 3. Remove newlines minified = minified.replace('\n', '').replace('\r', '') st.text_area("Minified Output", minified, height=200) # --- BATCH 3: DEVELOPER TOOLS --- def tool_qr_generator(): with st.spinner("Initializing QR Tool..."): import qrcode import io st.header("๐Ÿ QR Code Generator") data = st.text_input("Enter Link or Text", "https://lexicalspace.blogspot.com") if data: qr = qrcode.QRCode(version=1, box_size=10, border=5) qr.add_data(data) qr.make(fit=True) img = qr.make_image(fill='black', back_color='white') buf = io.BytesIO() img.save(buf) st.image(img.get_image(), width=300) st.download_button("Download QR", data=buf.getvalue(), file_name="qrcode.png") def tool_json_formatter(): st.header("โœจ JSON Prettifier") raw = st.text_area("Paste Messy JSON", '{"id":1,"name":"Lexical","roles":["admin","dev"]}', height=150) col1, col2 = st.columns(2) if col1.button("Format (Pretty)"): try: parsed = json.loads(raw) st.code(json.dumps(parsed, indent=4), language="json") except Exception as e: st.error(f"Invalid JSON: {e}") if col2.button("Minify (Compact)"): try: parsed = json.loads(raw) st.code(json.dumps(parsed, separators=(',', ':')), language="json") except Exception as e: st.error(f"Invalid JSON: {e}") def tool_base64(): st.header("๐Ÿ” Base64 Converter") mode = st.radio("Action", ["Encode", "Decode"], horizontal=True) text = st.text_area("Input Text") if st.button("Process"): try: if mode == "Encode": res = base64.b64encode(text.encode()).decode() else: res = base64.b64decode(text).decode() st.code(res) except Exception as e: st.error(f"Error: {e}") def tool_url_encoder(): st.header("๐Ÿ”— URL Encoder/Decoder") text = st.text_input("Input URL", "https://example.com/search?q=hello world") c1, c2 = st.columns(2) with c1: if st.button("Encode"): st.code(urllib.parse.quote(text)) with c2: if st.button("Decode"): st.code(urllib.parse.unquote(text)) def tool_markdown_editor(): st.header("๐Ÿ“ Markdown Editor") col1, col2 = st.columns(2) with col1: md_text = st.text_area("Write Markdown", "# Hello\n* Item 1\n* Item 2", height=400) with col2: st.markdown("### Preview") st.markdown(md_text) def tool_regex_tester(): st.header("๐Ÿงช Regex Tester") pattern = st.text_input("Regex Pattern", r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b") text = st.text_area("Test String", "Contact us at support@lexical.com or admin@site.org") if pattern and text: try: matches = re.findall(pattern, text) st.write(f"Found {len(matches)} matches:") st.json(matches) except Exception as e: st.error(f"Regex Error: {e}") def tool_uuid_gen(): st.header("๐Ÿ†” UUID/GUID Generator") count = st.number_input("How many?", 1, 100, 5) if st.button("Generate"): uuids = [str(uuid.uuid4()) for _ in range(count)] st.code("\n".join(uuids), language="text") def tool_hash_gen(): st.header("๐Ÿ”‘ Hash Generator") text = st.text_input("Input String", "mypassword") if text: st.write("**MD5:**") st.code(hashlib.md5(text.encode()).hexdigest()) st.write("**SHA256:**") st.code(hashlib.sha256(text.encode()).hexdigest()) # ... (Batch 1 & 2 Routing above) ... # BATCH 3 ROUTING elif mode == "qrcode": tool_qr_generator() elif mode == "json": tool_json_formatter() elif mode == "base64": tool_base64() elif mode == "url": tool_url_encoder() elif mode == "markdown": tool_markdown_editor() elif mode == "regex": tool_regex_tester() elif mode == "uuid": tool_uuid_gen() elif mode == "hash": tool_hash_gen() # ... (Home Dashboard below) ... st.write("### ๐Ÿ› ๏ธ Developer Tools") st.markdown(""" * [๐Ÿ QR Code Gen](?mode=qrcode) * [โœจ JSON Prettifier](?mode=json) * [๐Ÿ” Base64 Converter](?mode=base64) * [๐Ÿ”— URL Encode/Decode](?mode=url) * [๐Ÿ“ Markdown Editor](?mode=markdown) * [๐Ÿงช Regex Tester](?mode=regex) * [๐Ÿ†” UUID Generator](?mode=uuid) * [๐Ÿ”‘ Hash Generator](?mode=hash) """) # --- BATCH 4: TEXT, UTILITIES & EXTRAS --- def tool_case_converter(): st.header("๐Ÿ”  Case Converter") text = st.text_area("Input Text", "hello world") c1, c2, c3, c4 = st.columns(4) if c1.button("UPPERCASE"): st.code(text.upper(), language="text") if c2.button("lowercase"): st.code(text.lower(), language="text") if c3.button("Title Case"): st.code(text.title(), language="text") if c4.button("aLtErNaTiNg"): res = "".join([c.upper() if i%2==0 else c.lower() for i, c in enumerate(text)]) st.code(res, language="text") def tool_lorem_ipsum(): st.header("๐Ÿ“œ Lorem Ipsum Generator") paras = st.slider("Paragraphs", 1, 10, 3) dummy_text = [ "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.", "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum.", "Excepteur sint occaecat cupidatat non proident, sunt in culpa." ] if st.button("Generate"): result = "\n\n".join([random.choice(dummy_text) * 3 for _ in range(paras)]) st.text_area("Result", result, height=200) def tool_word_counter(): st.header("๐Ÿงฎ Word & Character Counter") text = st.text_area("Paste Text Here", height=200,key="counter_text") if text: words = len(text.split()) chars = len(text) no_space = len(text.replace(" ", "")) read_time = round(words / 200, 2) c1, c2, c3, c4 = st.columns(4) c1.metric("Words", words) c2.metric("Chars", chars) c3.metric("No Spaces", no_space) c4.metric("Read Time", f"{read_time} min") def tool_remove_duplicates(): st.header("๐Ÿ—‘๏ธ Remove Duplicate Lines") text = st.text_area("Paste List (One per line)", "Apple\nBanana\nApple\nOrange") if st.button("Clean"): lines = text.split('\n') seen = set() clean = [] for line in lines: if line not in seen and line.strip(): clean.append(line) seen.add(line) st.text_area("Cleaned List", "\n".join(clean), height=200) def tool_text_to_speech(): with st.spinner("Loading Audio Engine..."): from gtts import gTTS import io st.header("๐Ÿ—ฃ๏ธ Text to Speech") text = st.text_area("Enter Text", "Hello, welcome to Lexical Space.") lang = st.selectbox("Language", ["en", "es", "fr", "de", "hi"],key="tts_text") if st.button("Speak"): try: tts = gTTS(text=text, lang=lang, slow=False) buf = io.BytesIO() tts.write_to_fp(buf) st.audio(buf, format='audio/mp3') except Exception as e: st.error(f"Error: {e}") def tool_timestamp(): st.header("โฐ Unix Timestamp Converter") now = int(time.time()) st.write(f"Current Timestamp: `{now}`") col1, col2 = st.columns(2) with col1: ts_input = st.number_input("Timestamp to Date", value=now) if st.button("Convert to Date"): st.success(datetime.datetime.fromtimestamp(ts_input)) with col2: d_input = st.date_input("Date to Timestamp") if st.button("Convert to Timestamp"): ts = int(time.mktime(d_input.timetuple())) st.success(ts) def tool_color_palette(): st.header("๐ŸŽจ Image Color Palette") # ADD key="palette" uploaded_file = st.file_uploader("Upload Image", type=['jpg', 'png'], key="palette") if uploaded_file: img = Image.open(uploaded_file).convert("RGB") st.image(img, width=200) # Simple extraction by resizing to 5 pixels small = img.resize((5, 1)) colors = small.getdata() st.write("Dominant Colors:") cols = st.columns(5) for i, color in enumerate(colors): hex_code = '#{:02x}{:02x}{:02x}'.format(*color) cols[i].color_picker(f"Color {i+1}", hex_code, disabled=True) cols[i].code(hex_code) def tool_password_strength(): st.header("๐Ÿ’ช Password Strength") pwd = st.text_input("Test Password", type="password") if pwd: score = 0 if len(pwd) >= 8: score += 1 if re.search(r"[A-Z]", pwd): score += 1 if re.search(r"[a-z]", pwd): score += 1 if re.search(r"\d", pwd): score += 1 if re.search(r"[!@#$%^&*]", pwd): score += 1 st.progress(score / 5) if score < 3: st.warning("Weak") elif score < 5: st.info("Moderate") else: st.success("Strong!") def tool_aspect_ratio(): st.header("๐Ÿ–ฅ๏ธ Aspect Ratio Calculator") w = st.number_input("Width", 1920) h = st.number_input("Height", 1080) if w and h: def gcd(a, b): while b: a, b = b, a % b return a divisor = gcd(int(w), int(h)) st.metric("Aspect Ratio", f"{int(w/divisor)}:{int(h/divisor)}") def tool_stopwatch(): st.header("โฑ๏ธ Stopwatch") if 'start_time' not in st.session_state: st.session_state.start_time = None if st.button("Start/Reset"): st.session_state.start_time = time.time() if st.session_state.start_time: elapsed = time.time() - st.session_state.start_time st.metric("Time Elapsed", f"{elapsed:.2f}s") if st.button("Stop"): st.session_state.start_time = None def tool_python_checker(): st.header("๐Ÿ Python Syntax & Error Checker") st.markdown("Paste your Python code or upload a `.py` file to check for syntax errors.") # Import dependencies inside the function to avoid global scope clutter import tempfile import os import io try: from pylint.lint import Run from pylint.reporters.text import TextReporter except ImportError: st.error("โš ๏ธ Pylint is not installed. Please add `pylint` to your requirements.txt") return # --- INPUTS --- col1, col2 = st.columns(2) with col1: paste_code = st.text_area("Paste Code Here", height=300) with col2: file_obj = st.file_uploader("Or Upload .py File", type=[".py"]) # --- PROCESS BUTTON --- if st.button("Check Syntax ๐Ÿš€", type="primary"): code_to_check = "" # Logic: Prefer File > Paste if file_obj is not None: try: code_to_check = file_obj.getvalue().decode("utf-8") except Exception as e: st.error(f"โŒ Error reading file: {str(e)}") return elif paste_code.strip() != "": code_to_check = paste_code else: st.warning("โš ๏ธ Please either paste code or upload a file.") return # --- LINTING LOGIC --- # 1. Create Temp File (Pylint needs a file on disk) with tempfile.NamedTemporaryFile(delete=False, suffix=".py", mode='w', encoding='utf-8') as temp: temp.write(code_to_check) temp_path = temp.name # 2. Run Pylint pylint_output = io.StringIO() reporter = TextReporter(pylint_output) with st.spinner("Analyzing syntax..."): try: # --errors-only hides warnings, showing only code-breaking errors Run([temp_path, "--errors-only"], reporter=reporter, exit=False) except Exception as e: st.error(f"System Error: {e}") # 3. Cleanup & Display os.unlink(temp_path) # Delete temp file result = pylint_output.getvalue() st.markdown("---") if not result: st.success("โœ… No Syntax Errors Found! (Code looks valid)") st.balloons() else: st.error("โŒ Errors Found:") # Hide the messy temp file path from the user clean_report = result.replace(temp_path, "Your_Script.py") st.code(clean_report, language="text") # --- FINAL MAIN ROUTER (SPA VERSION) --- if __name__ == "__main__": # 1. INITIALIZE SESSION STATE (This replaces the URL logic) if 'mode' not in st.session_state: st.session_state.mode = 'home' # 3. NAVIGATION HANDLING # Function to change mode without URL reload def set_mode(new_mode): st.session_state.mode = new_mode # Show "Back to Dashboard" button if not home if st.session_state.mode != 'home': if st.button("โฌ…๏ธ Back to Grid"): set_mode('home') st.rerun() # 4. TOOL ROUTING (Checks session_state instead of URL) mode = st.session_state.mode if mode == "youtube": tool_youtube_downloader() elif mode == "smart_converter": tool_smart_converter() elif mode == "compressor": tool_image_compressor() elif mode == "resizer": tool_image_resizer() elif mode == "thumbnail": tool_thumbnail_generator() elif mode == "metatags": tool_meta_tag_generator() elif mode == "slug": tool_slug_generator() elif mode == "robots": tool_robots_generator() elif mode == "sitemap": tool_sitemap_builder() elif mode == "density": tool_keyword_density() elif mode == "plagiarism": tool_plagiarism_check() elif mode == "minify": tool_code_minifier() elif mode == "qrcode": tool_qr_generator() elif mode == "json": tool_json_formatter() elif mode == "base64": tool_base64() elif mode == "url": tool_url_encoder() elif mode == "markdown": tool_markdown_editor() elif mode == "regex": tool_regex_tester() elif mode == "uuid": tool_uuid_gen() elif mode == "hash": tool_hash_gen() elif mode == "case": tool_case_converter() elif mode == "lorem": tool_lorem_ipsum() elif mode == "counter": tool_word_counter() elif mode == "dedupe": tool_remove_duplicates() elif mode == "tts": tool_text_to_speech() elif mode == "timestamp": tool_timestamp() elif mode == "palette": tool_color_palette() elif mode == "password": tool_password_strength() elif mode == "ratio": tool_aspect_ratio() elif mode == "stopwatch": tool_stopwatch() elif mode == "python": tool_python_checker() elif mode == "seo": render_seo_ui() elif mode == "Pdf Converter": run_ultimate_pdf_converter() elif mode == "Replacer Tool": lexical_replacer_tool() # 5. HOME DASHBOARD (Button Grid) else: st.write("### โšก Select a tool to get started:") # We use standard Streamlit columns to create a grid layout # This replaces the Markdown links with actual Buttons c1, c2 = st.columns(2) with c1: st.info("**๐Ÿ“‚ Media & Files**") if st.button("Converter"): set_mode("Replacer Tool"); st.rerun() if st.button("๐ŸŽฅ Pdf"): set_mode("Pdf Converter"); st.rerun() if st.button("๐ŸŽฅ YouTube Downloader"): set_mode("youtube"); st.rerun() if st.button("๐ŸŽฅ Seo Generator"): set_mode("seo"); st.rerun() if st.button("๐Ÿ”„ Smart File Converter"): set_mode("smart_converter"); st.rerun() if st.button("๐Ÿ“‰ Image Compressor"): set_mode("compressor"); st.rerun() if st.button("๐Ÿ“ Image Resizer"): set_mode("resizer"); st.rerun() if st.button("๐Ÿ–ผ๏ธ Thumbnail Gen"): set_mode("thumbnail"); st.rerun() st.info("**๐Ÿ› ๏ธ Developer Tools**") if st.button("๐Ÿ QR Code Gen"): set_mode("qrcode"); st.rerun() if st.button("โœจ JSON Prettifier"): set_mode("json"); st.rerun() if st.button("๐Ÿ” Base64 Converter"): set_mode("base64"); st.rerun() if st.button("๐Ÿ”— URL Encoder"): set_mode("url"); st.rerun() if st.button("๐Ÿ“ Markdown Editor"): set_mode("markdown"); st.rerun() if st.button("๐Ÿงช Regex Tester"): set_mode("regex"); st.rerun() if st.button("๐Ÿ†” UUID Gen"): set_mode("uuid"); st.rerun() if st.button("๐Ÿ”‘ Hash Gen"): set_mode("hash"); st.rerun() with c2: st.info("**๐Ÿ•ธ๏ธ SEO & Webmaster**") if st.button("๐Ÿท๏ธ Meta Tag Gen"): set_mode("metatags"); st.rerun() if st.button("๐ŸŒ Slug Generator"): set_mode("slug"); st.rerun() if st.button("๐Ÿค– Robots.txt Gen"): set_mode("robots"); st.rerun() if st.button("๐Ÿ—บ๏ธ Sitemap Builder"): set_mode("sitemap"); st.rerun() if st.button("๐Ÿ“Š Density Checker"): set_mode("density"); st.rerun() if st.button("๐Ÿ•ต๏ธ Plagiarism Check"): set_mode("plagiarism"); st.rerun() if st.button("๐Ÿงน Code Minifier"): set_mode("minify"); st.rerun() st.info("**๐Ÿ“ Text & Utilities**") if st.button("๐Ÿ”  Case Converter"): set_mode("case"); st.rerun() if st.button("๐Ÿ“œ Lorem Ipsum"): set_mode("lorem"); st.rerun() if st.button("๐Ÿงฎ Word Counter"): set_mode("counter"); st.rerun() if st.button("๐Ÿ—‘๏ธ Dedupe Lines"): set_mode("dedupe"); st.rerun() if st.button("๐Ÿ—ฃ๏ธ Text to Speech"): set_mode("tts"); st.rerun() if st.button("โฐ Unix Timestamp"): set_mode("timestamp"); st.rerun() if st.button("๐ŸŽจ Color Palette"): set_mode("palette"); st.rerun() if st.button("๐Ÿ’ช Password Strength"): set_mode("password"); st.rerun() if st.button("๐Ÿ–ฅ๏ธ Aspect Ratio"): set_mode("ratio"); st.rerun() if st.button("โฑ๏ธ Stopwatch"): set_mode("stopwatch"); st.rerun() if st.button("Python Checker"): set_mode("python"); st.rerun()