GPT Oracle Discord Bot
GPT and DALL·E inside Discord, built Lite for small servers and Ultra to scale.A dual-tier Discord AI bot built for fast, clean, command-driven UX: Lite keeps setup dead simple with local key storage, Ultra moves keys to a remote SQL database for secure multi-user scale.
- Year
- 2024
- Role
- Development
- Built with
- PythonDiscordOpenAI APISQL

Two builds, one clean command line
GPT Oracle is a dual-tier Discord AI bot built for fast, clean, command-driven UX. Lite keeps setup dead simple with locally stored API keys for solo users and small servers. Ultra moves key management to a remote SQL database, for secure, concurrent use and smooth performance on large servers.
The commands
!save_key
Stores your OpenAI key once, locally in Lite or in your own SQL database in Ultra, so it is never pasted again.
!ask
Puts any question to GPT and answers in the channel, split cleanly across Discord's message limit.
!draw
Turns a prompt into an image with DALL·E, straight into the conversation.
Never blocks
Calls run off the event loop with a typing indicator, so the bot stays responsive while it thinks.
@bot.command()async def ask(ctx, *, question): # Get the API key for the author of the message api_key = await get_api_key(ctx.message.author.id) if not api_key: await ctx.send(f"{ctx.author.mention}, No API key found for your account. Please save your API key using the !save_key command.") return if bot.is_first_message: await ctx.send("Attention all! This is a fresh instance of the bot, so previous conversations have been forgotten!") bot.is_first_message = False loop = asyncio.get_event_loop() # Create a task for showing the typing indicator typing_task = bot.loop.create_task(typing_indicator(ctx)) try: # Run receive_input in the executor to avoid blocking the event loop replies = await loop.run_in_executor(executor, receive_input, api_key, question) for reply in replies: mention = f"{ctx.author.mention}, " # Split the reply into chunks and send each one separately for part in get_chunks(reply, limit=2000-len(mention)): await ctx.send(mention + part) except Exception as e: await ctx.send(f"{ctx.author.mention}, An error occurred: {str(e)}") finally: # Ensure the typing indicator is cancelled even if an error occurs typing_task.cancel()The !ask command: look up the caller's key, show typing, answer off the event loop, and chunk the reply under Discord's limit.
