# filepath: d:\shopai\app.py import gradio as gr import sqlite3 import whisper import re from datetime import datetime, timedelta import csv # Moved outside the function for efficiency # Load Whisper model once at module load time (only done once): model = whisper.load_model("tiny") # Initialize SQLite database def init_db(): conn = sqlite3.connect("sales.db") c = conn.cursor() c.execute(''' CREATE TABLE IF NOT EXISTS sales ( id INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT, item TEXT, quantity INTEGER, price REAL, revenue REAL, profit REAL ) ''') c.execute(''' CREATE TABLE IF NOT EXISTS expenses ( id INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT, description TEXT, amount REAL ) ''') c.execute(''' CREATE TABLE IF NOT EXISTS credits ( id INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT, customer TEXT, amount REAL, status TEXT ) ''') c.execute(''' CREATE TABLE IF NOT EXISTS items ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE, cost_price REAL, selling_price REAL ) ''') conn.commit() conn.close() def transcribe(audio): if audio is None: return "" try: result = model.transcribe(audio) return result["text"] except Exception as e: return f"Transcription error: {e}" # Placeholder for processing sales input def process_input(text): if not text or not text.strip(): return ( "⚠️ Please enter a command or sales record.\n\n" "Examples:\n" "- Sold 5 items of soap\n" "- Show today's sales\n" "- Show this week's sales\n" "- Show sales for 2025-06-08\n" "- Export sales" ) text = text.strip().lower() # (1) Show today's sales if "show today's sales" in text or "today sales" in text: date = datetime.now().strftime("%Y-%m-%d") return get_sales_summary(date=date) # (2) Show this week's sales elif "show this week's sales" in text or "this week sales" in text: today = datetime.now() start_of_week = (today - timedelta(days=today.weekday())).strftime("%Y-%m-%d") end_of_week = today.strftime("%Y-%m-%d") return get_sales_summary(start_date=start_of_week, end_date=end_of_week) # (3) Show this month's sales elif "show this month's sales" in text: today = datetime.now() start_of_month = today.replace(day=1).strftime("%Y-%m-%d") end_of_month = today.strftime("%Y-%m-%d") return get_sales_summary(start_date=start_of_month, end_date=end_of_month) # (4) Show this year's sales elif "show this year's sales" in text: today = datetime.now() start_of_year = today.replace(month=1, day=1).strftime("%Y-%m-%d") end_of_year = today.strftime("%Y-%m-%d") return get_sales_summary(start_date=start_of_year, end_date=end_of_year) # (5) Show sales for a specific date elif "show sales for" in text: match = re.search(r"show sales for (\d{4}-\d{2}-\d{2})", text) if match: date = match.group(1) return get_sales_summary(date=date) else: return ( "⚠️ Please specify the date in YYYY-MM-DD format.\n" "Example: `Show sales for 2025-06-08`" ) # (6) Export sales elif "export sales" in text: try: with sqlite3.connect("sales.db") as conn: c = conn.cursor() c.execute("SELECT * FROM sales") rows = c.fetchall() with open("sales_export.csv", "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow(["id", "date", "item", "quantity", "price", "revenue", "profit"]) writer.writerows(rows) return "✅ Sales data exported to **sales_export.csv**" except Exception as e: return f"❌ Error exporting data: {e}" # (7) Business analytics elif ( "show analytics" in text or "business analytics" in text or "show business report" in text or "business report" in text ): return get_business_analytics() # (8) Show recent expenses elif "show expenses" in text: with sqlite3.connect("sales.db") as conn: c = conn.cursor() c.execute("SELECT date, description, amount FROM expenses ORDER BY date DESC LIMIT 10") rows = c.fetchall() if not rows: return "No expenses recorded." summary = "### Recent Expenses\n\n" for row in rows: summary += f"- {row[0]}: {row[1]} ₹{row[2]}\n" return summary # (9) Show pending credits elif "show credits" in text: with sqlite3.connect("sales.db") as conn: c = conn.cursor() c.execute("SELECT date, customer, amount, status FROM credits WHERE status='pending' ORDER BY date DESC") rows = c.fetchall() if not rows: return "No pending credits." summary = "### Pending Credits\n\n" for row in rows: summary += f"- {row[0]}: {row[1]} ₹{row[2]} ({row[3]})\n" return summary # (10) Add expense elif text.startswith("expense"): match = re.search(r"expense\s+([\w\s]+)\s+(\d+)", text) if match: desc = match.group(1).strip() amount = float(match.group(2)) date = datetime.now().strftime("%Y-%m-%d") with sqlite3.connect("sales.db") as conn: c = conn.cursor() c.execute("INSERT INTO expenses (date, description, amount) VALUES (?, ?, ?)", (date, desc, amount)) conn.commit() return f"✅ Expense recorded: {desc} ₹{amount}" else: return "⚠️ Please use format: Expense [description] [amount] (e.g., Expense rent 5000)" # (11) Add credit elif text.startswith("credit"): match = re.search(r"credit\s+([\w\s]+)\s+(\d+)", text) if match: customer = match.group(1).strip() amount = float(match.group(2)) date = datetime.now().strftime("%Y-%m-%d") with sqlite3.connect("sales.db") as conn: c = conn.cursor() c.execute("INSERT INTO credits (date, customer, amount, status) VALUES (?, ?, ?, ?)", (date, customer, amount, "pending")) conn.commit() return f"✅ Credit recorded: {customer} ₹{amount} (pending)" else: return "⚠️ Please use format: Credit [customer] [amount] (e.g., Credit Ramesh 200)" # (12) Add or update item prices match = re.search(r"(add|update) item (\w+)\s+cost\s*([\d.]+)\s+sell(?:ing)?\s*([\d.]+)", text) if match: action = match.group(1) item = match.group(2).lower() cost = float(match.group(3)) sell = float(match.group(4)) try: with sqlite3.connect("sales.db") as conn: c = conn.cursor() c.execute( "INSERT OR REPLACE INTO items (name, cost_price, selling_price) VALUES (?, ?, ?)", (item, cost, sell) ) conn.commit() except sqlite3.Error as db_err: return f"❌ Database error while updating item: {db_err}" return f"✅ Item '{item}' {action}d: Cost ₹{cost}, Selling ₹{sell}" # (13) SALES: "Sold X items of Y" (Requires cost/sell in DB) match = re.search(r"sold\s*(\d+)\s*items?\s+of\s+(\w+)", text) if match: try: quantity = int(match.group(1)) item_name = match.group(2).lower() # Lookup cost & selling price with sqlite3.connect("sales.db") as conn: c = conn.cursor() c.execute("SELECT cost_price, selling_price FROM items WHERE name = ?", (item_name,)) row = c.fetchone() if not row: return ( f"⚠️ Item '{item_name}' not found.\n\n" "Please add it first using:\n" "`Add item soap cost 7 sell 10`" ) cost_price, selling_price = row revenue = quantity * selling_price profit = (selling_price - cost_price) * quantity gst_rate = 0.18 gst_amount = revenue * gst_rate total_with_gst = revenue + gst_amount date = datetime.now().strftime("%Y-%m-%d") # Insert sale with sqlite3.connect("sales.db") as conn: c = conn.cursor() c.execute( "INSERT INTO sales (date, item, quantity, price, revenue, profit) VALUES (?, ?, ?, ?, ?, ?)", (date, item_name, quantity, selling_price, revenue, profit) ) conn.commit() return ( f"✅ Recorded **{quantity} {item_name}(s)** at ₹{selling_price} each.\n" f"Revenue: ₹{revenue}, Profit: ₹{profit}\n" f"GST (18%): ₹{gst_amount:.2f}, Total with GST: ₹{total_with_gst:.2f}" ) except Exception as e: return f"❌ Error recording sale: {e}" # (14) Simple sales: "sold 5 soaps" match = re.search(r"sold\s*(\d+)\s+(\w+)", text) if match: quantity = int(match.group(1)) item = match.group(2).lower() with sqlite3.connect("sales.db") as conn: c = conn.cursor() c.execute("SELECT cost_price, selling_price FROM items WHERE name = ?", (item,)) row = c.fetchone() if row: cost_price, selling_price = row revenue = quantity * selling_price profit = (selling_price - cost_price) * quantity gst_rate = 0.18 gst_amount = revenue * gst_rate total_with_gst = revenue + gst_amount date = datetime.now().strftime("%Y-%m-%d") with sqlite3.connect("sales.db") as conn: c = conn.cursor() c.execute( "INSERT INTO sales (date, item, quantity, price, revenue, profit) VALUES (?, ?, ?, ?, ?, ?)", (date, item, quantity, selling_price, revenue, profit) ) conn.commit() return ( f"✅ Recorded: **{quantity} {item}(s)** at ₹{selling_price} each.\n" f"Revenue: ₹{revenue}, Profit: ₹{profit}\n" f"GST (18%): ₹{gst_amount:.2f}, Total with GST: ₹{total_with_gst:.2f}" ) else: return f"⚠️ Item '{item}' not found. Please add it first: `Add item {item} cost [cost] sell [sell_price]`" # (15) Fallback return ( "⚠️ Could not understand input.\n\n" "Please try commands like:\n" "- `Add item soap cost 7 sell 10`\n" "- `Sold 5 items of soap`\n" "- `Show today's sales`\n" "- `Export sales`\n" ) # Helper function for summaries def get_sales_summary(date=None, start_date=None, end_date=None): try: with sqlite3.connect("sales.db") as conn: c = conn.cursor() if date: c.execute("SELECT item, quantity, revenue, profit FROM sales WHERE date = ?", (date,)) elif start_date and end_date: c.execute("SELECT item, quantity, revenue, profit FROM sales WHERE date BETWEEN ? AND ?", (start_date, end_date)) else: return "Invalid date range." rows = c.fetchall() if not rows: return "No sales recorded for the selected period." summary = "### Sales Summary\n\n" total_revenue = 0 total_profit = 0 for row in rows: summary += f"- **{row[0]}**: {row[1]} sold, Revenue ₹{row[2]}, Profit ₹{row[3]}\n" total_revenue += row[2] total_profit += row[3] summary += f"\n**Total Revenue:** ₹{total_revenue}\n\n**Total Profit:** ₹{total_profit}" return summary except Exception as e: return f"Error fetching summary: {e}" def get_recent_sales(limit=10): try: conn = sqlite3.connect("sales.db") c = conn.cursor() c.execute("SELECT date, item, quantity, price, revenue, profit FROM sales ORDER BY id DESC LIMIT ?", (limit,)) rows = c.fetchall() conn.close() headers = ["Date", "Item", "Quantity", "Price", "Revenue", "Profit"] return [headers] + [list(row) for row in rows] except Exception as e: return [["Error fetching sales history:", str(e)]] def get_business_analytics(): try: conn = sqlite3.connect("sales.db") c = conn.cursor() # Total sales, revenue, profit c.execute("SELECT COUNT(*), SUM(quantity), SUM(revenue), SUM(profit) FROM sales") total_count, total_qty, total_revenue, total_profit = c.fetchone() # Top-selling item c.execute("SELECT item, SUM(quantity) as qty FROM sales GROUP BY item ORDER BY qty DESC LIMIT 1") top_item = c.fetchone() # Best day (by revenue) c.execute("SELECT date, SUM(revenue) as rev FROM sales GROUP BY date ORDER BY rev DESC LIMIT 1") best_day = c.fetchone() # Average sale value c.execute("SELECT AVG(revenue) FROM sales") avg_sale = c.fetchone()[0] # Unique items c.execute("SELECT COUNT(DISTINCT item) FROM sales") unique_items = c.fetchone()[0] # Total expenses c.execute("SELECT SUM(amount) FROM expenses") total_expenses = c.fetchone()[0] or 0 # Total credits c.execute("SELECT SUM(amount) FROM credits WHERE status='pending'") total_credits = c.fetchone()[0] or 0 # Net profit net_profit = (total_profit or 0) - total_expenses # Item-wise breakdown c.execute("SELECT item, SUM(quantity), SUM(revenue), SUM(profit) FROM sales GROUP BY item") item_rows = c.fetchall() conn.close() summary = "### 📊 Business Analytics\n\n" summary += f"- **Total sales records:** {total_count or 0}\n" summary += f"- **Total quantity sold:** {total_qty or 0}\n" summary += f"- **Unique items sold:** {unique_items or 0}\n" summary += f"- **Total revenue:** ₹{total_revenue or 0}\n" summary += f"- **Total profit:** ₹{total_profit or 0}\n" summary += f"- **Total expenses:** ₹{total_expenses}\n" summary += f"- **Net profit (after expenses):** ₹{net_profit}\n" summary += f"- **Pending credits:** ₹{total_credits}\n" if top_item: summary += f"- **Top-selling item:** {top_item[0]} ({top_item[1]} sold)\n" if best_day: summary += f"- **Best day:** {best_day[0]} (Revenue ₹{best_day[1]})\n" summary += f"- **Average sale value:** ₹{avg_sale or 0:.2f}\n" summary += "\n#### Item-wise Breakdown\n" for row in item_rows: summary += f"- **{row[0]}**: {row[1]} sold, Revenue ₹{row[2]}, Profit ₹{row[3]}\n" summary += "\n_Tip: For trends, export your data and use Excel or Google Sheets charts!_" return summary except Exception as e: return f"Error generating analytics: {e}" # Gradio interface def handle_input(text, audio): if audio is not None: text = transcribe(audio) result = process_input(text) sales_table = get_recent_sales() return result, sales_table init_db() iface = gr.Interface( fn=handle_input, inputs=[ gr.Textbox( label="Enter sales or summary", placeholder="E.g. Sold 5 soaps at 10 each\nShow today's sales\nShow this week's sales\nShow sales for 2025-06-08\nExport sales" ), gr.Audio(type="filepath", label="Or speak") ], outputs=[ gr.Markdown(label="Result"), # "label" might be deprecated in gr.Dataframe # rename to "header" or remove if it generates a warning: gr.Dataframe(headers=["Date", "Item", "Quantity", "Price", "Revenue", "Profit"]) ], title="ShopAI Assistant", description=( "Welcome to ShopAI! 🎤📝\n\n" "• **Record sales** by typing or speaking (e.g., `Sold 5 soaps at 10 each`).\n" "• **Get summaries**: `Show today's sales`, `Show this week's sales`, or `Show sales for 2025-06-08`.\n" "• **Export all sales as CSV**: `Export sales`.\n" "• **Add or update items**: `Add item soap cost 7 sell 10`\n" "• **Quick sales**: `Sold 5 soap`\n" "• All calculations are automatic!\n\n" "Below, you can also see your recent sales history.\n" "Click **Clear** to reset the form." ), flagging_mode="never", examples=[ ["Sold 3 biscuits at 5 each", None], ["Show today's sales", None], ["Show this week's sales", None], ["Show sales for 2025-06-08", None], ["Export sales", None] ], theme="default" ) if __name__ == "__main__": iface.launch()