AI analytics assistant framework — connect your database, get natural language querying
Project description
saas-graph
Connect your database. Get an AI analyst. Ship in a day.
A Python framework for SaaS companies that want to add a natural-language analytics assistant to their product. You provide your database connection and a schema description — saas-graph handles query understanding, schema-aware retrieval, SQL generation with retry loops, result formatting, and real-time streaming.
Quick Start
pip install saas-graph[openai,postgres,server]
1. Start a database
cd examples/ecommerce
docker compose up -d
This starts a local PostgreSQL with sample e-commerce data: 50 products, 200 customers, 500 orders, and ~1,500 order items.
2. Set your environment
export OPENAI_API_KEY=sk-...
export DATABASE_URL=postgresql://ecommerce:ecommerce@localhost:5432/ecommerce
3. Run the example
import asyncio
import os
from saas_graph import NLQPipeline, DomainConfig
from saas_graph.contrib.openai import OpenAIGateway
from saas_graph.contrib.postgres import PostgresExecutor
async def main():
executor = PostgresExecutor(os.environ["DATABASE_URL"])
pipeline = NLQPipeline(
llm=OpenAIGateway(api_key=os.environ["OPENAI_API_KEY"]),
executor=executor,
domain=DomainConfig(
name="ecommerce",
description="E-commerce platform with products, orders, and customers",
schema_path="schema_context.yaml",
column_display_names={
"total_amount": "Total ($)",
"line_total": "Line Total ($)",
"price": "Price ($)",
"revenue": "Revenue ($)",
"lifetime_value": "LTV ($)",
},
),
)
result = await pipeline.query("What are my top 10 products by revenue this quarter?")
print(result.response)
print(result.sql)
await executor.close()
asyncio.run(main())
Or run the example directly:
cd examples/ecommerce
python main.py
Example output
| Rank | Product Name | Total Revenue |
|------|------------------------------|---------------|
| 1 | 27" 4K Monitor | $4,949.89 |
| 2 | Adjustable Dumbbell Pair | $2,999.80 |
| 3 | Running Sneakers | $2,759.77 |
| 4 | Noise Cancelling Earbuds | $2,549.83 |
| 5 | Smart Watch Fitness Tracker | $2,199.89 |
| ... | ... | ... |
4. FastAPI server
from fastapi import FastAPI
from saas_graph import NLQPipeline, DomainConfig
from saas_graph.contrib.openai import OpenAIGateway
from saas_graph.contrib.postgres import PostgresExecutor
from saas_graph.server import create_router
app = FastAPI()
pipeline = NLQPipeline(
llm=OpenAIGateway(api_key="sk-..."),
executor=PostgresExecutor("postgresql://ecommerce:ecommerce@localhost:5432/ecommerce"),
domain=DomainConfig(
name="ecommerce",
schema_path="schema_context.yaml",
),
)
app.include_router(create_router(pipeline), prefix="/api")
This gives you:
POST /api/chat— non-streaming queryPOST /api/chat/stream— SSE streaming with thinking events
Architecture
User Question
│
▼
┌──────────┐ ┌───────────┐ ┌──────────────┐
│ Clarifier │────▶│ Router │────▶│ Schema Linker│
│ (optional)│ │int / ext │ │ semantic RAG │
└──────────┘ └───────────┘ └──────────────┘
│ external │
▼ ▼
┌──────────┐ ┌──────────────┐
│Web Search│ │ Planner │
└──────────┘ │ (optional) │
│ └──────────────┘
│ │
│ ▼
│ ┌──────────────┐
│ │SQL Generator │◀─── retry with
│ │ (LLM-based) │ error feedback
│ └──────────────┘
│ │
│ ▼
│ ┌──────────────┐
│ │ Executor │
│ │ (database) │
│ └──────────────┘
│ │
▼ ▼
┌─────────────────────────────┐
│ Formatter │
│ (LLM markdown formatting) │
└─────────────────────────────┘
│
▼
Formatted Response
Each node is a standalone async callable. The pipeline runs as a LangGraph state graph — or falls back to a pure-Python executor when LangGraph isn't installed.
Schema Context
Describe your database in schema_context.yaml:
tables:
products:
description: "Product catalog"
columns:
product_id: { type: integer, description: "Unique product ID" }
name: { type: text, description: "Product name" }
category: { type: text, description: "Product category" }
price: { type: numeric, description: "Current price in dollars" }
orders:
description: "Customer orders"
columns:
order_id: { type: integer, description: "Unique order ID" }
customer_id: { type: integer, description: "FK to customers" }
order_date: { type: timestamp, description: "When the order was placed" }
status: { type: text, description: "pending, shipped, delivered, returned" }
total_amount: { type: numeric, description: "Order total in dollars" }
joins:
- { to: customers, on: "customer_id = customer_id", type: LEFT }
business_rules:
- name: exclude_cancelled
trigger_terms: [orders, revenue, sales]
sql_condition: "status != 'cancelled'"
description: "Exclude cancelled orders from revenue/sales metrics by default"
golden_queries:
- name: top_products_by_revenue
question: "What are the top selling products by revenue?"
sql: |
SELECT p.name, SUM(oi.line_total) as revenue
FROM order_items oi
JOIN products p ON oi.product_id = p.product_id
JOIN orders o ON oi.order_id = o.order_id
WHERE o.status != 'cancelled'
GROUP BY p.name
ORDER BY revenue DESC
LIMIT 10
tables: [order_items, products, orders]
Auto-generate the initial YAML from any PostgreSQL database:
saas-graph scan postgres://user:pass@host/db
Swappable Components
Every infrastructure component is behind an abstract interface:
| Component | Interface | Built-in Adapters |
|---|---|---|
| LLM | ILLMGateway |
OpenAIGateway |
| Database | IQueryExecutor |
PostgresExecutor |
| Embeddings | IEmbeddingService |
(bring your own) |
| Schema | ISchemaContextLoader |
YAMLSchemaLoader |
| Knowledge | IKnowledgeRepository |
(bring your own) |
| Cache | ICacheStore |
InMemoryCache |
| Sessions | ISessionStore |
InMemorySessionStore |
| Web Search | IWebSearchService |
(bring your own) |
Installation
# Minimal (just the framework)
pip install saas-graph
# With OpenAI + PostgreSQL
pip install saas-graph[openai,postgres]
# With FastAPI server
pip install saas-graph[openai,postgres,server]
# Everything
pip install saas-graph[all]
License
Apache 2.0 — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file saas_graph-0.1.0.tar.gz.
File metadata
- Download URL: saas_graph-0.1.0.tar.gz
- Upload date:
- Size: 44.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4783e3222b0ad828822a9c6ce137cae8142df8eb99358b70e7ae84d142628bb2
|
|
| MD5 |
47238dd8d4fb8e9ee92f24b0d908a92a
|
|
| BLAKE2b-256 |
a7b20073a26b61bf69a645690731431cca54e90decb6fdcf89d452a42782246d
|
File details
Details for the file saas_graph-0.1.0-py3-none-any.whl.
File metadata
- Download URL: saas_graph-0.1.0-py3-none-any.whl
- Upload date:
- Size: 57.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ca3891ae2afed91d28ef888ce5f577ecaa9b4195f665a23a3cbe63fc1f305b3a
|
|
| MD5 |
27957bd1179e011804778b0a425d4a89
|
|
| BLAKE2b-256 |
5c060ed6ec7f4379377c9ca316034435fe558fe15e589ecbfd0fa1c1b835bda0
|