# Profile Picture Implementation

## Overview
Miku can now intelligently search for Hatsune Miku artwork on Danbooru and change her profile picture autonomously or manually. The system includes:

- **Danbooru Integration**: Searches for SFW Miku artwork (general/sensitive ratings only)
- **Vision Model Verification**: Confirms the image contains Miku and locates her if multiple characters present
- **Anime Face Detection**: Uses OpenCV with anime-specific cascade for intelligent cropping
- **Intelligent Cropping**: Centers on detected face or uses saliency detection fallback
- **Mood-Based Selection**: Searches for artwork matching Miku's current mood
- **Autonomous Action**: Once-per-day autonomous decision to change profile picture
- **Manual Controls**: Web UI and API endpoints for manual changes with optional custom uploads

## Architecture

### Core Components

#### 1. **Danbooru Client** (`utils/danbooru_client.py`)
- Interfaces with Danbooru's public API
- Searches for Hatsune Miku artwork with mood-based tag filtering
- Filters by rating (general/sensitive only, excludes questionable/explicit)
- Extracts image URLs and metadata

**Key Features:**
- Mood-to-tag mapping (e.g., "bubbly" → "smile", "happy")
- Random page selection for variety
- Proper rate limiting (2 req/sec, we use much less)

#### 2. **Profile Picture Manager** (`utils/profile_picture_manager.py`)
Main orchestrator for all profile picture operations.

**Workflow:**
1. **Source Image**:
   - Custom upload (if provided) OR
   - Danbooru search (filtered by mood and rating)

2. **Verification** (Danbooru images only):
   - Uses MiniCPM-V vision model to confirm Miku is present
   - Detects multiple characters and locates Miku's position
   - Extracts suggested crop region if needed

3. **Face Detection**:
   - Uses anime-specific face cascade (`lbpcascade_animeface`)
   - Falls back to saliency detection if no face found
   - Ultimate fallback: center crop

4. **Intelligent Cropping**:
   - Crops to square aspect ratio
   - Centers on detected face or salient region
   - Resizes to 512x512 for Discord

5. **Apply**:
   - Updates Discord bot avatar
   - Saves metadata (source, timestamp, Danbooru post info)
   - Keeps current image as backup

**Safety Features:**
- Current animated avatar saved as fallback
- Metadata logging for all changes
- Graceful error handling with rollback
- Rate limit awareness (Discord allows 2 changes per 10 min globally)

#### 3. **Autonomous Engine Integration** (`utils/autonomous_engine.py`)
New action type: `change_profile_picture`

**Decision Logic:**
- **Frequency**: Once per day maximum (20+ hour cooldown)
- **Time Window**: 10 AM - 10 PM only
- **Activity Requirement**: Low server activity (< 5 messages last hour)
- **Cooldown**: 1.5+ hours since last autonomous action
- **Mood Influence**: 2x more likely when bubbly/curious/excited/silly
- **Base Probability**: 1-2% per check (very rare)

**Why Once Per Day?**
- Respects Discord's rate limits
- Maintains consistency for users
- Preserves special nature of the feature
- Reduces API load on Danbooru

#### 4. **API Endpoints** (`api.py`)

##### **POST /profile-picture/change**
Change profile picture manually.

**Parameters:**
- `guild_id` (optional): Server ID to get mood from
- `file` (optional): Custom image upload (multipart/form-data)

**Behavior:**
- If `file` provided: Uses uploaded image
- If no `file`: Searches Danbooru with current mood
- Returns success status and metadata

**Example:**
```bash
# Auto (Danbooru search)
curl -X POST "http://localhost:8000/profile-picture/change?guild_id=123456"

# Custom upload
curl -X POST "http://localhost:8000/profile-picture/change" \
  -F "file=@miku_image.png"
```

##### **GET /profile-picture/metadata**
Get information about current profile picture.

**Returns:**
```json
{
  "status": "ok",
  "metadata": {
    "id": 12345,
    "source": "danbooru",
    "changed_at": "2025-12-05T14:30:00",
    "rating": "g",
    "tags": ["hatsune_miku", "solo", "smile"],
    "artist": "artist_name",
    "file_url": "https://..."
  }
}
```

##### **POST /profile-picture/restore-fallback**
Restore the original animated fallback avatar.

**Example:**
```bash
curl -X POST "http://localhost:8000/profile-picture/restore-fallback"
```

## Technical Details

### Face Detection
Uses `lbpcascade_animeface.xml` - specifically trained for anime faces:
- More accurate than general face detection for anime art
- Downloaded automatically on first run
- Detects multiple faces and selects largest

### Vision Model Integration
Uses existing MiniCPM-V model for verification:

**Prompt:**
```
Analyze this image and answer:
1. Is Hatsune Miku present in this image? (yes/no)
2. How many characters are in the image? (number)
3. If multiple characters, describe where Miku is located
   (left/right/center, top/bottom/middle)
```

**Response Parsing:**
- Extracts JSON from LLM response
- Maps location description to crop coordinates
- Handles multi-character images intelligently

### Cropping Strategy
1. **Face Detected**: Center on face center point
2. **No Face**: Use saliency detection (spectral residual method)
3. **Saliency Failed**: Center of image

**All crops:**
- Square aspect ratio (min dimension)
- 512x512 final output (Discord optimal size)
- High-quality Lanczos resampling

### Mood-Based Tag Mapping

| Mood | Danbooru Tags |
|------|---------------|
| bubbly | smile, happy |
| sleepy | sleepy, closed_eyes |
| curious | looking_at_viewer |
| shy | blush, embarrassed |
| excited | happy, open_mouth |
| silly | smile, tongue_out |
| melancholy | sad, tears |
| flirty | blush, wink |
| romantic | blush, heart |
| irritated | annoyed |
| angry | angry, frown |

**Note:** Only ONE random tag used to avoid over-filtering

## File Structure

```
bot/
├── utils/
│   ├── danbooru_client.py          # Danbooru API wrapper
│   ├── profile_picture_manager.py  # Main PFP logic
│   ├── autonomous_engine.py        # Decision logic (updated)
│   └── autonomous.py               # Action executor (updated)
├── memory/
│   └── profile_pictures/
│       ├── fallback.png            # Original avatar backup
│       ├── current.png             # Current processed image
│       ├── metadata.json           # Change history/metadata
│       └── lbpcascade_animeface.xml # Face detection model
├── api.py                          # Web API (updated)
├── bot.py                          # Main bot (updated)
└── requirements.txt                # Dependencies (updated)
```

## Dependencies Added

```
opencv-python    # Computer vision & face detection
numpy           # Array operations for image processing
```

Existing dependencies used:
- `Pillow` - Image manipulation
- `aiohttp` - Async HTTP for downloads
- `discord.py` - Avatar updates

## Initialization Sequence

On bot startup (`bot.py` → `on_ready`):

1. **Initialize Profile Picture Manager**
   ```python
   await profile_picture_manager.initialize()
   ```
   - Downloads anime face cascade if missing
   - Loads OpenCV cascade classifier
   - Prepares directory structure

2. **Save Current Avatar as Fallback**
   ```python
   await profile_picture_manager.save_current_avatar_as_fallback()
   ```
   - Downloads bot's current avatar
   - Saves as `fallback.png`
   - Preserves animated avatar if present

## Usage Examples

### Autonomous
Miku decides on her own (roughly once per day):
```python
# Automatic - handled by autonomous_tick_v2()
# No user intervention needed
```

### Manual via Web UI

**Location:** Actions Tab → Profile Picture section

**Available Controls:**

1. **🎨 Change Profile Picture (Danbooru)** - Automatic search
   - Uses current mood from selected server
   - Searches Danbooru for appropriate artwork
   - Automatically crops and applies

2. **Upload Custom Image** - Manual upload
   - Select image file from computer
   - Bot detects face and crops intelligently
   - Click "📤 Upload & Apply" to process

3. **🔄 Restore Original Avatar** - Rollback
   - Restores the fallback avatar saved on bot startup
   - Confirms before applying

**Features:**
- Real-time status updates
- Displays metadata after changes (source, tags, artist, etc.)
- Server selection dropdown to use specific server's mood
- File validation and error handling

### Manual via API
```bash
# Let Miku search Danbooru (uses current mood)
curl -X POST "http://localhost:8000/profile-picture/change?guild_id=123456"

# Upload custom image
curl -X POST "http://localhost:8000/profile-picture/change" \
  -F "file=@custom_miku.png"

# Check current PFP metadata
curl "http://localhost:8000/profile-picture/metadata"

# Restore original avatar
curl -X POST "http://localhost:8000/profile-picture/restore-fallback"
```

### Manual via Web UI
(Implementation in `static/index.html` - to be added)

**Actions Tab:**
- Button: "Change Profile Picture (Danbooru)"
- File upload: "Upload Custom Image"
- Button: "Restore Original Avatar"
- Display: Current PFP metadata

## Error Handling

### Graceful Degradation
1. **Vision model fails**: Assume it's Miku (trust Danbooru tags)
2. **Face detection fails**: Use saliency detection
3. **Saliency fails**: Center crop
4. **Danbooru API fails**: Retry or skip action
5. **Discord API fails**: Log error, don't retry (rate limit)

### Rollback
If Discord avatar update fails:
- Error logged
- Metadata not saved
- Original avatar unchanged
- Fallback available via API

## Performance Considerations

### API Rate Limits
- **Danbooru**: 2 requests/second (we use ~1/day)
- **Discord**: 2 avatar changes/10 min globally (we use ~1/day)
- **Vision Model**: Local, no external limits

### Resource Usage
- **Image Download**: ~1-5 MB per image
- **Processing**: ~1-2 seconds (face detection + crop)
- **Storage**: ~500 KB per saved image
- **Memory**: Minimal (images processed and discarded)

### Caching Strategy
- Fallback saved on startup (one-time)
- Current PFP saved after processing
- Metadata persisted to JSON
- No aggressive caching needed (infrequent operation)

## Future Enhancements

### Potential Improvements
1. **Multi-mood combos**: "bubbly + romantic" tag combinations
2. **Time-based themes**: Different art styles by time of day
3. **User voting**: Let server vote on next PFP
4. **Quality scoring**: Rank images by aesthetic appeal
5. **Artist credits**: Post artist attribution when changing
6. **Preview mode**: Show crop preview before applying
7. **Scheduled changes**: Weekly theme rotations
8. **Favorite images**: Build curated collection over time

### Web UI Additions
- Real-time preview of crop before applying
- Gallery of previously used profile pictures
- Manual tag selection for Danbooru search
- Artist credit display
- Change history timeline

## Testing

## Testing

### Web UI Testing
1. Navigate to the bot control panel (usually `http://localhost:8000`)
2. Click the **Actions** tab
3. Scroll to the **🎨 Profile Picture** section
4. Try each feature:
   - Click "Change Profile Picture (Danbooru)" - wait ~10-20 seconds
   - Upload a custom Miku image and click "Upload & Apply"
   - Click "Restore Original Avatar" to revert

**Expected Results:**
- Status messages appear below buttons
- Metadata displays when successful
- Bot's Discord avatar updates within ~5 seconds
- Errors display in red with clear messages

### Manual Testing Checklist
- [ ] Autonomous action triggers (set probability high for testing)
- [ ] Danbooru search returns results
- [ ] Vision model correctly identifies Miku
- [ ] Face detection works on anime art
- [ ] Saliency fallback works when no face
- [ ] Custom image upload works
- [ ] Discord avatar updates successfully
- [ ] Fallback restoration works
- [ ] Metadata saves correctly
- [ ] API endpoints respond properly
- [ ] Error handling works (bad images, API failures)
- [ ] Rate limiting prevents spam

### Test Commands
```bash
# Test Danbooru search
python -c "
import asyncio
from utils.danbooru_client import danbooru_client
async def test():
    post = await danbooru_client.get_random_miku_image(mood='bubbly')
    print(post)
asyncio.run(test())
"

# Test face detection (after downloading cascade)
# Upload test image via API

# Test autonomous trigger (increase probability temporarily)
# Edit autonomous_engine.py: base_chance = 1.0
```

## Deployment Notes

### First-Time Setup
1. Install new dependencies: `pip install opencv-python numpy`
2. Ensure `memory/profile_pictures/` directory exists
3. Bot will download face cascade on first run (~100 KB)
4. Current avatar automatically saved as fallback

### Docker Deployment
Already handled if using existing Dockerfile:
- `requirements.txt` includes new deps
- `memory/` directory persisted via volume
- Network access for Danbooru API

### Monitoring
Watch for these log messages:
- `📥 Downloading anime face detection cascade...`
- `✅ Anime face detection ready`
- `✅ Saved current avatar as fallback`
- `🎨 [V2] Changing profile picture (mood: ...)`
- `✅ Profile picture changed successfully!`

## Summary

This implementation provides Miku with a unique, personality-driven feature that:
- ✅ Fully autonomous (once per day decision-making)
- ✅ Mood-aware (searches match current emotional state)
- ✅ Intelligent (vision model verification + face detection)
- ✅ Safe (fallback preservation, error handling)
- ✅ Controllable (manual API endpoints with custom uploads)
- ✅ Well-integrated (fits existing autonomous engine architecture)

The feature showcases Miku's personality while respecting rate limits and providing users with visibility and control through the web UI.
