{"id":15112392,"url":"https://github.com/arcward/disconcierge","last_synced_at":"2026-01-29T09:03:12.011Z","repository":{"id":257155639,"uuid":"857445696","full_name":"arcward/DisConcierge","owner":"arcward","description":"Self-hosted Discord bot powered by your own OpenAI Assistant, written in Go, with a TypeScript/React admin interface","archived":false,"fork":false,"pushed_at":"2025-03-16T18:41:35.000Z","size":1738,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-05T18:14:41.067Z","etag":null,"topics":["ai","assistant","assistant-chat-bots","chatbot","chatbot-application","discord","discord-api","discord-bot","go","golang","gpt","gpt-4","gpt-4o","openai","openai-assistants","react","typescript"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arcward.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-14T17:19:07.000Z","updated_at":"2025-03-16T18:41:39.000Z","dependencies_parsed_at":"2024-10-09T15:41:02.859Z","dependency_job_id":"fde997e9-eed9-4454-a0b3-6977b2536945","html_url":"https://github.com/arcward/DisConcierge","commit_stats":null,"previous_names":["arcward/disconcierge"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arcward%2FDisConcierge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arcward%2FDisConcierge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arcward%2FDisConcierge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arcward%2FDisConcierge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arcward","download_url":"https://codeload.github.com/arcward/DisConcierge/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247378139,"owners_count":20929297,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","assistant","assistant-chat-bots","chatbot","chatbot-application","discord","discord-api","discord-bot","go","golang","gpt","gpt-4","gpt-4o","openai","openai-assistants","react","typescript"],"created_at":"2024-09-26T00:44:31.814Z","updated_at":"2026-01-29T09:03:11.921Z","avatar_url":"https://github.com/arcward.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DisConcierge\n\nDisConcierge is a Discord bot that allows users to interact with\nOpenAI assistants via Discord slash commands. It also features a\nweb-based admin interface for configuration and monitoring.\n\n## Use Cases\n\nThis project was developed with two primary uses cases in mind:\n\n- **Community support**: Deploy DisConcierge in your community server to answer frequently asked questions,\n  provide documentation references, and help new members. The feedback system allows you to track\n  response quality and improve the assistant over time.\n\n- **Knowledge base access**: Configure your OpenAI assistant with relevant documentation/files and\n  give your community/channel access to your knowledge base (product/service info, internal processes, etc)\n  through natural language queries.\n\n## Features\n\n- Discord slash commands (`/chat` and `/private`) to interact with your OpenAI assistant\n- Web-based admin interface for configuration and monitoring\n- User-specific settings and rate limiting (command limits per 6 hours)\n  and the ability to prioritize/ignore specific users.\n- Feedback system for user responses (Discord message components that allow\n  users to indicate the bot's response was good/outdated/inaccurate, or to\n  provide specific feedback via text modal)\n- Configurable logging levels (adjustable \"live\" - no restart required)\n- Database logging of OpenAI API calls and Discord interactions\n- Support for both **SQLite** and **PostgreSQL** databases (*Note*: SQLite\n  is the default, and most tested. PostgreSQL support is experimental)\n\n![](./docs/disconcierge-256x256.png)\n\n## Prerequisites\n\n- Go 1.22 or later\n- Node.js 22 or later (for building the frontend)\n- Discord Bot Token and Application ID. These can be found in the [Discord dev portal](https://discord.com/developers/applications)\n  under your bot, in 'General Information' (application ID) and 'Bot' (token)\n- OpenAI API Token and Assistant ID (assistant IDs can be found in the\n  [playground](https://platform.openai.com/playground/assistants) under 'Assistants', \n  under the \"Name\" field of your assistant)\n\n## Configuration\n\nDisConcierge is primarily configured through environment variables, or\n`.env` files (by default `.env` in the current directory, or you can\nspecify one with `--config foo.env`).\n\nExample dotenv (also see [`.env.example`](./.env.example)):\n\n```env\n# General/database config\n\nDC_DATABASE=/home/foo/disconcierge.sqlite3\nDC_DATABASE_TYPE=sqlite\nDC_DATABASE_LOG_LEVEL=INFO\nDC_DATABASE_SLOW_THRESHOLD=200ms\nDC_LOG_LEVEL=INFO\nDC_STARTUP_TIMEOUT=30s\nDC_SHUTDOWN_TIMEOUT=60s\nDC_DEVELOPMENT=true\n\n# In-memory ChatCommand queue config\n\nDC_QUEUE_SIZE=100\nDC_QUEUE_MAX_AGE=3m\nDC_QUEUE_SLEEP_EMPTY=1s\nDC_QUEUE_SLEEP_PAUSED=5s\n\n# OpenAI config\n\nDC_OPENAI_TOKEN=your-assistant-token\nDC_OPENAI_LOG_LEVEL=INFO\nDC_OPENAI_ASSISTANT_ID=asst_foo\n\n# Discord bot config\n\nDC_DISCORD_TOKEN=your-discord-bot-token\nDC_DISCORD_APPLICATION_ID=your-discord-bot-app-id\nDC_DISCORD_GUILD_ID=\nDC_DISCORD_LOG_LEVEL=WARN\nDC_DISCORD_DISCORDGO_LOG_LEVEL=WARN\nDC_DISCORD_STARTUP_MESSAGE=\"I'm here!\"\nDC_DISCORD_GATEWAY_INTENTS=3243773\n\n# Discord webhook server\n\nDC_DISCORD_WEBHOOK_SERVER_ENABLED=false\nDC_DISCORD_WEBHOOK_SERVER_LISTEN=127.0.0.1:5001\nDC_DISCORD_WEBHOOK_SERVER_SSL_CERT_FILE=/etc/ssl/cert.pem\nDC_DISCORD_WEBHOOK_SERVER_SSL_KEY_FILE=/etc/ssl/cert.key\nDC_DISCORD_WEBHOOK_SERVER_SSL_TLS_MIN_VERSION=771\nDC_DISCORD_WEBHOOK_SERVER_LOG_LEVEL=INFO\nDC_DISCORD_WEBHOOK_SERVER_PUBLIC_KEY=your_discord_public_key_here\nDC_DISCORD_WEBHOOK_SERVER_READ_TIMEOUT=5s\nDC_DISCORD_WEBHOOK_SERVER_READ_HEADER_TIMEOUT=5s\nDC_DISCORD_WEBHOOK_SERVER_WRITE_TIMEOUT=10s\nDC_DISCORD_WEBHOOK_SERVER_IDLE_TIMEOUT=30s\n\n# API server\n\nDC_API_LISTEN=127.0.0.1:5000\nDC_API_EXTERNAL_URL=https://127.0.0.1:5000\nDC_API_SSL_CERT_FILE=/etc/ssl/cert.pem\nDC_API_SSL_KEY_FILE=/etc/ssl/key.pem\nDC_API_SSL_TLS_MIN_VERSION=771\nDC_API_SECRET=your-api-secret\nDC_API_LOG_LEVEL=INFO\nDC_API_CORS_ALLOW_ORIGINS=https://127.0.0.1:5000 https://localhost:5000\nDC_API_CORS_ALLOW_METHODS=GET POST PUT PATCH DELETE OPTIONS HEAD\nDC_API_CORS_ALLOW_HEADERS=Origin Content-Length Content-Type Accept Authorization X-Requested-With Cache-Control X-CSRF-Token X-Request-ID\nDC_API_CORS_EXPOSE_HEADERS=Content-Type Content-Length Accept-Encoding X-Request-ID Location ETag Authorization Last-Modified\n\nDC_API_CORS_ALLOW_CREDENTIALS=true\nDC_API_CORS_MAX_AGE=12h\nDC_API_READ_TIMEOUT=5s\nDC_API_READ_HEADER_TIMEOUT=5s\nDC_API_WRITE_TIMEOUT=10s\nDC_API_IDLE_TIMEOUT=30s\nDC_API_SESSION_MAX_AGE=6h\n```\n\nHere's a list of all configuration options that can be specified\nas environment variables (* = required):\n\n### Database Configuration\n\n- *`DC_DATABASE_TYPE`: Database type (`sqlite` or `postgres`)\n- *`DC_DATABASE`: Database connection string or file path\n- `DC_DATABASE_SLOW_THRESHOLD`: Duration threshold for identifying slow database queries (default: \"200ms\")\n\n### Discord Configuration\n\n- *`DC_DISCORD_TOKEN`: Discord bot token\n- *`DC_DISCORD_APPLICATION_ID`: Discord application ID\n- `DC_DISCORD_GUILD_ID`: Discord guild ID for registering commands (leave empty for global commands)\n- `DC_DISCORD_LOG_LEVEL`: Log level for Discord operations\n- `DC_DISCORDGO_LOG_LEVEL`: Log level for the DiscordGo library\n- `DC_DISCORD_GATEWAY_INTENTS`: Set the gateway intents for the bot (default: 3243773)\n\n### OpenAI Configuration\n\n- *`DC_OPENAI_TOKEN`: OpenAI API token\n- *`DC_OPENAI_ASSISTANT_ID`: OpenAI Assistant ID\n- `DC_OPENAI_LOG_LEVEL`: Log level for OpenAI operations\n\n### API Server Configuration\n\n- *`DC_API_LISTEN`: API server listen address (default: \":5000\")\n- `DC_API_EXTERNAL_URL`: External URL for the API server. This is used in the\n  admin interface, and may be used by the bot to provide links to the admin\n  interface via Discord, if a notification channel is set.\n- `DC_API_SECRET`: Secret used to sign API session cookies\n- `DC_API_SSL_CERT_FILE`: Path to SSL certificate file\n- `DC_API_SSL_KEY_FILE`: Path to SSL key file\n- `DC_API_LOG_LEVEL`: Log level for API operations\n- `DC_API_SESSION_MAX_AGE`: Max age for session cookies (default: \"6h\")\n\n### CORS Configuration\n\n- `DC_API_CORS_ALLOW_ORIGINS`: Allowed origins for CORS\n- `DC_API_CORS_ALLOW_METHODS`: Allowed methods for CORS\n- `DC_API_CORS_ALLOW_HEADERS`: Allowed headers for CORS\n- `DC_API_CORS_EXPOSE_HEADERS`: Headers to expose for CORS\n- `DC_API_CORS_ALLOW_CREDENTIALS`: Allow credentials for CORS (default: true)\n- `DC_API_CORS_MAX_AGE`: Max age for CORS preflight requests (default: \"12h\")\n\n### Queue Configuration\n\n- `DC_QUEUE_SIZE`: Maximum queue size for chat commands\n- `DC_QUEUE_MAX_AGE`: Maximum age of a request in the queue\n- `DC_QUEUE_SLEEP_EMPTY`: Sleep duration when the queue is empty\n- `DC_QUEUE_SLEEP_PAUSED`: Sleep duration when the bot is paused\n\n### Miscellaneous Configuration\n\n- `DC_LOG_LEVEL`: General log level for the application\n- `DC_STARTUP_TIMEOUT`: Timeout for application startup\n- `DC_SHUTDOWN_TIMEOUT`: Timeout for graceful shutdown\n- `DC_DEVELOPMENT`: Enable development mode (default: false). Sets SameSite=None for session cookies.\n\n## Running the Application\n\n### Using Docker\n\n1. Build the Docker image:\n   ```shell\n   docker build -t disconcierge .\n   ```\n\n2. Run the container:\n   ```\n   docker run -p 5000:5000 -v /path/to/data:/data \\\n     -e DC_DISCORD_TOKEN=your_discord_token \\\n     -e DC_DISCORD_APPLICATION_ID=your_app_id \\\n     -e DC_OPENAI_TOKEN=your_openai_token \\\n     -e DC_OPENAI_ASSISTANT_ID=your_assistant_id \\\n     -e DC_API_SECRET=your_api_secret \\\n     disconcierge\n   ```\n\n### Build+Run Binary\n\nBoth the bot's backend and frontend compile to a single binary.\nTo compile, just run:\n\n```shell\n$ make all\n```\n\nSet the required environment variables (either via export or\nby dotfile, by default `.env` in your current directory) as described above.\n\nThen, create the database and set your admin credentials, followed by\nrunning the bot:\n\n```shell\n$ ./bin/disconcierge init\n ...\n$ ./bin/disconcierge run\n```\n\n## Usage\n\nOnce the bot is running and invited to your Discord server (or installed \nas a user app), you can interact with it using the following slash commands:\n\n- `/chat`: Start a conversation with the bot\n- `/private`: The same as `/chat`, but only the user invoking it can\n  see their message and the bot's response where they're executing it (ephemeral response).\n  The message/response is still logged in your configured DB by default.\n- `/clear`: Clears the conversation history / starts a new thread\n\nAccess the admin interface by navigating to `https://your-server:5000/disconcierge` in your web browser.\n\n**Note**: If your slash commands aren't showing up in Discord (after restarting\nyour client), you may need to register them again. This can be done in the\nadmin interface under \"Actions\" -\u003e \"Register Discord Commands\".\n\n## User Feedback System\n\nDisConcierge implements a user feedback system for your OpenAI assistant's responses, \nvia Discord message components (buttons and modals), allowing users to provide \neither quick feedback or more detailed feedback via a modal dialog.\n\nUser feedback is visible in the admin interface at `/disconcierge/user_feedback`\n(ex: `https://localhost:5000/disconcierge/user_feedback`), linked to the user's Discord ID\nand the `/chat` (or `/private`) command that was used:\n\n![](./docs/ui_feedback_detail.PNG)\n\n\n### Feedback Options\n\nAfter each `/chat` or `/private` response (assuming the command succeeded), \nusers are presented with the following feedback options:\n\n1. **Good**: Indicates the response was satisfactory.\n2. **Outdated**: Suggests the information provided is not up-to-date.\n3. **Inaccurate**: Indicates the response contains errors or hallucinations.\n4. **Other**: Allows users to provide custom feedback via a modal dialog.\n\n\n### Feedback Behavior\n\n- Feedback buttons are visible to all users in the channel, unless using\n  `/private` or using `/chat` in a DM to the bot.\n- Multiple users can provide feedback on the same response.\n- Feedback is stored individually for each user who responds.\n- When a user clicks a feedback button, a number on the button will increment\n  to confirm it was received, and to indicate the  number of users who have \n  selected that feedback option. Selecting a button more than once has no\n  effect. The exception to this rule is the \"*Other*\" button, which allows\n  a user to provide detailed feedback. The *Other* button will only be incremented\n  when the modal is submitted, and users can use this button multiple times.\n\n### Example Screenshots\n\nIn a \"private\" interaction (either via `/private` or using\n`/chat` in a DM to the bot) this is the initial state of the feedback buttons:\n\n![](./docs/feedback_initial.PNG)\n\nAfter clicking the feedback buttons, the labels are incremented to show\nthe number of users who have selected that feedback option:\n\n![](./docs/feedback_incremented.PNG)\n\n**Note**: Feedback buttons can be disabled entirely via the admin interface,\non the config page, under the *Discord User Feedback* section:\n\n![](./docs/ui_config_feedback.PNG)\n\n## Database Activity Logs\n\nDisConcierge maintains logs of interactions, activities, API calls, etc., in\nthe database you specify.\n\nThese provide some insight into the bot's operation and usage, including user \ninteractions, errors, OpenAI API calls being made (token usage, run steps, etc.), \nand more.\n\nThis generally helps with debugging, monitoring, and auditing the bot's behavior,\nor Discord/OpenAI behavior (such as if OpenAI runs are suddenly failing, or if\nDiscord interaction acknowledgments are timing out).\n\nThis *especially* helps if you're tweaking the assistant's instructions,\nthe files provided to the assistant, etc., and need to see whether the\nbot has had a change in feedback (such as users suddenly indicating\nresponses are inaccurate or outdated).\n\nHere's an overview of what's logged:\n\n### Discord Interactions\n\n- `discord_messages`: Logs specific Discord messages that mention the bot, \n  reply to the bot's interactions, or reference the bot's known slash commands. \n  Includes message content, user details, and context. This can be helpful to\n  determine if users are trying to @mention the bot to use it instead of\n  using the slash commands. These are available in the admin interface.\n- `interaction_logs`: Records all Discord interactions with the bot, including \n  slash commands and button clicks. Captures interaction type, user info, and payload data.\n  This can be helpful to debug errors in slash commands or button interactions that\n  encounter errors.\n- `chat_commands`: Logs details of `/chat` and `/private` slash command executions, \n  including user prompts, bot responses, and processing metadata. The processing\n  metadata allows the bot to pick up where it left off if it was interrupted\n  while processing a command. Discord interactions where the token has expired\n  will not be resumed, to avoid unnecessary token usage for interactions the\n  bot wouldn't be able to respond to anyway. This makes it safe to restart the\n  bot without abandoning in-progress interactions.\n- `clear_commands`: Tracks executions of the `/clear` slash command, \n  recording when users reset their conversation with the assistant. Also tracks\n  errors.\n- `user_feedback`: Records user feedback on the bot's responses, including \n  feedback type (good, bad, outdated, inaccurate, other), user details, \n  and the associated chat command.\n\n### OpenAI API Interactions\n\n- `openai_create_thread`: Logs the creation of new conversation threads in the OpenAI API.\n- `openai_create_message`: Records when new messages are added to OpenAI conversation threads.\n- `openai_create_run`: Logs the initiation of new runs (executions) in the OpenAI API.\n- `openai_retrieve_run`: Tracks retrievals of run status and results from the OpenAI API.\n- `openai_list_messages`: Records requests to list messages in an OpenAI conversation thread.\n- `openai_lits_run_steps`: Logs requests to list the steps of a specific run in the OpenAI API.\n\n### Accessing Logs\n\nSome of these records are currently available in the admin interface, while some\nare currently only available directly in the database.\n\n## Scaling/Multiple Instances / Webhook Support\n\nFor larger applications or scenarios requiring scalability, DisConcierge supports receiving\ninteractions via Discord webhooks. This can be used to run multiple instances of the same bot.\nIt's important to note that DisConcierge does *not* currently support sharding via Gateway connections.\n\nIf you just want to use webhooks instead of the gateway connection, that's\ncool too, just worry about the certs/configuration (although the bot won't appear online in Discord).\n\nThe gist of the process:\n\n1. Configure your Discord application to use webhooks for interactions in the Discord dev portal\n2. Set up your environment to route Discord webhook requests to your DisConcierge instance(s)\n3. Configure your instance(s) so they can handle+validate webhook requests\n4. If you're running multiple instances of the same bot, **use a PostgreSQL database**.\n   SQLite only supports a single writer at a time, and you know it!\n\n### Configuration\n\nThe DisConcierge webhook server can be enabled/configured via environment variables, or `.env` files.\n**Note**: The webhook server is disabled by default, and runs on a separate port from\nthe backend API server.\n\n```shell\nDC_DISCORD_WEBHOOK_ENABLED=true\nDC_DISCORD_WEBHOOK_LISTEN=127.0.0.1:5001\nDC_DISCORD_WEBHOOK_SSL_CERT_FILE=/etc/ssl/cert.pem\nDC_DISCORD_WEBHOOK_SSL_KEY_FILE=/etc/ssl/cert.key\nDC_DISCORD_WEBHOOK_PUBLIC_KEY=your_discord_bot_public_key\nDC_DISCORD_TOKEN=your_discord_token\nDC_DISCORD_APPLICATION_ID=your_discord_application_id\nDC_DISCORD_GUILD_ID=optional_discord_guild_id\n```\n\n### Considerations/Caveats for Multiple Instances\n\nIf you plan to run multiple instances of DisConcierge for the same Discord bot,\nthere are a few things to keep in mind.\n \n#### Use PostgreSQL\n\nUse a **PostgreSQL** database rather than SQLite.\n\n**SQLite doesn't support multiple writers, and you know it**\n\n**ಠ_ಠ**\n\n#### Configuration Updates\n\nConfiguration updates may not immediately propagate across all instances. \nThis is because each instance maintains a cache of its (database-backed) runtime \nconfiguration and user list. By default, the cache is refreshed every 5 minutes, and, when using postgres,\nupdating the configuration in the UI emits a `LISTEN/NOTIFY` signal to all instances, which\ntriggers an immediate refresh.\n\n#### Load Balancing\n\nUse a load balancer to distribute incoming webhook requests across your DisConcierge instances.\n\n#### Bot Status\n\nThe bot's online/offline and any custom status is set via the\nDiscord gateway. If the bot's gateway connection is enabled, then each instance\nwill set the bot's status independently as they connect. However, an update \nvia the admin interface _should_ only trigger a single update from the instance receiving \nthe update. If you disable the gateway connection, you avoid that scenario.\nAlternatively, you could run a single, separate instance with\nthe gateway connection enabled to manage the bot's status (though this would require\na separate database for its configuration).\n\n#### User command concurrency\n\nBy default, an instance of the bot will only allow\na user to run a single slash command at a time (similar to how ChatGPT requires you\nto wait until it's done before you can send another message). If you have multiple instances,\na user can potentially run as many commands concurrently as you have instances\n(a subsequent command will only be rejected if it's routed to an instance that's\nalready running a command for that same user). This potentially allows a user\nto exceed their 6-hour rate limit, as commands only count against that limit\nwhen they complete, or indicate token usage. (If a user is limited to\n10 `/chat` commands per 6 hours, and you have 20 instances, they could potentially\nrun 20 concurrent `/chat` commands, as they wouldn't yet be counted against the\nrate limit).\n\nThat said, the actual behavior in this case may be unpredictable, because\nthe OpenAI assistant API, while a run is in progress, is supposed to prevent\nnew messages from being added to existing threads, and prevent new runs from\nbeing created for the thread.\n\n\n#### OpenAI API Rate Limiting\n\nThe bot's internal rate limiter on the number\nof \"Create Run\" requests it can make per second via the OpenAI API is\nper-instance. If you set this limit at 1 request/second, and you have 10\ninstances, that's an effective limit of 10 requests/second. To maximize\nthis limit, set it according to your OpenAI API plan's rate limits and\nyour number of instances.\n\nAlso keep in mind that the bot currently maintains an in-memory cache of all users,\nwhich is loaded on startup and is periodically refreshed. This sets an upper limit on the \nnumber of users the bot can handle before encountering potential issues with database\nlatency during refreshes. Later on, support for a distributed cache (like Redis) may be added,\nbut until such a need arises, it's a bit overkill.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farcward%2Fdisconcierge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farcward%2Fdisconcierge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farcward%2Fdisconcierge/lists"}