Files
loyal_companion/docs/services/README.md
2026-01-13 17:20:52 +00:00

616 lines
15 KiB
Markdown

# Services Reference
This document provides detailed API documentation for all services in the Daemon Boyfriend bot.
## Table of Contents
- [Core Services](#core-services)
- [AIService](#aiservice)
- [DatabaseService](#databaseservice)
- [UserService](#userservice)
- [ConversationManager](#conversationmanager)
- [PersistentConversationManager](#persistentconversationmanager)
- [SearXNGService](#searxngservice)
- [MonitoringService](#monitoringservice)
- [AI Providers](#ai-providers)
- [Living AI Services](#living-ai-services)
---
## Core Services
### AIService
**File:** `services/ai_service.py`
Factory and facade for AI providers. Manages provider creation, switching, and provides a unified interface for generating responses.
#### Initialization
```python
from daemon_boyfriend.services.ai_service import AIService
from daemon_boyfriend.config import settings
# Use default settings
ai_service = AIService()
# Or with custom settings
ai_service = AIService(config=custom_settings)
```
#### Properties
| Property | Type | Description |
|----------|------|-------------|
| `provider` | `AIProvider` | Current AI provider instance |
| `provider_name` | `str` | Name of current provider |
| `model` | `str` | Current model name |
#### Methods
##### `chat(messages, system_prompt) -> AIResponse`
Generate a chat response.
```python
from daemon_boyfriend.services.providers import Message
response = await ai_service.chat(
messages=[
Message(role="user", content="Hello!"),
],
system_prompt="You are a helpful assistant."
)
print(response.content) # AI's response
print(response.model) # Model used
print(response.usage) # Token usage
```
##### `get_system_prompt() -> str`
Get the base system prompt for the bot.
```python
prompt = ai_service.get_system_prompt()
# Returns: "You are Daemon, a friendly and helpful Discord bot..."
```
##### `get_enhanced_system_prompt(...) -> str`
Build system prompt with all personality modifiers.
```python
enhanced_prompt = ai_service.get_enhanced_system_prompt(
mood=mood_state,
relationship=(relationship_level, relationship_record),
communication_style=user_style,
bot_opinions=relevant_opinions
)
```
**Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `mood` | `MoodState \| None` | Current mood state |
| `relationship` | `tuple[RelationshipLevel, UserRelationship] \| None` | Relationship info |
| `communication_style` | `UserCommunicationStyle \| None` | User's preferences |
| `bot_opinions` | `list[BotOpinion] \| None` | Relevant opinions |
---
### DatabaseService
**File:** `services/database.py`
Manages database connections and sessions.
#### Global Instance
```python
from daemon_boyfriend.services.database import db, get_db
# Get global instance
db_service = get_db()
```
#### Properties
| Property | Type | Description |
|----------|------|-------------|
| `is_configured` | `bool` | Whether DATABASE_URL is set |
| `is_initialized` | `bool` | Whether connection is initialized |
#### Methods
##### `init() -> None`
Initialize database connection.
```python
await db.init()
```
##### `close() -> None`
Close database connection.
```python
await db.close()
```
##### `create_tables() -> None`
Create all tables from `schema.sql`.
```python
await db.create_tables()
```
##### `session() -> AsyncGenerator[AsyncSession, None]`
Get a database session with automatic commit/rollback.
```python
async with db.session() as session:
# Use session for database operations
user = await session.execute(select(User).where(...))
# Auto-commits on exit, auto-rollbacks on exception
```
---
### UserService
**File:** `services/user_service.py`
Service for user-related operations.
#### Initialization
```python
from daemon_boyfriend.services.user_service import UserService
async with db.session() as session:
user_service = UserService(session)
```
#### Methods
##### `get_or_create_user(discord_id, username, display_name) -> User`
Get existing user or create new one.
```python
user = await user_service.get_or_create_user(
discord_id=123456789,
username="john_doe",
display_name="John"
)
```
##### `get_user_by_discord_id(discord_id) -> User | None`
Get a user by their Discord ID.
```python
user = await user_service.get_user_by_discord_id(123456789)
```
##### `set_custom_name(discord_id, custom_name) -> User | None`
Set a custom name for a user.
```python
user = await user_service.set_custom_name(123456789, "Johnny")
# Or clear custom name
user = await user_service.set_custom_name(123456789, None)
```
##### `add_fact(user, fact_type, fact_content, source, confidence) -> UserFact`
Add a fact about a user.
```python
fact = await user_service.add_fact(
user=user,
fact_type="hobby",
fact_content="enjoys playing chess",
source="conversation",
confidence=0.9
)
```
##### `get_user_facts(user, fact_type, active_only) -> list[UserFact]`
Get facts about a user.
```python
# All active facts
facts = await user_service.get_user_facts(user)
# Only hobby facts
hobby_facts = await user_service.get_user_facts(user, fact_type="hobby")
# Including inactive facts
all_facts = await user_service.get_user_facts(user, active_only=False)
```
##### `delete_user_facts(user) -> int`
Soft-delete all facts for a user.
```python
count = await user_service.delete_user_facts(user)
print(f"Deactivated {count} facts")
```
##### `set_preference(user, key, value) -> UserPreference`
Set a user preference.
```python
await user_service.set_preference(user, "theme", "dark")
```
##### `get_preference(user, key) -> str | None`
Get a user preference value.
```python
theme = await user_service.get_preference(user, "theme")
```
##### `get_user_context(user) -> str`
Build a context string about a user for the AI.
```python
context = await user_service.get_user_context(user)
# Returns:
# User's preferred name: John
# (You should address them as: Johnny)
#
# Known facts about this user:
# - [hobby] enjoys playing chess
# - [work] software developer
```
##### `get_user_with_facts(discord_id) -> User | None`
Get a user with their facts eagerly loaded.
```python
user = await user_service.get_user_with_facts(123456789)
print(user.facts) # Facts already loaded
```
---
### ConversationManager
**File:** `services/conversation.py`
In-memory conversation history manager (used when no database).
#### Initialization
```python
from daemon_boyfriend.services.conversation import ConversationManager
conversation_manager = ConversationManager(max_history=50)
```
#### Methods
##### `add_message(user_id, role, content) -> None`
Add a message to a user's conversation history.
```python
conversation_manager.add_message(
user_id=123456789,
role="user",
content="Hello!"
)
```
##### `get_history(user_id) -> list[dict]`
Get conversation history for a user.
```python
history = conversation_manager.get_history(123456789)
# Returns: [{"role": "user", "content": "Hello!"}, ...]
```
##### `clear_history(user_id) -> None`
Clear conversation history for a user.
```python
conversation_manager.clear_history(123456789)
```
---
### PersistentConversationManager
**File:** `services/persistent_conversation.py`
Database-backed conversation manager.
#### Key Features
- Conversations persist across restarts
- Timeout-based conversation separation (60 min default)
- Per-guild conversation tracking
#### Methods
##### `get_or_create_conversation(session, user, guild_id) -> Conversation`
Get active conversation or create new one.
```python
conversation = await pcm.get_or_create_conversation(
session=session,
user=user,
guild_id=123456789
)
```
##### `add_message(session, conversation, role, content) -> Message`
Add a message to a conversation.
```python
message = await pcm.add_message(
session=session,
conversation=conversation,
role="user",
content="Hello!"
)
```
##### `get_recent_messages(session, conversation, limit) -> list[Message]`
Get recent messages from a conversation.
```python
messages = await pcm.get_recent_messages(
session=session,
conversation=conversation,
limit=20
)
```
---
### SearXNGService
**File:** `services/searxng.py`
Web search integration using SearXNG.
#### Initialization
```python
from daemon_boyfriend.services.searxng import SearXNGService
searxng = SearXNGService()
```
#### Properties
| Property | Type | Description |
|----------|------|-------------|
| `is_configured` | `bool` | Whether SEARXNG_URL is set |
#### Methods
##### `search(query, num_results) -> list[SearchResult]`
Search the web for a query.
```python
if searxng.is_configured:
results = await searxng.search(
query="Python 3.12 new features",
num_results=5
)
for result in results:
print(f"{result.title}: {result.url}")
print(f" {result.snippet}")
```
---
### MonitoringService
**File:** `services/monitoring.py`
Health checks and metrics tracking.
#### Features
- Request counting
- Response time tracking
- Error rate monitoring
- Health status checks
#### Usage
```python
from daemon_boyfriend.services.monitoring import MonitoringService
monitoring = MonitoringService()
# Record a request
monitoring.record_request()
# Record response time
monitoring.record_response_time(0.5) # 500ms
# Record an error
monitoring.record_error("API timeout")
# Get health status
status = monitoring.get_health_status()
print(status)
# {
# "status": "healthy",
# "uptime": 3600,
# "total_requests": 100,
# "avg_response_time": 0.3,
# "error_rate": 0.02,
# "recent_errors": [...]
# }
```
---
## AI Providers
**Location:** `services/providers/`
### Base Classes
```python
from daemon_boyfriend.services.providers import (
AIProvider, # Abstract base class
Message, # Chat message
AIResponse, # Response from provider
ImageAttachment, # Image attachment
)
```
### Message Class
```python
@dataclass
class Message:
role: str # "user", "assistant", "system"
content: str # Message content
images: list[ImageAttachment] = [] # Optional image attachments
```
### AIResponse Class
```python
@dataclass
class AIResponse:
content: str # Generated response
model: str # Model used
usage: dict[str, int] # Token usage info
```
### Available Providers
| Provider | Class | Description |
|----------|-------|-------------|
| OpenAI | `OpenAIProvider` | GPT models via OpenAI API |
| OpenRouter | `OpenRouterProvider` | Multiple models via OpenRouter |
| Anthropic | `AnthropicProvider` | Claude models via Anthropic API |
| Gemini | `GeminiProvider` | Gemini models via Google API |
### Provider Interface
All providers implement:
```python
class AIProvider(ABC):
@abstractmethod
async def generate(
self,
messages: list[Message],
system_prompt: str | None = None,
max_tokens: int = 1024,
temperature: float = 0.7,
) -> AIResponse:
pass
@property
@abstractmethod
def provider_name(self) -> str:
pass
```
### Example: Direct Provider Usage
```python
from daemon_boyfriend.services.providers import OpenAIProvider, Message
provider = OpenAIProvider(
api_key="sk-...",
model="gpt-4"
)
response = await provider.generate(
messages=[Message(role="user", content="Hello!")],
system_prompt="You are helpful.",
max_tokens=500,
temperature=0.7
)
print(response.content)
```
---
## Living AI Services
See [Living AI Documentation](../living-ai/README.md) for detailed coverage:
| Service | Documentation |
|---------|--------------|
| MoodService | [mood-system.md](../living-ai/mood-system.md) |
| RelationshipService | [relationship-system.md](../living-ai/relationship-system.md) |
| FactExtractionService | [fact-extraction.md](../living-ai/fact-extraction.md) |
| OpinionService | [opinion-system.md](../living-ai/opinion-system.md) |
| CommunicationStyleService | [Living AI README](../living-ai/README.md#5-communication-style-system) |
| ProactiveService | [Living AI README](../living-ai/README.md#6-proactive-events-system) |
| AssociationService | [Living AI README](../living-ai/README.md#7-association-system) |
| SelfAwarenessService | [Living AI README](../living-ai/README.md#8-self-awareness-system) |
---
## Service Dependency Graph
```
┌────────────────────────────────────────────────────────────────────────┐
│ AIChatCog │
└────────────────────────────────────────────────────────────────────────┘
┌───────────────────────┼───────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ UserService │ │ AIService │ │ Conversation │
│ │ │ │ │ Manager │
│ - get_user │ │ - chat │ │ │
│ - get_context │ │ - get_prompt │ │ - get_history │
└───────────────┘ └───────────────┘ └───────────────┘
│ │ │
│ ┌────────┴────────┐ │
│ │ │ │
│ ▼ ▼ │
│ ┌───────────────┐ ┌───────────────┐ │
│ │ Provider │ │ Living AI │ │
│ │ (OpenAI, │ │ Services │ │
│ │ Anthropic) │ │ │ │
│ └───────────────┘ └───────────────┘ │
│ │
└──────────────────┬───────────────────────────┘
┌───────────────┐
│ Database │
│ Service │
│ │
│ - session() │
└───────────────┘
```