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()


Smart Code Review Assistant

 smart_code_review/

├── app.py

├── templates/

│   ├── index.html

│   └── result.html

└── uploads/



app.py

import os
from flask import Flask, render_template, request
from pylint import epylint as lint
import openai

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'uploads'
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)

# 🔑 Set your OpenAI API key
openai.api_key = "YOUR_OPENAI_API_KEY"

def analyze_with_pylint(file_path):
    """Run pylint analysis and return report."""
    (pylint_stdout, _) = lint.py_run(file_path + " --disable=R,C", return_std=True)
    return pylint_stdout.getvalue()

def analyze_with_ai(code):
    """Send code to OpenAI for smart suggestions."""
    prompt = f"""
    You are a senior Python reviewer.
    Review the following code and provide:
    1. Code quality feedback
    2. Security issues
    3. Performance suggestions
    4. Refactoring tips

    Code:
    {code}
    """
    response = openai.ChatCompletion.create(
        model="gpt-4o-mini",  # or 'gpt-4' if available
        messages=[{"role": "user", "content": prompt}],
        max_tokens=600,
        temperature=0.4,
    )
    return response.choices[0].message["content"]

@app.route("/", methods=["GET", "POST"])
def index():
    if request.method == "POST":
        if 'file' not in request.files:
            return "No file uploaded"

        file = request.files['file']
        if file.filename == "":
            return "No selected file"

        file_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
        file.save(file_path)

        with open(file_path, "r", encoding="utf-8") as f:
            code_content = f.read()

        pylint_result = analyze_with_pylint(file_path)
        ai_feedback = analyze_with_ai(code_content)

        return render_template("result.html",
                               ai_feedback=ai_feedback,
                               pylint_result=pylint_result)

    return render_template("index.html")

if __name__ == "__main__":
    app.run(debug=True)


templates/index.html


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Smart Code Review Assistant</title>
    <style>
        body { font-family: Arial; margin: 50px; background-color: #f9f9f9; }
        h1 { color: #333; }
        .upload-box { background: white; padding: 30px; border-radius: 10px; width: 400px; }
        input[type=file] { margin: 20px 0; }
        button { padding: 10px 20px; background: #4CAF50; color: white; border: none; border-radius: 5px; }
    </style>
</head>
<body>
    <h1>🤖 Smart Code Review Assistant</h1>
    <div class="upload-box">
        <form method="POST" enctype="multipart/form-data">
            <label>Upload your Python file (.py):</label><br>
            <input type="file" name="file" accept=".py" required><br>
            <button type="submit">Analyze Code</button>
        </form>
    </div>
</body>
</html>


templates/result.html


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Review Result</title>
    <style>
        body { font-family: Arial; margin: 40px; background-color: #f4f4f4; }
        pre { background: white; padding: 20px; border-radius: 8px; overflow-x: auto; }
        h2 { color: #444; }
    </style>
</head>
<body>
    <h1>✅ Code Review Results</h1>

    <h2>🧠 AI Feedback</h2>
    <pre>{{ ai_feedback }}</pre>

    <h2>🧩 Pylint Static Analysis</h2>
    <pre>{{ pylint_result }}</pre>

    <a href="/">⬅ Back</a>
</body>
</html>