Download database.py from arkapravac366/Eminem-Data-Entry: direct link, hf CLI and curl.
- Browser
- Download file 18.6 kB
-
https://huggingface.co/arkapravac366/Eminem-Data-Entry/resolve/main/database.py
- Command line
-
hf download hf://arkapravac366/Eminem-Data-Entry/database.py
-
curl -L -o database.py https://huggingface.co/arkapravac366/Eminem-Data-Entry/resolve/main/database.py
18.6 kB
| import os | |
| import sqlite3 | |
| import threading | |
| import pandas as pd | |
| import numpy as np | |
| from queue import Queue | |
| from typing import List, Dict, Any, Tuple | |
| from datetime import datetime, timedelta | |
| class DonationDatabase: | |
| _instance = None | |
| _lock = threading.Lock() | |
| _connection_pool = Queue(maxsize=5) | |
| def __new__(cls): | |
| if cls._instance is None: | |
| with cls._lock: | |
| if cls._instance is None: | |
| cls._instance = super(DonationDatabase, cls).__new__(cls) | |
| cls._instance._initialize_pool() | |
| return cls._instance | |
| def _initialize_pool(self): | |
| for _ in range(5): | |
| conn = sqlite3.connect('donations.db', check_same_thread=False) | |
| self._connection_pool.put(conn) | |
| def get_connection(self): | |
| return self._connection_pool.get() | |
| def release_connection(self, conn): | |
| self._connection_pool.put(conn) | |
| def _initialize_database(self): | |
| conn = self.get_connection() | |
| try: | |
| cursor = conn.cursor() | |
| cursor.execute(""" | |
| CREATE TABLE IF NOT EXISTS donations ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| donor_name TEXT NOT NULL, | |
| amount REAL NOT NULL, | |
| category TEXT NOT NULL, | |
| notes TEXT, | |
| date TIMESTAMP DEFAULT CURRENT_TIMESTAMP, | |
| is_recurring BOOLEAN DEFAULT 0, | |
| recurring_interval TEXT, | |
| next_donation_date TEXT | |
| ) | |
| """) | |
| cursor.execute(""" | |
| CREATE TABLE IF NOT EXISTS categories ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| name TEXT UNIQUE NOT NULL | |
| ) | |
| """) | |
| default_categories = ['General', 'Project', 'Emergency', 'Other'] | |
| for category in default_categories: | |
| cursor.execute( | |
| "INSERT OR IGNORE INTO categories (name) VALUES (?)", | |
| (category,) | |
| ) | |
| conn.commit() | |
| finally: | |
| self.release_connection(conn) | |
| def add_donation(self, donor_name: str, amount: float, category: str, notes: str = None) -> bool: | |
| """Add a new donation to the database.""" | |
| try: | |
| with sqlite3.connect(self.db_path) as conn: | |
| cursor = conn.cursor() | |
| cursor.execute( | |
| "INSERT INTO donations (donor_name, amount, category, notes) VALUES (?, ?, ?, ?)", | |
| (donor_name, amount, category, notes) | |
| ) | |
| return True | |
| except Exception as e: | |
| print(f"Error adding donation: {str(e)}") | |
| return False | |
| def get_total_donations(self, category: str = None) -> float: | |
| """Get total donations, optionally filtered by category.""" | |
| try: | |
| with sqlite3.connect(self.db_path) as conn: | |
| cursor = conn.cursor() | |
| if category: | |
| cursor.execute( | |
| "SELECT SUM(amount) FROM donations WHERE category = ?", | |
| (category,) | |
| ) | |
| else: | |
| cursor.execute("SELECT SUM(amount) FROM donations") | |
| result = cursor.fetchone()[0] | |
| return float(result) if result else 0.0 | |
| except Exception as e: | |
| print(f"Error getting total donations: {str(e)}") | |
| return 0.0 | |
| def get_recent_donations(self, limit: int = 5) -> List[Dict[str, Any]]: | |
| """Get recent donations with specified limit.""" | |
| try: | |
| with sqlite3.connect(self.db_path) as conn: | |
| conn.row_factory = sqlite3.Row | |
| cursor = conn.cursor() | |
| cursor.execute( | |
| "SELECT * FROM donations ORDER BY date DESC LIMIT ?", | |
| (limit,) | |
| ) | |
| return [dict(row) for row in cursor.fetchall()] | |
| except Exception as e: | |
| print(f"Error getting recent donations: {str(e)}") | |
| return [] | |
| def get_category_breakdown(self) -> Dict[str, float]: | |
| """Get donation totals broken down by category.""" | |
| try: | |
| with sqlite3.connect(self.db_path) as conn: | |
| cursor = conn.cursor() | |
| cursor.execute( | |
| "SELECT category, SUM(amount) FROM donations GROUP BY category" | |
| ) | |
| return {category: float(amount) for category, amount in cursor.fetchall()} | |
| except Exception as e: | |
| print(f"Error getting category breakdown: {str(e)}") | |
| return {} | |
| def process_nlp_query(self, query: str) -> Dict[str, Any]: | |
| """Process natural language queries about donations.""" | |
| query = query.lower() | |
| # Pattern matching for different types of queries | |
| if re.search(r'total|sum|all', query): | |
| if 'category' in query: | |
| # Extract category from query | |
| categories = ['general', 'project', 'emergency', 'other'] | |
| for category in categories: | |
| if category in query: | |
| return { | |
| 'type': 'total_category', | |
| 'amount': self.get_total_donations(category.capitalize()), | |
| 'category': category.capitalize() | |
| } | |
| return { | |
| 'type': 'total', | |
| 'amount': self.get_total_donations() | |
| } | |
| elif re.search(r'recent|latest|last', query): | |
| limit = 5 # Default limit | |
| # Try to extract number from query | |
| number_match = re.search(r'\d+', query) | |
| if number_match: | |
| limit = min(int(number_match.group()), 20) # Cap at 20 for reasonable output | |
| return { | |
| 'type': 'recent', | |
| 'donations': self.get_recent_donations(limit) | |
| } | |
| elif re.search(r'category|breakdown|distribution', query): | |
| return { | |
| 'type': 'breakdown', | |
| 'distribution': self.get_category_breakdown() | |
| } | |
| return { | |
| 'type': 'unknown', | |
| 'message': 'I could not understand your query. Please try asking about total donations, recent donations, or category breakdown.' | |
| } | |
| def get_donor_names(self) -> List[str]: | |
| """Get a list of all unique donor names from the database.""" | |
| try: | |
| with sqlite3.connect(self.db_path) as conn: | |
| cursor = conn.cursor() | |
| cursor.execute("SELECT DISTINCT donor_name FROM donations ORDER BY donor_name") | |
| return [row[0] for row in cursor.fetchall()] | |
| except Exception as e: | |
| print(f"Error getting donor names: {str(e)}") | |
| return [] | |
| def get_donor_statistics(self) -> Dict[str, Any]: | |
| """Get comprehensive donor statistics.""" | |
| try: | |
| with sqlite3.connect(self.db_path) as conn: | |
| cursor = conn.cursor() | |
| # Get total number of unique donors | |
| cursor.execute("SELECT COUNT(DISTINCT donor_name) FROM donations") | |
| total_donors = cursor.fetchone()[0] | |
| # Get average donation amount | |
| cursor.execute("SELECT AVG(amount) FROM donations") | |
| avg_donation = cursor.fetchone()[0] or 0.0 | |
| # Get donor frequency | |
| cursor.execute(""" | |
| SELECT donor_name, COUNT(*) as donation_count, SUM(amount) as total_amount | |
| FROM donations | |
| GROUP BY donor_name | |
| ORDER BY total_amount DESC | |
| LIMIT 5 | |
| """) | |
| top_donors = [{ | |
| 'name': row[0], | |
| 'donation_count': row[1], | |
| 'total_amount': row[2] | |
| } for row in cursor.fetchall()] | |
| return { | |
| 'total_donors': total_donors, | |
| 'average_donation': round(avg_donation, 2), | |
| 'top_donors': top_donors | |
| } | |
| except Exception as e: | |
| print(f"Error getting donor statistics: {str(e)}") | |
| return { | |
| 'total_donors': 0, | |
| 'average_donation': 0.0, | |
| 'top_donors': [] | |
| } | |
| def process_nlp_donation(self, text: str) -> Dict[str, Any]: | |
| """Process natural language donation entries.""" | |
| # Extract amount using regex | |
| amount_match = re.search(r'\$?(\d+(?:\.\d{2})?)', text) | |
| if not amount_match: | |
| return {'success': False, 'message': 'Could not find donation amount in the text.'} | |
| amount = float(amount_match.group(1)) | |
| # Extract category | |
| categories = ['general', 'project', 'emergency', 'other'] | |
| category = 'General' # Default category | |
| for cat in categories: | |
| if cat in text.lower(): | |
| category = cat.capitalize() | |
| break | |
| # Extract name (assume it's mentioned after 'from' or 'by') | |
| name_match = re.search(r'(?:from|by)\s+([\w\s]+?)(?:\s+(?:for|to|amount|\$|\d)|$)', text, re.IGNORECASE) | |
| donor_name = name_match.group(1).strip() if name_match else 'Anonymous' | |
| # Extract notes (anything after 'for' or 'notes') | |
| notes_match = re.search(r'(?:for|notes:?)\s+([^$\n]+)', text, re.IGNORECASE) | |
| notes = notes_match.group(1).strip() if notes_match else None | |
| # Add the donation | |
| success = self.add_donation(donor_name, amount, category, notes) | |
| return { | |
| 'success': success, | |
| 'message': f'Successfully recorded donation of ${amount:.2f} from {donor_name} in {category} category.' if success | |
| else 'Failed to record donation. Please try again.', | |
| 'details': { | |
| 'donor_name': donor_name, | |
| 'amount': amount, | |
| 'category': category, | |
| 'notes': notes | |
| } if success else None | |
| } | |
| def __init__(self): | |
| self.db_path = 'donations.db' | |
| if not os.path.exists(self.db_path): | |
| self._initialize_database() | |
| def get_categories(self) -> List[str]: | |
| """Get all available donation categories.""" | |
| try: | |
| with sqlite3.connect(self.db_path) as conn: | |
| cursor = conn.cursor() | |
| cursor.execute("SELECT name FROM categories ORDER BY name") | |
| return [row[0] for row in cursor.fetchall()] | |
| except Exception as e: | |
| print(f"Error getting categories: {str(e)}") | |
| return ['General', 'Project', 'Emergency', 'Other'] | |
| def generate_monthly_report(self, year: int, month: int) -> Dict[str, Any]: | |
| """Generate a comprehensive monthly donation report.""" | |
| try: | |
| with sqlite3.connect(self.db_path) as conn: | |
| cursor = conn.cursor() | |
| start_date = f"{year}-{month:02d}-01" | |
| if month == 12: | |
| end_date = f"{year + 1}-01-01" | |
| else: | |
| end_date = f"{year}-{month + 1:02d}-01" | |
| # Get total donations for the month | |
| cursor.execute(""" | |
| SELECT COUNT(*), SUM(amount), AVG(amount) | |
| FROM donations | |
| WHERE date >= ? AND date < ? | |
| """, (start_date, end_date)) | |
| count, total, avg = cursor.fetchone() | |
| # Get category breakdown | |
| cursor.execute(""" | |
| SELECT category, COUNT(*), SUM(amount) | |
| FROM donations | |
| WHERE date >= ? AND date < ? | |
| GROUP BY category | |
| """, (start_date, end_date)) | |
| categories = [{ | |
| 'category': row[0], | |
| 'count': row[1], | |
| 'total': row[2] | |
| } for row in cursor.fetchall()] | |
| # Get top donors | |
| cursor.execute(""" | |
| SELECT donor_name, COUNT(*), SUM(amount) | |
| FROM donations | |
| WHERE date >= ? AND date < ? | |
| GROUP BY donor_name | |
| ORDER BY SUM(amount) DESC | |
| LIMIT 5 | |
| """, (start_date, end_date)) | |
| top_donors = [{ | |
| 'name': row[0], | |
| 'count': row[1], | |
| 'total': row[2] | |
| } for row in cursor.fetchall()] | |
| return { | |
| 'year': year, | |
| 'month': month, | |
| 'total_donations': count or 0, | |
| 'total_amount': total or 0, | |
| 'average_amount': avg or 0, | |
| 'categories': categories, | |
| 'top_donors': top_donors | |
| } | |
| except Exception as e: | |
| print(f"Error generating monthly report: {str(e)}") | |
| return {} | |
| def export_to_excel(self, start_date: str = None, end_date: str = None, filepath: str = None) -> str: | |
| """Export donation data to Excel file with multiple sheets for different views.""" | |
| try: | |
| with sqlite3.connect(self.db_path) as conn: | |
| # Create a writer object | |
| if not filepath: | |
| filepath = f'donation_report_{datetime.now().strftime("%Y%m%d_%H%M%S")}.xlsx' | |
| writer = pd.ExcelWriter(filepath, engine='xlsxwriter') | |
| # Donations sheet | |
| query = "SELECT * FROM donations" | |
| params = [] | |
| if start_date and end_date: | |
| query += " WHERE date >= ? AND date <= ?" | |
| params.extend([start_date, end_date]) | |
| donations_df = pd.read_sql_query(query, conn, params=params) | |
| donations_df.to_excel(writer, sheet_name='Donations', index=False) | |
| # Category summary | |
| category_summary = pd.read_sql_query(""" | |
| SELECT category, | |
| COUNT(*) as donation_count, | |
| SUM(amount) as total_amount, | |
| AVG(amount) as average_amount | |
| FROM donations | |
| GROUP BY category | |
| """, conn) | |
| category_summary.to_excel(writer, sheet_name='Category Summary', index=False) | |
| # Donor summary | |
| donor_summary = pd.read_sql_query(""" | |
| SELECT donor_name, | |
| COUNT(*) as donation_count, | |
| SUM(amount) as total_amount, | |
| AVG(amount) as average_amount, | |
| MIN(date) as first_donation, | |
| MAX(date) as last_donation | |
| FROM donations | |
| GROUP BY donor_name | |
| ORDER BY total_amount DESC | |
| """, conn) | |
| donor_summary.to_excel(writer, sheet_name='Donor Summary', index=False) | |
| writer.close() | |
| return filepath | |
| except Exception as e: | |
| print(f"Error exporting to Excel: {str(e)}") | |
| return None | |
| def analyze_trends(self, months: int = 12) -> Dict[str, Any]: | |
| """Analyze donation trends over the specified number of months.""" | |
| try: | |
| end_date = datetime.now() | |
| start_date = end_date - timedelta(days=months * 30) | |
| with sqlite3.connect(self.db_path) as conn: | |
| # Monthly trends | |
| monthly_trends = pd.read_sql_query(""" | |
| SELECT strftime('%Y-%m', date) as month, | |
| COUNT(*) as donation_count, | |
| SUM(amount) as total_amount, | |
| AVG(amount) as average_amount | |
| FROM donations | |
| WHERE date >= ? | |
| GROUP BY month | |
| ORDER BY month | |
| """, conn, params=[start_date.strftime('%Y-%m-%d')]) | |
| # Category growth | |
| category_growth = pd.read_sql_query(""" | |
| SELECT category, | |
| COUNT(*) as total_donations, | |
| SUM(amount) as total_amount, | |
| COUNT(DISTINCT donor_name) as unique_donors | |
| FROM donations | |
| WHERE date >= ? | |
| GROUP BY category | |
| """, conn, params=[start_date.strftime('%Y-%m-%d')]) | |
| # Donor retention | |
| donor_retention = pd.read_sql_query(""" | |
| SELECT donor_name, | |
| COUNT(DISTINCT strftime('%Y-%m', date)) as active_months, | |
| COUNT(*) as total_donations, | |
| SUM(amount) as total_amount | |
| FROM donations | |
| WHERE date >= ? | |
| GROUP BY donor_name | |
| HAVING COUNT(*) > 1 | |
| ORDER BY total_amount DESC | |
| """, conn, params=[start_date.strftime('%Y-%m-%d')]) | |
| return { | |
| 'monthly_trends': monthly_trends.to_dict('records'), | |
| 'category_growth': category_growth.to_dict('records'), | |
| 'donor_retention': donor_retention.to_dict('records'), | |
| 'summary': { | |
| 'total_growth': float(monthly_trends['total_amount'].pct_change().mean() * 100), | |
| 'avg_monthly_donations': float(monthly_trends['donation_count'].mean()), | |
| 'top_category': category_growth.iloc[category_growth['total_amount'].idxmax()]['category'], | |
| 'retention_rate': float(len(donor_retention) / len(self.get_donor_names()) * 100) | |
| } | |
| } | |
| except Exception as e: | |
| print(f"Error analyzing trends: {str(e)}") | |
| return {} |