Download chatbot.py from arkapravac366/Eminem-Data-Entry: direct link, hf CLI and curl.
- Browser
- Download file 15.9 kB
-
https://huggingface.co/arkapravac366/Eminem-Data-Entry/resolve/main/chatbot.py
- Command line
-
hf download hf://arkapravac366/Eminem-Data-Entry/chatbot.py
-
curl -L -o chatbot.py https://huggingface.co/arkapravac366/Eminem-Data-Entry/resolve/main/chatbot.py
15.9 kB
| import google.generativeai as genai | |
| import sqlite3 | |
| import json | |
| import os | |
| from database import DonationDatabase | |
| from typing import Dict, Any | |
| from datetime import datetime | |
| class ChatBot: | |
| def __init__(self): | |
| # Initialize database connection lazily | |
| self._db = None | |
| self._model = None | |
| # Set API key directly | |
| self._api_key = "AIzaSyA9fEe8HncZmvJ3BaurihNMaS9ydSGqblk" | |
| if not self._api_key: | |
| raise ValueError("API key is not set") | |
| # Initialize conversation context | |
| self.conversation_context = [] | |
| self.context_window = 5 | |
| def db(self): | |
| if self._db is None: | |
| try: | |
| self._db = DonationDatabase() | |
| except Exception as e: | |
| print(f"Error initializing database: {str(e)}") | |
| raise | |
| return self._db | |
| def model(self): | |
| if self._model is None: | |
| try: | |
| genai.configure(api_key=self._api_key) | |
| self._model = genai.GenerativeModel("gemini-2.0-flash") | |
| except Exception as e: | |
| print(f"Error initializing Gemini model: {str(e)}") | |
| raise | |
| return self._model | |
| def _get_database_context(self) -> str: | |
| """Get current database context for the model""" | |
| try: | |
| if not self.db: | |
| return "Database connection not available" | |
| total_donations = self.db.get_total_donations() | |
| recent_donations = self.db.get_recent_donations(5) | |
| categories = self.db.get_categories() | |
| if total_donations is None or recent_donations is None or categories is None: | |
| return "Error retrieving database information" | |
| context = f"Current total donations: ${total_donations:.2f}\n" | |
| context += "Available categories: " + ", ".join(categories) + "\n" | |
| context += "Recent donations:\n" | |
| for donation in recent_donations: | |
| context += f"- {donation['donor_name']}: ${donation['amount']} ({donation['category']})\n" | |
| return context | |
| except Exception as e: | |
| print(f"Error in _get_database_context: {str(e)}") | |
| return "Error getting database context" | |
| def _format_prompt(self, user_input: str) -> str: | |
| """Format the prompt with context and user input""" | |
| system_prompt = ( | |
| "I am Eminem 1.0.0, a helpful and intelligent donation management assistant created by Arkaprava Chakraborty. " | |
| "I understand natural language queries and provide detailed, contextual responses. " | |
| "I can help you manage donations, analyze trends, generate insights, and provide personalized recommendations. " | |
| "I maintain context across conversations and can handle complex queries about donations, donors, and financial statistics. " | |
| "You have access to the following database context and capabilities:\n" | |
| "- Generate monthly donation reports\n" | |
| "- Export donation data to Excel\n" | |
| "- Analyze donation trends and patterns\n" | |
| "- Access comprehensive donor statistics\n" | |
| ) | |
| db_context = self._get_database_context() | |
| # Add more context about the conversation flow | |
| conversation_summary = "" | |
| if self.conversation_context: | |
| recent_topics = set() | |
| for msg in self.conversation_context[-self.context_window:]: | |
| if msg['role'] == 'user': | |
| # Extract key topics from user messages | |
| topics = [word.lower() for word in msg['content'].split() | |
| if len(word) > 3 and word.lower() not in {'what', 'when', 'how', 'why', 'where', 'who'}] | |
| recent_topics.update(topics) | |
| if recent_topics: | |
| conversation_summary = f"\nRecent conversation topics: {', '.join(recent_topics)}\n" | |
| conversation_context = "\n".join([f"{msg['role']}: {msg['content']}" | |
| for msg in self.conversation_context[-self.context_window:]]) | |
| # Enhanced prompt with better context integration | |
| return f"{system_prompt}\n{db_context}\n{conversation_summary}\nConversation history:\n{conversation_context}\n\nUser: {user_input}\n\nPlease provide a detailed and contextually relevant response." | |
| def _execute_db_command(self, command: Dict[str, Any]) -> str: | |
| """Execute database commands""" | |
| if not isinstance(command, dict): | |
| return "Invalid command format" | |
| try: | |
| action = command.get("action") | |
| if not action: | |
| return "No action specified in command" | |
| if not self.db: | |
| return "Database connection not available" | |
| if action == "generate_report": | |
| year = command.get("year", datetime.now().year) | |
| month = command.get("month", datetime.now().month) | |
| report = self.db.generate_monthly_report(year, month) | |
| if report: | |
| return f"Monthly report for {year}-{month:02d}:\n" + \ | |
| f"Total donations: {report['total_donations']}\n" + \ | |
| f"Total amount: ${report['total_amount']:.2f}\n" + \ | |
| f"Average amount: ${report['average_amount']:.2f}" | |
| return "Failed to generate report" | |
| elif action == "export_excel": | |
| start_date = command.get("start_date") | |
| end_date = command.get("end_date") | |
| filepath = self.db.export_to_excel(start_date, end_date) | |
| if filepath: | |
| return f"Data exported successfully to {filepath}" | |
| return "Failed to export data" | |
| elif action == "analyze_trends": | |
| months = command.get("months", 12) | |
| trends = self.db.analyze_trends(months) | |
| if trends: | |
| summary = trends['summary'] | |
| return f"Trend analysis for the past {months} months:\n" + \ | |
| f"Growth rate: {summary['total_growth']:.1f}%\n" + \ | |
| f"Average monthly donations: {summary['avg_monthly_donations']:.1f}\n" + \ | |
| f"Top category: {summary['top_category']}\n" + \ | |
| f"Donor retention rate: {summary['retention_rate']:.1f}%" | |
| return "Failed to analyze trends" | |
| elif action == "add_donation": | |
| success = self.db.add_donation( | |
| donor_name=command["donor_name"], | |
| amount=command["amount"], | |
| category=command["category"], | |
| notes=command.get("notes"), | |
| is_recurring=command.get("is_recurring", False), | |
| recurring_interval=command.get("recurring_interval"), | |
| next_donation_date=command.get("next_donation_date") | |
| ) | |
| return "Donation added successfully" if success else "Failed to add donation" | |
| elif action == "update_donation": | |
| with sqlite3.connect('donations.db') as conn: | |
| cursor = conn.cursor() | |
| update_fields = [] | |
| params = [] | |
| if "amount" in command: | |
| update_fields.append("amount = ?") | |
| params.append(command["amount"]) | |
| if "category" in command: | |
| update_fields.append("category = ?") | |
| params.append(command["category"]) | |
| if "notes" in command: | |
| update_fields.append("notes = ?") | |
| params.append(command["notes"]) | |
| if update_fields: | |
| params.append(command["donation_id"]) | |
| cursor.execute(f"UPDATE donations SET {', '.join(update_fields)} WHERE id = ?", params) | |
| conn.commit() | |
| return "Donation updated successfully" if cursor.rowcount > 0 else "Donation not found" | |
| return "No fields to update" | |
| elif action == "get_donations": | |
| donations = self.db.get_recent_donations(command.get("limit", 5)) | |
| total_count = len(donations) | |
| if total_count == 0: | |
| return "There are currently no donations in the system." | |
| response = f"There are {total_count} recent donations. " | |
| if total_count > 0: | |
| response += "Here are the details:\n" | |
| for donation in donations: | |
| response += f"- {donation['donor_name']} donated ${donation['amount']:.2f} for {donation['category']}\n" | |
| return response | |
| elif action == "get_donor_statistics": | |
| stats = self.db.get_donor_statistics() | |
| response = f"Total number of donors: {stats['total_donors']}\n" | |
| response += f"Average donation amount: ${stats['average_donation']:.2f}\n" | |
| if stats['top_donors']: | |
| response += "\nTop donors:\n" | |
| for donor in stats['top_donors']: | |
| response += f"- {donor['name']}: ${donor['total_amount']:.2f} ({donor['donation_count']} donations)\n" | |
| return response | |
| elif action == "get_donor_info": | |
| donor_name = command.get("donor_name") | |
| with sqlite3.connect('donations.db') as conn: | |
| cursor = conn.cursor() | |
| cursor.execute(""" | |
| SELECT dp.*, SUM(d.amount) as total_donated | |
| FROM donor_profiles dp | |
| LEFT JOIN donations d ON dp.name = d.donor_name | |
| WHERE dp.name = ? | |
| GROUP BY dp.id | |
| """, (donor_name,)) | |
| donor = cursor.fetchone() | |
| if donor: | |
| return f"Donor found: {donor[1]}, Total donations: ${donor[6]:.2f}" | |
| return "Donor not found" | |
| elif action == "add_donor": | |
| with sqlite3.connect('donations.db') as conn: | |
| cursor = conn.cursor() | |
| cursor.execute(""" | |
| INSERT INTO donor_profiles (name, email, phone, address) | |
| VALUES (?, ?, ?, ?) | |
| """, (command["donor_name"], command.get("email"), command.get("phone"), command.get("address"))) | |
| conn.commit() | |
| return "Donor added successfully" | |
| elif action == "update_donor": | |
| with sqlite3.connect('donations.db') as conn: | |
| cursor = conn.cursor() | |
| update_fields = [] | |
| params = [] | |
| for field in ["email", "phone", "address", "preferred_category", "notification_preferences"]: | |
| if field in command: | |
| update_fields.append(f"{field} = ?") | |
| params.append(command[field]) | |
| if update_fields: | |
| params.append(command["donor_name"]) | |
| cursor.execute(f"UPDATE donor_profiles SET {', '.join(update_fields)} WHERE name = ?", params) | |
| conn.commit() | |
| return "Donor updated successfully" if cursor.rowcount > 0 else "Donor not found" | |
| return "No fields to update" | |
| elif action == "remove_donor": | |
| with sqlite3.connect('donations.db') as conn: | |
| cursor = conn.cursor() | |
| cursor.execute("DELETE FROM donor_profiles WHERE name = ?", (command["donor_name"],)) | |
| if cursor.rowcount > 0: | |
| conn.commit() | |
| return "Donor removed successfully" | |
| return "Donor not found" | |
| return "Unknown database command" | |
| except Exception as e: | |
| return f"Error executing database command: {str(e)}" | |
| def _extract_db_command(self, response: str) -> Dict[str, Any]: | |
| """Extract database commands from the response""" | |
| try: | |
| if "[DB_COMMAND]" in response: | |
| command_start = response.index("[DB_COMMAND]") | |
| command_end = response.index("[/DB_COMMAND]") | |
| command_json = response[command_start + 12:command_end].strip() | |
| return json.loads(command_json) | |
| return None | |
| except Exception: | |
| return None | |
| def get_response(self, message: str) -> str: | |
| if not message or not message.strip(): | |
| return "Please provide a valid message" | |
| try: | |
| # Format prompt with context | |
| prompt = self._format_prompt(message) | |
| # Get response from Gemini with timeout and retry | |
| max_retries = 3 | |
| retry_count = 0 | |
| response = None | |
| last_error = None | |
| while retry_count < max_retries: | |
| try: | |
| response = self.model.generate_content(prompt) | |
| break | |
| except Exception as e: | |
| last_error = e | |
| retry_count += 1 | |
| print(f"Retry {retry_count} after error: {str(e)}") | |
| if retry_count < max_retries: | |
| import time | |
| time.sleep(1) # Add delay between retries | |
| if not response and last_error: | |
| raise last_error | |
| # Extract response text and handle potential None | |
| if not response or not hasattr(response, 'text'): | |
| return "I apologize, but I couldn't generate a response. Please try again." | |
| response_text = response.text.strip() | |
| if not response_text: | |
| return "I apologize, but I received an empty response. Please try again." | |
| # Extract and execute any database commands | |
| try: | |
| db_command = self._extract_db_command(response_text) | |
| if db_command: | |
| db_result = self._execute_db_command(db_command) | |
| response_text = response_text.replace( | |
| f"[DB_COMMAND]{json.dumps(db_command)}[/DB_COMMAND]", | |
| f"\n{db_result}\n" | |
| ) | |
| except Exception as e: | |
| print(f"Error processing database command: {str(e)}") | |
| # Continue with the response even if DB command fails | |
| # Update conversation context | |
| self.conversation_context.append({"role": "user", "content": message}) | |
| self.conversation_context.append({"role": "assistant", "content": response_text}) | |
| # Trim context if needed | |
| if len(self.conversation_context) > self.context_window * 2: | |
| self.conversation_context = self.conversation_context[-self.context_window * 2:] | |
| return response_text.strip() | |
| except Exception as e: | |
| print(f"Error in get_response: {str(e)}") | |
| # Reset conversation context on critical errors | |
| self.conversation_context = [] | |
| return "I apologize, but I'm having trouble processing that. Please try asking about donations, reports, or categories." |