lexicalspace commited on
Commit
39655da
·
verified ·
1 Parent(s): 72a0624

Delete app.py

Browse files
Files changed (1) hide show
  1. app.py +0 -1027
app.py DELETED
@@ -1,1027 +0,0 @@
1
- import streamlit as st
2
- import requests
3
- from PIL import Image, ImageDraw, ImageFont
4
- import io
5
- import time
6
- import json
7
- import base64
8
- import uuid
9
- import hashlib
10
- import urllib.parse
11
- import random
12
- import datetime
13
- import re
14
- from collections import Counter
15
- from bs4 import BeautifulSoup
16
-
17
-
18
-
19
- # --- BATCH 1: MEDIA & FILE FUNCTIONS ---
20
- import gradio as gr
21
- import os
22
- from huggingface_hub import InferenceClient
23
-
24
- def run_seo_app():
25
- """
26
- Encapsulates the entire SEO generation system, authentication, and UI
27
- into a single executable function.
28
- """
29
-
30
- # --- 1. SETUP & AUTHENTICATION ---
31
- # Get the token from the Space secrets to fix "Auth" errors
32
- hf_token = os.getenv("HF_TOKEN")
33
-
34
- # Initialize the client with Qwen 2.5 Coder 32B
35
- model_id = "Qwen/Qwen2.5-Coder-32B-Instruct"
36
- client = InferenceClient(token=hf_token)
37
-
38
- # --- 2. LOGIC FUNCTION ---
39
- def generate_seo(code_snippet, file_type):
40
- if not code_snippet.strip():
41
- return "⚠️ Error: Please paste some code first."
42
-
43
- # Define the strict SEO prompt
44
- system_instruction = f"""
45
- You are an expert Technical SEO Specialist. Analyze the user's {file_type} code.
46
-
47
- Your Goal: Generate Google-compliant JSON-LD structured data and SEO meta tags.
48
-
49
- Output Format (Strict Markdown):
50
- ## SEO Metadata
51
- **Title:** [Engaging Title, max 60 chars]
52
- **Description:** [Summary including keywords, max 160 chars]
53
- **Keywords:** [5-8 comma-separated keywords]
54
-
55
- ## JSON-LD Structured Data
56
- ```json
57
- [Insert VALID JSON-LD here.
58
- - If Python: Use schema.org/SoftwareSourceCode
59
- - If HTML: Use schema.org/WebPage or schema.org/TechArticle]
60
- ```
61
- """
62
-
63
- user_message = f"Analyze this {file_type} code:\n\n{code_snippet}"
64
-
65
- try:
66
- # Call the Chat Completion API
67
- response = client.chat_completion(
68
- model=model_id,
69
- messages=[
70
- {"role": "system", "content": system_instruction},
71
- {"role": "user", "content": user_message}
72
- ],
73
- max_tokens=1500,
74
- temperature=0.2
75
- )
76
- return response.choices[0].message.content
77
-
78
- except Exception as e:
79
- # Error handling logic
80
- error_msg = str(e)
81
- if "401" in error_msg:
82
- return "🔒 Authentication Error: Please check that you added 'HF_TOKEN' to your Space Secrets."
83
- elif "429" in error_msg:
84
- return "⏳ Rate Limit: The free model is busy. Please wait 1 minute and try again."
85
- elif "504" in error_msg:
86
- return "⏱️ Timeout: The code snippet might be too long. Try a shorter piece of code."
87
- else:
88
- return f"❌ System Error: {error_msg}"
89
-
90
- # --- 3. UI CONSTRUCTION ---
91
- with gr.Blocks(theme=gr.themes.Soft()) as demo:
92
- gr.Markdown(
93
- """
94
- # ⚡ SEO & JSON-LD Generator (Authenticated)
95
- **Status:** ✅ Connected to Qwen 2.5 Coder
96
- """
97
- )
98
-
99
- with gr.Row():
100
- with gr.Column(scale=1):
101
- input_type = gr.Radio(["python", "html"], label="Select File Type", value="python")
102
- code_input = gr.Code(language="python", label="Paste Code Here", lines=15)
103
- submit_btn = gr.Button("✨ Generate SEO Data", variant="primary", size="lg")
104
-
105
- with gr.Column(scale=1):
106
- output_markdown = gr.Markdown(label="Results will appear here...")
107
-
108
- # Dynamic syntax highlighting
109
- input_type.change(lambda x: gr.Code(language=x), inputs=input_type, outputs=code_input)
110
-
111
- # Button Click Action
112
- submit_btn.click(
113
- fn=generate_seo,
114
- inputs=[code_input, input_type],
115
- outputs=output_markdown
116
- )
117
-
118
- # --- 4. LAUNCH ---
119
- demo.launch()
120
-
121
-
122
-
123
-
124
-
125
- def tool_youtube_downloader():
126
- st.header("🎥 YouTube Media Extractor")
127
- url = st.text_input("Paste YouTube URL", placeholder="https://youtube.com/...")
128
- format_type = st.radio("Format", ["Video (MP4)", "Audio Only (MP3)"], horizontal=True)
129
-
130
- if url and st.button("🚀 Process Media"):
131
- with st.spinner("Contacting server..."):
132
- try:
133
- headers = {"Accept": "application/json", "Content-Type": "application/json"}
134
- payload = {
135
- "url": url,
136
- "vQuality": "1080",
137
- "isAudioOnly": True if "Audio" in format_type else False
138
- }
139
- # Using Cobalt API
140
- response = requests.post("https://api.cobalt.tools/api/json", headers=headers, json=payload)
141
- data = response.json()
142
-
143
- if "url" in data:
144
- st.success("�� Ready!")
145
- st.link_button(f"⬇️ Download {format_type}", data["url"])
146
- if "Audio" not in format_type:
147
- st.video(data["url"])
148
- else:
149
- st.audio(data["url"])
150
- else:
151
- st.error(f"Error: {data.get('text', 'Unknown error')}")
152
- except Exception as e:
153
- st.error(f"Connection failed: {str(e)}")
154
-
155
- def tool_smart_converter():
156
- with st.spinner("Starting File Engine..."):
157
-
158
- time.sleep(0.3)
159
-
160
-
161
- import pandas as pd
162
- st.header("🔄 Smart File Converter")
163
- st.info("Supports: Images (PNG/JPG/WEBP) and Data (CSV/JSON/Excel)")
164
-
165
- uploaded_file = st.file_uploader("Upload File", type=['png', 'jpg', 'jpeg', 'webp', 'csv', 'json', 'xlsx'],key="smart_conv_upload")
166
-
167
- if uploaded_file:
168
- file_type = uploaded_file.name.split('.')[-1].lower()
169
-
170
- # LOGIC: IMAGE CONVERSION
171
- if file_type in ['png', 'jpg', 'jpeg', 'webp']:
172
- image = Image.open(uploaded_file)
173
- st.image(image, caption="Preview", width=300)
174
- target_format = st.selectbox("Convert to:", ["PNG", "JPEG", "WEBP", "PDF"])
175
-
176
- if st.button("Convert Image"):
177
- buf = io.BytesIO()
178
- # RGB required for JPEG/PDF
179
- if image.mode in ("RGBA", "P") and target_format in ["JPEG", "PDF"]:
180
- image = image.convert("RGB")
181
-
182
- image.save(buf, format=target_format)
183
- st.download_button(f"Download {target_format}", data=buf.getvalue(), file_name=f"converted.{target_format.lower()}")
184
-
185
- # LOGIC: DATA CONVERSION
186
- elif file_type in ['csv', 'json', 'xlsx']:
187
- df = None
188
- try:
189
- if file_type == 'csv': df = pd.read_csv(uploaded_file)
190
- elif file_type == 'json': df = pd.read_json(uploaded_file)
191
- elif file_type == 'xlsx': df = pd.read_excel(uploaded_file)
192
-
193
- st.write("Data Preview:", df.head())
194
- target_data = st.selectbox("Convert to:", ["CSV", "JSON", "Excel"])
195
-
196
- if st.button("Convert Data"):
197
- buf = io.BytesIO()
198
- if target_data == "CSV":
199
- df.to_csv(buf, index=False)
200
- ext = "csv"
201
- elif target_data == "JSON":
202
- df.to_json(buf, orient='records')
203
- ext = "json"
204
- elif target_data == "Excel":
205
- df.to_excel(buf, index=False)
206
- ext = "xlsx"
207
-
208
- st.download_button(f"Download {target_data}", data=buf.getvalue(), file_name=f"converted.{ext}")
209
- except Exception as e:
210
- st.error(f"Error reading file: {e}")
211
-
212
- def tool_image_compressor():
213
- st.header("📉 Image Compressor")
214
- # ADD key="compressor"
215
- uploaded_file = st.file_uploader("Upload Image", type=['png', 'jpg', 'jpeg'], key="compressor")
216
-
217
-
218
-
219
- if uploaded_file:
220
- image = Image.open(uploaded_file)
221
- st.write(f"Original Size: {uploaded_file.size / 1024:.2f} KB")
222
- quality = st.slider("Quality (Lower = Smaller file)", 10, 95, 60)
223
-
224
- if st.button("Compress"):
225
- buf = io.BytesIO()
226
- if image.mode in ("RGBA", "P"): image = image.convert("RGB")
227
- image.save(buf, format="JPEG", quality=quality, optimize=True)
228
-
229
- size_kb = len(buf.getvalue()) / 1024
230
- st.success(f"Compressed Size: {size_kb:.2f} KB")
231
- st.download_button("Download Compressed Image", data=buf.getvalue(), file_name="compressed.jpg")
232
-
233
- def tool_image_resizer():
234
- st.header("📐 Image Resizer")
235
- # ADD key="resizer"
236
- uploaded_file = st.file_uploader("Upload Image", type=['png', 'jpg', 'jpeg', 'webp'], key="resizer")
237
-
238
-
239
-
240
- if uploaded_file:
241
- image = Image.open(uploaded_file)
242
- st.write(f"Current Dimensions: {image.size}")
243
-
244
- col1, col2 = st.columns(2)
245
- w = col1.number_input("Width", value=image.width)
246
- h = col2.number_input("Height", value=image.height)
247
-
248
- if st.button("Resize"):
249
- new_img = image.resize((int(w), int(h)))
250
- buf = io.BytesIO()
251
- new_img.save(buf, format=image.format)
252
- st.image(new_img, caption="Resized Preview")
253
- st.download_button("Download Resized Image", data=buf.getvalue(), file_name=f"resized.{image.format.lower()}")
254
-
255
- def tool_thumbnail_generator():
256
- st.header("🚀 Ultimate Thumbnail Studio")
257
-
258
- # --- DEPENDENCIES ---
259
- from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageEnhance, ImageOps, ImageColor
260
- import io
261
-
262
- # --- LAYOUT FIX FOR PC/MOBILE ---
263
- # We use a container for the controls to keep them tidy on PC
264
- # and "use_column_width" to fix the crash.
265
-
266
- # Top row: All Controls (Split into 2 columns for better PC spacing)
267
- with st.expander("🎨 Thumbnail Settings & Controls", expanded=True):
268
- col_c1, col_c2 = st.columns(2)
269
-
270
- # --- LEFT CONTROL COLUMN ---
271
- with col_c1:
272
- st.subheader("1. Background & Filters")
273
- bg_mode = st.radio("Background Type", ["Upload Image", "Solid Color", "Gradient"], horizontal=True)
274
-
275
- bg_image = None
276
- if bg_mode == "Upload Image":
277
- bg_file = st.file_uploader("Upload BG", type=['png', 'jpg', 'jpeg', 'webp'], key="max_bg")
278
- if bg_file: bg_image = Image.open(bg_file).convert("RGBA")
279
- elif bg_mode == "Solid Color":
280
- hex_bg = st.color_picker("Pick Color", "#1E1E1E")
281
- st.session_state.thumb_bg_color = hex_bg
282
- else: # Gradient
283
- c1_col, c2_col = st.columns(2)
284
- grad_c1 = c1_col.color_picker("Start", "#12c2e9")
285
- grad_c2 = c2_col.color_picker("End", "#c471ed")
286
- grad_dir = st.selectbox("Direction", ["Horizontal", "Vertical"])
287
-
288
- st.markdown("---")
289
- st.write("**Filters**")
290
- f1, f2 = st.columns(2)
291
- blur_amt = f1.slider("Blur", 0, 20, 0)
292
- brightness = f2.slider("Brightness", 0.5, 1.5, 1.0)
293
-
294
- # --- RIGHT CONTROL COLUMN ---
295
- with col_c2:
296
- st.subheader("2. Text & Branding")
297
- main_text = st.text_area("Main Title", "THE ULTIMATE\nGUIDE TO PYTHON", height=100)
298
-
299
- t1, t2 = st.columns(2)
300
- font_size = t1.slider("Size", 20, 200, 80)
301
- font_color = t2.color_picker("Text Color", "#FFFFFF")
302
-
303
- st.write("**Styling**")
304
- s1, s2 = st.columns(2)
305
- stroke_width = s1.slider("Outline", 0, 10, 2)
306
- stroke_color = s2.color_picker("Outline Color", "#000000")
307
-
308
- st.markdown("---")
309
- logo_file = st.file_uploader("Upload Logo (PNG)", type=['png', 'webp'], key="max_logo")
310
- if logo_file:
311
- l1, l2 = st.columns(2)
312
- logo_size = l1.slider("Logo Size", 50, 300, 150)
313
- logo_pos = l2.selectbox("Position", ["Top-Right", "Top-Left", "Bottom-Right", "Bottom-Left"])
314
- else:
315
- logo_size = 150
316
- logo_pos = "Top-Right"
317
-
318
- # --- PREVIEW SECTION (Full Width for PC clarity) ---
319
- st.subheader("👁️ Preview & Download")
320
-
321
- # GENERATION LOGIC
322
- CANVAS_W, CANVAS_H = 1280, 720
323
- canvas = Image.new("RGBA", (CANVAS_W, CANVAS_H), (0,0,0,0))
324
-
325
- # 1. Background
326
- if bg_mode == "Upload Image" and bg_image:
327
- bg_ratio = bg_image.width / bg_image.height
328
- target_ratio = CANVAS_W / CANVAS_H
329
- if bg_ratio > target_ratio:
330
- new_h = CANVAS_H
331
- new_w = int(new_h * bg_ratio)
332
- else:
333
- new_w = CANVAS_W
334
- new_h = int(new_w / bg_ratio)
335
- bg_image = bg_image.resize((new_w, new_h), Image.Resampling.LANCZOS)
336
- left = (new_w - CANVAS_W)/2
337
- top = (new_h - CANVAS_H)/2
338
- bg_image = bg_image.crop((left, top, left+CANVAS_W, top+CANVAS_H))
339
- canvas.paste(bg_image, (0,0))
340
- elif bg_mode == "Gradient":
341
- base = Image.new('RGB', (CANVAS_W, CANVAS_H), grad_c1)
342
- top_img = Image.new('RGB', (CANVAS_W, CANVAS_H), grad_c2)
343
- mask = Image.new("L", (CANVAS_W, CANVAS_H))
344
- mask_data = []
345
- for y in range(CANVAS_H):
346
- for x in range(CANVAS_W):
347
- if grad_dir == "Vertical": mask_data.append(int(255 * (y / CANVAS_H)))
348
- else: mask_data.append(int(255 * (x / CANVAS_W)))
349
- mask.putdata(mask_data)
350
- canvas = Image.composite(top_img, base, mask).convert("RGBA")
351
- else:
352
- if 'thumb_bg_color' not in st.session_state: st.session_state.thumb_bg_color = "#1E1E1E"
353
- canvas = Image.new("RGBA", (CANVAS_W, CANVAS_H), st.session_state.thumb_bg_color)
354
-
355
- # 2. Filters
356
- if blur_amt > 0: canvas = canvas.filter(ImageFilter.GaussianBlur(blur_amt))
357
- if brightness != 1.0:
358
- enhancer = ImageEnhance.Brightness(canvas)
359
- canvas = enhancer.enhance(brightness)
360
-
361
- # 3. Text
362
- txt_layer = Image.new("RGBA", canvas.size, (255,255,255,0))
363
- draw = ImageDraw.Draw(txt_layer)
364
-
365
- try:
366
- font = ImageFont.truetype("arialbd.ttf", font_size)
367
- except:
368
- try:
369
- font = ImageFont.truetype("arial.ttf", font_size)
370
- except:
371
- font = ImageFont.load_default()
372
-
373
- # Center Text Calculation
374
- # Using basic textsize for compatibility if textbbox fails in older Pillow
375
- try:
376
- bbox = draw.multiline_textbbox((0,0), main_text, font=font, align="center")
377
- text_w = bbox[2] - bbox[0]
378
- text_h = bbox[3] - bbox[1]
379
- except:
380
- # Fallback for very old Pillow versions
381
- text_w, text_h = draw.textsize(main_text, font=font)
382
-
383
- cx, cy = CANVAS_W // 2, CANVAS_H // 2
384
- text_x = cx - (text_w // 2)
385
- text_y = cy - (text_h // 2)
386
-
387
- # Shadow
388
- draw.multiline_text((text_x + 8, text_y + 8), main_text, font=font, align="center", fill="black")
389
- # Main Text
390
- draw.multiline_text((text_x, text_y), main_text, font=font, align="center", fill=font_color, stroke_width=stroke_width, stroke_fill=stroke_color)
391
-
392
- # 4. Logo
393
- if logo_file:
394
- logo = Image.open(logo_file).convert("RGBA")
395
- logo.thumbnail((logo_size, logo_size), Image.Resampling.LANCZOS)
396
- pad = 30
397
- if "Top" in logo_pos: ly = pad
398
- elif "Bottom" in logo_pos: ly = CANVAS_H - logo.height - pad
399
- if "Left" in logo_pos: lx = pad
400
- elif "Right" in logo_pos: lx = CANVAS_W - logo.width - pad
401
- txt_layer.paste(logo, (lx, ly), logo)
402
-
403
- # Final Composite
404
- final_comp = Image.alpha_composite(canvas, txt_layer)
405
-
406
- # --- DISPLAY & DOWNLOAD ---
407
- # Centered layout for PC look
408
- col_show, col_down = st.columns([3, 1])
409
-
410
- with col_show:
411
- # FIX: Changed use_container_width to use_column_width
412
- st.image(final_comp, caption="Result", use_column_width=True)
413
-
414
- with col_down:
415
- st.write("### Ready?")
416
- buf = io.BytesIO()
417
- final_comp.convert("RGB").save(buf, format="PNG")
418
- st.download_button("💾 Download PNG", data=buf.getvalue(), file_name="thumbnail.png", mime="image/png")
419
- # --- MAIN ROUTER (Paste this at the VERY END of app.py) ---
420
- # This checks the URL params and decides which function to run
421
- if __name__ == "__main__":
422
- st.set_page_config(page_title="Lexical Space Tools", layout="centered")
423
-
424
- # Get the 'mode' from the URL (e.g. ?mode=youtube)
425
- params = st.query_params
426
- mode = params.get("mode", "home")
427
-
428
-
429
-
430
-
431
-
432
- # --- BATCH 2: WEBMASTER & SEO FUNCTIONS ---
433
-
434
- def tool_meta_tag_generator():
435
- st.header("🏷️ Meta Tag Generator")
436
- title = st.text_input("Site Title", "My Awesome Blog")
437
- desc = st.text_area("Description", "A blog about technology and coding.")
438
- keywords = st.text_input("Keywords (comma separated)", "tech, coding, python")
439
- author = st.text_input("Author", "Lexical Space")
440
-
441
- if st.button("Generate Tags"):
442
- code = f"""
443
- <title>{title}</title>
444
- <meta name="description" content="{desc}">
445
- <meta name="keywords" content="{keywords}">
446
- <meta name="author" content="{author}">
447
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
448
- <meta property="og:type" content="website">
449
- <meta property="og:title" content="{title}">
450
- <meta property="og:description" content="{desc}">
451
- """
452
- st.code(code, language="html")
453
-
454
- def tool_slug_generator():
455
- st.header("🐌 URL Slug Generator")
456
- text = st.text_input("Enter Post Title", "How to Install Python on Windows 10!")
457
-
458
- if text:
459
- # Lowercase, strip whitespace, replace spaces with dashes, remove non-alphanumeric
460
- slug = text.lower().strip()
461
- slug = re.sub(r'[^a-z0-9\s-]', '', slug)
462
- slug = re.sub(r'[\s-]+', '-', slug)
463
- st.success(f"Slug: {slug}")
464
- st.code(slug, language="text")
465
-
466
- def tool_robots_generator():
467
- st.header("🤖 Robots.txt Generator")
468
- st.write("Control which crawlers can access your site.")
469
-
470
- all_agents = st.checkbox("Apply to all robots (*)", value=True)
471
- disallow_admin = st.checkbox("Disallow /admin", value=True)
472
- disallow_private = st.checkbox("Disallow /private", value=False)
473
- sitemap_url = st.text_input("Sitemap URL (Optional)", "https://yoursite.com/sitemap.xml")
474
-
475
- if st.button("Generate Robots.txt"):
476
- agent = "*" if all_agents else "Googlebot"
477
- txt = f"User-agent: {agent}\n"
478
- if disallow_admin: txt += "Disallow: /admin/\n"
479
- if disallow_private: txt += "Disallow: /private/\n"
480
- if sitemap_url: txt += f"\nSitemap: {sitemap_url}"
481
-
482
- st.text_area("Result", txt, height=150)
483
-
484
- def tool_sitemap_builder():
485
- st.header("🗺️ XML Sitemap Builder")
486
- urls = st.text_area("Paste URLs (one per line)", "https://site.com\nhttps://site.com/about")
487
-
488
- if st.button("Build XML"):
489
- xml = '<?xml version="1.0" encoding="UTF-8"?>\n'
490
- xml += '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n'
491
-
492
- for url in urls.split('\n'):
493
- if url.strip():
494
- xml += f' <url>\n <loc>{url.strip()}</loc>\n <changefreq>monthly</changefreq>\n </url>\n'
495
-
496
- xml += '</urlset>'
497
- st.text_area("Sitemap.xml", xml, height=200)
498
-
499
- def tool_keyword_density():
500
- with st.spinner("Loading Analytics..."):
501
- import pandas as pd
502
- from collections import Counter
503
-
504
-
505
- st.header("📊 Keyword Density Checker")
506
- text = st.text_area("Paste Article Text", height=200,key="density_text")
507
-
508
- if st.button("Analyze"):
509
- # Simple stopword list to ignore
510
- stopwords = set(['the', 'and', 'is', 'in', 'it', 'of', 'to', 'a', 'for', 'on', 'that', 'with', 'as'])
511
-
512
- words = re.findall(r'\w+', text.lower())
513
- filtered = [w for w in words if w not in stopwords and len(w) > 2]
514
-
515
- counts = Counter(filtered).most_common(10)
516
-
517
- df = pd.DataFrame(counts, columns=["Keyword", "Count"])
518
- df['Density %'] = (df['Count'] / len(words) * 100).round(2)
519
- st.table(df)
520
-
521
- def tool_plagiarism_check():
522
- st.header("🕵️ Plagiarism Scanner (Google Check)")
523
- st.info("Splits text into sentences and searches Google for exact matches.")
524
- text = st.text_area("Paste Text to Check", height=150,key="plag_text")
525
-
526
- if st.button("Check Text"):
527
- sentences = re.split(r'[.!?]', text)
528
- clean_sentences = [s.strip() for s in sentences if len(s.strip()) > 20]
529
-
530
- for i, s in enumerate(clean_sentences[:5]): # Limit to first 5 for demo
531
- query = f'"{s}"'
532
- url = f"https://www.google.com/search?q={query}"
533
- st.markdown(f"**Sentence {i+1}:** {s[:50]}...")
534
- st.link_button(f"🔍 Check Google for Match", url)
535
-
536
- def tool_code_minifier():
537
- st.header("🧹 Code Minifier")
538
- mode = st.radio("Type", ["HTML", "CSS"])
539
- raw_code = st.text_area("Input Code", height=200)
540
-
541
- if st.button("Minify"):
542
- minified = ""
543
- if mode == "HTML":
544
- # Basic whitespace removal between tags
545
- lines = raw_code.split('\n')
546
- minified = "".join([line.strip() for line in lines])
547
- elif mode == "CSS":
548
- # Remove comments and whitespace
549
- # 1. Remove comments
550
- minified = re.sub(r'/\*[\s\S]*?\*/', '', raw_code)
551
- # 2. Remove whitespace around braces/colons
552
- minified = re.sub(r'\s*([{:;,])\s*', r'\1', minified)
553
- # 3. Remove newlines
554
- minified = minified.replace('\n', '').replace('\r', '')
555
-
556
- st.text_area("Minified Output", minified, height=200)
557
- # --- BATCH 3: DEVELOPER TOOLS ---
558
-
559
- def tool_qr_generator():
560
- with st.spinner("Initializing QR Tool..."):
561
- import qrcode
562
- import io
563
-
564
- st.header("🏁 QR Code Generator")
565
- data = st.text_input("Enter Link or Text", "https://lexicalspace.blogspot.com")
566
-
567
- if data:
568
- qr = qrcode.QRCode(version=1, box_size=10, border=5)
569
- qr.add_data(data)
570
- qr.make(fit=True)
571
- img = qr.make_image(fill='black', back_color='white')
572
-
573
- buf = io.BytesIO()
574
- img.save(buf)
575
- st.image(img.get_image(), width=300)
576
- st.download_button("Download QR", data=buf.getvalue(), file_name="qrcode.png")
577
-
578
- def tool_json_formatter():
579
- st.header("✨ JSON Prettifier")
580
- raw = st.text_area("Paste Messy JSON", '{"id":1,"name":"Lexical","roles":["admin","dev"]}', height=150)
581
-
582
- col1, col2 = st.columns(2)
583
- if col1.button("Format (Pretty)"):
584
- try:
585
- parsed = json.loads(raw)
586
- st.code(json.dumps(parsed, indent=4), language="json")
587
- except Exception as e:
588
- st.error(f"Invalid JSON: {e}")
589
-
590
- if col2.button("Minify (Compact)"):
591
- try:
592
- parsed = json.loads(raw)
593
- st.code(json.dumps(parsed, separators=(',', ':')), language="json")
594
- except Exception as e:
595
- st.error(f"Invalid JSON: {e}")
596
-
597
- def tool_base64():
598
- st.header("🔐 Base64 Converter")
599
- mode = st.radio("Action", ["Encode", "Decode"], horizontal=True)
600
- text = st.text_area("Input Text")
601
-
602
- if st.button("Process"):
603
- try:
604
- if mode == "Encode":
605
- res = base64.b64encode(text.encode()).decode()
606
- else:
607
- res = base64.b64decode(text).decode()
608
- st.code(res)
609
- except Exception as e:
610
- st.error(f"Error: {e}")
611
-
612
- def tool_url_encoder():
613
- st.header("🔗 URL Encoder/Decoder")
614
- text = st.text_input("Input URL", "https://example.com/search?q=hello world")
615
-
616
- c1, c2 = st.columns(2)
617
- with c1:
618
- if st.button("Encode"):
619
- st.code(urllib.parse.quote(text))
620
- with c2:
621
- if st.button("Decode"):
622
- st.code(urllib.parse.unquote(text))
623
-
624
- def tool_markdown_editor():
625
- st.header("📝 Markdown Editor")
626
-
627
- col1, col2 = st.columns(2)
628
- with col1:
629
- md_text = st.text_area("Write Markdown", "# Hello\n* Item 1\n* Item 2", height=400)
630
-
631
- with col2:
632
- st.markdown("### Preview")
633
- st.markdown(md_text)
634
-
635
- def tool_regex_tester():
636
- st.header("🧪 Regex Tester")
637
- pattern = st.text_input("Regex Pattern", r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b")
638
- text = st.text_area("Test String", "Contact us at support@lexical.com or admin@site.org")
639
-
640
- if pattern and text:
641
- try:
642
- matches = re.findall(pattern, text)
643
- st.write(f"Found {len(matches)} matches:")
644
- st.json(matches)
645
- except Exception as e:
646
- st.error(f"Regex Error: {e}")
647
-
648
- def tool_uuid_gen():
649
- st.header("🆔 UUID/GUID Generator")
650
- count = st.number_input("How many?", 1, 100, 5)
651
-
652
- if st.button("Generate"):
653
- uuids = [str(uuid.uuid4()) for _ in range(count)]
654
- st.code("\n".join(uuids), language="text")
655
-
656
- def tool_hash_gen():
657
- st.header("🔑 Hash Generator")
658
- text = st.text_input("Input String", "mypassword")
659
-
660
- if text:
661
- st.write("**MD5:**")
662
- st.code(hashlib.md5(text.encode()).hexdigest())
663
- st.write("**SHA256:**")
664
- st.code(hashlib.sha256(text.encode()).hexdigest())
665
- # ... (Batch 1 & 2 Routing above) ...
666
-
667
- # BATCH 3 ROUTING
668
- elif mode == "qrcode": tool_qr_generator()
669
- elif mode == "json": tool_json_formatter()
670
- elif mode == "base64": tool_base64()
671
- elif mode == "url": tool_url_encoder()
672
- elif mode == "markdown": tool_markdown_editor()
673
- elif mode == "regex": tool_regex_tester()
674
- elif mode == "uuid": tool_uuid_gen()
675
- elif mode == "hash": tool_hash_gen()
676
-
677
- # ... (Home Dashboard below) ...
678
-
679
- st.write("### 🛠️ Developer Tools")
680
- st.markdown("""
681
- * [🏁 QR Code Gen](?mode=qrcode)
682
- * [✨ JSON Prettifier](?mode=json)
683
- * [🔐 Base64 Converter](?mode=base64)
684
- * [🔗 URL Encode/Decode](?mode=url)
685
- * [📝 Markdown Editor](?mode=markdown)
686
- * [🧪 Regex Tester](?mode=regex)
687
- * [🆔 UUID Generator](?mode=uuid)
688
- * [🔑 Hash Generator](?mode=hash)
689
- """)
690
- # --- BATCH 4: TEXT, UTILITIES & EXTRAS ---
691
-
692
- def tool_case_converter():
693
- st.header("🔠 Case Converter")
694
- text = st.text_area("Input Text", "hello world")
695
-
696
- c1, c2, c3, c4 = st.columns(4)
697
- if c1.button("UPPERCASE"): st.code(text.upper(), language="text")
698
- if c2.button("lowercase"): st.code(text.lower(), language="text")
699
- if c3.button("Title Case"): st.code(text.title(), language="text")
700
- if c4.button("aLtErNaTiNg"):
701
- res = "".join([c.upper() if i%2==0 else c.lower() for i, c in enumerate(text)])
702
- st.code(res, language="text")
703
-
704
- def tool_lorem_ipsum():
705
- st.header("📜 Lorem Ipsum Generator")
706
- paras = st.slider("Paragraphs", 1, 10, 3)
707
-
708
- dummy_text = [
709
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
710
- "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
711
- "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.",
712
- "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum.",
713
- "Excepteur sint occaecat cupidatat non proident, sunt in culpa."
714
- ]
715
-
716
- if st.button("Generate"):
717
- result = "\n\n".join([random.choice(dummy_text) * 3 for _ in range(paras)])
718
- st.text_area("Result", result, height=200)
719
-
720
- def tool_word_counter():
721
- st.header("🧮 Word & Character Counter")
722
- text = st.text_area("Paste Text Here", height=200,key="counter_text")
723
-
724
- if text:
725
- words = len(text.split())
726
- chars = len(text)
727
- no_space = len(text.replace(" ", ""))
728
- read_time = round(words / 200, 2)
729
-
730
- c1, c2, c3, c4 = st.columns(4)
731
- c1.metric("Words", words)
732
- c2.metric("Chars", chars)
733
- c3.metric("No Spaces", no_space)
734
- c4.metric("Read Time", f"{read_time} min")
735
-
736
- def tool_remove_duplicates():
737
- st.header("🗑️ Remove Duplicate Lines")
738
- text = st.text_area("Paste List (One per line)", "Apple\nBanana\nApple\nOrange")
739
-
740
- if st.button("Clean"):
741
- lines = text.split('\n')
742
- seen = set()
743
- clean = []
744
- for line in lines:
745
- if line not in seen and line.strip():
746
- clean.append(line)
747
- seen.add(line)
748
- st.text_area("Cleaned List", "\n".join(clean), height=200)
749
-
750
- def tool_text_to_speech():
751
- with st.spinner("Loading Audio Engine..."):
752
- from gtts import gTTS
753
- import io
754
-
755
- st.header("🗣️ Text to Speech")
756
- text = st.text_area("Enter Text", "Hello, welcome to Lexical Space.")
757
- lang = st.selectbox("Language", ["en", "es", "fr", "de", "hi"],key="tts_text")
758
-
759
- if st.button("Speak"):
760
- try:
761
- tts = gTTS(text=text, lang=lang, slow=False)
762
- buf = io.BytesIO()
763
- tts.write_to_fp(buf)
764
- st.audio(buf, format='audio/mp3')
765
- except Exception as e:
766
- st.error(f"Error: {e}")
767
-
768
- def tool_timestamp():
769
- st.header("⏰ Unix Timestamp Converter")
770
- now = int(time.time())
771
- st.write(f"Current Timestamp: `{now}`")
772
-
773
- col1, col2 = st.columns(2)
774
- with col1:
775
- ts_input = st.number_input("Timestamp to Date", value=now)
776
- if st.button("Convert to Date"):
777
- st.success(datetime.datetime.fromtimestamp(ts_input))
778
-
779
- with col2:
780
- d_input = st.date_input("Date to Timestamp")
781
- if st.button("Convert to Timestamp"):
782
- ts = int(time.mktime(d_input.timetuple()))
783
- st.success(ts)
784
-
785
- def tool_color_palette():
786
- st.header("🎨 Image Color Palette")
787
- # ADD key="palette"
788
- uploaded_file = st.file_uploader("Upload Image", type=['jpg', 'png'], key="palette")
789
-
790
-
791
-
792
- if uploaded_file:
793
- img = Image.open(uploaded_file).convert("RGB")
794
- st.image(img, width=200)
795
-
796
- # Simple extraction by resizing to 5 pixels
797
- small = img.resize((5, 1))
798
- colors = small.getdata()
799
-
800
- st.write("Dominant Colors:")
801
- cols = st.columns(5)
802
- for i, color in enumerate(colors):
803
- hex_code = '#{:02x}{:02x}{:02x}'.format(*color)
804
- cols[i].color_picker(f"Color {i+1}", hex_code, disabled=True)
805
- cols[i].code(hex_code)
806
-
807
- def tool_password_strength():
808
- st.header("💪 Password Strength")
809
- pwd = st.text_input("Test Password", type="password")
810
-
811
- if pwd:
812
- score = 0
813
- if len(pwd) >= 8: score += 1
814
- if re.search(r"[A-Z]", pwd): score += 1
815
- if re.search(r"[a-z]", pwd): score += 1
816
- if re.search(r"\d", pwd): score += 1
817
- if re.search(r"[!@#$%^&*]", pwd): score += 1
818
-
819
- st.progress(score / 5)
820
- if score < 3: st.warning("Weak")
821
- elif score < 5: st.info("Moderate")
822
- else: st.success("Strong!")
823
-
824
- def tool_aspect_ratio():
825
- st.header("🖥️ Aspect Ratio Calculator")
826
- w = st.number_input("Width", 1920)
827
- h = st.number_input("Height", 1080)
828
-
829
- if w and h:
830
- def gcd(a, b):
831
- while b: a, b = b, a % b
832
- return a
833
- divisor = gcd(int(w), int(h))
834
- st.metric("Aspect Ratio", f"{int(w/divisor)}:{int(h/divisor)}")
835
-
836
- def tool_stopwatch():
837
- st.header("⏱️ Stopwatch")
838
- if 'start_time' not in st.session_state: st.session_state.start_time = None
839
-
840
- if st.button("Start/Reset"):
841
- st.session_state.start_time = time.time()
842
-
843
- if st.session_state.start_time:
844
- elapsed = time.time() - st.session_state.start_time
845
- st.metric("Time Elapsed", f"{elapsed:.2f}s")
846
- if st.button("Stop"):
847
- st.session_state.start_time = None
848
-
849
-
850
- def tool_python_checker():
851
- st.header("🐍 Python Syntax & Error Checker")
852
- st.markdown("Paste your Python code or upload a `.py` file to check for syntax errors.")
853
-
854
- # Import dependencies inside the function to avoid global scope clutter
855
- import tempfile
856
- import os
857
- import io
858
- try:
859
- from pylint.lint import Run
860
- from pylint.reporters.text import TextReporter
861
- except ImportError:
862
- st.error("⚠️ Pylint is not installed. Please add `pylint` to your requirements.txt")
863
- return
864
-
865
- # --- INPUTS ---
866
- col1, col2 = st.columns(2)
867
- with col1:
868
- paste_code = st.text_area("Paste Code Here", height=300)
869
- with col2:
870
- file_obj = st.file_uploader("Or Upload .py File", type=[".py"])
871
-
872
- # --- PROCESS BUTTON ---
873
- if st.button("Check Syntax 🚀", type="primary"):
874
- code_to_check = ""
875
-
876
- # Logic: Prefer File > Paste
877
- if file_obj is not None:
878
- try:
879
- code_to_check = file_obj.getvalue().decode("utf-8")
880
- except Exception as e:
881
- st.error(f"❌ Error reading file: {str(e)}")
882
- return
883
- elif paste_code.strip() != "":
884
- code_to_check = paste_code
885
- else:
886
- st.warning("⚠️ Please either paste code or upload a file.")
887
- return
888
-
889
- # --- LINTING LOGIC ---
890
- # 1. Create Temp File (Pylint needs a file on disk)
891
- with tempfile.NamedTemporaryFile(delete=False, suffix=".py", mode='w', encoding='utf-8') as temp:
892
- temp.write(code_to_check)
893
- temp_path = temp.name
894
-
895
- # 2. Run Pylint
896
- pylint_output = io.StringIO()
897
- reporter = TextReporter(pylint_output)
898
-
899
- with st.spinner("Analyzing syntax..."):
900
- try:
901
- # --errors-only hides warnings, showing only code-breaking errors
902
- Run([temp_path, "--errors-only"], reporter=reporter, exit=False)
903
- except Exception as e:
904
- st.error(f"System Error: {e}")
905
-
906
- # 3. Cleanup & Display
907
- os.unlink(temp_path) # Delete temp file
908
- result = pylint_output.getvalue()
909
-
910
- st.markdown("---")
911
- if not result:
912
- st.success("✅ No Syntax Errors Found! (Code looks valid)")
913
- st.balloons()
914
- else:
915
- st.error("❌ Errors Found:")
916
- # Hide the messy temp file path from the user
917
- clean_report = result.replace(temp_path, "Your_Script.py")
918
- st.code(clean_report, language="text")
919
-
920
-
921
- # --- FINAL MAIN ROUTER (SPA VERSION) ---
922
- if __name__ == "__main__":
923
- # 1. INITIALIZE SESSION STATE (This replaces the URL logic)
924
- if 'mode' not in st.session_state:
925
- st.session_state.mode = 'home'
926
-
927
-
928
- # 3. NAVIGATION HANDLING
929
- # Function to change mode without URL reload
930
- def set_mode(new_mode):
931
- st.session_state.mode = new_mode
932
-
933
- # Show "Back to Dashboard" button if not home
934
- if st.session_state.mode != 'home':
935
- if st.button("⬅️ Back to Grid"):
936
- set_mode('home')
937
- st.rerun()
938
-
939
- # 4. TOOL ROUTING (Checks session_state instead of URL)
940
- mode = st.session_state.mode
941
-
942
- if mode == "youtube": tool_youtube_downloader()
943
- elif mode == "smart_converter": tool_smart_converter()
944
- elif mode == "compressor": tool_image_compressor()
945
- elif mode == "resizer": tool_image_resizer()
946
- elif mode == "thumbnail": tool_thumbnail_generator()
947
- elif mode == "metatags": tool_meta_tag_generator()
948
- elif mode == "slug": tool_slug_generator()
949
- elif mode == "robots": tool_robots_generator()
950
- elif mode == "sitemap": tool_sitemap_builder()
951
- elif mode == "density": tool_keyword_density()
952
- elif mode == "plagiarism": tool_plagiarism_check()
953
- elif mode == "minify": tool_code_minifier()
954
- elif mode == "qrcode": tool_qr_generator()
955
- elif mode == "json": tool_json_formatter()
956
- elif mode == "base64": tool_base64()
957
- elif mode == "url": tool_url_encoder()
958
- elif mode == "markdown": tool_markdown_editor()
959
- elif mode == "regex": tool_regex_tester()
960
- elif mode == "uuid": tool_uuid_gen()
961
- elif mode == "hash": tool_hash_gen()
962
- elif mode == "case": tool_case_converter()
963
- elif mode == "lorem": tool_lorem_ipsum()
964
- elif mode == "counter": tool_word_counter()
965
- elif mode == "dedupe": tool_remove_duplicates()
966
- elif mode == "tts": tool_text_to_speech()
967
- elif mode == "timestamp": tool_timestamp()
968
- elif mode == "palette": tool_color_palette()
969
- elif mode == "password": tool_password_strength()
970
- elif mode == "ratio": tool_aspect_ratio()
971
- elif mode == "stopwatch": tool_stopwatch()
972
- elif mode == "python": tool_python_checker()
973
- elif mode == "seo": run_seo_app()
974
-
975
-
976
- # 5. HOME DASHBOARD (Button Grid)
977
- else:
978
- st.write("### ⚡ Select a tool to get started:")
979
-
980
- # We use standard Streamlit columns to create a grid layout
981
- # This replaces the Markdown links with actual Buttons
982
-
983
- c1, c2 = st.columns(2)
984
-
985
- with c1:
986
- st.info("**📂 Media & Files**")
987
- if st.button("Seo Writer"): set_mode("seo"); st.rerun()
988
- if st.button("🎥 YouTube Downloader"): set_mode("youtube"); st.rerun()
989
- if st.button("🔄 Smart File Converter"): set_mode("smart_converter"); st.rerun()
990
- if st.button("📉 Image Compressor"): set_mode("compressor"); st.rerun()
991
- if st.button("📐 Image Resizer"): set_mode("resizer"); st.rerun()
992
- if st.button("🖼️ Thumbnail Gen"): set_mode("thumbnail"); st.rerun()
993
-
994
- st.info("**🛠️ Developer Tools**")
995
- if st.button("🏁 QR Code Gen"): set_mode("qrcode"); st.rerun()
996
- if st.button("✨ JSON Prettifier"): set_mode("json"); st.rerun()
997
- if st.button("🔐 Base64 Converter"): set_mode("base64"); st.rerun()
998
- if st.button("🔗 URL Encoder"): set_mode("url"); st.rerun()
999
- if st.button("📝 Markdown Editor"): set_mode("markdown"); st.rerun()
1000
- if st.button("🧪 Regex Tester"): set_mode("regex"); st.rerun()
1001
- if st.button("🆔 UUID Gen"): set_mode("uuid"); st.rerun()
1002
- if st.button("🔑 Hash Gen"): set_mode("hash"); st.rerun()
1003
-
1004
- with c2:
1005
- st.info("**🕸️ SEO & Webmaster**")
1006
- if st.button("🏷️ Meta Tag Gen"): set_mode("metatags"); st.rerun()
1007
- if st.button("🐌 Slug Generator"): set_mode("slug"); st.rerun()
1008
- if st.button("🤖 Robots.txt Gen"): set_mode("robots"); st.rerun()
1009
- if st.button("🗺️ Sitemap Builder"): set_mode("sitemap"); st.rerun()
1010
- if st.button("📊 Density Checker"): set_mode("density"); st.rerun()
1011
- if st.button("🕵️ Plagiarism Check"): set_mode("plagiarism"); st.rerun()
1012
- if st.button("🧹 Code Minifier"): set_mode("minify"); st.rerun()
1013
-
1014
- st.info("**📝 Text & Utilities**")
1015
- if st.button("🔠 Case Converter"): set_mode("case"); st.rerun()
1016
- if st.button("📜 Lorem Ipsum"): set_mode("lorem"); st.rerun()
1017
- if st.button("🧮 Word Counter"): set_mode("counter"); st.rerun()
1018
- if st.button("🗑️ Dedupe Lines"): set_mode("dedupe"); st.rerun()
1019
- if st.button("🗣️ Text to Speech"): set_mode("tts"); st.rerun()
1020
- if st.button("⏰ Unix Timestamp"): set_mode("timestamp"); st.rerun()
1021
- if st.button("🎨 Color Palette"): set_mode("palette"); st.rerun()
1022
- if st.button("💪 Password Strength"): set_mode("password"); st.rerun()
1023
- if st.button("🖥️ Aspect Ratio"): set_mode("ratio"); st.rerun()
1024
- if st.button("⏱️ Stopwatch"): set_mode("stopwatch"); st.rerun()
1025
- if st.button("Python Checker"): set_mode("python"); st.rerun()
1026
-
1027
-