GyanSpark
Send student chat exchanges to the GyanBeej knowledge graph backend, and get back a ready-to-inject summary of what's known about that student — their misconceptions, strengths, and strategies — to ground your own LLM's next reply.
GyanSpark never touches your LLM calls. You call OpenAI, Anthropic, Gemini, or whatever you like yourself, however you like. This is a thin, explicit client for two backend calls, not a proxy or wrapper around your LLM client.
from gyanspark import GyanSpark
gs = GyanSpark() # reads GYANSPARK_API_KEY from the environment
turn = gs.fill_kg(chat_history, "Which one is cosine again?", roll_number="A-101", name="Jane Doe")
print(turn.context.context_block if turn.context else "(new student, nothing recorded yet)")
fill_kg() resolves the student, fires the actual knowledge-graph write in
the background, and — for a student who already exists — hands back a
ready-to-inject context summary in that same call, no separate read call
needed.
Contents
- Install
- Quick start
- How fill_kg works
- API
- Configuration
- Environment variables
- Error handling
- Testing this repo
- License
Install
pip install gyanspark
Requires Python 3.9+.
Quick start
from gyanspark import GyanSpark
# Reads the key from GYANSPARK_API_KEY if not passed explicitly.
# Construct once per process and reuse across every student.
gs = GyanSpark()
# You make your own LLM call, however you like:
history = [{"role": "user", "content": "I keep mixing up sine and cosine."}]
ai_reply = call_your_llm(history) # your own code
history.append({"role": "assistant", "content": ai_reply})
# One call: resolves identity, fires the KG write in the background, and —
# for a student who already exists — returns a context summary right away.
turn = gs.fill_kg(history, "Which one is cosine again?", roll_number="A-101", name="Jane Doe")
student_id = turn.student_id # capture this — reuse it on future calls
if turn.context is not None:
print(turn.context.context_block) # ready to paste into your next LLM prompt
else:
print("brand-new student — nothing recorded yet to summarize")
# Optional: check on the background write later (never block on this).
status = gs.check_call(turn.call_id)
See examples/basic_usage.py for a complete
runnable version.
How fill_kg works
fill_kg does three things in one call:
- Resolves identity synchronously — fast (Redis-cached, no LLM call):
student_idif you have it, elseroll_number(+nameto auto-create if the student doesn't exist yet). - Fires the actual knowledge-graph write in the background and returns
immediately — the real classification pipeline (2 sequential Gemini
calls) takes 7–45s, so this never blocks the caller. Use
check_callto look up what happened to it later; you don't have to. - For a student who already exists, calls
get_context()synchronously and returns it asturn.context— ready to use for this reply. A brand-new student has nothing recorded yet, so this step is skipped:turn.contextisNoneandturn.is_new_studentisTrue.
turn = gs.fill_kg(history, next_query, student_id=known_id)
# turn.context is ready to use right now for this reply.
# The write is already running in the background — nothing to wait on.
# Whenever convenient (e.g. on the student's next message), check it:
status = gs.check_call(turn.call_id)
if status.status == "failed":
log.warning("fill_kg write failed: %s", status.error)
Even if you never call check_call, a failed write is still logged
automatically (via the SDK's own logger) — so it's never silent, just
non-blocking.
API
student_id / roll_number are per-call arguments, not constructor
arguments — build one GyanSpark() instance per process and share it across
every student your server handles concurrently.
gs.fill_kg(chat_history, query, student_id=None, roll_number=None, name=None, prev_ai="", recent_prompt_timestamp=None, top_n=15, directive=None) -> TurnResult
chat_history— the exchange that just completed (your student's prior prompt + your AI's reply), written to the graph in the background.query— the student's new, not-yet-answered message; what the synchronous context summary (for existing students) is fetched for.- At least one of
student_id/roll_numberis required, same as before.prev_ai/directiveare passed straight through to the internalget_context()call. - Returns a
TurnResult:student_id,is_new_student— capturestudent_idfor future calls.context— aContextResultfor an existing student,Nonefor a brand-new one (nothing recorded yet to summarize).call_id— pass tocheck_call()to look up the background write's outcome whenever you want.
- Raises if the identity-resolve step (step 1 above) fails — this is
synchronous and blocks the rest of the call, so it raises the same way
the old blocking write used to:
ValidationError— bad input, caught before any network call.AuthenticationError— invalid/deactivated API key (401/403).GyanSparkTimeoutError/GyanSparkConnectionError— network failure.GyanSparkAPIError— any other non-2xx response.- The background write itself never raises here — see
check_call.
gs.check_call(call_id) -> CallResult
Looks up a background write kicked off by fill_kg() (or a Future from
fill_kg_async(), tracked the same way). Returns CallResult with
status — "pending", "succeeded" (result set, a FillKGResult with
the same status/summaries shape the old blocking write returned), or
"failed" (error set, same exceptions the old blocking write would have
raised — auth failures, timeouts, the backend's own pipeline errors, etc.).
Raises ValidationError for an unrecognized call_id.
Caveat: this registry lives in the calling process's memory only — a
call_id isn't checkable from a different worker process/replica. Fine for
a single-process deployment; don't rely on it across multiple workers.
gs.fill_kg_async(...) -> concurrent.futures.Future[FillKGResult]
Lower-level primitive: fires the raw knowledge-graph write in the
background and returns its Future directly — no identity-resolve step,
no context fetch, for callers who want manual control instead of
fill_kg()'s all-in-one orchestration. Same student_id/roll_number
semantics as before (roll_number still auto-creates a student
server-side). Exceptions are stored on the Future and only raised when
you call .result().
gs.get_context(student_id, query, prev_ai="", directive=None) -> ContextResult
Calls POST /user-context/statements. Built for the hot path.
- Returns a
ContextResultwithcontext_block(a string ready to paste into your next LLM prompt,""if nothing's available),ok(whether the call actually succeeded), anderror(populated whenok=False). - Never raises for a backend/network failure — a timeout, connection
error, or non-2xx response degrades to
ok=Falsewith an emptycontext_block. - Still raises
ValidationErrorfor bad input andAuthenticationErrorfor a bad API key — a silently-empty context forever because of a misconfigured key would be a worse failure mode than a loud one.
Configuration
gs = GyanSpark(
api_key=None, # falls back to GYANSPARK_API_KEY env var
base_url=None, # falls back to GYANSPARK_BASE_URL env var, then https://api.gyanspark.com
fill_kg_timeout=45, # seconds — real KG analysis (2 sequential Gemini calls + writes)
context_timeout=5, # seconds — backend's <1-2s SLA plus margin
)
Environment variables
| Variable | Required | Purpose |
|---|---|---|
GYANSPARK_API_KEY |
Yes, unless passed to GyanSpark(api_key=...) |
Your org's API key (from knowledge-graph-gb's create_organisation.py) |
GYANSPARK_BASE_URL |
No | Overrides the default backend URL — set this for local testing, e.g. http://localhost:8000 |
See .env.example.
Error handling
Identity resolve (fill_kg's synchronous step) |
Background write (check_call) |
Read (get_context) |
|
|---|---|---|---|
| Bad input | raises ValidationError |
n/a — never reaches the network | raises ValidationError |
| Bad/deactivated API key | raises AuthenticationError |
status="failed", error set |
raises AuthenticationError |
| Timeout / connection error | raises GyanSparkTimeoutError / GyanSparkConnectionError |
status="failed", error set |
degrades — ok=False |
| Other non-2xx | raises GyanSparkAPIError |
status="failed", error set |
degrades — ok=False |
| Backend pipeline error inside a 200 | n/a | status="failed", error set |
n/a |
fill_kg()'s identity-resolve step raises synchronously — it blocks the
rest of the call, so a failure there needs to be loud immediately. The
background write never raises to the caller; check check_call() if you
want to know its outcome (a failure is also always logged automatically,
even if you never check). The read path degrades gracefully because
missing context is a soft failure — the student's conversation shouldn't
break over it. Auth failures are the one case that's never silent anywhere
in this table, since a bad key degrading silently would go unnoticed
indefinitely.
Testing this repo
From a checkout of the source repository:
pip install -e ".[dev]"
pytest
Unit tests mock the HTTP layer (requests_mock) — no live backend needed.
For end-to-end testing against a real knowledge-graph-gb instance, see
smoke_test_AZOPAI.py / smoke_test.py / smoke_test_claude.py (each needs
its own LLM provider key plus a real GYANSPARK_API_KEY).
License
MIT — see LICENSE.
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 gyanspark-0.1.0.tar.gz.
File metadata
- Download URL: gyanspark-0.1.0.tar.gz
- Upload date:
- Size: 22.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
35cfa2f169327ae4ea1b291abde3ef9133330cfd30bcb8f03325587426485c85
|
|
| MD5 |
9979f1bd70dd3e49e352bb40630a04b1
|
|
| BLAKE2b-256 |
9c8127563ae1ba5c40ebd0cd17d6c15d2c00897c819f3d668572ec8f2bf8c7ef
|
File details
Details for the file gyanspark-0.1.0-py3-none-any.whl.
File metadata
- Download URL: gyanspark-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d1a53e910eb09bca24e011c2bbc2b9c7eec7f96a8c271222939c0bfeaae48c19
|
|
| MD5 |
2213e81f34da98d26f53eb1decc81082
|
|
| BLAKE2b-256 |
0fbc254bece5e52347a6288ddc8a371398a0e44b680f347865b48045356937fb
|