lowersa commited on
Commit
1048408
·
1 Parent(s): e47c697

Added 30 tools and requirements

Browse files
Files changed (2) hide show
  1. app.py +669 -111
  2. requirements.txt +7 -5
app.py CHANGED
@@ -1,136 +1,694 @@
1
  import streamlit as st
2
  import requests
3
- import json
4
- import time
5
- from PIL import Image
6
  import io
 
 
 
 
 
 
 
 
 
 
7
  import re
 
8
  from bs4 import BeautifulSoup
9
- import markdown
10
-
11
- # --- PAGE CONFIG ---
12
- st.set_page_config(
13
- page_title="Lexical Tools",
14
- page_icon="⚡",
15
- layout="centered",
16
- initial_sidebar_state="expanded"
17
- )
18
-
19
- # --- SIDEBAR NAVIGATION ---
20
- st.sidebar.title("Navigation")
21
- query_params = st.query_params
22
- default_index = 1 if query_params.get("mode") == "downloader" else 0
23
-
24
- app_mode = st.sidebar.radio(
25
- "Choose Tool:",
26
- ["Webmaster Toolkit", "YouTube Downloader"],
27
- index=default_index
28
- )
29
-
30
- # ==========================================
31
- # VIEW 1: YOUTUBE DOWNLOADER (API Version)
32
- # ==========================================
33
- if app_mode == "YouTube Downloader":
34
- st.title("🎥 YouTube Media Extractor")
35
- st.info("High-Speed Downloader (Powered by Cobalt API)")
36
-
37
- url = st.text_input("Paste YouTube URL", placeholder="https://youtube.com/watch?v=...")
38
-
39
- col1, col2 = st.columns(2)
40
- with col1:
41
- # Cobalt supports various qualities. We'll map them simple.
42
- format_type = st.radio("Format", ["Video (MP4)", "Audio Only (MP3)"])
43
 
44
  if url and st.button("🚀 Process Media"):
45
- status_area = st.empty()
46
- status_area.info("⏳ Contacting processing server...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
 
48
- try:
49
- # Cobalt API Configuration
50
- api_url = "https://api.cobalt.tools/api/json"
51
- headers = {
52
- "Accept": "application/json",
53
- "Content-Type": "application/json",
54
- "User-Agent": "LexicalTools/1.0"
55
- }
56
 
57
- payload = {
58
- "url": url,
59
- "vCodec": "h264",
60
- "vQuality": "1080",
61
- "aFormat": "mp3",
62
- "isAudioOnly": True if "Audio" in format_type else False
63
- }
64
-
65
- # Send Request
66
- response = requests.post(api_url, headers=headers, json=payload)
67
- data = response.json()
68
-
69
- if "url" in data:
70
- download_link = data["url"]
71
- status_area.success("✅ Media Ready!")
 
72
 
73
- # Show a Direct Download Link (Fastest method)
74
- st.link_button(f"⬇️ Click to Download {format_type}", download_link)
75
 
76
- # Optional: Preview
77
- if "Audio" not in format_type:
78
- st.video(download_link)
79
- else:
80
- st.audio(download_link)
 
 
 
 
 
 
81
 
82
- elif "text" in data:
83
- # API returned an error message
84
- st.error(f"Server Error: {data['text']}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  else:
86
- st.error("Unknown error from processing server.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  except Exception as e:
89
- st.error(f"Connection Error: {str(e)}")
90
 
91
- # ==========================================
92
- # VIEW 2: WEBMASTER TOOLKIT (Existing)
93
- # ==========================================
94
- elif app_mode == "Webmaster Toolkit":
95
- st.title("⚡ Webmaster's Toolkit")
96
 
97
- tab1, tab2 = st.tabs(["📝 Text Cleaner & SEO", "🖼️ Media Optimizer"])
 
 
 
 
 
 
98
 
99
- # --- TEXT CLEANER TAB ---
100
- with tab1:
101
- st.write("Paste your raw text or messy HTML below.")
102
- raw_text = st.text_area("Input Text", height=200)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
- c1, c2, c3 = st.columns(3)
105
- processed_text = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
- if c1.button("Strip HTML"):
108
- soup = BeautifulSoup(raw_text, "html.parser")
109
- processed_text = soup.get_text(separator=" ")
110
-
111
- if c2.button("Fix Spacing"):
112
- processed_text = re.sub(r'\s+', ' ', raw_text).strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
- if c3.button("MD to HTML"):
115
- processed_text = markdown.markdown(raw_text)
 
 
 
116
 
117
- if processed_text:
118
- st.success("Done!")
119
- st.text_area("Result", value=processed_text, height=200)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
- # --- MEDIA OPTIMIZER TAB ---
122
- with tab2:
123
- st.write("Convert heavy images to WebP.")
124
- uploaded_file = st.file_uploader("Upload Image", type=['png', 'jpg', 'jpeg'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
 
126
- if uploaded_file:
127
- original_image = Image.open(uploaded_file)
128
- st.image(original_image, caption="Original", use_column_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
 
130
- if st.button("Convert to WebP"):
131
- buffer = io.BytesIO()
132
- original_image.save(buffer, format="WEBP", quality=80, optimize=True)
133
- buffer.seek(0)
134
- st.success("Converted!")
135
-
136
- st.download_button("Download WebP", data=buffer, file_name="image.webp")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
  import requests
3
+ import pandas as pd
4
+ from PIL import Image, ImageDraw, ImageFont
 
5
  import io
6
+ import time
7
+ import json
8
+ import base64
9
+ import uuid
10
+ import hashlib
11
+ import qrcode
12
+ import urllib.parse
13
+ import random
14
+ import datetime
15
+ from gtts import gTTS
16
  import re
17
+ from collections import Counter
18
  from bs4 import BeautifulSoup
19
+
20
+
21
+
22
+ # --- BATCH 1: MEDIA & FILE FUNCTIONS ---
23
+
24
+ def tool_youtube_downloader():
25
+ st.header("🎥 YouTube Media Extractor")
26
+ url = st.text_input("Paste YouTube URL", placeholder="https://youtube.com/...")
27
+ format_type = st.radio("Format", ["Video (MP4)", "Audio Only (MP3)"], horizontal=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  if url and st.button("🚀 Process Media"):
30
+ with st.spinner("Contacting server..."):
31
+ try:
32
+ headers = {"Accept": "application/json", "Content-Type": "application/json"}
33
+ payload = {
34
+ "url": url,
35
+ "vQuality": "1080",
36
+ "isAudioOnly": True if "Audio" in format_type else False
37
+ }
38
+ # Using Cobalt API
39
+ response = requests.post("https://api.cobalt.tools/api/json", headers=headers, json=payload)
40
+ data = response.json()
41
+
42
+ if "url" in data:
43
+ st.success("✅ Ready!")
44
+ st.link_button(f"⬇️ Download {format_type}", data["url"])
45
+ if "Audio" not in format_type:
46
+ st.video(data["url"])
47
+ else:
48
+ st.audio(data["url"])
49
+ else:
50
+ st.error(f"Error: {data.get('text', 'Unknown error')}")
51
+ except Exception as e:
52
+ st.error(f"Connection failed: {str(e)}")
53
+
54
+ def tool_smart_converter():
55
+ st.header("🔄 Smart File Converter")
56
+ st.info("Supports: Images (PNG/JPG/WEBP) and Data (CSV/JSON/Excel)")
57
+
58
+ uploaded_file = st.file_uploader("Upload File", type=['png', 'jpg', 'jpeg', 'webp', 'csv', 'json', 'xlsx'])
59
+
60
+ if uploaded_file:
61
+ file_type = uploaded_file.name.split('.')[-1].lower()
62
 
63
+ # LOGIC: IMAGE CONVERSION
64
+ if file_type in ['png', 'jpg', 'jpeg', 'webp']:
65
+ image = Image.open(uploaded_file)
66
+ st.image(image, caption="Preview", width=300)
67
+ target_format = st.selectbox("Convert to:", ["PNG", "JPEG", "WEBP", "PDF"])
 
 
 
68
 
69
+ if st.button("Convert Image"):
70
+ buf = io.BytesIO()
71
+ # RGB required for JPEG/PDF
72
+ if image.mode in ("RGBA", "P") and target_format in ["JPEG", "PDF"]:
73
+ image = image.convert("RGB")
74
+
75
+ image.save(buf, format=target_format)
76
+ st.download_button(f"Download {target_format}", data=buf.getvalue(), file_name=f"converted.{target_format.lower()}")
77
+
78
+ # LOGIC: DATA CONVERSION
79
+ elif file_type in ['csv', 'json', 'xlsx']:
80
+ df = None
81
+ try:
82
+ if file_type == 'csv': df = pd.read_csv(uploaded_file)
83
+ elif file_type == 'json': df = pd.read_json(uploaded_file)
84
+ elif file_type == 'xlsx': df = pd.read_excel(uploaded_file)
85
 
86
+ st.write("Data Preview:", df.head())
87
+ target_data = st.selectbox("Convert to:", ["CSV", "JSON", "Excel"])
88
 
89
+ if st.button("Convert Data"):
90
+ buf = io.BytesIO()
91
+ if target_data == "CSV":
92
+ df.to_csv(buf, index=False)
93
+ ext = "csv"
94
+ elif target_data == "JSON":
95
+ df.to_json(buf, orient='records')
96
+ ext = "json"
97
+ elif target_data == "Excel":
98
+ df.to_excel(buf, index=False)
99
+ ext = "xlsx"
100
 
101
+ st.download_button(f"Download {target_data}", data=buf.getvalue(), file_name=f"converted.{ext}")
102
+ except Exception as e:
103
+ st.error(f"Error reading file: {e}")
104
+
105
+ def tool_image_compressor():
106
+ st.header("📉 Image Compressor")
107
+ uploaded_file = st.file_uploader("Upload Image", type=['png', 'jpg', 'jpeg'])
108
+
109
+ if uploaded_file:
110
+ image = Image.open(uploaded_file)
111
+ st.write(f"Original Size: {uploaded_file.size / 1024:.2f} KB")
112
+ quality = st.slider("Quality (Lower = Smaller file)", 10, 95, 60)
113
+
114
+ if st.button("Compress"):
115
+ buf = io.BytesIO()
116
+ if image.mode in ("RGBA", "P"): image = image.convert("RGB")
117
+ image.save(buf, format="JPEG", quality=quality, optimize=True)
118
+
119
+ size_kb = len(buf.getvalue()) / 1024
120
+ st.success(f"Compressed Size: {size_kb:.2f} KB")
121
+ st.download_button("Download Compressed Image", data=buf.getvalue(), file_name="compressed.jpg")
122
+
123
+ def tool_image_resizer():
124
+ st.header("📐 Image Resizer")
125
+ uploaded_file = st.file_uploader("Upload Image", type=['png', 'jpg', 'jpeg', 'webp'])
126
+
127
+ if uploaded_file:
128
+ image = Image.open(uploaded_file)
129
+ st.write(f"Current Dimensions: {image.size}")
130
+
131
+ col1, col2 = st.columns(2)
132
+ w = col1.number_input("Width", value=image.width)
133
+ h = col2.number_input("Height", value=image.height)
134
+
135
+ if st.button("Resize"):
136
+ new_img = image.resize((int(w), int(h)))
137
+ buf = io.BytesIO()
138
+ new_img.save(buf, format=image.format)
139
+ st.image(new_img, caption="Resized Preview")
140
+ st.download_button("Download Resized Image", data=buf.getvalue(), file_name=f"resized.{image.format.lower()}")
141
+
142
+ def tool_thumbnail_generator():
143
+ st.header("🖼️ Blog Thumbnail Generator")
144
+ uploaded_file = st.file_uploader("Background Image", type=['png', 'jpg', 'jpeg'])
145
+ title_text = st.text_input("Title Text", "My Awesome Post")
146
+
147
+ if uploaded_file:
148
+ image = Image.open(uploaded_file).convert("RGBA")
149
+
150
+ # Simple Overlay Logic
151
+ txt_img = Image.new("RGBA", image.size, (255, 255, 255, 0))
152
+ draw = ImageDraw.Draw(txt_img)
153
+
154
+ # We use default font because loading system fonts on servers is risky
155
+ # For a real app, we would load a .ttf file included in the repo
156
+ # Drawing a semi-transparent black box for text readability
157
+ w, h = image.size
158
+ draw.rectangle([(0, h-100), (w, h)], fill=(0, 0, 0, 180))
159
+ draw.text((20, h-70), title_text, fill="white")
160
+
161
+ final = Image.alpha_composite(image, txt_img)
162
+
163
+ st.image(final, caption="Preview", use_column_width=True)
164
+
165
+ if st.button("Download Thumbnail"):
166
+ buf = io.BytesIO()
167
+ final.convert("RGB").save(buf, format="JPEG")
168
+ st.download_button("Download", data=buf.getvalue(), file_name="thumbnail.jpg")
169
+
170
+ # --- MAIN ROUTER (Paste this at the VERY END of app.py) ---
171
+ # This checks the URL params and decides which function to run
172
+ if __name__ == "__main__":
173
+ st.set_page_config(page_title="Lexical Space Tools", layout="centered")
174
+
175
+ # Get the 'mode' from the URL (e.g. ?mode=youtube)
176
+ params = st.query_params
177
+ mode = params.get("mode", "home")
178
+
179
+ # Routing Logic
180
+ if mode == "youtube":
181
+ tool_youtube_downloader()
182
+ elif mode == "smart_converter":
183
+ tool_smart_converter()
184
+ elif mode == "compressor":
185
+ tool_image_compressor()
186
+ elif mode == "resizer":
187
+ tool_image_resizer()
188
+ elif mode == "thumbnail":
189
+ tool_thumbnail_generator()
190
+ else:
191
+ st.title("⚡ Lexical Space Tools")
192
+ st.write("Select a tool to get started:")
193
+
194
+ # Dashboard Links (Batch 1)
195
+ st.markdown("""
196
+ * [🎥 YouTube Downloader](?mode=youtube)
197
+ * [🔄 Smart File Converter](?mode=smart_converter)
198
+ * [📉 Image Compressor](?mode=compressor)
199
+ * [📐 Image Resizer](?mode=resizer)
200
+ * [🖼️ Thumbnail Generator](?mode=thumbnail)
201
+ """)
202
+ # --- BATCH 2: WEBMASTER & SEO FUNCTIONS ---
203
+
204
+ def tool_meta_tag_generator():
205
+ st.header("🏷️ Meta Tag Generator")
206
+ title = st.text_input("Site Title", "My Awesome Blog")
207
+ desc = st.text_area("Description", "A blog about technology and coding.")
208
+ keywords = st.text_input("Keywords (comma separated)", "tech, coding, python")
209
+ author = st.text_input("Author", "Lexical Space")
210
+
211
+ if st.button("Generate Tags"):
212
+ code = f"""
213
+ <title>{title}</title>
214
+ <meta name="description" content="{desc}">
215
+ <meta name="keywords" content="{keywords}">
216
+ <meta name="author" content="{author}">
217
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
218
+ <meta property="og:type" content="website">
219
+ <meta property="og:title" content="{title}">
220
+ <meta property="og:description" content="{desc}">
221
+ """
222
+ st.code(code, language="html")
223
+
224
+ def tool_slug_generator():
225
+ st.header("🐌 URL Slug Generator")
226
+ text = st.text_input("Enter Post Title", "How to Install Python on Windows 10!")
227
+
228
+ if text:
229
+ # Lowercase, strip whitespace, replace spaces with dashes, remove non-alphanumeric
230
+ slug = text.lower().strip()
231
+ slug = re.sub(r'[^a-z0-9\s-]', '', slug)
232
+ slug = re.sub(r'[\s-]+', '-', slug)
233
+ st.success(f"Slug: {slug}")
234
+ st.code(slug, language="text")
235
+
236
+ def tool_robots_generator():
237
+ st.header("🤖 Robots.txt Generator")
238
+ st.write("Control which crawlers can access your site.")
239
+
240
+ all_agents = st.checkbox("Apply to all robots (*)", value=True)
241
+ disallow_admin = st.checkbox("Disallow /admin", value=True)
242
+ disallow_private = st.checkbox("Disallow /private", value=False)
243
+ sitemap_url = st.text_input("Sitemap URL (Optional)", "https://yoursite.com/sitemap.xml")
244
+
245
+ if st.button("Generate Robots.txt"):
246
+ agent = "*" if all_agents else "Googlebot"
247
+ txt = f"User-agent: {agent}\n"
248
+ if disallow_admin: txt += "Disallow: /admin/\n"
249
+ if disallow_private: txt += "Disallow: /private/\n"
250
+ if sitemap_url: txt += f"\nSitemap: {sitemap_url}"
251
+
252
+ st.text_area("Result", txt, height=150)
253
+
254
+ def tool_sitemap_builder():
255
+ st.header("🗺️ XML Sitemap Builder")
256
+ urls = st.text_area("Paste URLs (one per line)", "https://site.com\nhttps://site.com/about")
257
+
258
+ if st.button("Build XML"):
259
+ xml = '<?xml version="1.0" encoding="UTF-8"?>\n'
260
+ xml += '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
261
+
262
+ for url in urls.split('\n'):
263
+ if url.strip():
264
+ xml += f' <url>\n <loc>{url.strip()}</loc>\n <changefreq>monthly</changefreq>\n </url>\n'
265
+
266
+ xml += '</urlset>'
267
+ st.text_area("Sitemap.xml", xml, height=200)
268
+
269
+ def tool_keyword_density():
270
+ st.header("📊 Keyword Density Checker")
271
+ text = st.text_area("Paste Article Text", height=200)
272
+
273
+ if st.button("Analyze"):
274
+ # Simple stopword list to ignore
275
+ stopwords = set(['the', 'and', 'is', 'in', 'it', 'of', 'to', 'a', 'for', 'on', 'that', 'with', 'as'])
276
+
277
+ words = re.findall(r'\w+', text.lower())
278
+ filtered = [w for w in words if w not in stopwords and len(w) > 2]
279
+
280
+ counts = Counter(filtered).most_common(10)
281
+
282
+ df = pd.DataFrame(counts, columns=["Keyword", "Count"])
283
+ df['Density %'] = (df['Count'] / len(words) * 100).round(2)
284
+ st.table(df)
285
+
286
+ def tool_plagiarism_check():
287
+ st.header("🕵️ Plagiarism Scanner (Google Check)")
288
+ st.info("Splits text into sentences and searches Google for exact matches.")
289
+ text = st.text_area("Paste Text to Check", height=150)
290
+
291
+ if st.button("Check Text"):
292
+ sentences = re.split(r'[.!?]', text)
293
+ clean_sentences = [s.strip() for s in sentences if len(s.strip()) > 20]
294
+
295
+ for i, s in enumerate(clean_sentences[:5]): # Limit to first 5 for demo
296
+ query = f'"{s}"'
297
+ url = f"https://www.google.com/search?q={query}"
298
+ st.markdown(f"**Sentence {i+1}:** {s[:50]}...")
299
+ st.link_button(f"🔍 Check Google for Match", url)
300
+
301
+ def tool_code_minifier():
302
+ st.header("🧹 Code Minifier")
303
+ mode = st.radio("Type", ["HTML", "CSS"])
304
+ raw_code = st.text_area("Input Code", height=200)
305
+
306
+ if st.button("Minify"):
307
+ minified = ""
308
+ if mode == "HTML":
309
+ # Basic whitespace removal between tags
310
+ lines = raw_code.split('\n')
311
+ minified = "".join([line.strip() for line in lines])
312
+ elif mode == "CSS":
313
+ # Remove comments and whitespace
314
+ # 1. Remove comments
315
+ minified = re.sub(r'/\*[\s\S]*?\*/', '', raw_code)
316
+ # 2. Remove whitespace around braces/colons
317
+ minified = re.sub(r'\s*([{:;,])\s*', r'\1', minified)
318
+ # 3. Remove newlines
319
+ minified = minified.replace('\n', '').replace('\r', '')
320
+
321
+ st.text_area("Minified Output", minified, height=200)
322
+ # --- BATCH 3: DEVELOPER TOOLS ---
323
+
324
+ def tool_qr_generator():
325
+ st.header("🏁 QR Code Generator")
326
+ data = st.text_input("Enter Link or Text", "https://lexicalspace.blogspot.com")
327
+
328
+ if data:
329
+ qr = qrcode.QRCode(version=1, box_size=10, border=5)
330
+ qr.add_data(data)
331
+ qr.make(fit=True)
332
+ img = qr.make_image(fill='black', back_color='white')
333
+
334
+ buf = io.BytesIO()
335
+ img.save(buf)
336
+ st.image(img.get_image(), width=300)
337
+ st.download_button("Download QR", data=buf.getvalue(), file_name="qrcode.png")
338
+
339
+ def tool_json_formatter():
340
+ st.header("✨ JSON Prettifier")
341
+ raw = st.text_area("Paste Messy JSON", '{"id":1,"name":"Lexical","roles":["admin","dev"]}', height=150)
342
+
343
+ col1, col2 = st.columns(2)
344
+ if col1.button("Format (Pretty)"):
345
+ try:
346
+ parsed = json.loads(raw)
347
+ st.code(json.dumps(parsed, indent=4), language="json")
348
+ except Exception as e:
349
+ st.error(f"Invalid JSON: {e}")
350
+
351
+ if col2.button("Minify (Compact)"):
352
+ try:
353
+ parsed = json.loads(raw)
354
+ st.code(json.dumps(parsed, separators=(',', ':')), language="json")
355
+ except Exception as e:
356
+ st.error(f"Invalid JSON: {e}")
357
+
358
+ def tool_base64():
359
+ st.header("🔐 Base64 Converter")
360
+ mode = st.radio("Action", ["Encode", "Decode"], horizontal=True)
361
+ text = st.text_area("Input Text")
362
+
363
+ if st.button("Process"):
364
+ try:
365
+ if mode == "Encode":
366
+ res = base64.b64encode(text.encode()).decode()
367
  else:
368
+ res = base64.b64decode(text).decode()
369
+ st.code(res)
370
+ except Exception as e:
371
+ st.error(f"Error: {e}")
372
+
373
+ def tool_url_encoder():
374
+ st.header("🔗 URL Encoder/Decoder")
375
+ text = st.text_input("Input URL", "https://example.com/search?q=hello world")
376
+
377
+ c1, c2 = st.columns(2)
378
+ with c1:
379
+ if st.button("Encode"):
380
+ st.code(urllib.parse.quote(text))
381
+ with c2:
382
+ if st.button("Decode"):
383
+ st.code(urllib.parse.unquote(text))
384
 
385
+ def tool_markdown_editor():
386
+ st.header("📝 Markdown Editor")
387
+
388
+ col1, col2 = st.columns(2)
389
+ with col1:
390
+ md_text = st.text_area("Write Markdown", "# Hello\n* Item 1\n* Item 2", height=400)
391
+
392
+ with col2:
393
+ st.markdown("### Preview")
394
+ st.markdown(md_text)
395
+
396
+ def tool_regex_tester():
397
+ st.header("🧪 Regex Tester")
398
+ pattern = st.text_input("Regex Pattern", r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b")
399
+ text = st.text_area("Test String", "Contact us at support@lexical.com or admin@site.org")
400
+
401
+ if pattern and text:
402
+ try:
403
+ matches = re.findall(pattern, text)
404
+ st.write(f"Found {len(matches)} matches:")
405
+ st.json(matches)
406
  except Exception as e:
407
+ st.error(f"Regex Error: {e}")
408
 
409
+ def tool_uuid_gen():
410
+ st.header("🆔 UUID/GUID Generator")
411
+ count = st.number_input("How many?", 1, 100, 5)
 
 
412
 
413
+ if st.button("Generate"):
414
+ uuids = [str(uuid.uuid4()) for _ in range(count)]
415
+ st.code("\n".join(uuids), language="text")
416
+
417
+ def tool_hash_gen():
418
+ st.header("🔑 Hash Generator")
419
+ text = st.text_input("Input String", "mypassword")
420
 
421
+ if text:
422
+ st.write("**MD5:**")
423
+ st.code(hashlib.md5(text.encode()).hexdigest())
424
+ st.write("**SHA256:**")
425
+ st.code(hashlib.sha256(text.encode()).hexdigest())
426
+ # ... (Batch 1 & 2 Routing above) ...
427
+
428
+ # BATCH 3 ROUTING
429
+ elif mode == "qrcode": tool_qr_generator()
430
+ elif mode == "json": tool_json_formatter()
431
+ elif mode == "base64": tool_base64()
432
+ elif mode == "url": tool_url_encoder()
433
+ elif mode == "markdown": tool_markdown_editor()
434
+ elif mode == "regex": tool_regex_tester()
435
+ elif mode == "uuid": tool_uuid_gen()
436
+ elif mode == "hash": tool_hash_gen()
437
+
438
+ # ... (Home Dashboard below) ...
439
 
440
+ st.write("### 🛠️ Developer Tools")
441
+ st.markdown("""
442
+ * [🏁 QR Code Gen](?mode=qrcode)
443
+ * [✨ JSON Prettifier](?mode=json)
444
+ * [🔐 Base64 Converter](?mode=base64)
445
+ * [🔗 URL Encode/Decode](?mode=url)
446
+ * [📝 Markdown Editor](?mode=markdown)
447
+ * [🧪 Regex Tester](?mode=regex)
448
+ * [🆔 UUID Generator](?mode=uuid)
449
+ * [🔑 Hash Generator](?mode=hash)
450
+ """)
451
+ # --- BATCH 4: TEXT, UTILITIES & EXTRAS ---
452
+
453
+ def tool_case_converter():
454
+ st.header("🔠 Case Converter")
455
+ text = st.text_area("Input Text", "hello world")
456
+
457
+ c1, c2, c3, c4 = st.columns(4)
458
+ if c1.button("UPPERCASE"): st.code(text.upper(), language="text")
459
+ if c2.button("lowercase"): st.code(text.lower(), language="text")
460
+ if c3.button("Title Case"): st.code(text.title(), language="text")
461
+ if c4.button("aLtErNaTiNg"):
462
+ res = "".join([c.upper() if i%2==0 else c.lower() for i, c in enumerate(text)])
463
+ st.code(res, language="text")
464
+
465
+ def tool_lorem_ipsum():
466
+ st.header("📜 Lorem Ipsum Generator")
467
+ paras = st.slider("Paragraphs", 1, 10, 3)
468
+
469
+ dummy_text = [
470
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
471
+ "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
472
+ "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.",
473
+ "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum.",
474
+ "Excepteur sint occaecat cupidatat non proident, sunt in culpa."
475
+ ]
476
+
477
+ if st.button("Generate"):
478
+ result = "\n\n".join([random.choice(dummy_text) * 3 for _ in range(paras)])
479
+ st.text_area("Result", result, height=200)
480
+
481
+ def tool_word_counter():
482
+ st.header("🧮 Word & Character Counter")
483
+ text = st.text_area("Paste Text Here", height=200)
484
+
485
+ if text:
486
+ words = len(text.split())
487
+ chars = len(text)
488
+ no_space = len(text.replace(" ", ""))
489
+ read_time = round(words / 200, 2)
490
 
491
+ c1, c2, c3, c4 = st.columns(4)
492
+ c1.metric("Words", words)
493
+ c2.metric("Chars", chars)
494
+ c3.metric("No Spaces", no_space)
495
+ c4.metric("Read Time", f"{read_time} min")
496
+
497
+ def tool_remove_duplicates():
498
+ st.header("🗑️ Remove Duplicate Lines")
499
+ text = st.text_area("Paste List (One per line)", "Apple\nBanana\nApple\nOrange")
500
+
501
+ if st.button("Clean"):
502
+ lines = text.split('\n')
503
+ seen = set()
504
+ clean = []
505
+ for line in lines:
506
+ if line not in seen and line.strip():
507
+ clean.append(line)
508
+ seen.add(line)
509
+ st.text_area("Cleaned List", "\n".join(clean), height=200)
510
+
511
+ def tool_text_to_speech():
512
+ st.header("🗣️ Text to Speech")
513
+ text = st.text_area("Enter Text", "Hello, welcome to Lexical Space.")
514
+ lang = st.selectbox("Language", ["en", "es", "fr", "de", "hi"])
515
+
516
+ if st.button("Speak"):
517
+ try:
518
+ tts = gTTS(text=text, lang=lang, slow=False)
519
+ buf = io.BytesIO()
520
+ tts.write_to_fp(buf)
521
+ st.audio(buf, format='audio/mp3')
522
+ except Exception as e:
523
+ st.error(f"Error: {e}")
524
+
525
+ def tool_timestamp():
526
+ st.header("⏰ Unix Timestamp Converter")
527
+ now = int(time.time())
528
+ st.write(f"Current Timestamp: `{now}`")
529
+
530
+ col1, col2 = st.columns(2)
531
+ with col1:
532
+ ts_input = st.number_input("Timestamp to Date", value=now)
533
+ if st.button("Convert to Date"):
534
+ st.success(datetime.datetime.fromtimestamp(ts_input))
535
 
536
+ with col2:
537
+ d_input = st.date_input("Date to Timestamp")
538
+ if st.button("Convert to Timestamp"):
539
+ ts = int(time.mktime(d_input.timetuple()))
540
+ st.success(ts)
541
 
542
+ def tool_color_palette():
543
+ st.header("🎨 Image Color Palette")
544
+ uploaded_file = st.file_uploader("Upload Image", type=['jpg', 'png'])
545
+
546
+ if uploaded_file:
547
+ img = Image.open(uploaded_file).convert("RGB")
548
+ st.image(img, width=200)
549
+
550
+ # Simple extraction by resizing to 5 pixels
551
+ small = img.resize((5, 1))
552
+ colors = small.getdata()
553
+
554
+ st.write("Dominant Colors:")
555
+ cols = st.columns(5)
556
+ for i, color in enumerate(colors):
557
+ hex_code = '#{:02x}{:02x}{:02x}'.format(*color)
558
+ cols[i].color_picker(f"Color {i+1}", hex_code, disabled=True)
559
+ cols[i].code(hex_code)
560
 
561
+ def tool_password_strength():
562
+ st.header("💪 Password Strength")
563
+ pwd = st.text_input("Test Password", type="password")
564
+
565
+ if pwd:
566
+ score = 0
567
+ if len(pwd) >= 8: score += 1
568
+ if re.search(r"[A-Z]", pwd): score += 1
569
+ if re.search(r"[a-z]", pwd): score += 1
570
+ if re.search(r"\d", pwd): score += 1
571
+ if re.search(r"[!@#$%^&*]", pwd): score += 1
572
+
573
+ st.progress(score / 5)
574
+ if score < 3: st.warning("Weak")
575
+ elif score < 5: st.info("Moderate")
576
+ else: st.success("Strong!")
577
+
578
+ def tool_aspect_ratio():
579
+ st.header("🖥️ Aspect Ratio Calculator")
580
+ w = st.number_input("Width", 1920)
581
+ h = st.number_input("Height", 1080)
582
+
583
+ if w and h:
584
+ def gcd(a, b):
585
+ while b: a, b = b, a % b
586
+ return a
587
+ divisor = gcd(int(w), int(h))
588
+ st.metric("Aspect Ratio", f"{int(w/divisor)}:{int(h/divisor)}")
589
+
590
+ def tool_stopwatch():
591
+ st.header("⏱️ Stopwatch")
592
+ if 'start_time' not in st.session_state: st.session_state.start_time = None
593
+
594
+ if st.button("Start/Reset"):
595
+ st.session_state.start_time = time.time()
596
 
597
+ if st.session_state.start_time:
598
+ elapsed = time.time() - st.session_state.start_time
599
+ st.metric("Time Elapsed", f"{elapsed:.2f}s")
600
+ if st.button("Stop"):
601
+ st.session_state.start_time = None
602
+ # --- FINAL MAIN ROUTER ---
603
+ if __name__ == "__main__":
604
+ st.set_page_config(page_title="Lexical Tools", layout="centered")
605
+
606
+ # Hide Streamlit Style
607
+ st.markdown("""
608
+ <style>
609
+ #MainMenu {visibility: hidden;}
610
+ footer {visibility: hidden;}
611
+ header {visibility: hidden;}
612
+ </style>
613
+ """, unsafe_allow_html=True)
614
+
615
+ params = st.query_params
616
+ mode = params.get("mode", "home")
617
+
618
+ # --- ROUTING MAP ---
619
+ if mode == "youtube": tool_youtube_downloader()
620
+ elif mode == "smart_converter": tool_smart_converter()
621
+ elif mode == "compressor": tool_image_compressor()
622
+ elif mode == "resizer": tool_image_resizer()
623
+ elif mode == "thumbnail": tool_thumbnail_generator()
624
+ elif mode == "metatags": tool_meta_tag_generator()
625
+ elif mode == "slug": tool_slug_generator()
626
+ elif mode == "robots": tool_robots_generator()
627
+ elif mode == "sitemap": tool_sitemap_builder()
628
+ elif mode == "density": tool_keyword_density()
629
+ elif mode == "plagiarism": tool_plagiarism_check()
630
+ elif mode == "minify": tool_code_minifier()
631
+ elif mode == "qrcode": tool_qr_generator()
632
+ elif mode == "json": tool_json_formatter()
633
+ elif mode == "base64": tool_base64()
634
+ elif mode == "url": tool_url_encoder()
635
+ elif mode == "markdown": tool_markdown_editor()
636
+ elif mode == "regex": tool_regex_tester()
637
+ elif mode == "uuid": tool_uuid_gen()
638
+ elif mode == "hash": tool_hash_gen()
639
+ elif mode == "case": tool_case_converter()
640
+ elif mode == "lorem": tool_lorem_ipsum()
641
+ elif mode == "counter": tool_word_counter()
642
+ elif mode == "dedupe": tool_remove_duplicates()
643
+ elif mode == "tts": tool_text_to_speech()
644
+ elif mode == "timestamp": tool_timestamp()
645
+ elif mode == "palette": tool_color_palette()
646
+ elif mode == "password": tool_password_strength()
647
+ elif mode == "ratio": tool_aspect_ratio()
648
+ elif mode == "stopwatch": tool_stopwatch()
649
+
650
+ else:
651
+ st.title("⚡ Lexical Space Tools")
652
+ st.markdown("### The Ultimate Blogger & Dev Toolkit")
653
+
654
+ c1, c2 = st.columns(2)
655
+
656
+ with c1:
657
+ st.write("**📂 Media & Files**")
658
+ st.write("[🎥 YouTube Downloader](?mode=youtube)")
659
+ st.write("[🔄 Smart Converter](?mode=smart_converter)")
660
+ st.write("[📉 Image Compressor](?mode=compressor)")
661
+ st.write("[📐 Image Resizer](?mode=resizer)")
662
+ st.write("[🖼️ Thumbnail Gen](?mode=thumbnail)")
663
 
664
+ st.write("**🛠️ Developer**")
665
+ st.write("[🏁 QR Code Gen](?mode=qrcode)")
666
+ st.write("[✨ JSON Prettifier](?mode=json)")
667
+ st.write("[🔐 Base64 Tool](?mode=base64)")
668
+ st.write("[🔗 URL Encode](?mode=url)")
669
+ st.write("[📝 Markdown Editor](?mode=markdown)")
670
+ st.write("[🧪 Regex Tester](?mode=regex)")
671
+ st.write("[🆔 UUID Gen](?mode=uuid)")
672
+ st.write("[🔑 Hash Gen](?mode=hash)")
673
+
674
+ with c2:
675
+ st.write("**🕸️ SEO & Web**")
676
+ st.write("[🏷️ Meta Tag Gen](?mode=metatags)")
677
+ st.write("[🐌 Slug Gen](?mode=slug)")
678
+ st.write("[🤖 Robots.txt](?mode=robots)")
679
+ st.write("[🗺️ Sitemap Builder](?mode=sitemap)")
680
+ st.write("[📊 Density Check](?mode=density)")
681
+ st.write("[🕵️ Plagiarism](?mode=plagiarism)")
682
+ st.write("[🧹 Code Minifier](?mode=minify)")
683
+
684
+ st.write("**📝 Text & Utils**")
685
+ st.write("[🔠 Case Converter](?mode=case)")
686
+ st.write("[📜 Lorem Ipsum](?mode=lorem)")
687
+ st.write("[🧮 Word Counter](?mode=counter)")
688
+ st.write("[🗑️ Dedupe Lines](?mode=dedupe)")
689
+ st.write("[🗣️ Text to Speech](?mode=tts)")
690
+ st.write("[⏰ Unix Timestamp](?mode=timestamp)")
691
+ st.write("[🎨 Color Palette](?mode=palette)")
692
+ st.write("[💪 Password Check](?mode=password)")
693
+ st.write("[🖥️ Aspect Ratio](?mode=ratio)")
694
+ st.write("[⏱️ Stopwatch](?mode=stopwatch)")
requirements.txt CHANGED
@@ -1,9 +1,11 @@
1
  streamlit
 
2
  beautifulsoup4
3
  markdown
4
  Pillow
5
- fastapi
6
- uvicorn
7
- yt-dlp
8
- gradio
9
- ffmpeg-python
 
 
1
  streamlit
2
+ requests
3
  beautifulsoup4
4
  markdown
5
  Pillow
6
+ pandas
7
+ openpyxl
8
+ pypdf
9
+ qrcode[pil]
10
+ gTTS
11
+ moviepy