- Removed the `analyze_data_file` function from tool definitions to streamline functionality. - Enhanced the `execute_python_code` function description to clarify auto-installation of packages and file handling. - Deleted the `python_executor.py` module to simplify the codebase and improve maintainability. - Introduced a new `token_counter.py` module for efficient token counting for OpenAI API requests, including support for Discord image links and cost estimation.
5.0 KiB
Bug Fix: Missing Database Methods
Issue
The bot was crashing with the error:
'DatabaseHandler' object has no attribute 'get_user_files'
Root Cause
The message_handler.py was calling db.get_user_files() but this method didn't exist in the DatabaseHandler class. The database had a user_files collection with indexes defined, but no methods to interact with it.
Solution
Added four new methods to DatabaseHandler class in src/database/db_handler.py:
1. get_user_files(user_id: int) -> List[Dict[str, Any]]
Purpose: Retrieve all non-expired files for a specific user
Features:
- Filters out expired files (expires_at < current_time)
- Handles files with no expiration (expires_at = None)
- Returns empty list on error
Usage:
user_files = await db.get_user_files(user_id)
file_ids = [f['file_id'] for f in user_files]
2. save_user_file(file_data: Dict[str, Any]) -> None
Purpose: Save or update a user file record in the database
Features:
- Uses upsert (update or insert)
- Updates by file_id
- Stores complete file metadata
Expected file_data format:
{
"file_id": "unique_file_id",
"user_id": 123456789,
"filename": "data.csv",
"file_type": "csv",
"file_path": "/tmp/bot_code_interpreter/user_files/123456789/data.csv",
"size": 1024,
"created_at": datetime.now(),
"expires_at": datetime.now() + timedelta(hours=48) # or None
}
3. delete_user_file(file_id: str) -> bool
Purpose: Delete a specific file record from the database
Returns: True if file was deleted, False otherwise
Usage:
success = await db.delete_user_file(file_id)
4. delete_expired_files() -> int
Purpose: Cleanup task to remove all expired file records
Returns: Number of deleted records
Usage (for scheduled cleanup):
deleted_count = await db.delete_expired_files()
logging.info(f"Cleaned up {deleted_count} expired files")
Files Modified
src/database/db_handler.py
- Lines Added: ~60 lines (4 new methods)
- Location: After
reset_user_token_stats()method - Dependencies: Uses existing
datetime,timedelta,loggingimports
src/module/message_handler.py
- Lines 299-302: Added variable assignments for display purposes
packages_to_install = install_packages # For display input_data = args.get("input_data", "") # For display
Testing
Verification Commands
# Compile check
python3 -m py_compile src/database/db_handler.py
python3 -m py_compile src/module/message_handler.py
# Run bot
python3 bot.py
Test Cases
-
✅ Upload a file to Discord
- File should be saved with file_id
- Record stored in user_files collection
-
✅ Execute Python code with file access
get_user_files()retrieves all user files- Code can use
load_file(file_id)
-
✅ File expiration
- Files older than FILE_EXPIRATION_HOURS are filtered out
delete_expired_files()can clean up old records
-
✅ User file limit
- When MAX_FILES_PER_USER is reached
- Oldest file is deleted before new upload
Database Schema
user_files Collection
{
"_id": ObjectId("..."),
"file_id": "file_123456789_1234567890", // Unique identifier
"user_id": 123456789, // Discord user ID
"filename": "data.csv", // Original filename
"file_type": "csv", // Detected file type
"file_path": "/tmp/.../file.csv", // Full file path
"size": 1024, // File size in bytes
"created_at": ISODate("..."), // Upload timestamp
"expires_at": ISODate("...") // Expiration time (or null)
}
Indexes
// Compound index for user queries with expiration
{ "user_id": 1, "expires_at": -1 }
// Unique index for file_id lookups
{ "file_id": 1 } // unique: true
// Index for cleanup queries
{ "expires_at": 1 }
Configuration
Environment Variables (.env)
FILE_EXPIRATION_HOURS=48 # Files expire after 48 hours (-1 = never)
MAX_FILES_PER_USER=20 # Maximum files per user
How It Works
- Upload: User uploads file →
save_user_file()creates record - Access: Code execution →
get_user_files()retrieves file_ids - Load: Python code calls
load_file(file_id)→ file loaded into memory - Expire: After 48 hours → file filtered out by
get_user_files() - Cleanup: Periodic task →
delete_expired_files()removes old records
Impact
- ✅ Fixed:
'DatabaseHandler' object has no attribute 'get_user_files'error - ✅ Added: Complete file management system
- ✅ Enabled: Per-user file limits with automatic cleanup
- ✅ Enabled: File expiration system
- ✅ Enabled: Code interpreter file access