Daily Habit Forecasting Using Time-Series

import pandas as pd

import matplotlib.pyplot as plt

from statsmodels.tsa.holtwinters import ExponentialSmoothing


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

# Load & Prepare Data

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

def load_habit_data(csv_path, habit_name):

    df = pd.read_csv(csv_path)

    df["date"] = pd.to_datetime(df["date"])


    habit_df = df[df["habit"] == habit_name]

    habit_df = habit_df.sort_values("date")


    habit_df.set_index("date", inplace=True)

    ts = habit_df["completed"]


    return ts


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

# Forecast Habit Completion

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

def forecast_habit(ts, days=7):

    model = ExponentialSmoothing(

        ts,

        trend="add",

        seasonal=None,

        initialization_method="estimated"

    )


    fitted_model = model.fit()

    forecast = fitted_model.forecast(days)


    return fitted_model, forecast


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

# Risk Analysis

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

def habit_risk_score(forecast):

    avg_completion = forecast.mean()


    if avg_completion < 0.4:

        return "🚨 High Risk (likely to break)"

    elif avg_completion < 0.7:

        return "⚠️ Medium Risk"

    else:

        return "✅ Low Risk (stable habit)"


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

# Visualization

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

def plot_forecast(ts, forecast, habit_name):

    plt.figure(figsize=(10, 5))


    plt.plot(ts.index, ts.values, label="Past Completion", marker="o")

    plt.plot(forecast.index, forecast.values, label="Forecast", linestyle="--", marker="x")


    plt.ylim(-0.1, 1.1)

    plt.ylabel("Habit Completed (1=yes, 0=no)")

    plt.title(f"Habit Forecast: {habit_name}")

    plt.legend()

    plt.grid(True)


    plt.show()


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

# MAIN

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

if __name__ == "__main__":

    csv_file = input("Enter CSV file path: ").strip()

    habit = input("Enter habit name (case-sensitive): ").strip()


    ts = load_habit_data(csv_file, habit)


    model, forecast = forecast_habit(ts, days=7)


    risk = habit_risk_score(forecast)


    print("\nšŸ“Š HABIT FORECAST REPORT")

    print("------------------------")

    print(f"Habit: {habit}")

    print(f"Next 7-day average completion: {forecast.mean():.2f}")

    print(f"Risk Level: {risk}")


    plot_forecast(ts, forecast, habit)


Local Password Strength Analyzer

import tkinter as tk

from tkinter import ttk

import math

import re


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

# Heuristics & helpers

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


COMMON_PASSWORDS = {

    "password", "123456", "123456789", "qwerty", "abc123",

    "letmein", "welcome", "admin", "iloveyou", "monkey"

}


SEQUENCES = [

    "abcdefghijklmnopqrstuvwxyz",

    "ABCDEFGHIJKLMNOPQRSTUVWXYZ",

    "0123456789",

    "qwertyuiop", "asdfghjkl", "zxcvbnm"

]


def shannon_entropy(password: str) -> float:

    """Approximate entropy based on character sets used."""

    pool = 0

    if re.search(r"[a-z]", password): pool += 26

    if re.search(r"[A-Z]", password): pool += 26

    if re.search(r"\d", password):    pool += 10

    if re.search(r"[^\w\s]", password): pool += 32  # symbols

    if pool == 0:

        return 0.0

    return len(password) * math.log2(pool)


def has_repeats(password: str) -> bool:

    return bool(re.search(r"(.)\1{2,}", password))  # aaa, 111


def has_sequence(password: str) -> bool:

    p = password

    for seq in SEQUENCES:

        for i in range(len(seq) - 3):

            if seq[i:i+4] in p:

                return True

    return False


def keyboard_walk(password: str) -> bool:

    walks = ["qwerty", "asdf", "zxcv", "poiuy", "lkjhg", "mnbv"]

    p = password.lower()

    return any(w in p for w in walks)


def analyze_password(password: str):

    issues = []

    score = 0


    # Length

    if len(password) < 8:

        issues.append("Too short (minimum 8 characters).")

    else:

        score += min(20, (len(password) - 7) * 3)


    # Character classes

    classes = 0

    classes += bool(re.search(r"[a-z]", password))

    classes += bool(re.search(r"[A-Z]", password))

    classes += bool(re.search(r"\d", password))

    classes += bool(re.search(r"[^\w\s]", password))

    score += classes * 10


    if classes < 3:

        issues.append("Use at least 3 character types (upper/lower/digits/symbols).")


    # Entropy

    ent = shannon_entropy(password)

    score += min(30, int(ent / 3))  # cap contribution


    if ent < 40:

        issues.append("Low entropy. Add length and variety.")


    # Patterns

    if password.lower() in COMMON_PASSWORDS:

        issues.append("Common password detected.")

        score -= 30


    if has_repeats(password):

        issues.append("Repeated characters detected (e.g., 'aaa').")

        score -= 10


    if has_sequence(password):

        issues.append("Sequential pattern detected (e.g., 'abcd', '1234').")

        score -= 10


    if keyboard_walk(password):

        issues.append("Keyboard pattern detected (e.g., 'qwerty').")

        score -= 10


    score = max(0, min(100, score))


    if score >= 80:

        verdict = "Strong"

    elif score >= 60:

        verdict = "Good"

    elif score >= 40:

        verdict = "Weak"

    else:

        verdict = "Very Weak"


    return {

        "score": score,

        "verdict": verdict,

        "entropy": round(ent, 1),

        "issues": issues

    }


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

# GUI

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


class App(tk.Tk):

    def __init__(self):

        super().__init__()

        self.title("Local Password Strength Analyzer")

        self.geometry("520x420")

        self.resizable(False, False)


        ttk.Label(self, text="Enter Password:", font=("Arial", 12)).pack(pady=10)

        self.pw = ttk.Entry(self, show="*", width=40)

        self.pw.pack()


        self.show_var = tk.BooleanVar(value=False)

        ttk.Checkbutton(self, text="Show password", variable=self.show_var,

                        command=self.toggle_show).pack(pady=5)


        ttk.Button(self, text="Analyze", command=self.run).pack(pady=10)


        self.score_lbl = ttk.Label(self, text="Score: —", font=("Arial", 12, "bold"))

        self.score_lbl.pack()


        self.ent_lbl = ttk.Label(self, text="Entropy: — bits")

        self.ent_lbl.pack(pady=5)


        self.verdict_lbl = ttk.Label(self, text="Verdict: —", font=("Arial", 12))

        self.verdict_lbl.pack(pady=5)


        ttk.Label(self, text="Feedback:", font=("Arial", 11, "bold")).pack(pady=8)

        self.feedback = tk.Text(self, height=8, width=60, wrap="word")

        self.feedback.pack(padx=10)


    def toggle_show(self):

        self.pw.config(show="" if self.show_var.get() else "*")


    def run(self):

        pwd = self.pw.get()

        res = analyze_password(pwd)


        self.score_lbl.config(text=f"Score: {res['score']}/100")

        self.ent_lbl.config(text=f"Entropy: {res['entropy']} bits")

        self.verdict_lbl.config(text=f"Verdict: {res['verdict']}")


        self.feedback.delete("1.0", "end")

        if res["issues"]:

            for i in res["issues"]:

                self.feedback.insert("end", f"• {i}\n")

        else:

            self.feedback.insert("end", "No issues found. Great password!")


if __name__ == "__main__":

    App().mainloop()

Image Duplicate Finder (Hash-Based)

import os

import tkinter as tk

from tkinter import filedialog, ttk, messagebox

from PIL import Image, ImageTk

import imagehash



class ImageDuplicateFinder:

    def __init__(self, root):

        self.root = root

        self.root.title("Image Duplicate Finder (Hash-Based)")

        self.root.geometry("900x600")


        self.image_hash_map = {}

        self.duplicates = []


        self.setup_ui()


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

    def setup_ui(self):

        top_frame = tk.Frame(self.root)

        top_frame.pack(fill=tk.X, pady=10)


        tk.Button(top_frame, text="Select Folder", command=self.select_folder).pack(side=tk.LEFT, padx=10)

        tk.Button(top_frame, text="Scan for Duplicates", command=self.scan_duplicates).pack(side=tk.LEFT, padx=10)


        self.result_tree = ttk.Treeview(self.root, columns=("img1", "img2"), show="headings")

        self.result_tree.heading("img1", text="Image 1")

        self.result_tree.heading("img2", text="Duplicate Image")

        self.result_tree.pack(fill="both", expand=True, pady=10)


        self.result_tree.bind("<Double-1>", self.show_preview)


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

    def select_folder(self):

        self.folder_path = filedialog.askdirectory()

        if self.folder_path:

            messagebox.showinfo("Selected Folder", self.folder_path)


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

    def scan_duplicates(self):

        if not hasattr(self, "folder_path"):

            messagebox.showerror("Error", "Please select a folder first!")

            return


        self.image_hash_map = {}

        self.duplicates = []

        self.result_tree.delete(*self.result_tree.get_children())


        supported_ext = (".jpg", ".jpeg", ".png", ".bmp")


        for filename in os.listdir(self.folder_path):

            if filename.lower().endswith(supported_ext):

                full_path = os.path.join(self.folder_path, filename)


                try:

                    img = Image.open(full_path)

                    img_hash = imagehash.average_hash(img)


                    if img_hash in self.image_hash_map:

                        self.duplicates.append((self.image_hash_map[img_hash], full_path))


                    else:

                        self.image_hash_map[img_hash] = full_path


                except Exception as e:

                    print("Error loading:", filename, e)


        # Show results in table

        for dup in self.duplicates:

            self.result_tree.insert("", tk.END, values=dup)


        if not self.duplicates:

            messagebox.showinfo("Result", "No duplicates found!")

        else:

            messagebox.showinfo("Result", f"Found {len(self.duplicates)} duplicate pairs.")


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

    def show_preview(self, event):

        selected = self.result_tree.focus()

        if not selected:

            return


        img1_path, img2_path = self.result_tree.item(selected, "values")

        self.preview_window(img1_path, img2_path)


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

    def preview_window(self, img1_path, img2_path):

        win = tk.Toplevel(self.root)

        win.title("Duplicate Image Preview")

        win.geometry("850x450")


        tk.Label(win, text=f"Image 1: {os.path.basename(img1_path)}", font=("Arial", 10)).pack(pady=5)

        tk.Label(win, text=f"Image 2: {os.path.basename(img2_path)}", font=("Arial", 10)).pack(pady=5)


        frame = tk.Frame(win)

        frame.pack(expand=True)


        # Load images

        img1 = Image.open(img1_path).resize((350, 350))

        img2 = Image.open(img2_path).resize((350, 350))


        img1_tk = ImageTk.PhotoImage(img1)

        img2_tk = ImageTk.PhotoImage(img2)


        left_label = tk.Label(frame, image=img1_tk)

        left_label.image = img1_tk

        left_label.pack(side=tk.LEFT, padx=10)


        right_label = tk.Label(frame, image=img2_tk)

        right_label.image = img2_tk

        right_label.pack(side=tk.RIGHT, padx=10)



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

# RUN APP

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

root = tk.Tk()

app = ImageDuplicateFinder(root)

root.mainloop()

 

Smart PDF Page Extractor

import fitz  # PyMuPDF

import tkinter as tk

from tkinter import filedialog, messagebox, ttk

from PIL import Image, ImageTk



class PDFExtractorApp:

    def __init__(self, root):

        self.root = root

        self.root.title("Smart PDF Page Extractor")

        self.root.geometry("900x600")


        self.pdf_doc = None

        self.page_images = []

        self.selected_pages = []


        self.create_ui()


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

    # UI SETUP

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

    def create_ui(self):

        top_frame = tk.Frame(self.root)

        top_frame.pack(fill=tk.X, pady=10)


        tk.Button(top_frame, text="Open PDF", command=self.open_pdf).pack(side=tk.LEFT, padx=10)

        tk.Button(top_frame, text="Extract Selected", command=self.extract_pages).pack(side=tk.LEFT, padx=10)

        tk.Button(top_frame, text="Save New PDF", command=self.save_new_pdf).pack(side=tk.LEFT, padx=10)


        self.canvas = tk.Canvas(self.root, bg="white")

        self.scroll_y = tk.Scrollbar(self.root, orient="vertical", command=self.canvas.yview)

        self.canvas.configure(yscrollcommand=self.scroll_y.set)


        self.frame = tk.Frame(self.canvas)

        self.canvas.create_window((0, 0), window=self.frame, anchor="nw")


        self.canvas.pack(side=tk.LEFT, fill="both", expand=True)

        self.scroll_y.pack(side=tk.RIGHT, fill="y")


        self.frame.bind("<Configure>", lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all")))


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

    # OPEN PDF

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

    def open_pdf(self):

        filepath = filedialog.askopenfilename(

            filetypes=[("PDF Files", "*.pdf")],

            title="Choose a PDF"

        )

        if not filepath:

            return


        try:

            self.pdf_doc = fitz.open(filepath)

            self.load_pages()

        except Exception as e:

            messagebox.showerror("Error", f"Failed to open PDF:\n{e}")


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

    # LOAD AND DISPLAY PAGE THUMBNAILS

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

    def load_pages(self):

        for widget in self.frame.winfo_children():

            widget.destroy()


        self.selected_pages = []

        self.page_images = []


        for page_num in range(len(self.pdf_doc)):

            page = self.pdf_doc.load_page(page_num)

            pix = page.get_pixmap(matrix=fitz.Matrix(0.3, 0.3))  # thumbnail scale


            image = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)

            img_tk = ImageTk.PhotoImage(image)


            self.page_images.append(img_tk)


            page_frame = tk.Frame(self.frame, bd=2, relief="groove")

            page_frame.pack(padx=10, pady=10, anchor="w")


            label = tk.Label(page_frame, image=img_tk)

            label.pack()


            tk.Label(page_frame, text=f"Page {page_num + 1}", font=("Arial", 12, "bold")).pack()


            btn = tk.Button(

                page_frame,

                text="Select",

                command=lambda n=page_num: self.toggle_page(n)

            )

            btn.pack(pady=5)


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

    # SELECT / UNSELECT PAGE

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

    def toggle_page(self, page_num):

        if page_num in self.selected_pages:

            self.selected_pages.remove(page_num)

            messagebox.showinfo("Page Unselected", f"Page {page_num + 1} removed.")

        else:

            self.selected_pages.append(page_num)

            messagebox.showinfo("Page Selected", f"Page {page_num + 1} selected.")


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

    # EXTRACT SELECTED PAGES

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

    def extract_pages(self):

        if not self.selected_pages:

            messagebox.showerror("Error", "No pages selected!")

            return


        self.selected_pages.sort()


        messagebox.showinfo("Selected Pages", f"Extracting pages: {[p+1 for p in self.selected_pages]}")


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

    # SAVE NEW PDF WITH SELECTED PAGES

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

    def save_new_pdf(self):

        if not self.selected_pages:

            messagebox.showerror("Error", "Select pages before saving!")

            return


        output_path = filedialog.asksaveasfilename(

            defaultextension=".pdf",

            filetypes=[("PDF Files", "*.pdf")],

            title="Save Extracted PDF"

        )


        if not output_path:

            return


        try:

            new_pdf = fitz.open()


            for page_num in self.selected_pages:

                new_pdf.insert_pdf(self.pdf_doc, from_page=page_num, to_page=page_num)


            new_pdf.save(output_path)

            new_pdf.close()


            messagebox.showinfo("Success", "New PDF saved successfully!")


        except Exception as e:

            messagebox.showerror("Error", f"Failed to save PDF:\n{e}")



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

# RUN APP

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

root = tk.Tk()

app = PDFExtractorApp(root)

root.mainloop()


Offline Travel Expense Splitter App

import tkinter as tk

from tkinter import ttk, messagebox

import sqlite3

from fpdf import FPDF


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

# DATABASE SETUP

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

conn = sqlite3.connect("travel_expenses.db")

cursor = conn.cursor()


cursor.execute("""

CREATE TABLE IF NOT EXISTS members (

    id INTEGER PRIMARY KEY AUTOINCREMENT,

    name TEXT NOT NULL

)

""")


cursor.execute("""

CREATE TABLE IF NOT EXISTS expenses (

    id INTEGER PRIMARY KEY AUTOINCREMENT,

    member_id INTEGER,

    description TEXT,

    amount REAL,

    FOREIGN KEY(member_id) REFERENCES members(id)

)

""")


conn.commit()


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

# MAIN APPLICATION

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

class TravelExpenseApp:


    def __init__(self, root):

        self.root = root

        self.root.title("Travel Expense Splitter")

        self.root.geometry("600x500")


        self.create_ui()


    # ------------------------ UI ------------------------

    def create_ui(self):

        tab_control = ttk.Notebook(self.root)


        self.tab_members = ttk.Frame(tab_control)

        self.tab_expenses = ttk.Frame(tab_control)

        self.tab_summary = ttk.Frame(tab_control)


        tab_control.add(self.tab_members, text="Members")

        tab_control.add(self.tab_expenses, text="Expenses")

        tab_control.add(self.tab_summary, text="Summary")

        tab_control.pack(expand=1, fill="both")


        self.setup_members_tab()

        self.setup_expenses_tab()

        self.setup_summary_tab()


    # ------------------------ MEMBERS TAB ------------------------

    def setup_members_tab(self):

        tk.Label(self.tab_members, text="Add Member", font=("Arial", 14)).pack(pady=10)


        self.member_entry = tk.Entry(self.tab_members, font=("Arial", 12))

        self.member_entry.pack(pady=5)


        tk.Button(self.tab_members, text="Add Member", command=self.add_member).pack(pady=10)


        self.members_list = tk.Listbox(self.tab_members, width=40, height=10)

        self.members_list.pack(pady=10)


        self.load_members()


    def add_member(self):

        name = self.member_entry.get()

        if not name:

            messagebox.showerror("Error", "Please enter a name!")

            return


        cursor.execute("INSERT INTO members (name) VALUES (?)", (name,))

        conn.commit()

        self.member_entry.delete(0, tk.END)

        self.load_members()


    def load_members(self):

        self.members_list.delete(0, tk.END)

        cursor.execute("SELECT name FROM members")

        for row in cursor.fetchall():

            self.members_list.insert(tk.END, row[0])


    # ------------------------ EXPENSE TAB ------------------------

    def setup_expenses_tab(self):

        tk.Label(self.tab_expenses, text="Add Expense", font=("Arial", 14)).pack(pady=10)


        tk.Label(self.tab_expenses, text="Select Member:").pack()

        self.member_dropdown = ttk.Combobox(self.tab_expenses, state="readonly")

        self.member_dropdown.pack(pady=5)


        self.load_member_dropdown()


        tk.Label(self.tab_expenses, text="Description:").pack()

        self.desc_entry = tk.Entry(self.tab_expenses, font=("Arial", 12))

        self.desc_entry.pack(pady=5)


        tk.Label(self.tab_expenses, text="Amount:").pack()

        self.amount_entry = tk.Entry(self.tab_expenses, font=("Arial", 12))

        self.amount_entry.pack(pady=5)


        tk.Button(self.tab_expenses, text="Add Expense", command=self.add_expense).pack(pady=10)


        self.expense_tree = ttk.Treeview(self.tab_expenses, columns=("member", "desc", "amount"), show="headings")

        self.expense_tree.heading("member", text="Member")

        self.expense_tree.heading("desc", text="Description")

        self.expense_tree.heading("amount", text="Amount")

        self.expense_tree.pack(fill="both", expand=True)


        self.load_expenses()


    def load_member_dropdown(self):

        cursor.execute("SELECT name FROM members")

        members = [row[0] for row in cursor.fetchall()]

        self.member_dropdown["values"] = members


    def add_expense(self):

        member = self.member_dropdown.get()

        desc = self.desc_entry.get()

        amount = self.amount_entry.get()


        if not member or not desc or not amount:

            messagebox.showerror("Error", "All fields are required!")

            return


        try:

            amount = float(amount)

        except:

            messagebox.showerror("Error", "Amount must be a number!")

            return


        cursor.execute("SELECT id FROM members WHERE name=?", (member,))

        member_id = cursor.fetchone()[0]


        cursor.execute("INSERT INTO expenses (member_id, description, amount) VALUES (?, ?, ?)",

                       (member_id, desc, amount))

        conn.commit()


        self.desc_entry.delete(0, tk.END)

        self.amount_entry.delete(0, tk.END)


        self.load_expenses()


    def load_expenses(self):

        for i in self.expense_tree.get_children():

            self.expense_tree.delete(i)


        cursor.execute("""

            SELECT members.name, expenses.description, expenses.amount

            FROM expenses

            JOIN members ON expenses.member_id = members.id

        """)


        for row in cursor.fetchall():

            self.expense_tree.insert("", tk.END, values=row)


    # ------------------------ SUMMARY TAB ------------------------

    def setup_summary_tab(self):

        tk.Label(self.tab_summary, text="Expense Summary", font=("Arial", 14)).pack(pady=10)


        tk.Button(self.tab_summary, text="Calculate Summary", command=self.calculate_summary).pack(pady=10)

        tk.Button(self.tab_summary, text="Export PDF", command=self.export_pdf).pack(pady=10)


        self.summary_box = tk.Text(self.tab_summary, height=20, width=70)

        self.summary_box.pack()


    def calculate_summary(self):

        cursor.execute("SELECT COUNT(*) FROM members")

        num_members = cursor.fetchone()[0]


        cursor.execute("SELECT SUM(amount) FROM expenses")

        total_expense = cursor.fetchone()[0] or 0


        split_amount = total_expense / num_members if num_members > 0 else 0


        self.summary_box.delete(1.0, tk.END)

        self.summary_box.insert(tk.END, f"Total Expense: ₹{total_expense:.2f}\n")

        self.summary_box.insert(tk.END, f"Each Person Should Pay: ₹{split_amount:.2f}\n\n")


        cursor.execute("""

            SELECT members.name, SUM(expenses.amount)

            FROM members

            LEFT JOIN expenses ON members.id = expenses.member_id

            GROUP BY members.name

        """)


        for name, paid in cursor.fetchall():

            paid = paid or 0

            diff = paid - split_amount

            status = "owes" if diff < 0 else "gets back"

            self.summary_box.insert(tk.END, f"{name}: Paid ₹{paid:.2f} → {status} ₹{abs(diff):.2f}\n")


    # ------------------------ PDF EXPORT ------------------------

    def export_pdf(self):

        pdf = FPDF()

        pdf.add_page()

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


        pdf.cell(200, 10, "Travel Expense Summary", ln=True, align="C")

        pdf.ln(10)


        summary_text = self.summary_box.get(1.0, tk.END).split("\n")

        for line in summary_text:

            pdf.cell(0, 10, txt=line, ln=True)


        pdf.output("Travel_Expense_Summary.pdf")

        messagebox.showinfo("Success", "PDF Exported Successfully!")


# ------------------------ RUN APP ------------------------

root = tk.Tk()

app = TravelExpenseApp(root)

root.mainloop()