15 KiB
Services Reference
This document provides detailed API documentation for all services in the Daemon Boyfriend bot.
Table of Contents
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
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.
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.
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.
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
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.
await db.init()
close() -> None
Close database connection.
await db.close()
create_tables() -> None
Create all tables from schema.sql.
await db.create_tables()
session() -> AsyncGenerator[AsyncSession, None]
Get a database session with automatic commit/rollback.
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
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.
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.
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.
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.
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.
# 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.
count = await user_service.delete_user_facts(user)
print(f"Deactivated {count} facts")
set_preference(user, key, value) -> UserPreference
Set a user preference.
await user_service.set_preference(user, "theme", "dark")
get_preference(user, key) -> str | None
Get a user preference value.
theme = await user_service.get_preference(user, "theme")
get_user_context(user) -> str
Build a context string about a user for the AI.
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.
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
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.
conversation_manager.add_message(
user_id=123456789,
role="user",
content="Hello!"
)
get_history(user_id) -> list[dict]
Get conversation history for a user.
history = conversation_manager.get_history(123456789)
# Returns: [{"role": "user", "content": "Hello!"}, ...]
clear_history(user_id) -> None
Clear conversation history for a user.
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.
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.
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.
messages = await pcm.get_recent_messages(
session=session,
conversation=conversation,
limit=20
)
SearXNGService
File: services/searxng.py
Web search integration using SearXNG.
Initialization
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.
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
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
from daemon_boyfriend.services.providers import (
AIProvider, # Abstract base class
Message, # Chat message
AIResponse, # Response from provider
ImageAttachment, # Image attachment
)
Message Class
@dataclass
class Message:
role: str # "user", "assistant", "system"
content: str # Message content
images: list[ImageAttachment] = [] # Optional image attachments
AIResponse Class
@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:
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
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 for detailed coverage:
| Service | Documentation |
|---|---|
| MoodService | mood-system.md |
| RelationshipService | relationship-system.md |
| FactExtractionService | fact-extraction.md |
| OpinionService | opinion-system.md |
| CommunicationStyleService | Living AI README |
| ProactiveService | Living AI README |
| AssociationService | Living AI README |
| SelfAwarenessService | Living AI README |
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() │
└───────────────┘