Files
ChatGPT-Discord-Bot/docs/BUGFIX_DATABASE_METHODS.md
cauvang32 9c180bdd89 Refactor OpenAI utilities and remove Python executor
- 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.
2025-10-02 21:49:48 +07:00

170 lines
5.0 KiB
Markdown

# 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**:
```python
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**:
```python
{
"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**:
```python
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):
```python
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`, `logging` imports
### src/module/message_handler.py
- **Lines 299-302**: Added variable assignments for display purposes
```python
packages_to_install = install_packages # For display
input_data = args.get("input_data", "") # For display
```
## Testing
### Verification Commands
```bash
# 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
1. ✅ Upload a file to Discord
- File should be saved with file_id
- Record stored in user_files collection
2. ✅ Execute Python code with file access
- `get_user_files()` retrieves all user files
- Code can use `load_file(file_id)`
3. ✅ File expiration
- Files older than FILE_EXPIRATION_HOURS are filtered out
- `delete_expired_files()` can clean up old records
4. ✅ User file limit
- When MAX_FILES_PER_USER is reached
- Oldest file is deleted before new upload
## Database Schema
### user_files Collection
```javascript
{
"_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
```javascript
// 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)
```bash
FILE_EXPIRATION_HOURS=48 # Files expire after 48 hours (-1 = never)
MAX_FILES_PER_USER=20 # Maximum files per user
```
### How It Works
1. **Upload**: User uploads file → `save_user_file()` creates record
2. **Access**: Code execution → `get_user_files()` retrieves file_ids
3. **Load**: Python code calls `load_file(file_id)` → file loaded into memory
4. **Expire**: After 48 hours → file filtered out by `get_user_files()`
5. **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
## Related Documentation
- [FILE_STORAGE_AND_CONTEXT_MANAGEMENT.md](FILE_STORAGE_AND_CONTEXT_MANAGEMENT.md)
- [UNIFIED_FILE_SYSTEM_SUMMARY.md](UNIFIED_FILE_SYSTEM_SUMMARY.md)
- [CODE_INTERPRETER_GUIDE.md](CODE_INTERPRETER_GUIDE.md)