complete restructure
This commit is contained in:
@@ -9,7 +9,9 @@ A Discord bot that stores long-term chat history using SQLite with RAG (Retrieva
|
||||
- [Text-to-Speech](#text-to-speech)
|
||||
- [Image Commands](#image-commands)
|
||||
- [Bot Conversations](#bot-conversations)
|
||||
- [Chat History](#chat-history)
|
||||
- [Admin & Debug](#admin--debug)
|
||||
- [Design Notes](#design-notes)
|
||||
- [Limits & Cooldowns](#limits--cooldowns)
|
||||
- [Features](#features)
|
||||
- [Setup](#setup)
|
||||
- [Prerequisites](#prerequisites)
|
||||
@@ -47,24 +49,24 @@ Once you create a custom bot, interact with it by prefixing your message with th
|
||||
**Example:**
|
||||
|
||||
1. Create a bot: `!custom-bot alfred you are a proper british butler`
|
||||
2. Use the bot: `alfred Could you fetch me some tea?`
|
||||
2. Use the bot: `!alfred Could you fetch me some tea?`
|
||||
3. The bot will respond in character as a British butler
|
||||
|
||||
### Text-to-Speech
|
||||
|
||||
| Command | Description | Example Usage |
|
||||
| ------------------------------------ | ----------------------------------------------------- | ------------------------------------------ |
|
||||
| `!speak <text>` | Convert text to speech (MP3 attachment) | `!speak hello world` |
|
||||
| `!speak <text> --voice <voice>` | Convert text to speech with a specific voice | `!speak hello world --voice af_bella` |
|
||||
| `!speak <bot_name> <text>` | Have a custom bot respond and speak | `!speak alfred what time is it` |
|
||||
| Command | Description | Example Usage |
|
||||
| ------------------------------------ | ----------------------------------------------------- | ----------------------------------------- |
|
||||
| `!speak <text>` | Convert text to speech (MP3 attachment) | `!speak hello world` |
|
||||
| `!speak <text> --voice <voice>` | Convert text to speech with a specific voice | `!speak hello world --voice af_bella` |
|
||||
| `!speak <bot_name> <text>` | Have a custom bot respond and speak | `!speak alfred what time is it` |
|
||||
| `!speak <bot_name> <text> --voice` | Have a custom bot respond and speak with a voice | `!speak alfred what time is it --voice am_puck` |
|
||||
| `!voices` | List all available TTS voices by category | `!voices` |
|
||||
| `!voices` | List all available TTS voices by category | `!voices` |
|
||||
|
||||
### Image Commands
|
||||
|
||||
| Command | Description | Example Usage |
|
||||
| ------------ | ------------------------------------ | ------------------------------------------ |
|
||||
| `!doodlebob` | Generate an image from a text prompt | `!doodlebob a cat sitting on the moon` |
|
||||
| Command | Description | Example Usage |
|
||||
| ------------ | ------------------------------------ | ----------------------------------------- |
|
||||
| `!doodlebob` | Generate an image from a text prompt | `!doodlebob a cat sitting on the moon` |
|
||||
| `!retcon` | Edit an attached image with text | `!retcon <image attachment> Make it sunny` |
|
||||
|
||||
### Bot Conversations
|
||||
@@ -73,11 +75,53 @@ Once you create a custom bot, interact with it by prefixing your message with th
|
||||
| -------------------------------------- | ------------------------------------------- | ------------------------------------------------ |
|
||||
| `!talkforme <bot1> <bot2> <n> <topic>` | Have two bots discuss a topic for n replies | `!talkforme alfred jarvis 4 the meaning of life` |
|
||||
|
||||
### Chat History
|
||||
### Admin & Debug
|
||||
|
||||
| Command | Description | Example Usage |
|
||||
| --------------------- | ------------------------------------- | ----------------- |
|
||||
| `!history <bot_name>` | View the chat history of a custom bot | `!history alfred` |
|
||||
| Command | Description | Example Usage |
|
||||
| --------------------- | ------------------------------------------------------- | --------------------- |
|
||||
| `!lobotomize` | Clear all conversation history and memory for all bots | `!lobotomize` |
|
||||
| `!debug` | Show the debug menu | `!debug` |
|
||||
| `!debug members` | List all members in the current channel | `!debug members` |
|
||||
| `!debug whoami` | Show all information the bot has about you | `!debug whoami` |
|
||||
| `!debug tools` | Show the LLM's available tools | `!debug tools` |
|
||||
| `!history <bot_name>` | View the chat history of a custom bot | `!history alfred` |
|
||||
|
||||
## Design Notes
|
||||
|
||||
These semantics are intentional:
|
||||
|
||||
- **Shared memory**: message history is not siloed per bot. Any user's history can inform
|
||||
any bot's RAG context — the semantic (embedding) search runs over the whole message
|
||||
store, so a fact one user told bot A can resurface in a later conversation with bot B.
|
||||
- **Shared bot namespace**: bot names are global, not per-user. Creating a bot with a
|
||||
name that already exists **replaces** it (you will be told it was replaced); only
|
||||
deletion is restricted to the bot's creator.
|
||||
- **Any member may use any bot**: custom-bot chat (`!<bot_name> <message>`) is open to
|
||||
every member of the server, regardless of who created the bot.
|
||||
|
||||
## Limits & Cooldowns
|
||||
|
||||
**Input limits** (over-limit input is rejected with a friendly message before any
|
||||
LLM/DB work):
|
||||
|
||||
| Input | Limit |
|
||||
| ------------------------- | ------------------------------------------------ |
|
||||
| Custom bot name | 2–50 characters |
|
||||
| Custom bot personality | 10–1000 characters |
|
||||
| `!speak` text | 5000 characters (after `--voice` parsing) |
|
||||
| `!doodlebob` / `!retcon` prompt | 2000 characters |
|
||||
| `!talkforme` topic | 500 characters |
|
||||
| `!talkforme` reply count | Capped at 20 replies per invocation |
|
||||
| LLM responses | `MAX_COMPLETION_TOKENS` tokens (default 1000) |
|
||||
| `!retcon` downloads | Discord CDN hosts only, 8 MB per image |
|
||||
|
||||
**Cooldowns** (per user; a friendly "try again in Ns" message is sent when hit):
|
||||
|
||||
| Command | Cooldown |
|
||||
| ------------- | ----------- |
|
||||
| `!doodlebob` | 1 / 60 s |
|
||||
| `!talkforme` | 1 / 120 s |
|
||||
| `!speak` | 3 / 30 s |
|
||||
|
||||
## Features
|
||||
|
||||
@@ -110,11 +154,8 @@ DISCORD_TOKEN=your_discord_bot_token
|
||||
|
||||
# Chat/Completion API (required)
|
||||
CHAT_ENDPOINT=https://your-api.com/v1
|
||||
COMPLETION_ENDPOINT=https://your-api.com/v1
|
||||
CHAT_ENDPOINT_KEY=your_api_key
|
||||
COMPLETION_ENDPOINT_KEY=your_api_key
|
||||
CHAT_MODEL=your_model_name
|
||||
COMPLETION_MODEL=your_model_name
|
||||
|
||||
# Image Generation (required)
|
||||
IMAGE_GEN_ENDPOINT=https://your-api.com/v1
|
||||
@@ -169,16 +210,16 @@ uv run python -m vibe_bot.main
|
||||
|
||||
### Database Structure
|
||||
|
||||
The system uses SQLite with three tables:
|
||||
The system uses SQLite with four tables:
|
||||
|
||||
1. **chat_messages**: Stores message metadata
|
||||
- `message_id`, `user_id`, `username`, `content`, `bot_name`, `timestamp`, `channel_id`, `guild_id`
|
||||
|
||||
- `message_id`, `user_id`, `username`, `content`, `bot_name`, `role`, `timestamp`, `channel_id`, `guild_id`
|
||||
2. **message_embeddings**: Stores vector embeddings for RAG
|
||||
- `message_id` (PK), `embedding` (binary blob of float32 values)
|
||||
|
||||
3. **custom_bots**: Stores custom bot configurations
|
||||
- `bot_name` (PK), `system_prompt`, `created_by`, `created_at`, `is_active`
|
||||
4. **image_generation_times**: Stores per-generation durations for the ETA estimate
|
||||
- `id` (PK), `duration_seconds`, `generated_at`
|
||||
|
||||
### RAG Process
|
||||
|
||||
@@ -195,26 +236,76 @@ The system uses SQLite with three tables:
|
||||
```text
|
||||
vibe_discord_bots/
|
||||
├── vibe_bot/
|
||||
│ ├── __init__.py # Package marker
|
||||
│ ├── main.py # Main bot application (commands, event handlers)
|
||||
│ ├── config.py # Environment variable loading and validation
|
||||
│ ├── database.py # SQLite database with RAG + CustomBotManager
|
||||
│ ├── llama_wrapper.py # OpenAI-compatible API wrappers (chat, images, embeddings)
|
||||
│ ├── tts.py # Kokoro TTS engine
|
||||
│ ├── __init__.py # Package marker
|
||||
│ ├── app.py # Composition root: App, services, bot event handlers
|
||||
│ ├── commands/
|
||||
│ │ ├── __init__.py # register_all: wires every command group
|
||||
│ │ ├── _state.py # Shared App holder for command handlers
|
||||
│ │ ├── admin.py # !lobotomize, !debug, !history
|
||||
│ │ ├── chat.py # Custom-bot chat group (dispatched via on_message)
|
||||
│ │ ├── conversation.py # !talkforme
|
||||
│ │ ├── custom_bots.py # !custom-bot, !list-custom-bots, !delete-custom-bot
|
||||
│ │ ├── images.py # !doodlebob, !retcon
|
||||
│ │ └── speech.py # !speak, !voices
|
||||
│ ├── config.py # Environment variable loading and validation
|
||||
│ ├── database.py # Facade over the db/ package
|
||||
│ ├── db/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── bots.py # CustomBotManager (create/read/list/delete)
|
||||
│ │ ├── connection.py # Shared SQLite connect() helper
|
||||
│ │ ├── messages.py # ChatDatabase: persistence, cleanup, RAG context
|
||||
│ │ ├── schema.py # Table creation and migrations
|
||||
│ │ ├── search.py # Similarity search and history lookups
|
||||
│ │ ├── timing.py # Image-generation timing statistics
|
||||
│ │ └── vectors.py # Embedding vector helpers
|
||||
│ ├── llm/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── chat.py # Chat completion clients (instruct/tools/history)
|
||||
│ │ ├── images.py # Image gen/edit clients
|
||||
│ │ └── registry.py # Tool registry (schema + dispatch)
|
||||
│ ├── llm_client.py # Public LLM/image/embedding client facade
|
||||
│ ├── main.py # Entrypoint
|
||||
│ ├── prompts.py # LLM prompt constants
|
||||
│ ├── services/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── chat_service.py # Custom-bot chat turn (context -> LLM -> persist)
|
||||
│ │ ├── conversation_service.py # Bot-vs-bot conversation runner
|
||||
│ │ ├── image_service.py # !doodlebob / !retcon logic
|
||||
│ │ └── speech_service.py # !speak logic
|
||||
│ ├── textutil.py # Message splitting and user-info helpers
|
||||
│ ├── tools.py # LLM tool stubs and channel-member helper
|
||||
│ ├── tts.py # Kokoro TTS engine
|
||||
│ └── tests/
|
||||
│ ├── conftest.py # Shared test fixtures
|
||||
│ ├── test_main.py # Bot command tests
|
||||
│ ├── test_config.py # Config loading tests
|
||||
│ ├── test_database.py # Database + CustomBotManager tests
|
||||
│ ├── test_llama_wrapper.py # API wrapper tests
|
||||
│ └── test_tts.py # TTS engine tests
|
||||
├── pyproject.toml # Project dependencies (uv)
|
||||
├── uv.lock # Locked dependency versions
|
||||
├── .env # Environment variables
|
||||
├── kokoro-v1.0.onnx # Kokoro TTS model
|
||||
├── voices-v1.0.bin # Kokoro voice definitions
|
||||
├── Containerfile # Podman/Docker build file
|
||||
└── README.md # This file
|
||||
│ ├── __init__.py
|
||||
│ ├── _helpers.py # Shared test helpers
|
||||
│ ├── conftest.py # Shared test fixtures
|
||||
│ ├── test_app.py # Composition root and bot handler tests
|
||||
│ ├── test_commands.py # Discord command tests
|
||||
│ ├── test_config.py # Config loading tests
|
||||
│ ├── test_database.py # Database + CustomBotManager tests
|
||||
│ ├── test_docs.py # README sync tests (commands + file tree)
|
||||
│ ├── test_llm_client.py # LLM client tests
|
||||
│ ├── test_logging.py # No-content logging tests
|
||||
│ ├── test_prompts.py # Prompt constant tests
|
||||
│ ├── test_services.py # Service-layer tests
|
||||
│ ├── test_textutil.py # Text utility tests
|
||||
│ ├── test_tools.py # Tool stub tests
|
||||
│ └── test_tts.py # TTS engine tests
|
||||
├── .gitea/
|
||||
│ └── workflows/
|
||||
│ └── build-push.yml # CI: build and push the container image
|
||||
├── AGENTS.md # Agent instructions
|
||||
├── Containerfile # Podman/Docker build file
|
||||
├── MANUAL_TESTS.md # Manual Discord testing guide
|
||||
├── README.md # This file
|
||||
├── build.sh # Podman build wrapper
|
||||
├── kokoro-v1.0.onnx # Kokoro TTS model
|
||||
├── pyproject.toml # Project metadata and dependencies (uv)
|
||||
├── scripts/
|
||||
│ └── bench_rag.py # RAG p95 latency benchmark (standalone)
|
||||
├── uv.lock # Locked dependency versions
|
||||
├── vibe-bot.container # systemd unit for running the bot container
|
||||
└── voices-v1.0.bin # Kokoro voice definitions
|
||||
```
|
||||
|
||||
## Building
|
||||
@@ -233,7 +324,7 @@ uv run python -m vibe_bot.main
|
||||
|
||||
```bash
|
||||
# Build the container image
|
||||
podman build -t vibe-bot:latest .
|
||||
podman build -t localhost/vibe-bot:latest -f Containerfile .
|
||||
|
||||
# Run with environment file
|
||||
podman run --env-file .env localhost/vibe-bot:latest
|
||||
@@ -241,12 +332,19 @@ podman run --env-file .env localhost/vibe-bot:latest
|
||||
|
||||
## Testing
|
||||
|
||||
Run the full test suite:
|
||||
Run the full test suite (hermetic by default; network-dependent `live` tests are
|
||||
deselected):
|
||||
|
||||
```bash
|
||||
uv run pytest vibe_bot/tests/ -v
|
||||
```
|
||||
|
||||
Run the network-dependent live tests explicitly:
|
||||
|
||||
```bash
|
||||
uv run pytest -m live
|
||||
```
|
||||
|
||||
Run linters:
|
||||
|
||||
```bash
|
||||
@@ -265,24 +363,30 @@ uv run black --check vibe_bot/
|
||||
|
||||
## Configuration
|
||||
|
||||
| Variable | Default | Description |
|
||||
| ----------------------- | ------------------ | ------------------------------------- |
|
||||
| `DISCORD_TOKEN` | *(required)* | Discord bot authentication token |
|
||||
| `CHAT_ENDPOINT` | *(required)* | OpenAI-compatible chat API URL |
|
||||
| `CHAT_MODEL` | *(required)* | Model name for chat completions |
|
||||
| `IMAGE_GEN_ENDPOINT` | *(required)* | Image generation API URL |
|
||||
| `IMAGE_EDIT_ENDPOINT` | *(required)* | Image editing API URL |
|
||||
| `IMAGE_GEN_SIZE_SQUARE` | `1024x1024` | Square canvas size for image generation |
|
||||
| `IMAGE_GEN_SIZE_PORTRAIT` | `1024x1536` | Portrait (tall) canvas size for image generation |
|
||||
| `IMAGE_GEN_SIZE_LANDSCAPE`| `1536x1024` | Landscape (wide) canvas size for image generation |
|
||||
| `EMBEDDING_ENDPOINT` | *(required)* | Embedding API URL |
|
||||
| `EMBEDDING_MODEL` | *(required)* | Model name for text embeddings |
|
||||
| `MAX_COMPLETION_TOKENS` | `1000` | Max tokens in LLM responses |
|
||||
| `MAX_HISTORY_MESSAGES` | `1000` | Max messages kept in the database |
|
||||
| `SIMILARITY_THRESHOLD` | `0.7` | Min cosine similarity for RAG context |
|
||||
| `TOP_K_RESULTS` | `5` | Number of similar messages retrieved |
|
||||
| `TTS_MODEL_PATH` | `kokoro-v1.0.onnx` | Path to Kokoro ONNX model file |
|
||||
| `TTS_VOICES_PATH` | `voices-v1.0.bin` | Path to Kokoro voices binary file |
|
||||
| `TTS_VOICE` | `af_sarah` | Default voice for TTS |
|
||||
| `TTS_SPEED` | `1.0` | Speech speed multiplier |
|
||||
| `DB_PATH` | `chat_history.db` | SQLite database file path |
|
||||
| Variable | Default | Description |
|
||||
| -------------------------- | ------------------ | --------------------------------------------- |
|
||||
| `DISCORD_TOKEN` | *(required)* | Discord bot authentication token |
|
||||
| `CHAT_ENDPOINT` | *(required)* | OpenAI-compatible chat API URL |
|
||||
| `CHAT_ENDPOINT_KEY` | `placeholder` | API key for the chat endpoint |
|
||||
| `CHAT_MODEL` | *(required)* | Model name for chat completions |
|
||||
| `IMAGE_GEN_ENDPOINT` | *(required)* | Image generation API URL |
|
||||
| `IMAGE_GEN_ENDPOINT_KEY` | `placeholder` | API key for the image generation endpoint |
|
||||
| `IMAGE_GEN_MODEL` | *(required)* | Model name for image generation |
|
||||
| `IMAGE_GEN_SIZE_SQUARE` | `1024x1024` | Square canvas size for image generation |
|
||||
| `IMAGE_GEN_SIZE_PORTRAIT` | `1024x1536` | Portrait (tall) canvas size for image generation |
|
||||
| `IMAGE_GEN_SIZE_LANDSCAPE` | `1536x1024` | Landscape (wide) canvas size for image generation |
|
||||
| `IMAGE_EDIT_ENDPOINT` | *(required)* | Image editing API URL |
|
||||
| `IMAGE_EDIT_ENDPOINT_KEY` | `placeholder` | API key for the image editing endpoint |
|
||||
| `IMAGE_EDIT_MODEL` | *(required)* | Model name for image editing |
|
||||
| `EMBEDDING_ENDPOINT` | *(required)* | Embedding API URL |
|
||||
| `EMBEDDING_ENDPOINT_KEY` | `placeholder` | API key for the embedding endpoint |
|
||||
| `EMBEDDING_MODEL` | *(required)* | Model name for text embeddings |
|
||||
| `MAX_COMPLETION_TOKENS` | `1000` | Max tokens in LLM responses |
|
||||
| `DB_PATH` | `chat_history.db` | SQLite database file path |
|
||||
| `MAX_HISTORY_MESSAGES` | `1000` | Max messages kept in the database |
|
||||
| `SIMILARITY_THRESHOLD` | `0.7` | Min cosine similarity for RAG context |
|
||||
| `TOP_K_RESULTS` | `5` | Number of similar messages retrieved |
|
||||
| `TTS_MODEL_PATH` | `kokoro-v1.0.onnx` | Path to Kokoro ONNX model file |
|
||||
| `TTS_VOICES_PATH` | `voices-v1.0.bin` | Path to Kokoro voices binary file |
|
||||
| `TTS_VOICE` | `af_sarah` | Default voice for TTS |
|
||||
| `TTS_SPEED` | `1.0` | Speech speed multiplier |
|
||||
|
||||
Reference in New Issue
Block a user