An AI-powered Discord bot and meeting transcript integration system for business information management.
- Meeting Transcript Processing: Automatically extract participants, projects, topics, tasks, and generate summaries from meeting transcripts using GPT-4.1-mini.
- Task Extraction: Detect and record explicitly assigned tasks with deadlines and assignees, linked back to meetings and members.
- Fuzzy Matching: Intelligently match extracted names to existing database records (supports full names, unique first names, and strips a bit of extra “noisy” text).
- File Watcher: Monitor a landing folder for new transcripts with an interactive renaming and routing flow.
- Discord Chatbot: Talk to Secretary AI in Discord to retrieve information (“What are my tasks?”, “Who is Sam Choong?”, “What did I miss?”) and perform allowed updates/creations.
- Agentic Tool Use: The chatbot decides which database tools to call, runs them, and answers based strictly on those results (no raw SQL from the model).
- Async Architecture: Built for performance with async database operations and API calls.
You can use either pip or uv. If you’re using uv, prefer running your app via uv run so it uses the right environment.
# Using pip + venv (recommended)
python -m venv .venv
.venv\Scripts\activate # on Windows
pip install -r requirements.txt
# Or using uv
uv pip install -r requirements.txtCopy .env.example to .env and fill in your credentials:
cp .env.example .envRequired environment variables:
DISCORD_TOKEN- Your Discord bot tokenOPENAI_API_KEY- Your OpenAI API keyDATABASE_URL- PostgreSQL connection string
# Start Discord bot
python main.py bot
# or with uv
uv run python main.py bot
# Start file watcher
python main.py watch
# or with uv
uv run python main.py watch
# Process a file directly
python main.py process landing/my_transcript.txtpython main.py bot # Start the Discord bot
python main.py watch # Start the file watcher
python main.py process FILE # Process a specific transcript
python main.py setup # Create/verify database tables
python main.py help # Show help- Mention the bot to chat:
@SecretaryAI ... - Example queries:
@SecretaryAI what are my current tasks?@SecretaryAI what did I miss in the last full committee meeting?@SecretaryAI who is Michael Huang?@SecretaryAI create a new task to review recruitment email copy, due next Friday, and assign it to me.@SecretaryAI add a project called "O-Week Preparation" and assign it to all executives.@SecretaryAI what time is it right now?
secretary-ai/
├── main.py # Main entry point
├── discord_bot/
│ └── bot.py # Discord bot and chat logic
├── transcript_integrator/
│ ├── __init__.py
│ ├── integrator.py # Main transcript processing engine
│ ├── models.py # SQLAlchemy database models
│ ├── database_tools.py # Async database tools used by the chatbot
│ └── file_watcher.py # File monitoring and renaming
├── landing/ # Drop transcript files here
│ ├── executive/
│ ├── projects_subcommittee/
│ ├── events_subcommittee/
│ ├── sponsorships_subcommittee/
│ ├── marketing_subcommittee/
│ ├── content-creation_subcommittee/
│ ├── hr_subcommittee/
│ ├── full/
│ └── unscheduled/
├── database-erd.txt # Database schema reference
├── requirements.txt
├── pyproject.toml
└── .env # Environment configuration
The system uses the following tables:
| Table | Description |
|---|---|
committee |
Organization members with Discord IDs and roles |
meeting |
Meeting records with summaries |
meeting_members |
Links meetings to attendees |
meeting_projects |
Links meetings to discussed projects |
meeting_topics |
Links meetings to discussion topics |
meeting_tasks |
Links meetings to assigned tasks |
projects |
Project information |
project_members |
Links projects to team members |
tasks |
Task records with deadlines |
task_members |
Links tasks to assignees |
topic |
Discussion topics |
The system supports the following meeting types:
executive- Executive Committee Meetingprojects_subcommittee- Projects Subcommittee Meetingevents_subcommittee- Events Subcommittee Meetingsponsorships_subcommittee- Sponsorships Subcommittee Meetingmarketing_subcommittee- Marketing Subcommittee Meetingcontent-creation_subcommittee- Content Creation Subcommittee Meetinghr_subcommittee- HR Subcommittee Meetingfull- Full Committee Meetingunscheduled- Unscheduled / Ad-hoc Meeting
- Drop a transcript file (
.txt) into thelanding/folder - The watcher detects the new file and prompts you:
- Select meeting type
- Enter meeting date (DD-MM-YYYY)
- Enter meeting name
- Choose destination subfolder
- File is renamed with
INGESTED_prefix and moved to the selected folder - Optionally run AI analysis to extract meeting information
- Member Extraction: Identifies participants from the transcript and matches them to committee members using fuzzy matching over full names and first names.
- Project Linking: Detects project mentions and links them to the meeting.
- Topic Identification: Extracts discussion topics, linking to existing topics or creating new ones if needed.
- Task Detection: Finds explicitly assigned tasks with deadlines and assignees (multiple assignees become multiple
task_membersrows). - Summary Generation: Creates a comprehensive meeting summary.
The system uses Python's difflib.get_close_matches() to handle:
- Typos and misspellings
- Name variations (plural/singular)
- Case differences
Default cutoffs:
- Members: 70% similarity
- Projects: 60% similarity
- Topics: 70% similarity
| Variable | Required | Default | Description |
|---|---|---|---|
DISCORD_TOKEN |
Yes | - | Discord bot token |
OPENAI_API_KEY |
Yes | - | OpenAI API key |
DATABASE_URL |
Yes | - | PostgreSQL connection URL |
OPENAI_MODEL |
No | gpt-4.1-mini |
OpenAI model to use |
DISCORD_PROXY |
No | - | Proxy for Discord connection |
DISCORD_TOKEN=your_discord_token_here
DATABASE_URL=postgresql://user:password@host:5432/database
OPENAI_API_KEY=sk-your-openai-key-here
OPENAI_MODEL=gpt-4.1-mini
# DISCORD_PROXY=socks5://127.0.0.1:7898pytest# Using black
black .
# Using ruff
ruff check --fix .The member name in the transcript doesn't closely match any names in the committee table. Either:
- Add the member to the database
- Use a name that more closely matches existing records
The database tables don't exist. Run:
python main.py setupIf you see an error like:
duplicate key value violates unique constraint "tasks_pkey"
Key (task_id)=(1) already exists.
the PostgreSQL identity/sequence for that table is out of sync with existing data. You can fix it by resetting the sequence to MAX(id) + 1, for example:
SELECT setval(
pg_get_serial_sequence('public.tasks', 'task_id'),
COALESCE((SELECT MAX(task_id) FROM public.tasks), 0) + 1,
false
);Repeat with the appropriate table/column (e.g. public.topic / topic_id, public.meeting / meeting_id) if you see similar errors there.
- Check that
DISCORD_TOKENis set correctly - Ensure the bot has been invited to your server with proper permissions
- Enable "Message Content Intent" in Discord Developer Portal
- If behind a firewall, set
DISCORD_PROXY
MIT License