Smart Typing Speed Trainer

import tkinter as tk

from tkinter import ttk, messagebox, simpledialog

import time

import random

import json

import os


STATS_FILE = "typing_stats.json"


SAMPLE_PARAGRAPHS = {

    "Easy": [

        "The quick brown fox jumps over the lazy dog.",

        "Practice makes perfect. Keep typing every day.",

        "Sunrise over the hills gave a golden glow."

    ],

    "Medium": [

        "Learning to type faster requires consistent short sessions and focused practice.",

        "Productivity improves when repetitive tasks are automated and simplified.",

        "A small daily habit can compound into significant improvement over time."

    ],

    "Hard": [

        "Synthesis of knowledge emerges when creativity meets disciplined experimentation and reflection.",

        "Contributing to open-source projects accelerates learning through real-world code review and collaboration.",

        "Concurrency issues often surface under load where assumptions about ordering and state break down."

    ]

}


# -----------------------

# Utilities: stats file

# -----------------------

def load_stats():

    if not os.path.exists(STATS_FILE):

        return []

    try:

        with open(STATS_FILE, "r", encoding="utf-8") as f:

            return json.load(f)

    except Exception:

        return []


def save_stats(stats):

    with open(STATS_FILE, "w", encoding="utf-8") as f:

        json.dump(stats, f, indent=2)


# -----------------------

# Typing logic helpers

# -----------------------

def calc_wpm(char_count, elapsed_seconds):

    # Standard WPM uses 5 characters per word

    minutes = elapsed_seconds / 60.0 if elapsed_seconds > 0 else 1/60.0

    return (char_count / 5.0) / minutes


def calc_accuracy(correct_chars, total_typed):

    if total_typed == 0:

        return 0.0

    return (correct_chars / total_typed) * 100.0


# -----------------------

# Main App

# -----------------------

class TypingTrainerApp:

    def __init__(self, root):

        self.root = root

        self.root.title("Smart Typing Speed Trainer")

        self.root.geometry("900x600")


        self.difficulty = tk.StringVar(value="Easy")

        self.username = tk.StringVar(value="Guest")

        self.paragraph = ""

        self.start_time = None

        self.end_time = None

        self.running = False

        self.correct_chars = 0

        self.total_typed = 0

        self.errors = 0


        self.stats = load_stats()


        self.build_ui()

        self.new_paragraph()


    def build_ui(self):

        top = ttk.Frame(self.root)

        top.pack(side=tk.TOP, fill=tk.X, padx=8, pady=8)


        ttk.Label(top, text="Name:").pack(side=tk.LEFT)

        name_entry = ttk.Entry(top, textvariable=self.username, width=18)

        name_entry.pack(side=tk.LEFT, padx=6)


        ttk.Label(top, text="Difficulty:").pack(side=tk.LEFT, padx=(12,0))

        diff_menu = ttk.OptionMenu(top, self.difficulty, self.difficulty.get(), *SAMPLE_PARAGRAPHS.keys())

        diff_menu.pack(side=tk.LEFT, padx=6)


        ttk.Button(top, text="Next Paragraph", command=self.new_paragraph).pack(side=tk.LEFT, padx=6)

        ttk.Button(top, text="Restart", command=self.restart).pack(side=tk.LEFT, padx=6)

        ttk.Button(top, text="Save Result", command=self.save_result).pack(side=tk.LEFT, padx=6)

        ttk.Button(top, text="Leaderboard", command=self.show_leaderboard).pack(side=tk.LEFT, padx=6)

        ttk.Button(top, text="Clear Stats", command=self.clear_stats).pack(side=tk.RIGHT, padx=6)


        # Paragraph display

        paragraph_frame = ttk.LabelFrame(self.root, text="Type the text below")

        paragraph_frame.pack(fill=tk.BOTH, expand=False, padx=10, pady=8)


        self.paragraph_text = tk.Text(paragraph_frame, height=6, wrap="word", font=("Consolas", 14), padx=8, pady=8, state="disabled")

        self.paragraph_text.pack(fill=tk.BOTH, expand=True)


        # Typing area

        typing_frame = ttk.LabelFrame(self.root, text="Your typing")

        typing_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=8)


        self.typing_text = tk.Text(typing_frame, height=10, wrap="word", font=("Consolas", 14), padx=8, pady=8)

        self.typing_text.pack(fill=tk.BOTH, expand=True)

        self.typing_text.bind("<Key>", self.on_key_press)

        # Disable paste

        self.typing_text.bind("<<Paste>>", lambda e: "break")

        self.typing_text.bind("<Control-v>", lambda e: "break")

        self.typing_text.bind("<Button-2>", lambda e: "break")


        # Stats

        stats_frame = ttk.Frame(self.root)

        stats_frame.pack(fill=tk.X, padx=10, pady=6)


        self.wpm_var = tk.StringVar(value="WPM: 0.0")

        self.acc_var = tk.StringVar(value="Accuracy: 0.0%")

        self.err_var = tk.StringVar(value="Errors: 0")

        self.time_var = tk.StringVar(value="Time: 0.0s")


        ttk.Label(stats_frame, textvariable=self.wpm_var, font=("Arial", 12)).pack(side=tk.LEFT, padx=8)

        ttk.Label(stats_frame, textvariable=self.acc_var, font=("Arial", 12)).pack(side=tk.LEFT, padx=8)

        ttk.Label(stats_frame, textvariable=self.err_var, font=("Arial", 12)).pack(side=tk.LEFT, padx=8)

        ttk.Label(stats_frame, textvariable=self.time_var, font=("Arial", 12)).pack(side=tk.LEFT, padx=8)


        # Progress / highlight correct vs incorrect

        lower = ttk.Frame(self.root)

        lower.pack(fill=tk.BOTH, expand=False, padx=10, pady=6)

        ttk.Label(lower, text="Tips: Start typing to begin the timer. Pasting is disabled.").pack(side=tk.LEFT)


    def new_paragraph(self):

        self.pause()

        diff = self.difficulty.get()

        pool = SAMPLE_PARAGRAPHS.get(diff, SAMPLE_PARAGRAPHS["Easy"])

        self.paragraph = random.choice(pool)

        # show paragraph readonly

        self.paragraph_text.config(state="normal")

        self.paragraph_text.delete("1.0", tk.END)

        self.paragraph_text.insert(tk.END, self.paragraph)

        self.paragraph_text.config(state="disabled")

        self.restart()


    def restart(self):

        self.pause()

        self.typing_text.delete("1.0", tk.END)

        self.start_time = None

        self.end_time = None

        self.running = False

        self.correct_chars = 0

        self.total_typed = 0

        self.errors = 0

        self.update_stats_display(0.0)

        self.typing_text.focus_set()


    def pause(self):

        self.running = False


    def on_key_press(self, event):

        # ignore non-printing keys that don't change text (Shift, Ctrl, Alt)

        if event.keysym in ("Shift_L","Shift_R","Control_L","Control_R","Alt_L","Alt_R","Caps_Lock","Tab","Escape"):

            return

        # start timer on first real key

        if not self.running:

            self.start_time = time.time()

            self.running = True

            # schedule first update

            self.root.after(100, self.periodic_update)


        # schedule update immediately after Tk has applied the key to the widget

        self.root.after(1, self.evaluate_typing)


    def evaluate_typing(self):

        typed = self.typing_text.get("1.0", tk.END)[:-1]  # drop trailing newline Tk adds

        target = self.paragraph


        # compute per-character correctness up to typed length

        total = len(typed)

        correct = 0

        errors = 0


        for i, ch in enumerate(typed):

            if i < len(target) and ch == target[i]:

                correct += 1

            else:

                errors += 1


        # count omissions beyond target length as errors too if user keeps typing

        if total > len(target):

            errors += total - len(target)


        self.correct_chars = correct

        self.total_typed = total

        self.errors = errors


        # if user finished (typed length equals paragraph length), stop timer

        if total >= len(target):

            # check final correctness

            if correct == len(target):

                self.end_time = time.time()

                self.running = False

                self.update_stats_display(final=True)

                messagebox.showinfo("Completed", f"Well done, {self.username.get()}!\nYou finished the paragraph.")

                return


        # otherwise update live stats

        self.update_stats_display(final=False)


    def periodic_update(self):

        if self.running:

            self.update_stats_display(final=False)

            self.root.after(200, self.periodic_update)


    def update_stats_display(self, final=False):

        elapsed = (self.end_time - self.start_time) if (self.start_time and self.end_time) else (time.time() - self.start_time if self.start_time else 0.0)

        wpm = calc_wpm(self.total_typed, elapsed) if self.total_typed > 0 else 0.0

        acc = calc_accuracy(self.correct_chars, self.total_typed) if self.total_typed > 0 else 0.0


        self.wpm_var.set(f"WPM: {wpm:.1f}")

        self.acc_var.set(f"Accuracy: {acc:.1f}%")

        self.err_var.set(f"Errors: {self.errors}")

        self.time_var.set(f"Time: {elapsed:.1f}s")


        if final and self.start_time:

            # show final summary and auto-save to stats (ask username)

            pass


    def save_result(self):

        if not self.start_time:

            messagebox.showwarning("No attempt", "Start typing first to record a result.")

            return

        # If still running, finalize end time

        if self.running:

            self.end_time = time.time()

            self.running = False

            self.evaluate_typing()


        elapsed = (self.end_time - self.start_time) if (self.start_time and self.end_time) else 0.0

        wpm = calc_wpm(self.total_typed, elapsed) if elapsed > 0 else 0.0

        acc = calc_accuracy(self.correct_chars, self.total_typed) if self.total_typed > 0 else 0.0


        name = self.username.get().strip() or "Guest"

        record = {

            "name": name,

            "difficulty": self.difficulty.get(),

            "wpm": round(wpm, 1),

            "accuracy": round(acc, 1),

            "errors": int(self.errors),

            "chars_typed": int(self.total_typed),

            "time_seconds": round(elapsed, 1),

            "paragraph": self.paragraph

        }

        self.stats.append(record)

        # keep only latest 200

        self.stats = self.stats[-200:]

        save_stats(self.stats)

        messagebox.showinfo("Saved", f"Result saved for {name}.\nWPM={record['wpm']}, Accuracy={record['accuracy']}%")

        # refresh leaderboard

        self.show_leaderboard()


    def show_leaderboard(self):

        lb_win = tk.Toplevel(self.root)

        lb_win.title("Leaderboard / Recent Attempts")

        lb_win.geometry("700x400")

        frame = ttk.Frame(lb_win)

        frame.pack(fill=tk.BOTH, expand=True, padx=8, pady=8)


        cols = ("name", "difficulty", "wpm", "accuracy", "errors", "time_seconds")

        tree = ttk.Treeview(frame, columns=cols, show="headings")

        for c in cols:

            tree.heading(c, text=c.capitalize())

            tree.column(c, width=100, anchor="center")

        tree.pack(fill=tk.BOTH, expand=True)


        # sort by wpm desc

        sorted_stats = sorted(self.stats, key=lambda r: r.get("wpm", 0), reverse=True)

        for rec in sorted_stats:

            tree.insert("", "end", values=(rec["name"], rec["difficulty"], rec["wpm"], rec["accuracy"], rec["errors"], rec["time_seconds"]))


        btn_frame = ttk.Frame(lb_win)

        btn_frame.pack(fill=tk.X, pady=6)

        ttk.Button(btn_frame, text="Close", command=lb_win.destroy).pack(side=tk.RIGHT, padx=6)


    def clear_stats(self):

        if messagebox.askyesno("Confirm", "Clear all saved stats? This cannot be undone."):

            self.stats = []

            save_stats(self.stats)

            messagebox.showinfo("Cleared", "All saved stats removed.")


# -----------------------

# Run

# -----------------------

def main():

    root = tk.Tk()

    app = TypingTrainerApp(root)

    root.mainloop()


if __name__ == "__main__":

    main()


Image Style Transfer

 """

Image Style Transfer demo (TensorFlow Hub + Tkinter UI)


- Pick a content image (photo) and a style image (painting).

- Apply Magenta arbitrary-image-stylization-v1-256 model.

- Preview and save the stylized result.


Requirements:

    pip install tensorflow tensorflow-hub pillow opencv-python

"""


import tkinter as tk

from tkinter import ttk, filedialog, messagebox

from PIL import Image, ImageTk

import numpy as np

import tensorflow as tf

import tensorflow_hub as hub

import cv2

import os


# Model URL

TFHUB_MODEL_URL = "https://tfhub.dev/google/magenta/arbitrary-image-stylization-v1-256/2"


# --------------------------

# Helper functions

# --------------------------

def load_img(path, max_dim=512):

    """Load image with PIL, resize keeping aspect ratio so long side = max_dim."""

    img = Image.open(path).convert("RGB")

    # resize

    long = max(img.size)

    if long > max_dim:

        scale = max_dim / long

        new_size = (int(img.size[0]*scale), int(img.size[1]*scale))

        img = img.resize(new_size, Image.ANTIALIAS)

    return img


def img_to_tensor(img):

    """PIL Image -> float32 tensor shape [1, H, W, 3] in [0,1]."""

    arr = np.array(img).astype(np.float32) / 255.0

    # add batch dim

    return tf.expand_dims(arr, axis=0)


def tensor_to_pil(tensor):

    """Tensor [1,H,W,3] in [0,1] -> PIL Image."""

    arr = tensor[0].numpy()

    arr = np.clip(arr * 255.0, 0, 255).astype(np.uint8)

    return Image.fromarray(arr)


# --------------------------

# Load model once

# --------------------------

print("Loading style transfer model from TensorFlow Hub...")

model = hub.load(TFHUB_MODEL_URL)

print("Model loaded.")


# --------------------------

# Simple CLI function (optional)

# --------------------------

def stylize_image(content_img_path, style_img_path, output_path="stylized.png", max_dim=512):

    content_img = load_img(content_img_path, max_dim=max_dim)

    style_img = load_img(style_img_path, max_dim=max_dim)

    content_t = img_to_tensor(content_img)

    style_t = img_to_tensor(style_img)

    # The hub model expects float tensors in [0,1]

    outputs = model(tf.constant(content_t), tf.constant(style_t))

    stylized = outputs[0]

    pil = tensor_to_pil(stylized)

    pil.save(output_path)

    print(f"Saved stylized image to {output_path}")

    return output_path


# --------------------------

# Tkinter GUI

# --------------------------

class StyleTransferGUI:

    def __init__(self, root):

        self.root = root

        root.title("AI Image Style Transfer — RootRace")

        root.geometry("1000x700")


        self.content_path = None

        self.style_path = None

        self.result_image = None  # PIL Image


        # Controls frame

        ctrl = ttk.Frame(root)

        ctrl.pack(side=tk.TOP, fill=tk.X, padx=8, pady=8)


        ttk.Button(ctrl, text="Choose Content Image", command=self.choose_content).pack(side=tk.LEFT, padx=4)

        ttk.Button(ctrl, text="Choose Style Image", command=self.choose_style).pack(side=tk.LEFT, padx=4)

        ttk.Button(ctrl, text="Apply Style Transfer", command=self.apply_style).pack(side=tk.LEFT, padx=8)

        ttk.Button(ctrl, text="Save Result", command=self.save_result).pack(side=tk.LEFT, padx=4)

        ttk.Button(ctrl, text="Quit", command=root.quit).pack(side=tk.RIGHT, padx=4)


        # Preview frames

        preview = ttk.Frame(root)

        preview.pack(fill=tk.BOTH, expand=True)


        # Left: content & style thumbnails

        left = ttk.Frame(preview)

        left.pack(side=tk.LEFT, fill=tk.Y, padx=6, pady=6)


        ttk.Label(left, text="Content Image").pack()

        self.content_label = ttk.Label(left)

        self.content_label.pack(padx=6, pady=6)


        ttk.Label(left, text="Style Image").pack()

        self.style_label = ttk.Label(left)

        self.style_label.pack(padx=6, pady=6)


        # Right: result canvas

        right = ttk.Frame(preview)

        right.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=6, pady=6)

        ttk.Label(right, text="Result").pack()

        self.canvas = tk.Canvas(right, bg="black")

        self.canvas.pack(fill=tk.BOTH, expand=True)


        # Status

        self.status = ttk.Label(root, text="Load a content and style image to start.", relief=tk.SUNKEN, anchor="w")

        self.status.pack(side=tk.BOTTOM, fill=tk.X)


    def choose_content(self):

        path = filedialog.askopenfilename(filetypes=[("Images","*.jpg *.jpeg *.png *.bmp"),("All files","*.*")])

        if not path:

            return

        self.content_path = path

        img = load_img(path, max_dim=400)

        self._set_thumbnail(self.content_label, img)

        self.status.config(text=f"Selected content: {os.path.basename(path)}")


    def choose_style(self):

        path = filedialog.askopenfilename(filetypes=[("Images","*.jpg *.jpeg *.png *.bmp"),("All files","*.*")])

        if not path:

            return

        self.style_path = path

        img = load_img(path, max_dim=200)

        self._set_thumbnail(self.style_label, img)

        self.status.config(text=f"Selected style: {os.path.basename(path)}")


    def _set_thumbnail(self, widget, pil_img):

        tk_img = ImageTk.PhotoImage(pil_img)

        widget.image = tk_img  # keep ref

        widget.config(image=tk_img)


    def apply_style(self):

        if not self.content_path or not self.style_path:

            messagebox.showwarning("Missing images", "Please choose both content and style images.")

            return

        try:

            self.status.config(text="Running style transfer... (this may take a few seconds)")

            self.root.update_idletasks()


            content_img = load_img(self.content_path, max_dim=512)

            style_img = load_img(self.style_path, max_dim=512)

            content_t = img_to_tensor(content_img)

            style_t = img_to_tensor(style_img)


            outputs = model(tf.constant(content_t), tf.constant(style_t))

            stylized = outputs[0]  # [1,H,W,3]

            pil = tensor_to_pil(stylized)

            self.result_image = pil


            # display result on canvas, scaled to fit

            self._display_result_on_canvas(pil)

            self.status.config(text="Done. You can save the result.")

        except Exception as e:

            messagebox.showerror("Error", f"Style transfer failed: {e}")

            self.status.config(text="Error during style transfer")


    def _display_result_on_canvas(self, pil_img):

        # resize to fit canvas while preserving aspect ratio

        cw = self.canvas.winfo_width() or 600

        ch = self.canvas.winfo_height() or 400

        w,h = pil_img.size

        scale = min(cw/w, ch/h, 1.0)

        new_size = (int(w*scale), int(h*scale))

        disp = pil_img.resize(new_size, Image.ANTIALIAS)

        tk_img = ImageTk.PhotoImage(disp)

        self.canvas.image = tk_img

        self.canvas.delete("all")

        # center image

        x = (cw - new_size[0]) // 2

        y = (ch - new_size[1]) // 2

        self.canvas.create_image(x, y, anchor="nw", image=tk_img)


    def save_result(self):

        if self.result_image is None:

            messagebox.showwarning("No result", "No stylized image to save. Apply style transfer first.")

            return

        path = filedialog.asksaveasfilename(defaultextension=".png", filetypes=[("PNG","*.png"),("JPEG","*.jpg")])

        if not path:

            return

        self.result_image.save(path)

        messagebox.showinfo("Saved", f"Saved stylized image to {path}")

        self.status.config(text=f"Saved: {path}")


# --------------------------

# CLI usage entrypoint

# --------------------------

def main():

    root = tk.Tk()

    app = StyleTransferGUI(root)

    root.mainloop()


if __name__ == "__main__":

    main()

Audio Frequency Spectrum Visualizer

 """

Audio Frequency Spectrum Visualizer (Tkinter + matplotlib)


- Select a WAV file

- Shows waveform (top) and animated FFT spectrum bars (bottom)

- Works with mono or stereo WAV files

- Uses scipy.io.wavfile to read WAV

- Animation scrolls through the audio buffer, computing FFT per frame to simulate live visualization


Limitations:

- Only WAV supported out of the box. For MP3, use pydub to convert to raw samples (instructions below).

- No audio playback included by default (keeps dependencies minimal). See comments for how to add playback.

"""


import tkinter as tk

from tkinter import ttk, filedialog, messagebox

import numpy as np

import matplotlib

matplotlib.use("TkAgg")

import matplotlib.pyplot as plt

from matplotlib.animation import FuncAnimation

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

from scipy.io import wavfile

import os


# -----------------------

# Visualization settings

# -----------------------

FRAME_SIZE = 2048        # samples per frame for FFT (power of two recommended)

HOP_SIZE = 1024          # step between frames (overlap)

SPECTRUM_BINS = 80       # number of bars to display

SAMPLE_REDUCE = 1        # reduce sampling rate by factor (keep 1 unless memory issue)


# -----------------------

# Helper utilities

# -----------------------

def load_wav_file(path):

    """Read WAV file and return (rate, samples as float32 mono)."""

    rate, data = wavfile.read(path)

    # normalize and convert to float32 in range [-1,1]

    if data.dtype == np.int16:

        data = data.astype(np.float32) / 32768.0

    elif data.dtype == np.int32:

        data = data.astype(np.float32) / 2147483648.0

    elif data.dtype == np.uint8:

        data = (data.astype(np.float32) - 128) / 128.0

    else:

        data = data.astype(np.float32)


    # if stereo, convert to mono by averaging channels

    if data.ndim == 2:

        data = data.mean(axis=1)


    # optionally downsample (by integer factor)

    if SAMPLE_REDUCE > 1:

        data = data[::SAMPLE_REDUCE]

        rate = rate // SAMPLE_REDUCE


    return rate, data


def compute_spectrum(frame, rate, n_bins=SPECTRUM_BINS):

    """

    Compute FFT amplitude spectrum for a frame (1D array).

    Returns frequency centers and amplitudes (log-scaled).

    """

    # apply a window to reduce spectral leakage

    window = np.hanning(len(frame))

    frame_windowed = frame * window

    # FFT

    fft = np.fft.rfft(frame_windowed, n=FRAME_SIZE)

    mags = np.abs(fft)

    # convert to dB scale

    mags_db = 20 * np.log10(mags + 1e-6)

    freqs = np.fft.rfftfreq(FRAME_SIZE, d=1.0 / rate)

    # reduce to n_bins by averaging contiguous bands (log spaced bins could be better)

    # we'll use linear bins for simplicity

    bins = np.array_split(np.arange(len(freqs)), n_bins)

    bfreqs = []

    bampl = []

    for b in bins:

        if len(b) == 0:

            bfreqs.append(0)

            bampl.append(-120.0)

            continue

        bfreqs.append(freqs[b].mean())

        bampl.append(mags_db[b].mean())

    # normalize amplitudes to 0..1 for plotting bars

    a = np.array(bampl)

    a = (a - a.min()) / (np.maximum(a.max() - a.min(), 1e-6))

    return np.array(bfreqs), a


# -----------------------

# Main App

# -----------------------

class SpectrumVisualizerApp:

    def __init__(self, root):

        self.root = root

        self.root.title("Audio Frequency Spectrum Visualizer")

        self.root.geometry("1000x650")


        # Top controls

        ctrl = ttk.Frame(root)

        ctrl.pack(side=tk.TOP, fill=tk.X, padx=8, pady=6)


        self.path_var = tk.StringVar()

        ttk.Label(ctrl, text="Audio File:").pack(side=tk.LEFT)

        self.path_entry = ttk.Entry(ctrl, textvariable=self.path_var, width=60)

        self.path_entry.pack(side=tk.LEFT, padx=6)

        ttk.Button(ctrl, text="Browse", command=self.browse_file).pack(side=tk.LEFT, padx=4)

        ttk.Button(ctrl, text="Load", command=self.load_file).pack(side=tk.LEFT, padx=4)

        ttk.Button(ctrl, text="Start", command=self.start).pack(side=tk.LEFT, padx=4)

        ttk.Button(ctrl, text="Pause/Resume", command=self.toggle_pause).pack(side=tk.LEFT, padx=4)

        ttk.Button(ctrl, text="Stop", command=self.stop).pack(side=tk.LEFT, padx=4)


        # Status

        self.status_var = tk.StringVar(value="No file loaded")

        ttk.Label(root, textvariable=self.status_var).pack(side=tk.TOP, anchor="w", padx=8)


        # Matplotlib figure with two subplots (waveform + spectrum)

        self.fig, (self.ax_wave, self.ax_spec) = plt.subplots(2, 1, figsize=(9, 6), gridspec_kw={'height_ratios':[1,1]})

        plt.tight_layout(pad=3.0)


        self.canvas = FigureCanvasTkAgg(self.fig, master=root)

        self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)


        # controls / internal state

        self.sr = None

        self.samples = None

        self.num_frames = 0

        self.current_frame_idx = 0

        self.paused = True

        self.ani = None


        # waveform plot placeholders

        self.wave_x = None

        self.wave_plot = None

        # spectrum bars

        self.bar_container = None

        self.freq_centers = None


        # initialize plots

        self.setup_empty_plots()


    def setup_empty_plots(self):

        self.ax_wave.clear()

        self.ax_wave.set_title("Waveform (time domain)")

        self.ax_wave.set_xlabel("Time (s)")

        self.ax_wave.set_ylabel("Amplitude")

        self.ax_spec.clear()

        self.ax_spec.set_title("Frequency Spectrum (animated)")

        self.ax_spec.set_xlabel("Frequency (Hz)")

        self.ax_spec.set_ylabel("Normalized amplitude")

        self.canvas.draw_idle()


    def browse_file(self):

        p = filedialog.askopenfilename(filetypes=[("WAV files", "*.wav"), ("All files", "*.*")])

        if p:

            self.path_var.set(p)


    def load_file(self):

        path = self.path_var.get().strip()

        if not path or not os.path.exists(path):

            messagebox.showerror("Error", "Please choose a valid WAV file.")

            return

        try:

            self.sr, self.samples = load_wav_file(path)

        except Exception as e:

            messagebox.showerror("Error", f"Failed to read WAV: {e}")

            return


        # compute frames count

        self.num_frames = max(1, (len(self.samples) - FRAME_SIZE) // HOP_SIZE + 1)

        self.current_frame_idx = 0

        self.status_var.set(f"Loaded: {os.path.basename(path)} | SR={self.sr} Hz | Samples={len(self.samples)} | Frames={self.num_frames}")


        # draw full waveform

        t = np.arange(len(self.samples)) / float(self.sr)

        self.ax_wave.clear()

        self.ax_wave.plot(t, self.samples, color='gray', linewidth=0.5)

        self.ax_wave.set_xlim(t.min(), t.max())

        self.ax_wave.set_ylim(-1.0, 1.0)

        self.ax_wave.set_title("Waveform (time domain)")

        self.ax_wave.set_xlabel("Time (s)")

        self.ax_wave.set_ylabel("Amplitude")


        # prepare spectrum bar placeholders using first frame

        frame0 = self.samples[:FRAME_SIZE]

        freqs, amps = compute_spectrum(frame0, self.sr, n_bins=SPECTRUM_BINS)

        self.freq_centers = freqs

        x = np.arange(len(amps))

        self.ax_spec.clear()

        self.bar_container = self.ax_spec.bar(x, amps, align='center', alpha=0.8)

        self.ax_spec.set_xticks(x[::max(1,len(x)//10)])

        # show frequency labels at a few ticks

        tick_idx = np.linspace(0, len(freqs)-1, min(10, len(freqs))).astype(int)

        tick_labels = [f"{int(freqs[i])}Hz" for i in tick_idx]

        self.ax_spec.set_xticks(tick_idx)

        self.ax_spec.set_xticklabels(tick_labels, rotation=45)

        self.ax_spec.set_ylim(0, 1.02)

        self.ax_spec.set_title("Frequency Spectrum (animated)")


        # vertical line on waveform to show current frame

        self.wave_marker = self.ax_wave.axvline(0, color='red', linewidth=1.0)


        self.canvas.draw_idle()


    def start(self):

        if self.samples is None:

            messagebox.showwarning("No file", "Load a WAV file first.")

            return

        if self.ani:

            # reset animation

            self.ani.event_source.stop()

            self.ani = None

        self.paused = False

        # Create animation that updates every ~30 ms

        self.ani = FuncAnimation(self.fig, self.update_frame, interval=30, blit=False)

        self.canvas.draw_idle()

        self.status_var.set("Playing visualization... (simulation)")


    def toggle_pause(self):

        if self.ani is None:

            return

        if self.paused:

            self.paused = False

            self.status_var.set("Resumed")

        else:

            self.paused = True

            self.status_var.set("Paused")


    def stop(self):

        if self.ani:

            self.ani.event_source.stop()

            self.ani = None

        self.current_frame_idx = 0

        self.paused = True

        self.status_var.set("Stopped")

        # reset waveform marker

        if hasattr(self, 'wave_marker') and self.wave_marker:

            self.wave_marker.set_xdata(0)

        self.canvas.draw_idle()


    def update_frame(self, *args):

        if self.samples is None or self.paused:

            return


        # compute frame start/end

        start = int(self.current_frame_idx * HOP_SIZE)

        end = start + FRAME_SIZE

        if end > len(self.samples):

            # loop to start for continuous visual demo

            self.current_frame_idx = 0

            start = 0

            end = FRAME_SIZE


        frame = self.samples[start:end]

        # update waveform marker

        t_pos = (start + FRAME_SIZE/2) / float(self.sr)

        self.wave_marker.set_xdata(t_pos)


        # compute spectrum

        freqs, amps = compute_spectrum(frame, self.sr, n_bins=SPECTRUM_BINS)


        # update bars

        for rect, h in zip(self.bar_container, amps):

            rect.set_height(h)


        # optional: change bar colors based on amplitude

        for rect, h in zip(self.bar_container, amps):

            rect.set_color(plt.cm.viridis(h))


        self.current_frame_idx += 1

        if self.current_frame_idx >= self.num_frames:

            self.current_frame_idx = 0  # loop


        self.canvas.draw_idle()


# -----------------------

# Run the app

# -----------------------

def main():

    root = tk.Tk()

    app = SpectrumVisualizerApp(root)

    root.mainloop()


if __name__ == "__main__":

    main()


AI Business Idea Generator

import streamlit as st

from openai import OpenAI

from fpdf import FPDF

from datetime import datetime


# Initialize OpenAI client

client = OpenAI(api_key="YOUR_OPENAI_API_KEY")  # 🔑 Replace with your API key


# -------------------------------

# Function: Generate business ideas

# -------------------------------

def generate_ideas(industry):

    prompt = f"""

    You are an experienced startup strategist and product consultant.

    Suggest 3 innovative startup ideas in the {industry} industry.

    

    For each idea, include:

    1️⃣ **Startup Name / Concept Title**

    2️⃣ **Problem / Pain Points**

    3️⃣ **Proposed Solution**

    4️⃣ **Target Audience**

    5️⃣ **Monetization Model**

    6️⃣ **Recommended Tech Stack**

    7️⃣ **Potential Challenges**

    

    Keep each idea concise, creative, and practical for 2025.

    Format neatly with bullet points.

    """

    response = client.chat.completions.create(

        model="gpt-4o-mini",  # Lightweight & fast

        messages=[{"role": "user", "content": prompt}],

        temperature=0.8,

        max_tokens=800

    )

    return response.choices[0].message.content


# -------------------------------

# Function: Export to PDF

# -------------------------------

def export_to_pdf(industry, content):

    pdf = FPDF()

    pdf.add_page()

    pdf.set_font("Arial", size=12)

    pdf.multi_cell(0, 10, f"AI Business Ideas for: {industry}\nGenerated on {datetime.now().strftime('%Y-%m-%d %H:%M')}\n\n")

    pdf.multi_cell(0, 8, content)

    filename = f"business_ideas_{industry.replace(' ', '_')}.pdf"

    pdf.output(filename)

    return filename


# -------------------------------

# Streamlit UI

# -------------------------------

st.set_page_config(page_title="AI Business Idea Generator", page_icon="💡", layout="wide")


st.title("💡 AI Business Idea Generator")

st.markdown("Generate startup ideas with **real-world problems & solutions** — powered by GPT!")


industry = st.text_input("🌍 Enter your industry or niche (e.g., Healthcare, Education, FinTech):", "")


col1, col2 = st.columns([2, 1])


with col1:

    temperature = st.slider("Creativity Level (Higher = more unique ideas)", 0.2, 1.0, 0.8)


if st.button("🚀 Generate Business Ideas"):

    if industry.strip() == "":

        st.warning("Please enter an industry or niche to continue.")

    else:

        with st.spinner("Generating ideas... please wait ⏳"):

            ideas = generate_ideas(industry)

            st.success("✨ Done! Here are your AI-generated business ideas:")

            st.markdown(ideas)

            st.session_state["ideas_output"] = ideas

            st.session_state["industry"] = industry


# -------------------------------

# Export options

# -------------------------------

if "ideas_output" in st.session_state:

    st.markdown("---")

    st.subheader("📤 Export or Share Your Ideas")

    col1, col2 = st.columns(2)

    

    with col1:

        if st.button("💾 Download as Text"):

            st.download_button(

                label="Click to Download .txt",

                data=st.session_state["ideas_output"],

                file_name=f"business_ideas_{st.session_state['industry']}.txt",

                mime="text/plain"

            )

    

    with col2:

        if st.button("📄 Export as PDF"):

            filename = export_to_pdf(st.session_state["industry"], st.session_state["ideas_output"])

            with open(filename, "rb") as f:

                st.download_button(

                    label="Download PDF",

                    data=f,

                    file_name=filename,

                    mime="application/pdf"

                )


Recipe Cost Estimator

import tkinter as tk

from tkinter import ttk, messagebox, filedialog

import pandas as pd

import re

import os

import requests

from bs4 import BeautifulSoup

import webbrowser

from io import StringIO


# -------------------------

# Configuration & Helpers

# -------------------------


PRICE_DB = "prices.csv"  # local prices DB: columns -> item,price,unit (unit: kg or piece)

DEFAULT_PRICE_DATA = """item,price,unit

flour,40,kg

sugar,55,kg

milk,60,l

egg,6,piece

butter,450,kg

salt,20,kg

olive oil,600,litre

rice,60,kg

onion,40,kg

garlic,400,kg

"""


# Unit conversions to grams or ml (approximate / generic)

# you can refine per-ingredient or add density based conversions

UNIT_TO_GRAMS = {

    "g": 1,

    "gram": 1,

    "grams": 1,

    "kg": 1000,

    "kilogram": 1000,

    "kilograms": 1000,

    "mg": 0.001,

    "lb": 453.592,

    "oz": 28.3495,

    # common kitchen volume to grams approximations (generic)

    "cup": 240,       # ml ~ grams for water-like density; adapt per-ingredient

    "cups": 240,

    "tbsp": 15,

    "tablespoon": 15,

    "tsp": 5,

    "teaspoon": 5,

    "ml": 1,          # ml ~ grams for water-like density

    "l": 1000,

    "litre": 1000,

    "liter": 1000,

    "piece": None,    # piece handled separately

    "pcs": None,

    "pc": None

}


# Normalize function

def normalize_item_name(name):

    return re.sub(r'[^a-z0-9 ]', '', name.lower()).strip()


# -------------------------

# Price DB functions

# -------------------------

def ensure_price_db_exists():

    if not os.path.exists(PRICE_DB):

        with open(PRICE_DB, "w", encoding="utf-8") as f:

            f.write(DEFAULT_PRICE_DATA)


def load_price_db():

    ensure_price_db_exists()

    df = pd.read_csv(PRICE_DB)

    # normalize item column to match lookups

    df['item_norm'] = df['item'].apply(lambda x: normalize_item_name(str(x)))

    return df


def save_price_db(df):

    df = df.copy()

    if 'item_norm' in df.columns:

        df = df.drop(columns=['item_norm'])

    df.to_csv(PRICE_DB, index=False)


# -------------------------

# Parsing ingredient lines

# -------------------------

# Accept lines like:

# 2 cups flour

# 150 g sugar

# 1.5 tbsp olive oil

# 3 eggs

ING_LINE_REGEX = re.compile(r'^\s*(?P<qty>[\d/.]+)\s*(?P<unit>[a-zA-Z]+)?\s*(?P<item>.+)$')


def parse_quantity(q):

    """Parse numeric quantities (support fractions like 1/2)."""

    try:

        if '/' in q:

            parts = q.split('/')

            if len(parts) == 2:

                return float(parts[0]) / float(parts[1])

        return float(q)

    except Exception:

        return None


def parse_ingredient_line(line):

    m = ING_LINE_REGEX.match(line)

    if not m:

        return None

    qty_raw = m.group('qty')

    unit = m.group('unit') or ""

    item = m.group('item')

    qty = parse_quantity(qty_raw)

    if qty is None:

        return None

    return {"qty": qty, "unit": unit.lower(), "item": item.strip()}


# -------------------------

# Cost calculation

# -------------------------

def compute_cost_for_row(row, prices_df):

    """

    row: dict with keys qty, unit, item

    prices_df: DataFrame with columns item, price, unit

    returns (cost, price_used, reason)

    """

    item_norm = normalize_item_name(row['item'])

    # find best match in prices

    match = prices_df[prices_df['item_norm'] == item_norm]

    if match.empty:

        # try partial matching (contains)

        match = prices_df[prices_df['item_norm'].str.contains(item_norm.split()[0])]


    if not match.empty:

        # pick first match

        m = match.iloc[0]

        price = float(m['price'])

        price_unit = str(m['unit']).lower()

        # If price_unit is kg, convert qty/unit to kg

        if row['unit'] in UNIT_TO_GRAMS and UNIT_TO_GRAMS[row['unit']] is not None:

            grams = row['qty'] * UNIT_TO_GRAMS[row['unit']]

            if price_unit in ('kg', 'kilogram', 'kilograms'):

                kg = grams / 1000.0

                cost = kg * price

                return cost, price, f"price per kg ({price_unit})"

            elif price_unit in ('l','litre','liter','ml'):

                # assume ml ~ grams for simplicity

                liters = grams / 1000.0

                cost = liters * price

                return cost, price, f"price per litre ({price_unit})"

            elif price_unit in ('g','gram','grams'):

                cost = (grams/1.0) * price

                return cost, price, f"price per gram ({price_unit})"

            else:

                # unknown price unit, fallback

                return None, price, f"unknown price unit: {price_unit}"

        else:

            # piece-like units

            if price_unit in ('piece','pc','pcs'):

                # qty is number of pieces

                cost = row['qty'] * price

                return cost, price, "price per piece"

            elif price_unit in ('kg','kilogram','kg'):

                # if unit is piece but price is per kg, we cannot convert; ask user

                return None, price, "needs manual conversion (piece vs kg)"

            else:

                return None, price, f"unhandled conversion: {row['unit']} -> {price_unit}"

    else:

        return None, None, "no price found"


# -------------------------

# Online scraping stub (adapt for your local grocery site)

# -------------------------

def fetch_online_price_stub(item_name):

    """

    Placeholder demo using BeautifulSoup.

    This function is intentionally generic and will NOT work out-of-the-box for a real grocery site.

    To adapt:

      1. Choose a grocery site (that permits scraping).

      2. Inspect search result HTML and find the selector that contains price.

      3. Update SEARCH_URL and selector below.

      4. Handle pagination / blocking / headers and respect robots.txt.


    Example (pseudo):

    SEARCH_URL = f"https://yourgrocer.example/search?q={item_name_encoded}"

    r = requests.get(SEARCH_URL, headers={...})

    soup = BeautifulSoup(r.text, "html.parser")

    price_tag = soup.select_one(".price-class")

    price_text = price_tag.get_text()

    parse price_text to float and return.


    For demo: we'll return None and a helpful search url so the user can confirm manually.

    """

    # Provide a helpful web search link so user can check and paste price

    query = requests.utils.requote_uri(item_name + " price")

    search_url = f"https://www.google.com/search?q={query}"

    return None, f"Please check prices manually: {search_url}"


# -------------------------

# GUI Application

# -------------------------

class RecipeCostApp:

    def __init__(self, root):

        self.root = root

        self.root.title("Recipe Cost Estimator")

        self.root.geometry("900x700")


        # Load price DB

        self.prices = load_price_db()


        # Top frame: recipe input

        top = ttk.Frame(root)

        top.pack(fill='both', padx=10, pady=6)


        ttk.Label(top, text="Paste recipe (one ingredient per line):", font=("Arial", 11)).pack(anchor='w')

        self.recipe_text = tk.Text(top, height=10)

        self.recipe_text.pack(fill='x')


        btn_frame = ttk.Frame(top)

        btn_frame.pack(fill='x', pady=6)

        ttk.Button(btn_frame, text="Load Prices CSV", command=self.load_prices_csv).pack(side='left', padx=4)

        ttk.Button(btn_frame, text="Save Prices CSV", command=self.save_prices_csv).pack(side='left', padx=4)

        ttk.Button(btn_frame, text="Estimate Cost", command=self.estimate_cost).pack(side='left', padx=4)

        ttk.Button(btn_frame, text="Clear", command=lambda: self.recipe_text.delete("1.0", "end")).pack(side='left', padx=4)


        # Middle: results table and edit area

        mid = ttk.Frame(root)

        mid.pack(fill='both', expand=True, padx=10, pady=6)


        left_mid = ttk.Frame(mid)

        left_mid.pack(side='left', fill='both', expand=True)


        ttk.Label(left_mid, text="Cost Breakdown:", font=("Arial", 11)).pack(anchor='w')

        self.tree = ttk.Treeview(left_mid, columns=("qty", "unit", "item", "price_used", "cost", "note"), show='headings')

        for c in ("qty", "unit", "item", "price_used", "cost", "note"):

            self.tree.heading(c, text=c.capitalize())

            self.tree.column(c, width=110, anchor='center')

        self.tree.pack(fill='both', expand=True)


        right_mid = ttk.Frame(mid, width=320)

        right_mid.pack(side='right', fill='y', padx=6)


        ttk.Label(right_mid, text="Edit / Add Price (selected item):", font=("Arial", 11)).pack(anchor='w', pady=4)

        ttk.Label(right_mid, text="Item name:").pack(anchor='w')

        self.price_item_entry = ttk.Entry(right_mid)

        self.price_item_entry.pack(fill='x', pady=2)

        ttk.Label(right_mid, text="Price (numeric):").pack(anchor='w')

        self.price_value_entry = ttk.Entry(right_mid)

        self.price_value_entry.pack(fill='x', pady=2)

        ttk.Label(right_mid, text="Unit (kg/piece/litre):").pack(anchor='w')

        self.price_unit_entry = ttk.Entry(right_mid)

        self.price_unit_entry.pack(fill='x', pady=2)


        ttk.Button(right_mid, text="Save Price", command=self.save_price_from_entries).pack(pady=6)

        ttk.Button(right_mid, text="Fetch Online Price (open search)", command=self.fetch_online_for_selected).pack(pady=6)

        ttk.Button(right_mid, text="Export Breakdown CSV", command=self.export_breakdown_csv).pack(pady=6)


        # bottom: totals

        bottom = ttk.Frame(root)

        bottom.pack(fill='x', padx=10, pady=8)

        self.total_label = ttk.Label(bottom, text="Total Cost: ₹0.00", font=("Arial", 12, "bold"))

        self.total_label.pack(anchor='e')


        # Bind selection

        self.tree.bind("<<TreeviewSelect>>", self.on_row_select)


        # internal

        self.last_breakdown = []  # list of dicts


    # -------------------------

    # UI Callbacks

    # -------------------------

    def load_prices_csv(self):

        path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv"), ("All files", "*.*")])

        if not path:

            return

        try:

            df = pd.read_csv(path)

            if 'item' not in df.columns or 'price' not in df.columns or 'unit' not in df.columns:

                messagebox.showerror("Error", "CSV must have columns: item,price,unit")

                return

            save_price_db(df)

            self.prices = load_price_db()

            messagebox.showinfo("Loaded", f"Prices loaded and saved to {PRICE_DB}")

        except Exception as e:

            messagebox.showerror("Error", f"Failed to load file: {e}")


    def save_prices_csv(self):

        save_price_db(self.prices)

        messagebox.showinfo("Saved", f"Prices saved to {PRICE_DB}")


    def estimate_cost(self):

        # Clear tree

        for r in self.tree.get_children():

            self.tree.delete(r)

        text = self.recipe_text.get("1.0", "end").strip()

        if not text:

            messagebox.showwarning("Input", "Please paste recipe ingredient lines")

            return

        lines = [ln.strip() for ln in text.splitlines() if ln.strip()]

        parsed = []

        for ln in lines:

            p = parse_ingredient_line(ln)

            if p:

                parsed.append(p)

            else:

                parsed.append({"qty": None, "unit": "", "item": ln})

        prices_df = self.prices.copy()

        breakdown = []

        total = 0.0

        for row in parsed:

            if row['qty'] is None:

                cost, price_used, note = None, None, "Could not parse quantity"

            else:

                cost, price_used, note = compute_cost_for_row(row, prices_df)

            if cost is None:

                note = note or "price missing or conversion needed"

                cost_display = ""

            else:

                cost_display = f"{cost:.2f}"

                total += cost

            price_used_display = "" if price_used is None else str(price_used)

            breakdown_entry = {

                "qty": row.get('qty'),

                "unit": row.get('unit'),

                "item": row.get('item'),

                "price_used": price_used_display,

                "cost": cost_display,

                "note": note

            }

            breakdown.append(breakdown_entry)

            self.tree.insert("", "end", values=(breakdown_entry['qty'], breakdown_entry['unit'],

                                                breakdown_entry['item'], breakdown_entry['price_used'],

                                                breakdown_entry['cost'], breakdown_entry['note']))

        self.total_label.config(text=f"Total Cost: ₹{total:.2f}")

        self.last_breakdown = breakdown


    def on_row_select(self, event):

        sel = self.tree.selection()

        if not sel:

            return

        vals = self.tree.item(sel[0], 'values')

        item_name = vals[2]

        # prefill edit fields

        self.price_item_entry.delete(0, 'end')

        self.price_item_entry.insert(0, item_name)

        # try to fill existing price if present

        norm = normalize_item_name(item_name)

        m = self.prices[self.prices['item_norm'] == norm]

        if not m.empty:

            row = m.iloc[0]

            self.price_value_entry.delete(0, 'end')

            self.price_value_entry.insert(0, str(row['price']))

            self.price_unit_entry.delete(0, 'end')

            self.price_unit_entry.insert(0, str(row['unit']))

        else:

            self.price_value_entry.delete(0, 'end')

            self.price_unit_entry.delete(0, 'end')


    def save_price_from_entries(self):

        item = self.price_item_entry.get().strip()

        price = self.price_value_entry.get().strip()

        unit = self.price_unit_entry.get().strip()

        if not item or not price or not unit:

            messagebox.showwarning("Input", "Please supply item, price, and unit")

            return

        try:

            price_f = float(price)

        except:

            messagebox.showerror("Input", "Price must be numeric")

            return

        norm = normalize_item_name(item)

        df = self.prices

        if (df['item_norm'] == norm).any():

            idx = df[df['item_norm'] == norm].index[0]

            df.at[idx, 'price'] = price_f

            df.at[idx, 'unit'] = unit

            df.at[idx, 'item'] = item

            df.at[idx, 'item_norm'] = norm

        else:

            new_row = {'item': item, 'price': price_f, 'unit': unit, 'item_norm': norm}

            self.prices = pd.concat([df, pd.DataFrame([new_row])], ignore_index=True)

        save_price_db(self.prices)

        messagebox.showinfo("Saved", "Price saved to local DB")

        self.estimate_cost()  # refresh


    def fetch_online_for_selected(self):

        sel = self.tree.selection()

        if not sel:

            messagebox.showwarning("Select", "Select an ingredient row first")

            return

        vals = self.tree.item(sel[0], 'values')

        item_name = vals[2]

        price, hint = fetch_online_price_stub(item_name)

        if price is not None:

            # automatically fill fields

            self.price_item_entry.delete(0,'end'); self.price_item_entry.insert(0, item_name)

            self.price_value_entry.delete(0,'end'); self.price_value_entry.insert(0, str(price))

            self.price_unit_entry.delete(0,'end'); self.price_unit_entry.insert(0, 'kg')

            messagebox.showinfo("Fetched", f"Fetched price: {price}")

        else:

            # open browser with search link or show hint

            if hint:

                webbrowser.open(hint)

                messagebox.showinfo("Manual lookup", f"Opened browser to help find price.\n\n{hint}")

            else:

                messagebox.showinfo("No results", "No price found online (please enter manually)")


    def export_breakdown_csv(self):

        if not self.last_breakdown:

            messagebox.showwarning("No data", "Please estimate cost first")

            return

        df = pd.DataFrame(self.last_breakdown)

        path = filedialog.asksaveasfilename(defaultextension=".csv", filetypes=[("CSV files","*.csv")])

        if not path:

            return

        df.to_csv(path, index=False)

        messagebox.showinfo("Exported", f"Breakdown exported to {path}")


# -------------------------

# Run

# -------------------------

def main():

    ensure_price_db_exists()

    root = tk.Tk()

    app = RecipeCostApp(root)

    root.mainloop()


if __name__ == "__main__":

    main()