!!Built with Vibe Coding - AI-assisted development!!
Vanilla is a LINE chatbot that role-plays as an ancient palace lady (inspired by the Chinese TV drama "Legend of Zhen Huan"), powered by OpenAI language models and LangGraph for conversation management. The bot integrates with LINE's Square Chat platform and includes web search capabilities via Tavily.
- Ancient palace lady persona with classical Chinese speech patterns
- Conversation state management via LangGraph
- LINE Square Chat (OpenChat) and Talk (Group/DM) integration
- End-to-end encryption (E2EE) support for messages
- Web search functionality via Tavily
- Sticker analysis with GPT-4 Vision
- Automatic LINE reactions to messages
- Cron-based task scheduler for timed messages
- User preferences persistence (nicknames, custom rules)
- PostgreSQL persistence for conversation state and user data
- Langfuse LLM observability and tracing
- Python 3.11+
- uv (Python package manager)
- PostgreSQL 17+
- LINE account (with "Login with password" and "Letter Sealing" enabled)
# Full setup (install packages + create .env + configure PostgreSQL)
make setup
# Edit .env and fill in the required credentials
cp .env.example .env
vi .env
# Start the service
make run- Install uv (if not already installed)
curl -LsSf https://astral.sh/uv/install.sh | sh- Install Python packages
uv sync- Configure environment variables
cp .env.example .env
# Edit .env and fill in the required credentials- Set up PostgreSQL
./scripts/setup-postgres.sh- Start the service
uv run python -m src.mainCopy .env.example to .env and configure the following:
| Variable | Description | Required |
|---|---|---|
CATGIRL_NAME |
Bot display name (default: 香草) | No |
LINE_EMAIL |
LINE account email | Yes |
LINE_PASSWORD |
LINE account password | Yes |
OPENAI_API_KEY |
OpenAI API key | Yes |
OPENAI_API_ENDPOINT |
Custom OpenAI API endpoint | No |
TAVILY_API_KEY |
Tavily API key for web search | Yes |
POSTGRES_URL |
PostgreSQL connection string | Yes |
LANGFUSE_SECRET_KEY |
Langfuse secret key | No |
LANGFUSE_PUBLIC_KEY |
Langfuse public key | No |
LANGFUSE_HOST |
Langfuse host URL | No |
LOG_LEVEL |
Logging level (default: INFO, set to DEBUG for verbose output) | No |
make help # Show all available commands| Command | Description |
|---|---|
make setup |
Full setup (packages + env + PostgreSQL) |
make install |
Install Python packages |
make install-dev |
Install with dev dependencies |
make setup-env |
Create .env from .env.example |
make setup-postgres |
Install and configure PostgreSQL |
| Command | Description |
|---|---|
make run |
Start the service |
make dev |
Full setup and start |
make bg |
Run in background |
make stop |
Stop background process |
make logs |
View background logs |
| Command | Description |
|---|---|
make test |
Run tests |
make test-cov |
Run tests with coverage report |
make test-ui |
Start interactive test UI |
| Command | Description |
|---|---|
make lint |
Run linting |
make lint-fix |
Fix linting issues |
make format |
Format code |
make clean |
Clean cache and build files |
vanilla/
├── src/
│ ├── linepy/ # LINE client library
│ │ ├── client/ # Client and login functionality
│ │ ├── e2ee/ # End-to-end encryption
│ │ ├── obs/ # Object storage (media)
│ │ ├── server/ # FastAPI server
│ │ ├── services/ # Talk and Square services
│ │ ├── storage/ # Storage backends
│ │ └── thrift/ # Thrift protocol
│ ├── bot.py # ChatBot class
│ ├── graph.py # LangGraph workflow
│ ├── helpers.py # Helper functions and nodes
│ ├── main.py # Entry point
│ ├── preferences.py # User preferences store
│ ├── prompts.py # Prompt templates
│ ├── scheduler.py # Task scheduler
│ ├── search.py # Tavily search
│ ├── tools.py # LangChain tools
│ └── types.py # Type definitions
├── tests/ # Test files
│ ├── linepy/ # linepy module tests
│ └── ...
├── scripts/ # Setup scripts
├── pyproject.toml # Project configuration
├── Makefile # Make commands
└── .env.example # Environment variables template
┌─────────────────────────────────────────────────────────────────────────────┐
│ LINE Server │
│ (Square Chat / Talk) │
└─────────────────────────────────────────────────────────────────────────────┘
│
┌─────────┴─────────┐
│ Thrift Protocol │
│ (HTTP/HTTPS) │
└─────────┬─────────┘
│
┌─────────────────────────────────────────────────────────────────────────────┐
│ linepy/ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ LineClient │ │
│ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────────────┐ │ │
│ │ │ TalkService │ │ SquareService │ │ E2EE (Encryption) │ │ │
│ │ │ - sync() │ │ - fetchEvents │ │ - encrypt/decrypt │ │ │
│ │ │ - sendMsg() │ │ - sendMessage │ │ - key management │ │ │
│ │ └───────────────┘ └───────────────┘ └───────────────────────┘ │ │
│ │ │ │
│ │ ┌───────────────────────────────────────────────────────────────┐ │ │
│ │ │ Event Listeners (asyncio) │ │ │
│ │ │ _listen_talk() ←──┬──→ _listen_square() │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ emit("message") │ emit("message") │ │ │
│ │ └──────────┬───────────┴────────────┬───────────────────────────┘ │ │
│ └─────────────┼────────────────────────┼──────────────────────────────┘ │
│ │ │ │
└────────────────┼────────────────────────┼───────────────────────────────────┘
│ │
└──────────┬─────────────┘
│
┌─────▼─────┐
│ asyncio │
│ Queue │
└─────┬─────┘
│
┌───────────────────────────┼──────────────────────────────────────────────────┐
│ │ vanilla/ │
│ ┌─────▼─────┐ │
│ │ ChatBot │ (src/bot.py) │
│ │ _process_ │ │
│ │ _message()│ │
│ └─────┬─────┘ │
│ │ │
│ ┌─────────────────┼─────────────────┐ │
│ │ │ │ │
│ ┌─────▼─────┐ ┌──────▼──────┐ ┌──────▼──────┐ │
│ │ LangGraph │ │ Scheduler │ │PostgreSQL │ │
│ │ Workflow │ │ Message │ │Checkpointer │ │
│ └─────┬─────┘ └─────────────┘ └─────────────┘ │
│ │ │
│ ┌─────▼─────────────────────────────────────────────┐ │
│ │ Graph Nodes │ │
│ │ ┌────────────────────┐ ┌────────────────┐ ┌───────────────┐ │
│ │ │ updateChatInfo │→ │addReaction │→ │ chat │ │
│ │ │ - Check Messages │ │ - Add Reaction │ │ - AI Response │ │
│ │ │ - Check Status │ │ - LLM │ │ - Tools │ │
│ │ │ - Check Condition │ │ │ │ - LLM │ │
│ │ └────────────────────┘ └────────────────┘ └───────────────┘ │
│ └───────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────▼─────┐ │
│ │ Tools │ │
│ │- websearch│ │
│ │- datetime │ │
│ │- schedule │ │
│ │- prefs │ │
│ └───────────┘ │
└──────────────────────────────────────────────────────────────────────────────┘
| Message Type | Trigger Condition | Description |
|---|---|---|
| Text | @mention or reply |
Triggered when @mentioned or replying to bot's message |
| Sticker | reply only |
Only triggered when replying to bot's message |
| Image/Video/Audio/File | Not triggered | Logged but no response generated |
Message Received
│
▼
┌─────────────────────┐
│ updateChatInfo │
│ - Check Messages │
│ - Check Status │
│ - Check Condition │
└──────────┬──────────┘
│
┌─────┴─────┐
│ Trigger? │
└─────┬─────┘
No │ Yes
▼ │ ▼
End │ ┌──────────────────────┐
│ │ Parallel Execution │
│ │ │
│ ▼ ▼
│ addReaction chat
│ │ │
│ ▼ ▼
│ Send Reaction Send Response
│ │ │
└───────┴──────────────────────┘
│
▼
End
- Message Reception: Received via
_listen_talk()or_listen_square() - Queue: Messages are queued for processing via asyncio.Queue
- updateChatInfo:
- Validate content type (only text and stickers processed)
- Update chat state and member information
- Check for mentions or replies
- Stickers only trigger when replying to bot's message
- addReaction (parallel): Select and apply emoji reaction
- chat (parallel): Generate AI response with persona
- Send Response: Reply via LINE API
A Rich-based terminal interface for direct LLM interaction and tool usage inspection:
make test-uiFeatures:
- Send messages and interact with the AI
- View AI responses
- Inspect tool usage and parameters
- Commands:
/help,/clear,/history,/tasks,/quit
# Run all tests
make test
# Run tests with coverage
make test-cov# Check code style
make lint
# Format code
make format- https://langchain-ai.github.io/langgraph/
- https://python.langchain.com/docs/introduction/
- https://docs.astral.sh/uv
- https://github.com/evex-dev/linejs
MIT