Skip to main content

Embeddable chatbot widget that answers natural-language questions about your database.

Project description

db-chat-widget

Embeddable chatbot widget that lets end users ask natural-language questions about a SQL database and get back answers with the underlying query and data.

  • Any SQLAlchemy-compatible database: PostgreSQL, MySQL, SQLite, etc.
  • Pluggable LLM backend: Anthropic Claude, OpenAI, Groq, or a local Ollama model.
  • Read-only by default: generated SQL is parsed and only SELECT statements are allowed unless you explicitly opt into write access.
  • Embeddable widget: a small vanilla-JS chat component you can drop into any existing web page with a single <script> tag, backed by a FastAPI server.

Install

pip install "db-chat-widget[server]"

This includes every LLM provider (Anthropic, OpenAI, Groq, Ollama), every database driver (PostgreSQL, MySQL), and the standalone FastAPI server + CLI serve command used below. Pick which provider and database to use afterwards, at configuration time, via --llm-provider / Settings.llm_provider and --db-url / Settings.db_url.

If you only need the ChatEngine as a library — e.g. from django-db-chat-widget, which brings its own web layer — pip install db-chat-widget (without [server]) skips FastAPI/uvicorn/Jinja2 entirely.

Quickstart

export DB_CHAT_LLM_API_KEY=gsk_...   # your Groq API key

db-chat-widget serve \
  --db-url "postgresql://user:pass@localhost/mydb" \
  --llm-provider groq \
  --port 8000

(--llm-provider anthropic / openai work the same way, with the matching API key.)

Open http://127.0.0.1:8000 for a demo chat page, or embed the widget in your own site.

Popup mode (floating chat bubble)

Drops a chat bubble launcher into the bottom-right corner of the page — the most common way to bolt this onto an existing template with zero markup changes. Clicking it opens/closes the chat panel.

<link rel="stylesheet" href="http://127.0.0.1:8000/static/widget.css" />
<script
  src="http://127.0.0.1:8000/static/widget.js"
  data-mode="bubble"
  data-api-url="http://127.0.0.1:8000/api/chat"
  data-title="Ask about our data"
></script>

Use data-position="bottom-left" to anchor it to the bottom-left instead.

Inline mode

Embeds the chat panel directly into an element already on the page, instead of floating:

<link rel="stylesheet" href="http://127.0.0.1:8000/static/widget.css" />
<div id="my-db-chat"></div>
<script
  src="http://127.0.0.1:8000/static/widget.js"
  data-target="#my-db-chat"
  data-api-url="http://127.0.0.1:8000/api/chat"
  data-title="Ask about our data"
></script>

Programmatic API

Both modes are also available from JavaScript, e.g. after dynamically injecting the script, or to control the popup (.open() / .close()):

<script src="http://127.0.0.1:8000/static/widget.js"></script>
<script>
  const chat = DBChatWidget.init({
    mode: "bubble", // or "inline" (requires `target`)
    apiUrl: "http://127.0.0.1:8000/api/chat",
    title: "Ask about our data",
    position: "bottom-right", // or "bottom-left"
  });
  // chat.open(); chat.close(); chat.ask("How many orders today?");
</script>

See examples/embed_example.html and examples/demo_app.py for a runnable, self-contained example with a seeded SQLite database.

Using it as a library

from db_chat_widget import ChatEngine, Settings

settings = Settings(
    db_url="sqlite:///mydb.sqlite",
    llm_provider="groq",
    llm_api_key="gsk_...",
    read_only=True,       # default: only SELECT statements are allowed
    max_rows=200,          # cap on rows returned per query
    allowed_tables=None,   # optionally restrict which tables can be queried
)

engine = ChatEngine(settings)
result = engine.ask("How many orders were placed last month?")

print(result.answer)
print(result.sql)
print(result.rows)

To mount just the FastAPI app (e.g. behind your own ASGI server or reverse proxy):

from db_chat_widget.config import Settings
from db_chat_widget.server.app import create_app

app = create_app(Settings(db_url="...", llm_provider="openai", llm_api_key="..."))

How it works

  1. The database schema (tables, columns, types, foreign keys) is introspected via SQLAlchemy and sent to the configured LLM as context.
  2. The LLM is asked to translate the user's question into a single SQL SELECT statement (or reply CANNOT_ANSWER).
  3. The generated SQL is parsed with sqlglot and rejected if it contains anything other than a single read-only SELECT (no INSERT/UPDATE/ DELETE/DROP/multiple statements/disallowed tables).
  4. The query is executed with a row limit and the result, generated SQL, and a short natural-language summary are returned to the widget.

Default encoding

MySQL/MariaDB servers commonly default their client connection to latin1, which mangles accented characters (e.g. French text) unless the client asks for UTF-8 explicitly. When your db_url is a MySQL URL without a charset query parameter, db-chat-widget automatically connects with charset=utf8mb4:

mysql+pymysql://user:pass@localhost:3306/mydb
# connects as:
mysql+pymysql://user:pass@localhost:3306/mydb?charset=utf8mb4

If your URL already specifies a charset (e.g. ?charset=latin1), it is left untouched. Other database backends (PostgreSQL, SQLite) already default to UTF-8 and are not affected.

Safety notes

  • read_only=True (the default) is enforced at the SQL-parsing level, not just by prompting the model — treat it as the actual security boundary.
  • Use allowed_tables to scope the chatbot to specific tables (e.g. exclude a users/secrets table containing sensitive columns).
  • The demo server enables permissive CORS (*) for convenience; pass cors_origins=[...] (or --cors-origin on the CLI) to restrict this in production.
  • Run the database user backing db_url with least-privilege, read-only grants where possible, as defense in depth.

Development

pip install -e ".[dev]"
pytest
ruff check .

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

db_chat_widget-0.1.0.tar.gz (20.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

db_chat_widget-0.1.0-py3-none-any.whl (24.5 kB view details)

Uploaded Python 3

File details

Details for the file db_chat_widget-0.1.0.tar.gz.

File metadata

  • Download URL: db_chat_widget-0.1.0.tar.gz
  • Upload date:
  • Size: 20.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for db_chat_widget-0.1.0.tar.gz
Algorithm Hash digest
SHA256 7b3fe2d4fa7c3b455adb6769c1c9e3ed481aaa5af0b7b9cba48a2bf6a7fbf5f0
MD5 8ab089dcfcb53e64802df581c791a84c
BLAKE2b-256 224497eeeb78c60496d63f635e5cc61d39c5e5810d1e1b30c152317843463f4d

See more details on using hashes here.

File details

Details for the file db_chat_widget-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: db_chat_widget-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 24.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for db_chat_widget-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fb0f8361f231757151bbd1effb25c8c9bbe24b4b7edba7d9547156248ffd3520
MD5 16183b23f0d8abee3ac87f4641f3b4e9
BLAKE2b-256 88cbcebf3d62e9eddb554364e07778ea5c884d2aa19c18804e8777960e7e4b41

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page