feat: add Discord bot integration for PDF receipt uploads and manual entry
Co-authored-by: aider (openai/unsloth/Qwen3-Coder-Next) <aider@aider.chat>
This commit is contained in:
141
app.py
141
app.py
@@ -1,6 +1,9 @@
|
|||||||
import sqlite3
|
import sqlite3
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import os
|
import os
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
import io
|
||||||
|
|
||||||
DB_PATH = "grocery_receipts.db"
|
DB_PATH = "grocery_receipts.db"
|
||||||
|
|
||||||
@@ -151,34 +154,114 @@ def list_receipts():
|
|||||||
# Initialize the database when the module is imported
|
# Initialize the database when the module is imported
|
||||||
init_db()
|
init_db()
|
||||||
|
|
||||||
|
# Discord bot setup
|
||||||
|
intents = discord.Intents.default()
|
||||||
|
intents.message_content = True
|
||||||
|
intents.members = True
|
||||||
|
|
||||||
|
bot = commands.Bot(command_prefix='!', intents=intents)
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_ready():
|
||||||
|
print(f'{bot.user} has connected to Discord!')
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_message(message):
|
||||||
|
# Ignore messages from the bot itself
|
||||||
|
if message.author == bot.user:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Process commands
|
||||||
|
await bot.process_commands(message)
|
||||||
|
|
||||||
|
# Handle receipt uploads
|
||||||
|
if message.attachments:
|
||||||
|
for attachment in message.attachments:
|
||||||
|
if attachment.filename.lower().endswith('.pdf'):
|
||||||
|
# Download the PDF
|
||||||
|
pdf_bytes = await attachment.read()
|
||||||
|
|
||||||
|
# For now, we'll just acknowledge receipt and save the file
|
||||||
|
# In a full implementation, you'd extract text from the PDF using OCR
|
||||||
|
|
||||||
|
# Save the PDF to a receipts folder
|
||||||
|
os.makedirs('receipts', exist_ok=True)
|
||||||
|
file_path = os.path.join('receipts', attachment.filename)
|
||||||
|
with open(file_path, 'wb') as f:
|
||||||
|
f.write(pdf_bytes)
|
||||||
|
|
||||||
|
# Send confirmation message
|
||||||
|
await message.channel.send(f"Receipt '{attachment.filename}' received and saved!")
|
||||||
|
|
||||||
|
@bot.command(name='add_receipt')
|
||||||
|
async def add_receipt_command(ctx, store_name: str, date: str, *, items: str):
|
||||||
|
"""
|
||||||
|
Add a receipt manually.
|
||||||
|
Usage: !add_receipt StoreName 2023-10-15 "Product1,2,1.50;Product2,1,2.00"
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Parse items: format is "Product1,quantity,price;Product2,quantity,price"
|
||||||
|
item_list = []
|
||||||
|
for item_str in items.split(';'):
|
||||||
|
parts = item_str.strip().split(',')
|
||||||
|
if len(parts) == 3:
|
||||||
|
product_name = parts[0].strip()
|
||||||
|
quantity = float(parts[1].strip())
|
||||||
|
price = float(parts[2].strip())
|
||||||
|
item_list.append((product_name, quantity, price))
|
||||||
|
|
||||||
|
add_receipt(store_name, date, item_list)
|
||||||
|
await ctx.send(f"Receipt added for {store_name} on {date} with {len(item_list)} items!")
|
||||||
|
except Exception as e:
|
||||||
|
await ctx.send(f"Error adding receipt: {str(e)}")
|
||||||
|
|
||||||
|
@bot.command(name='prices')
|
||||||
|
async def prices_command(ctx, *, product_name: str):
|
||||||
|
"""
|
||||||
|
Get price history for a product.
|
||||||
|
Usage: !prices ProductName
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
prices = get_product_prices(product_name)
|
||||||
|
if not prices:
|
||||||
|
await ctx.send(f"No price history found for '{product_name}'.")
|
||||||
|
return
|
||||||
|
|
||||||
|
message = f"Price history for '{product_name}':\n"
|
||||||
|
for date, store, qty, price in prices:
|
||||||
|
message += f"- {date} at {store}: ${price:.2f} per unit (qty: {qty})\n"
|
||||||
|
|
||||||
|
await ctx.send(message)
|
||||||
|
except Exception as e:
|
||||||
|
await ctx.send(f"Error retrieving prices: {str(e)}")
|
||||||
|
|
||||||
|
@bot.command(name='receipts')
|
||||||
|
async def receipts_command(ctx):
|
||||||
|
"""
|
||||||
|
List all receipts.
|
||||||
|
Usage: !receipts
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
receipts = list_receipts()
|
||||||
|
if not receipts:
|
||||||
|
await ctx.send("No receipts found in the database.")
|
||||||
|
return
|
||||||
|
|
||||||
|
message = "All receipts:\n"
|
||||||
|
for receipt_id, store, date, total in receipts:
|
||||||
|
message += f"- ID: {receipt_id}, Store: {store}, Date: {date}, Total: ${total:.2f}\n"
|
||||||
|
|
||||||
|
await ctx.send(message)
|
||||||
|
except Exception as e:
|
||||||
|
await ctx.send(f"Error listing receipts: {str(e)}")
|
||||||
|
|
||||||
|
# Run the bot
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Example usage
|
# You'll need to set your Discord bot token as an environment variable
|
||||||
print("Grocery Receipt Tracker - Demo")
|
# or replace the token parameter with your actual token (not recommended for production)
|
||||||
print("=" * 30)
|
DISCORD_TOKEN = os.getenv('DISCORD_BOT_TOKEN')
|
||||||
|
if not DISCORD_TOKEN:
|
||||||
|
print("Error: DISCORD_BOT_TOKEN environment variable not set")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
# Add a sample receipt
|
bot.run(DISCORD_TOKEN)
|
||||||
items = [
|
|
||||||
("Milk", 2, 1.50),
|
|
||||||
("Bread", 1, 2.00),
|
|
||||||
("Apples", 3, 0.80)
|
|
||||||
]
|
|
||||||
add_receipt("SuperMarket", "2023-10-15", items)
|
|
||||||
print("Added sample receipt to database.")
|
|
||||||
|
|
||||||
# Add another receipt for comparison
|
|
||||||
items2 = [
|
|
||||||
("Milk", 1, 1.30),
|
|
||||||
("Bread", 1, 1.80)
|
|
||||||
]
|
|
||||||
add_receipt("Corner Store", "2023-10-20", items2)
|
|
||||||
print("Added another receipt to database.")
|
|
||||||
|
|
||||||
# Show all receipts
|
|
||||||
print("\nAll Receipts:")
|
|
||||||
for receipt in list_receipts():
|
|
||||||
print(f" ID: {receipt[0]}, Store: {receipt[1]}, Date: {receipt[2]}, Total: ${receipt[3]:.2f}")
|
|
||||||
|
|
||||||
# Show prices for a specific product
|
|
||||||
print("\nMilk Prices Over Time:")
|
|
||||||
for price_info in get_product_prices("Milk"):
|
|
||||||
print(f" Date: {price_info[0]}, Store: {price_info[1]}, Qty: {price_info[2]}, Price: ${price_info[3]:.2f}")
|
|
||||||
|
|||||||
@@ -1,2 +1,6 @@
|
|||||||
# No external dependencies required for this SQLite-based implementation
|
# Core dependencies for the grocery receipt tracker
|
||||||
# Python standard library is sufficient for the core functionality
|
discord.py>=2.0.0
|
||||||
|
# For PDF processing (optional, for future OCR implementation)
|
||||||
|
# PyPDF2
|
||||||
|
# pytesseract
|
||||||
|
# pillow
|
||||||
|
|||||||
Reference in New Issue
Block a user