Metadata-Version: 2.4
Name: pyds-ai
Version: 0.1.0
Summary: Data science and LLM work from a notebook, without writing much code. The LLM writes the query and the words; a deterministic engine computes the answer.
Project-URL: Homepage, https://github.com/pyds-ai/pyds-ai
Project-URL: Documentation, https://github.com/pyds-ai/pyds-ai#readme
Project-URL: Issues, https://github.com/pyds-ai/pyds-ai/issues
Author: pyds-ai contributors
License: Apache-2.0
License-File: LICENSE
Keywords: agents,automl,data science,duckdb,llm,notebook,pandas,rag
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: Jupyter
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Requires-Dist: duckdb>=0.10
Requires-Dist: httpx>=0.27
Requires-Dist: jinja2>=3.1
Requires-Dist: pandas>=2.0
Requires-Dist: pydantic>=2.0
Requires-Dist: tomli-w>=1.0
Requires-Dist: tomli>=2.0; python_version < '3.11'
Provides-Extra: all
Requires-Dist: anthropic>=0.34; extra == 'all'
Requires-Dist: beautifulsoup4>=4.12; extra == 'all'
Requires-Dist: chromadb>=0.5; extra == 'all'
Requires-Dist: google-genai>=0.3; extra == 'all'
Requires-Dist: joblib>=1.3; extra == 'all'
Requires-Dist: markdown-it-py>=3.0; extra == 'all'
Requires-Dist: openai>=1.40; extra == 'all'
Requires-Dist: pypdf>=4.0; extra == 'all'
Requires-Dist: python-docx>=1.1; extra == 'all'
Requires-Dist: python-pptx>=0.6.23; extra == 'all'
Requires-Dist: scikit-learn>=1.3; extra == 'all'
Requires-Dist: shap>=0.44; extra == 'all'
Requires-Dist: weasyprint>=61; extra == 'all'
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.34; extra == 'anthropic'
Provides-Extra: gemini
Requires-Dist: google-genai>=0.3; extra == 'gemini'
Provides-Extra: ml
Requires-Dist: joblib>=1.3; extra == 'ml'
Requires-Dist: scikit-learn>=1.3; extra == 'ml'
Requires-Dist: shap>=0.44; extra == 'ml'
Provides-Extra: openai
Requires-Dist: openai>=1.40; extra == 'openai'
Provides-Extra: rag
Requires-Dist: beautifulsoup4>=4.12; extra == 'rag'
Requires-Dist: markdown-it-py>=3.0; extra == 'rag'
Requires-Dist: pypdf>=4.0; extra == 'rag'
Requires-Dist: python-docx>=1.1; extra == 'rag'
Provides-Extra: rag-chroma
Requires-Dist: chromadb>=0.5; extra == 'rag-chroma'
Provides-Extra: rag-faiss
Requires-Dist: faiss-cpu>=1.8; extra == 'rag-faiss'
Provides-Extra: rag-pgvector
Requires-Dist: pgvector>=0.2; extra == 'rag-pgvector'
Requires-Dist: psycopg[binary]>=3.1; extra == 'rag-pgvector'
Provides-Extra: report
Requires-Dist: python-docx>=1.1; extra == 'report'
Requires-Dist: python-pptx>=0.6.23; extra == 'report'
Requires-Dist: weasyprint>=61; extra == 'report'
Provides-Extra: test
Requires-Dist: pytest>=8.0; extra == 'test'
Description-Content-Type: text/markdown

# pyds-ai

Data science and LLM work from a notebook, without writing much code.

```bash
pip install pyds-ai
```

**The one rule that decides everything: the LLM never produces a number.
It writes the query and it writes the words. A deterministic engine
(DuckDB) computes the answer.** Every result can show you the exact code
that produced it via `result.code()`.

## Quickstart

```python
import pyds_ai as pyds

pyds.setup()  # one-time key wizard, writes to ~/.pyds_ai/config.toml

d = pyds.load("sales.csv")
d.ask("which region grew fastest last quarter?")
d.chart("revenue by month, split by channel")

m = d.model(target="churn")
m.explain()
m.what_if(tenure=12, plan="premium")

k = pyds.knowledge("policies/")
k.ask("what is our refund window for enterprise?")

a = pyds.agent(uses=[d, k])
a.ask("did churn spike in any region where we changed the refund policy?")

e = pyds.evaluate(a, cases="qa_cases.csv")
e.watch()
```

## Every result is the same shape

Every call returns a `Result` — never a bare DataFrame, never a dict:

```python
result.explain()   # what was done and why, in sentences
result.code()       # the exact SQL/code that produced it
result.data()       # the underlying DataFrame
result.next()       # up to three suggested follow-up questions
result.why()        # trace: prompt version, model, cost, row counts
result.save(path)   # .html, .csv, .docx, .pptx, .pdf
```

A failed call returns a `Failure` (also a `Result`) instead of a raw
traceback: what broke, what it looked like, and the one-line fix to try.

## Privacy default

`send_data_values = false` by default: the model gets column names, types
and summary statistics, not your raw rows. Your data does not leave the
building unless you explicitly opt in. Set it via:

```python
import pyds_ai as pyds
cfg = pyds.config.load_config()
cfg["privacy"]["send_data_values"] = True
pyds.config.save_config(cfg)
```

## Installing extras

```bash
pip install pyds-ai[ml]          # AutoML: scikit-learn (+ joblib, shap)
pip install pyds-ai[rag]         # RAG: pdf/docx/html parsing
pip install pyds-ai[rag-chroma]  # persistent vector store (Chroma)
pip install pyds-ai[rag-faiss]   # in-process ANN vector store (FAISS)
pip install pyds-ai[rag-pgvector]# Postgres + pgvector vector store
pip install pyds-ai[report]      # result.save(): .pptx, .docx, .pdf
pip install pyds-ai[anthropic]   # or [openai], [gemini] — Ollama needs no extra
pip install pyds-ai[all]
```

Importing a missing extra returns a friendly message with the exact pip
command, never a bare `ImportError`. The default `pyds.knowledge()` vector
store is a zero-dependency in-memory hashing embedder — RAG works the
moment `pyds-ai[rag]` is installed, no embedding API call required.

## Plugins

Internal teams can register a company database reader or a private model
provider without forking, via entry points:

```toml
[project.entry-points."pyds.providers"]
internal = "mycompany.pyds_plugin:InternalLLM"
```

Anything registered under the `pyds.providers` group is picked up by
`pyds.setup(provider="internal")` / `pyds.config.get_llm_client()` the
same way the four built-in providers are.

## Development

```bash
git clone <this repo> && cd pyds-ai
python -m venv .venv && .venv/Scripts/activate   # or source .venv/bin/activate
pip install -e ".[all,test]"
pytest
```

The test suite runs fully offline: a fake LLM client (`tests/support.py`)
stands in for every provider, so no API key or network access is needed
to validate the package.

## Publishing (maintainers)

```bash
python -m pip install --upgrade build twine
python -m build            # writes dist/*.whl and dist/*.tar.gz
twine check dist/*
twine upload dist/*        # or: twine upload --repository testpypi dist/*
```

## License

Apache-2.0 — see [LICENSE](LICENSE).
