AdkraftAI / app /database.py
PavaniKadari's picture
Deploy MAdVerse AI to Hugging Face Spaces
24cd5a5
# SQLite product catalog and analytics storage.
import json
import os
import sqlite3
import uuid
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional
from app.models import DB_DIR
class Database:
def __init__(self):
db_path_override = os.getenv("MADVERSE_DB_PATH")
self.db_path = Path(db_path_override).resolve() if db_path_override else (DB_DIR / "adcraft.db")
self.db_path.parent.mkdir(parents=True, exist_ok=True)
print(f" [DATABASE] Initializing SQLite database: {self.db_path}")
self._init_db()
print(f" [DATABASE] Tables ready: products, generated_content, clicks")
def _init_db(self):
conn = sqlite3.connect(str(self.db_path))
conn.execute("""
CREATE TABLE IF NOT EXISTS products (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
description TEXT,
price TEXT,
category TEXT,
brand TEXT,
image_paths TEXT,
enhanced_image_path TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL
)
""")
conn.execute("""
CREATE TABLE IF NOT EXISTS generated_content (
id TEXT PRIMARY KEY,
product_id TEXT,
content_type TEXT,
language TEXT,
content_json TEXT,
pamphlet_path TEXT,
product_image_path TEXT,
created_at TEXT NOT NULL,
FOREIGN KEY (product_id) REFERENCES products(id)
)
""")
conn.execute("""
CREATE TABLE IF NOT EXISTS clicks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
product_id TEXT,
platform TEXT,
source TEXT,
clicked_at TEXT NOT NULL,
FOREIGN KEY (product_id) REFERENCES products(id)
)
""")
conn.commit()
conn.close()
def _conn(self):
conn = sqlite3.connect(str(self.db_path))
conn.row_factory = sqlite3.Row
return conn
def create_product(self, name: str, description: str = "",
price: str = "", category: str = "",
brand: str = "", image_paths: list = None) -> str:
product_id = str(uuid.uuid4())[:8]
now = datetime.now().isoformat()
print(f" [DB] Creating product: id={product_id} | name={name} | brand={brand} | category={category}")
conn = self._conn()
conn.execute(
"INSERT INTO products VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
(product_id, name, description, price, category, brand,
json.dumps(image_paths or []), None, now, now)
)
conn.commit()
conn.close()
print(f" [DB] Product created: {product_id} | Images: {len(image_paths or [])}")
return product_id
def get_product(self, product_id: str) -> Optional[dict]:
conn = self._conn()
row = conn.execute("SELECT * FROM products WHERE id = ?", (product_id,)).fetchone()
conn.close()
if row:
d = dict(row)
d["image_paths"] = json.loads(d["image_paths"])
return d
return None
def list_products(self) -> List[dict]:
conn = self._conn()
rows = conn.execute("SELECT * FROM products ORDER BY created_at DESC").fetchall()
conn.close()
products = []
for row in rows:
d = dict(row)
d["image_paths"] = json.loads(d["image_paths"])
products.append(d)
return products
def update_product(self, product_id: str, **kwargs) -> bool:
"""Update product fields. Only updates provided fields."""
conn = self._conn()
product = conn.execute("SELECT * FROM products WHERE id = ?", (product_id,)).fetchone()
if not product:
conn.close()
return False
updatable = ["name", "description", "price", "category", "brand",
"image_paths", "enhanced_image_path"]
sets = []
values = []
for key in updatable:
if key in kwargs:
val = kwargs[key]
if key == "image_paths" and isinstance(val, list):
val = json.dumps(val)
sets.append(f"{key} = ?")
values.append(val)
if not sets:
conn.close()
return False
sets.append("updated_at = ?")
values.append(datetime.now().isoformat())
values.append(product_id)
conn.execute(f"UPDATE products SET {', '.join(sets)} WHERE id = ?", values)
conn.commit()
conn.close()
print(f" [DB] Product updated: {product_id} | Fields: {list(kwargs.keys())}")
return True
def delete_product(self, product_id: str):
conn = self._conn()
conn.execute("DELETE FROM generated_content WHERE product_id = ?", (product_id,))
conn.execute("DELETE FROM clicks WHERE product_id = ?", (product_id,))
conn.execute("DELETE FROM products WHERE id = ?", (product_id,))
conn.commit()
conn.close()
def save_generated_content(self, product_id: str, content_type: str,
language: str, content: dict,
pamphlet_path: str = None,
product_image_path: str = None) -> str:
content_id = str(uuid.uuid4())[:8]
now = datetime.now().isoformat()
print(f" [DB] Saving content: id={content_id} | product={product_id} | type={content_type} | lang={language}")
conn = self._conn()
conn.execute(
"INSERT INTO generated_content VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
(content_id, product_id, content_type, language,
json.dumps(content, ensure_ascii=False), pamphlet_path,
product_image_path, now)
)
conn.commit()
conn.close()
print(f" [DB] Content saved: {content_id}")
return content_id
def get_product_content(self, product_id: str) -> List[dict]:
conn = self._conn()
rows = conn.execute(
"SELECT * FROM generated_content WHERE product_id = ? ORDER BY created_at DESC",
(product_id,)
).fetchall()
conn.close()
results = []
for row in rows:
d = dict(row)
d["content_json"] = json.loads(d["content_json"])
results.append(d)
return results
def track_click(self, product_id: str, platform: str, source: str = ""):
now = datetime.now().isoformat()
print(f" [DB] Tracking click: product={product_id} | platform={platform} | source={source}")
conn = self._conn()
conn.execute(
"INSERT INTO clicks (product_id, platform, source, clicked_at) VALUES (?, ?, ?, ?)",
(product_id, platform, source, now)
)
conn.commit()
conn.close()
def get_analytics(self, product_id: str) -> dict:
conn = self._conn()
rows = conn.execute(
"SELECT platform, COUNT(*) as count FROM clicks WHERE product_id = ? GROUP BY platform",
(product_id,)
).fetchall()
total = conn.execute(
"SELECT COUNT(*) FROM clicks WHERE product_id = ?", (product_id,)
).fetchone()[0]
conn.close()
platforms = {row["platform"]: row["count"] for row in rows}
return {"total_clicks": total, "by_platform": platforms}