diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..8b1752a052d5db1256b7b15db2533f052854e826 100644 --- a/.gitattributes +++ b/.gitattributes @@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text *.zip filter=lfs diff=lfs merge=lfs -text *.zst filter=lfs diff=lfs merge=lfs -text *tfevents* filter=lfs diff=lfs merge=lfs -text +*.sqlite3 filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..f72fff0aff5cc4b4331aecff029d71208d528e8d --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +.env +__pycache__/ +*.pyc +*.pyo +data/raw/ +data/enrichment_cache.jsonl +data/corpus.jsonl +artifacts/gepa_logs/ +artifacts/gepa_state.bin +artifacts/*.log +Gita-advisor/ +sources_local/ +sources/ +.DS_Store diff --git a/README.md b/README.md index 46cd47ee9035d4c5b289824ab0c1883ebb8e8466..d6ba72d21b7c8eabdcdbbfd55913394a1abeb3a5 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,125 @@ --- title: Gita Advisor -emoji: 📊 -colorFrom: indigo -colorTo: green +emoji: 🕉️ +colorFrom: yellow +colorTo: orange sdk: gradio -sdk_version: 6.13.0 +sdk_version: 5.33.0 app_file: app.py pinned: false -license: mit -short_description: 'Bhagvad Gita Spiritual Advisor ' --- -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference +# Gītā Advisor + +A spiritual advisor grounded in Advaita Vedānta as taught by Śaṅkarācārya, +optimized via DSPy + GEPA against a local LM Studio model. The advisor takes +real-life questions or vents and produces responses that are empathetic to +the felt experience, faithful to the non-dual lineage, and grounded in +exact-cited verses from the Gītā with Śaṅkara's bhāṣya, the principal +Upaniṣads, the Brahma Sūtras, and the prakaraṇa-granthas. + +## What makes this design unusual + +The first unusual choice is that the unit of retrieval is the verse, not +the chunk. Scripture is not arbitrary prose: each Gītā śloka, each +Upaniṣadic mantra, each sūtra is a sealed teaching unit with a stable +citation reference. We index by `verse_id` (e.g. `bhagavad_gita_02_47`, +which renders as `BG 2.47` in citations) so the advisor's references can be +exact-match-verified against the retrieved set. + +The second unusual choice is that we use the local LLM, in a one-time +offline pass, to enrich each verse with structured fields a real person's +question can match against. A user does not write "I am experiencing +rāga toward kāmya-karma"; they write "I worked on this for three years and +it just failed." So we ask the local model, for each verse, to produce a +plain-English paraphrase, the Vedāntic themes engaged, the life situations +addressed, the emotions met, the practical teaching offered, and five +hypothetical first-person questions the verse would speak to. We then +embed three views of each verse — the literal translation, Śaṅkara's +bhāṣya, and the LLM-enriched advisor view — and at retrieval time query +all three and merge by verse ID. + +The advisor view dominates retrieval because that is where the language +gap closes. The literal and bhāṣya views act as insurance against the +enrichment pipeline missing a topic. + +## Where the texts come from + +Every source is unambiguously open. The verse-indexed JSON at +`github.com/gita/gita`, released under the Unlicense, gives us Sanskrit +plus IAST transliteration plus word-by-word glosses for the Gītā. Alladi +Mahadeva Sastry's 1897 translation of Śaṅkara's Gītā Bhāṣya, in the public +domain and full-text on archive.org, gives us Śaṅkara's commentary +attached to each verse. The wisdomlib mirror of the *Sacred Books of the +East* is staged for the Upaniṣad-with-Śaṅkara texts and the Brahma Sūtra +bhāṣya; those parsers are registered but not yet implemented. See +`sources_registry.py` for the complete catalog and `CLAUDE.md` for the +licensing rationale. + +We deliberately exclude the modern Advaita Ashrama translations (active +copyright), modern Ramaṇa and Nisargadatta editions, and Prabhupada's +commentary. If you have your own license-cleared copies, drop them in +`sources_local/` and the `plain_text` parser will fold them in. + +## Pipeline of commands + +```bash +pip install -r requirements.txt + +# 1. Download the registered open sources to data/raw// +python download_sources.py + +# 2. Parse + merge into data/corpus.jsonl (one verse per line) +python ingest_corpus.py + +# 3. Enrich every verse via the local LLM. SLOW — overnight. +# Resumable; kill -9 is safe (append-mode cache). +python enrich_corpus.py --limit 50 # smoke-test the prompt first +python enrich_corpus.py # then the real run + +# 4. Build the three-view Chroma index +python knowledge_base.py --build + +# 5. Try a query against the index +python knowledge_base.py --query "I just got laid off and feel hollow" + +# 6. Smoke-test the full advisor pipeline +python smoke_test.py "I just got laid off and feel hollow" + +# 7. Generate the synthetic question dataset and run GEPA +python dataset_generator.py --n 500 +python optimize_gepa.py --auto medium + +# 8. Open the chat CLI +python chat.py +``` + +## Project structure + +The project is laid out so the data flow is left-to-right through the +pipeline: each script reads what the previous one wrote, with all +intermediate state on disk so any stage can be re-run independently. The +data model lives in `corpus.py` (`Verse` and `EnrichedVerse` dataclasses) +and is the contract between modules. The advisor itself is a `dspy.Module` +that GEPA optimizes; the metric in `metrics.py` is the specification GEPA +optimizes against, combining rule-based hygiene checks with an LLM-judge +rubric and producing structured feedback for GEPA's reflection step. See +`CLAUDE.md` for the full file map and the design commitments that should +not be silently broken. + +## Configuration + +`config.py` reads a small number of environment variables. The two that +matter most are `LM_STUDIO_BASE` (defaults to `http://localhost:1234/v1`) +and `LOCAL_MODEL` (defaults to `google/gemma-4-26b-a4b`, but copy whatever +LM Studio reports verbatim). The embedding model defaults to BGE-small on +Apple Silicon's MPS device; switch `EMBED_DEVICE` to `cpu` if you are not +on Apple Silicon. + +## License + +The code in this repository is yours to use. The texts in `data/raw/` come +with their own licenses, all unambiguously open and tracked in +`sources_registry.py`. Attributions for translators are preserved through +the pipeline and surfaced in citation footers. +# gita_advisor diff --git a/advisor.py b/advisor.py new file mode 100644 index 0000000000000000000000000000000000000000..04c6441a4711c198122fc09c24c4362a8eba2b67 --- /dev/null +++ b/advisor.py @@ -0,0 +1,157 @@ +""" +advisor.py — the composed DSPy module. + +This is what GEPA optimizes. It chains four predictors: + + UnderstandQuery → PlanRetrieval → [retrieve] → SelectPassages → SynthesizeAdvice + +Each predictor uses ChainOfThought so GEPA has a `reasoning` field to inspect +in its reflection step. The retriever itself is not optimized (it's vector +search), but the *queries given to it* are — that's where PlanRetrieval lives. +""" + +from __future__ import annotations +import json +from dataclasses import dataclass +from typing import Any +import dspy + +from signatures import ( + UnderstandQuery, + PlanRetrieval, + SelectPassages, + SynthesizeAdvice, +) +from knowledge_base import AdvaitaRetriever, format_passages_for_llm +import config + + +@dataclass +class AdviceTrace: + """Everything the pipeline produced — useful for the metric to reason over.""" + user_question: str + felt_emotion: str + surface_concern: str + deeper_concern: str + vedantic_themes: list[str] + queries: list[str] + retrieved_passages: list[dict] # raw hits with metadata + selected_indices: list[int] + selection_rationale: str + response: str + sources_cited: list[str] + + +class GitaAdvisor(dspy.Module): + def __init__(self, retriever: AdvaitaRetriever | None = None): + super().__init__() + self.understand = dspy.ChainOfThought(UnderstandQuery) + self.plan = dspy.ChainOfThought(PlanRetrieval) + self.select = dspy.ChainOfThought(SelectPassages) + self.synthesize = dspy.ChainOfThought(SynthesizeAdvice) + # Retriever is not a Predictor; held as a plain attribute so DSPy + # introspection ignores it during optimization. + self._retriever = retriever or AdvaitaRetriever() + + def forward( + self, + user_question: str, + history: dspy.History | None = None, + _stage_cb=None, + ) -> dspy.Prediction: + if history is None: + history = dspy.History(messages=[]) + + # 1. Understand — history lets it interpret follow-ups correctly + if _stage_cb: + _stage_cb("understanding your question...") + u = self.understand( + history=history, + user_question=user_question, + ) + + # 2. Plan retrieval queries + if _stage_cb: + _stage_cb("planning search queries...") + p = self.plan( + surface_concern=u.surface_concern, + deeper_concern=u.deeper_concern, + vedantic_themes=u.vedantic_themes, + ) + queries = p.queries[: config.N_RETRIEVAL_QUERIES] if p.queries else [u.deeper_concern] + + # 3. Retrieve + if _stage_cb: + _stage_cb("searching scriptures...") + hits = self._retriever.search_many(queries, k_per=config.TOP_K_RETRIEVE) + # Cap candidate set so the selector prompt stays focused + candidates = hits[: max(8, config.TOP_K_RETRIEVE)] + candidates_text = format_passages_for_llm(candidates) + # Pre-serialize hits to dicts so the dspy.Prediction we return below + # can be pickled by GEPA's bookkeeping. The metric reads from these + # dicts, not from Hit objects, so it doesn't need the knowledge_base + # import either. + candidates_as_dicts = [h.to_dict() for h in candidates] + + # 4. Select — tell the selector what's already been cited so it prefers fresh sources + if _stage_cb: + _stage_cb("selecting passages...") + previously_cited = [ + src + for msg in history.messages + for src in msg.get("sources_cited", []) + ] + s = self.select( + deeper_concern=u.deeper_concern, + candidate_passages=candidates_text, + previously_cited=previously_cited, + ) + # Defensive: clamp indices to valid range + valid_idx = [ + i for i in (s.selected_indices or []) + if isinstance(i, int) and 1 <= i <= len(candidates) + ] + if not valid_idx: + # Fallback: take the top-3 candidates so synthesis isn't starved + valid_idx = list(range(1, min(4, len(candidates) + 1))) + + selected = [candidates[i - 1] for i in valid_idx] + selected_text = format_passages_for_llm(selected) + + # 5. Synthesize — history lets it build across turns, avoid repetition + if _stage_cb: + _stage_cb("composing response...") + a = self.synthesize( + history=history, + user_question=user_question, + felt_emotion=u.felt_emotion, + deeper_concern=u.deeper_concern, + selected_passages=selected_text, + ) + + return dspy.Prediction( + response=a.response, + sources_cited=a.sources_cited or [], + synthesis_reasoning=getattr(a, "reasoning", ""), + # Carry intermediate state for the metric / debugging: + felt_emotion=u.felt_emotion, + surface_concern=u.surface_concern, + deeper_concern=u.deeper_concern, + vedantic_themes=u.vedantic_themes, + queries=queries, + retrieved_passages=candidates_as_dicts, + selected_indices=valid_idx, + selection_rationale=s.selection_rationale, + ) + + +def load_optimized(path: str | None = None) -> GitaAdvisor: + """Load an advisor with GEPA-optimized prompts if available, else fresh.""" + advisor = GitaAdvisor() + p = path or str(config.OPTIMIZED_PROGRAM_PATH) + try: + advisor.load(p) + print(f"Loaded optimized advisor from {p}") + except FileNotFoundError: + print(f"No optimized program at {p} — using base prompts.") + return advisor diff --git a/app.py b/app.py new file mode 100644 index 0000000000000000000000000000000000000000..6c2e9147841408581bd0ae4a01fe31d5da5e66bc --- /dev/null +++ b/app.py @@ -0,0 +1,72 @@ +""" +app.py — Gradio web interface for the Gītā Advisor. + +Wraps the same advisor pipeline as chat.py but exposes it as a Gradio +ChatInterface suitable for Hugging Face Spaces (free CPU tier). + +Deploy: + - Set GEMINI_API_KEY as a Space Secret (Space Settings → Secrets) + - Push this file + all project files + artifacts/chroma/ + data/corpus_enriched.jsonl +""" + +import gradio as gr +import dspy + +import config +from advisor import load_optimized +from knowledge_base import AdvaitaRetriever + +# ── startup — runs once when the Space boots ─────────────────────────────────── +config.configure_dspy() +_advisor = load_optimized() + +# Pre-warm retriever so the first user request isn't slow +_retriever = AdvaitaRetriever() +_retriever._ensure() + + +# ── chat handler ─────────────────────────────────────────────────────────────── +def chat(message: str, history: list) -> str: + # Gradio type="messages" passes history as list of {"role": ..., "content": ...} + dspy_msgs = [] + i = 0 + while i + 1 < len(history): + user_msg = history[i] + bot_msg = history[i + 1] + if user_msg.get("role") == "user" and bot_msg.get("role") == "assistant": + dspy_msgs.append({ + "user_question": user_msg["content"], + "response": bot_msg["content"], + "sources_cited": [], + }) + i += 2 + dspy_history = dspy.History(messages=dspy_msgs) + + pred = _advisor(user_question=message, history=dspy_history) + + reply = pred.response + if pred.sources_cited: + reply += "\n\n---\n**Sources:** " + " · ".join(pred.sources_cited) + return reply + + +# ── Gradio app ───────────────────────────────────────────────────────────────── +demo = gr.ChatInterface( + fn=chat, + title="Gītā Advisor", + description=( + "A spiritual advisor grounded in Advaita Vedānta as taught by Śaṅkarācārya. " + "Speak from where you actually are. The advisor cites exact verses from the " + "Gītā with Śaṅkara's commentary." + ), + type="messages", + examples=[ + "I just got laid off and feel like nothing makes sense.", + "I'm terrified of dying. Is that irrational?", + "I keep hurting the people I love without meaning to.", + "I've been meditating for years but still feel empty. What am I missing?", + ], +) + +if __name__ == "__main__": + demo.launch() diff --git a/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/data_level0.bin b/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/data_level0.bin new file mode 100644 index 0000000000000000000000000000000000000000..6544968d71e197a5f2c287e898fb35a88a45e122 --- /dev/null +++ b/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/data_level0.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e83b9e9a3e97ce6dc11715a48ebb2e9bc6f5b24f91c82d3fbc8d6b46085afb44 +size 1174876 diff --git a/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/header.bin b/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/header.bin new file mode 100644 index 0000000000000000000000000000000000000000..05883250299fa5033d3005af71d077ddbe31719a --- /dev/null +++ b/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/header.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:90261dc9d8649c19b95dcba5fa4ef3bb2f5a64b26da0aefc9e58ba7a3f2fcbe0 +size 100 diff --git a/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/index_metadata.pickle b/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/index_metadata.pickle new file mode 100644 index 0000000000000000000000000000000000000000..a7b8072f2250931a38eb52da260ca569308723be --- /dev/null +++ b/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/index_metadata.pickle @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b626b118ac6ec87f4d2ecdb13193aa4eaadc0514fe351c284c77edcc0b491fea +size 40786 diff --git a/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/length.bin b/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/length.bin new file mode 100644 index 0000000000000000000000000000000000000000..48143f64ba9a525bf9dca40197bf4bf8c6f241ad --- /dev/null +++ b/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/length.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b57dc524397d289a5ec9f2dfd69bf88c097d397d354c600fff6cbd958cadda89 +size 2804 diff --git a/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/link_lists.bin b/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/link_lists.bin new file mode 100644 index 0000000000000000000000000000000000000000..47f7da1627b2f2ffb5ba41211e78d70616e7cc93 --- /dev/null +++ b/artifacts/chroma/1cb22ce3-5b5d-4ea7-84da-8e74f131266a/link_lists.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bdb3c70e56609aecebbde493e89cc3f2eff23d6375c762bca900dd5edc46738b +size 6204 diff --git a/artifacts/chroma/1f1f3474-209f-41fb-91d3-d45fd026fb05/data_level0.bin b/artifacts/chroma/1f1f3474-209f-41fb-91d3-d45fd026fb05/data_level0.bin new file mode 100644 index 0000000000000000000000000000000000000000..5edca25980f114fa5cc621acf8f77033d4cb7bfa --- /dev/null +++ b/artifacts/chroma/1f1f3474-209f-41fb-91d3-d45fd026fb05/data_level0.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:66cd81ca458bd620e24b378f6ce96e6d77ba4c8789d4ece914775c339be10e26 +size 167600 diff --git a/artifacts/chroma/1f1f3474-209f-41fb-91d3-d45fd026fb05/header.bin b/artifacts/chroma/1f1f3474-209f-41fb-91d3-d45fd026fb05/header.bin new file mode 100644 index 0000000000000000000000000000000000000000..effb48f6f27689353c65f7d65d720babc00524d6 --- /dev/null +++ b/artifacts/chroma/1f1f3474-209f-41fb-91d3-d45fd026fb05/header.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0e81c3b22454233bc12d0762f06dcca48261a75231cf87c79b75e69a6c00150 +size 100 diff --git a/artifacts/chroma/1f1f3474-209f-41fb-91d3-d45fd026fb05/length.bin b/artifacts/chroma/1f1f3474-209f-41fb-91d3-d45fd026fb05/length.bin new file mode 100644 index 0000000000000000000000000000000000000000..af9fb07fd21ff833eb4afa6fd8da65ab547cd493 --- /dev/null +++ b/artifacts/chroma/1f1f3474-209f-41fb-91d3-d45fd026fb05/length.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a12e561363385e9dfeeab326368731c030ed4b374e7f5897ac819159d2884c5 +size 400 diff --git a/artifacts/chroma/1f1f3474-209f-41fb-91d3-d45fd026fb05/link_lists.bin b/artifacts/chroma/1f1f3474-209f-41fb-91d3-d45fd026fb05/link_lists.bin new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/artifacts/chroma/52cdeb15-0631-44ed-8618-782f1d4d27bb/data_level0.bin b/artifacts/chroma/52cdeb15-0631-44ed-8618-782f1d4d27bb/data_level0.bin new file mode 100644 index 0000000000000000000000000000000000000000..77be4d43f44bb153ce023f49c8881e64bf07010e --- /dev/null +++ b/artifacts/chroma/52cdeb15-0631-44ed-8618-782f1d4d27bb/data_level0.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:201b998f2a013f78cea5960b05174ceffedbd046c4dfc10a8d2492ff8a1398a7 +size 167600 diff --git a/artifacts/chroma/52cdeb15-0631-44ed-8618-782f1d4d27bb/header.bin b/artifacts/chroma/52cdeb15-0631-44ed-8618-782f1d4d27bb/header.bin new file mode 100644 index 0000000000000000000000000000000000000000..effb48f6f27689353c65f7d65d720babc00524d6 --- /dev/null +++ b/artifacts/chroma/52cdeb15-0631-44ed-8618-782f1d4d27bb/header.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0e81c3b22454233bc12d0762f06dcca48261a75231cf87c79b75e69a6c00150 +size 100 diff --git a/artifacts/chroma/52cdeb15-0631-44ed-8618-782f1d4d27bb/length.bin b/artifacts/chroma/52cdeb15-0631-44ed-8618-782f1d4d27bb/length.bin new file mode 100644 index 0000000000000000000000000000000000000000..af9fb07fd21ff833eb4afa6fd8da65ab547cd493 --- /dev/null +++ b/artifacts/chroma/52cdeb15-0631-44ed-8618-782f1d4d27bb/length.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a12e561363385e9dfeeab326368731c030ed4b374e7f5897ac819159d2884c5 +size 400 diff --git a/artifacts/chroma/52cdeb15-0631-44ed-8618-782f1d4d27bb/link_lists.bin b/artifacts/chroma/52cdeb15-0631-44ed-8618-782f1d4d27bb/link_lists.bin new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/artifacts/chroma/8707047c-50b3-41ba-ad04-329e93917e30/data_level0.bin b/artifacts/chroma/8707047c-50b3-41ba-ad04-329e93917e30/data_level0.bin new file mode 100644 index 0000000000000000000000000000000000000000..40963bc26df65c6315d13f695e6c53a086f61190 --- /dev/null +++ b/artifacts/chroma/8707047c-50b3-41ba-ad04-329e93917e30/data_level0.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:121a03535f783813fa1ec964dd84095d2da0d83c0e5dad98955bdf0e252b33d8 +size 167600 diff --git a/artifacts/chroma/8707047c-50b3-41ba-ad04-329e93917e30/header.bin b/artifacts/chroma/8707047c-50b3-41ba-ad04-329e93917e30/header.bin new file mode 100644 index 0000000000000000000000000000000000000000..effb48f6f27689353c65f7d65d720babc00524d6 --- /dev/null +++ b/artifacts/chroma/8707047c-50b3-41ba-ad04-329e93917e30/header.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0e81c3b22454233bc12d0762f06dcca48261a75231cf87c79b75e69a6c00150 +size 100 diff --git a/artifacts/chroma/8707047c-50b3-41ba-ad04-329e93917e30/length.bin b/artifacts/chroma/8707047c-50b3-41ba-ad04-329e93917e30/length.bin new file mode 100644 index 0000000000000000000000000000000000000000..af9fb07fd21ff833eb4afa6fd8da65ab547cd493 --- /dev/null +++ b/artifacts/chroma/8707047c-50b3-41ba-ad04-329e93917e30/length.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a12e561363385e9dfeeab326368731c030ed4b374e7f5897ac819159d2884c5 +size 400 diff --git a/artifacts/chroma/8707047c-50b3-41ba-ad04-329e93917e30/link_lists.bin b/artifacts/chroma/8707047c-50b3-41ba-ad04-329e93917e30/link_lists.bin new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/data_level0.bin b/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/data_level0.bin new file mode 100644 index 0000000000000000000000000000000000000000..98f17502e1f321dfc283b566e1981a469c52be5c --- /dev/null +++ b/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/data_level0.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68a485ecde933131e39b14c078dc82c3e0e27454cdb837d76f4be92f00bef026 +size 1136328 diff --git a/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/header.bin b/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/header.bin new file mode 100644 index 0000000000000000000000000000000000000000..dc50d9b296c65c5197c56f286aae6d40751f733e --- /dev/null +++ b/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/header.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3ce56f617adc30c61cd845ab6c84720756b445d622b4bc3160ce70dc5ce91e7e +size 100 diff --git a/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/index_metadata.pickle b/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/index_metadata.pickle new file mode 100644 index 0000000000000000000000000000000000000000..0b9b42bde1191125aa4f50057fe8cf58a50f0307 --- /dev/null +++ b/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/index_metadata.pickle @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bde285e65f8c89d9d82ad8cd02cd29c9bfcbe7009e37a2ef50f2fc58dd630af1 +size 39452 diff --git a/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/length.bin b/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/length.bin new file mode 100644 index 0000000000000000000000000000000000000000..d2106001efe3aece36c341d13b80045d966972cb --- /dev/null +++ b/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/length.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:360e5acdc3007feb7ef856ed67807c4a8995beb723091091828f729ccba9dbcb +size 2712 diff --git a/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/link_lists.bin b/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/link_lists.bin new file mode 100644 index 0000000000000000000000000000000000000000..15f56a7531cd09f82f5f4fdf7773738099a86029 --- /dev/null +++ b/artifacts/chroma/9c71c1cd-5694-4e9f-abe6-12ba1e74225b/link_lists.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fef3ffac7707ea201b174e47e15c161162d3f38b6fdbeccc43aab1af3c35e617 +size 6044 diff --git a/artifacts/chroma/chroma.sqlite3 b/artifacts/chroma/chroma.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..8e19c6f850944aae506ebc6b8e586e34bbe2e918 --- /dev/null +++ b/artifacts/chroma/chroma.sqlite3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:acd63ba75ad75f6234302822709e44e8e560d80e120f31519c20f73d41821d22 +size 20459520 diff --git a/artifacts/chroma/d091e62b-3e8b-4cd6-842e-ff3411b384f5/data_level0.bin b/artifacts/chroma/d091e62b-3e8b-4cd6-842e-ff3411b384f5/data_level0.bin new file mode 100644 index 0000000000000000000000000000000000000000..263370125d4157d82f699599b1a33f350ed7062c --- /dev/null +++ b/artifacts/chroma/d091e62b-3e8b-4cd6-842e-ff3411b384f5/data_level0.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:88b9416504c97719067232f4ef2a042eb4015b033f8c4a3137cd90e9f2faa468 +size 167600 diff --git a/artifacts/chroma/d091e62b-3e8b-4cd6-842e-ff3411b384f5/header.bin b/artifacts/chroma/d091e62b-3e8b-4cd6-842e-ff3411b384f5/header.bin new file mode 100644 index 0000000000000000000000000000000000000000..effb48f6f27689353c65f7d65d720babc00524d6 --- /dev/null +++ b/artifacts/chroma/d091e62b-3e8b-4cd6-842e-ff3411b384f5/header.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0e81c3b22454233bc12d0762f06dcca48261a75231cf87c79b75e69a6c00150 +size 100 diff --git a/artifacts/chroma/d091e62b-3e8b-4cd6-842e-ff3411b384f5/length.bin b/artifacts/chroma/d091e62b-3e8b-4cd6-842e-ff3411b384f5/length.bin new file mode 100644 index 0000000000000000000000000000000000000000..af9fb07fd21ff833eb4afa6fd8da65ab547cd493 --- /dev/null +++ b/artifacts/chroma/d091e62b-3e8b-4cd6-842e-ff3411b384f5/length.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7a12e561363385e9dfeeab326368731c030ed4b374e7f5897ac819159d2884c5 +size 400 diff --git a/artifacts/chroma/d091e62b-3e8b-4cd6-842e-ff3411b384f5/link_lists.bin b/artifacts/chroma/d091e62b-3e8b-4cd6-842e-ff3411b384f5/link_lists.bin new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/artifacts/optimized_advisor.json b/artifacts/optimized_advisor.json new file mode 100644 index 0000000000000000000000000000000000000000..53eae5fe2ad92ab66b61252d6d9309868c40a1f2 --- /dev/null +++ b/artifacts/optimized_advisor.json @@ -0,0 +1,157 @@ +{ + "understand.predict": { + "traces": [], + "train": [], + "demos": [], + "signature": { + "instructions": "Read the user's life situation carefully, taking into account the full\nconversation so far. If there is prior exchange, use it to understand\nfollow-up messages, references like 'what you said earlier', or shifts in\nthe user's emotional state across turns. Identify the felt emotion, the\nunderlying spiritual concern (not just the surface complaint), and the\nVedāntic themes that are most relevant — drawing only from concepts native\nto Advaita Vedānta.", + "fields": [ + { + "prefix": "History:", + "description": "Prior turns as a list of message dicts with 'user_question' and 'response' keys. Empty history means this is the first message." + }, + { + "prefix": "User Question:", + "description": "The user's current message; may be a question, a vent, a follow-up, or a description of a situation." + }, + { + "prefix": "Reasoning:", + "description": "${reasoning}" + }, + { + "prefix": "Felt Emotion:", + "description": "The dominant emotion the user is experiencing, named precisely (e.g. 'anticipatory grief', not just 'sad')." + }, + { + "prefix": "Surface Concern:", + "description": "What the user is literally asking about, in one sentence." + }, + { + "prefix": "Deeper Concern:", + "description": "The underlying existential/spiritual concern — usually about identity, attachment, fear, dharma, or meaning — that the surface concern is a symptom of. One sentence." + }, + { + "prefix": "Vedantic Themes:", + "description": "2-4 Advaita-Vedānta concepts most relevant to this situation. Use Sanskrit terms with brief gloss, e.g. 'adhyāsa (superimposition of self onto roles)', 'vairāgya (dispassion)', 'sākṣī (witness consciousness)'." + } + ] + }, + "lm": null + }, + "plan.predict": { + "traces": [], + "train": [], + "demos": [], + "signature": { + "instructions": "Given the user's situation and identified themes, generate diverse search\nqueries to find relevant passages from the Advaita corpus (Bhagavad Gītā with\nŚaṅkara bhāṣya, Upaniṣads, Brahma Sūtras, prakaraṇa texts). Each query should\ntarget a different angle — one query about the philosophical principle,\none about a parallel situation in the texts, one about the practical\nteaching offered by the lineage.", + "fields": [ + { + "prefix": "Surface Concern:", + "description": "${surface_concern}" + }, + { + "prefix": "Deeper Concern:", + "description": "${deeper_concern}" + }, + { + "prefix": "Vedantic Themes:", + "description": "${vedantic_themes}" + }, + { + "prefix": "Reasoning:", + "description": "${reasoning}" + }, + { + "prefix": "Queries:", + "description": "3 distinct search queries (each 5-15 words). Vary in angle: principle, parallel, practice." + } + ] + }, + "lm": null + }, + "select.predict": { + "traces": [], + "train": [], + "demos": [], + "signature": { + "instructions": "From the retrieved candidate passages, select the ones that genuinely\nspeak to this user's situation. Prefer primary sources (Gītā verses,\nUpaniṣadic mantras, Śaṅkara's bhāṣya) over secondary or modern commentary\nwhen both are available. Reject passages that are merely topically adjacent\nbut don't address the actual spiritual concern. Avoid re-selecting passages\nwhose source was already cited in a prior turn — prefer fresh ground.", + "fields": [ + { + "prefix": "Deeper Concern:", + "description": "${deeper_concern}" + }, + { + "prefix": "Candidate Passages:", + "description": "Numbered candidate passages with source attribution." + }, + { + "prefix": "Previously Cited:", + "description": "Source references already cited in earlier turns of this conversation (e.g. ['BG 2.47', 'BG 18.66']). Prefer passages not on this list so the conversation covers new ground. Empty list on the first turn." + }, + { + "prefix": "Reasoning:", + "description": "${reasoning}" + }, + { + "prefix": "Selected Indices:", + "description": "Indices (1-based) of the 2-4 most relevant passages." + }, + { + "prefix": "Selection Rationale:", + "description": "One sentence per selection explaining why that passage speaks to this concern." + } + ] + }, + "lm": null + }, + "synthesize.predict": { + "traces": [], + "train": [], + "demos": [], + "signature": { + "instructions": "Compose a response that is grounded in Advaita Vedānta as taught by\nŚaṅkarācārya, empathetic to the user's felt experience, and practically\nuseful for their situation. Honor the two-truths distinction: meet the user\nin vyāvahārika (transactional reality) without ever denying the\npāramārthika (absolute) view. Cite specific verses/passages by reference,\nintegrate them into prose rather than dumping quotes, and keep wit gentle —\nlight around the cosmic predicament, never light about the user's pain.\n\nIf history has prior turns: do not repeat citations or teachings already\ngiven; build on or deepen what was said; acknowledge any shift the user has\nexpressed since the last turn. If the user is following up, open by briefly\nacknowledging the continuity before moving forward.", + "fields": [ + { + "prefix": "History:", + "description": "Prior turns as a list of message dicts with 'user_question' and 'response' keys. Use this to avoid repetition and to build across turns." + }, + { + "prefix": "User Question:", + "description": "${user_question}" + }, + { + "prefix": "Felt Emotion:", + "description": "${felt_emotion}" + }, + { + "prefix": "Deeper Concern:", + "description": "${deeper_concern}" + }, + { + "prefix": "Selected Passages:", + "description": "The selected passages with full source attribution." + }, + { + "prefix": "Reasoning:", + "description": "${reasoning}" + }, + { + "prefix": "Response:", + "description": "The advisor's reply to the user. 250-450 words. Open by acknowledging the felt experience. Move into the Vedāntic perspective. Cite at least one primary source (Gītā chapter:verse, Upaniṣad name + section, etc.). Close with a concrete practice or shift in perspective they can try this week. Address the user as 'you' throughout. Avoid Western therapy clichés." + }, + { + "prefix": "Sources Cited:", + "description": "Source references actually cited in the response, e.g. 'BG 2.47', 'Bṛhadāraṇyaka Up. 4.4.5', 'Vivekacūḍāmaṇi 11'." + } + ] + }, + "lm": null + }, + "metadata": { + "dependency_versions": { + "python": "3.11", + "dspy": "3.2.0", + "cloudpickle": "3.1" + } + } +} diff --git a/chat.py b/chat.py new file mode 100644 index 0000000000000000000000000000000000000000..594619469786c3492e6be62d50a4ea5042f8a333 --- /dev/null +++ b/chat.py @@ -0,0 +1,392 @@ +""" +chat.py — interactive conversation with the advisor. + +By default it loads the GEPA-optimized program from artifacts/. If that file +doesn't exist yet, it falls back to the un-optimized base prompts so you can +sanity-check the pipeline before running optimization. + +Flags: + --debug Show intermediate pipeline state (felt emotion, queries, etc.) + --thinking Show the full synthesis reasoning trace (default: first 6 lines) + --no-thinking Hide the reasoning trace entirely + +After each response, source references are printed with numbers. + show Display the verse text, translation, and Śaṅkara's bhāṣya. + explain Show the verse then stream a contextual explanation of how + it applies to the current conversation. +""" + +from __future__ import annotations +import argparse +import time +import threading +from typing import Optional + +import dspy +from rich.console import Console +from rich.live import Live +from rich.markdown import Markdown +from rich.panel import Panel +from rich.rule import Rule +from rich.text import Text + +import config +from advisor import load_optimized +from corpus import EnrichedVerse, Verse, read_jsonl_enriched, read_jsonl_verses + + +# ── speed constants ──────────────────────────────────────────────────────────── +_THINKING_CPS = 800 # chars/sec for reasoning stream (secondary content, fast) +_RESPONSE_CPS = 300 # chars/sec for advisor response (primary content) +_THINKING_PREVIEW = 6 # lines shown in collapsed thinking mode + + +# ── verse corpus lookup ──────────────────────────────────────────────────────── +def _load_verse_lookup() -> dict[str, Verse]: + """Build a case-insensitive verse_ref → Verse dict from the corpus.""" + lookup: dict[str, Verse] = {} + enriched = config.DATA_DIR / "corpus_enriched.jsonl" + plain = config.DATA_DIR / "corpus.jsonl" + + if enriched.exists(): + loader, path = read_jsonl_enriched, enriched + elif plain.exists(): + loader, path = read_jsonl_verses, plain + else: + return lookup + + for verse in loader(path): + lookup[verse.verse_ref.lower().strip()] = verse + return lookup + + +def _find_verse(lookup: dict, ref: str) -> Optional[Verse]: + return lookup.get(ref.lower().strip()) + + +def _resolve_ref(arg: str, sources_cited: list[str]) -> str: + """Turn '1' → sources_cited[0], or return arg unchanged for direct ref lookup.""" + try: + n = int(arg.strip()) + if 1 <= n <= len(sources_cited): + return sources_cited[n - 1] + except ValueError: + pass + return arg.strip() + + +# ── DSPy signature for contextual explanation ───────────────────────────────── +class _ExplainInContext(dspy.Signature): + """You are the Gītā Advisor continuing a conversation. The user has asked + you to unpack a specific verse or passage you cited. Explain what it means + and why it speaks precisely to their situation — go deeper than the initial + response did. Reference the user's words. Close with one concrete way to + hold or work with this text this week.""" + + verse_ref: str = dspy.InputField() + verse_content: str = dspy.InputField( + desc="Translation, original text (if available), and Śaṅkara's commentary." + ) + conversation_context: str = dspy.InputField( + desc="The user's question and the advisor's response where this verse was cited." + ) + + explanation: str = dspy.OutputField( + desc="150-250 words. Grounded in Advaita. Do not merely restate the translation. " + "End with a practical suggestion for this week." + ) + + +# ── streaming helpers ───────────────────────────────────────────────────────── +def _stream_chars(console: Console, text: str, cps: int): + """Write text to the terminal character by character.""" + if not text: + return + delay = 1.0 / cps + for ch in text: + console.file.write(ch) + console.file.flush() + time.sleep(delay) + console.file.write("\n") + console.file.flush() + + +def _stream_response(console: Console, text: str, cps: int = _RESPONSE_CPS): + """Stream the advisor response into a growing Markdown Panel via Rich Live.""" + if not text: + return + displayed = "" + delay = 1.0 / cps + with Live(console=console, refresh_per_second=min(cps, 30)) as live: + for ch in text: + displayed += ch + live.update(Panel( + Markdown(displayed), + title="[bold]advisor[/bold]", + border_style="yellow", + padding=(1, 2), + )) + time.sleep(delay) + + +def _show_thinking(console: Console, reasoning: str, full: bool): + """Stream the synthesis reasoning below a dim rule, collapsed to _THINKING_PREVIEW lines.""" + if not reasoning: + return + + lines = reasoning.strip().splitlines() + if not full and len(lines) > _THINKING_PREVIEW: + display = "\n".join(lines[:_THINKING_PREVIEW]) + n_hidden = len(lines) - _THINKING_PREVIEW + else: + display = "\n".join(lines) + n_hidden = 0 + + console.print(Rule("[dim]thinking[/dim]", style="dim blue")) + # Write dim italic via ANSI since we're streaming to file directly + # (Rich markup can't be applied char-by-char; dim is cosmetic here) + _stream_chars(console, display, cps=_THINKING_CPS) + + if n_hidden: + console.print(f"[dim] ↳ {n_hidden} more lines — use --thinking to expand[/dim]") + console.print() + + +# ── verse display helpers ───────────────────────────────────────────────────── +def _show_verse(console: Console, verse: Verse): + """Render a verse with its translation, original text, and commentary.""" + body = Text() + + if verse.sanskrit: + body.append(verse.sanskrit + "\n", style="bold") + if verse.transliteration: + body.append(verse.transliteration + "\n", style="italic dim") + + if verse.translation: + label = f"Translation ({verse.translator})" if verse.translator else "Translation" + body.append(f"\n{label}:\n", style="dim") + body.append(verse.translation + "\n") + + if verse.bhashya: + translator_note = f" ({verse.bhashya_translator})" if verse.bhashya_translator else "" + body.append(f"\nŚaṅkara's Bhāṣya{translator_note}:\n", style="dim") + preview = verse.bhashya[:800] + ("…" if len(verse.bhashya) > 800 else "") + body.append(preview + "\n", style="dim") + + ev = verse if isinstance(verse, EnrichedVerse) else None + if ev and ev.paraphrase: + body.append("\nTeaching: ", style="bold dim") + body.append(ev.paraphrase + "\n", style="dim") + if ev and ev.themes: + body.append("Themes: ", style="bold dim") + body.append(", ".join(ev.themes) + "\n", style="dim") + if ev and ev.practical_teaching: + body.append("Practical shift: ", style="bold dim") + body.append(ev.practical_teaching + "\n", style="dim") + + section = verse.section_display or verse.section + subtitle = verse.work_display + (f" — {section}" if section else "") + console.print(Panel( + body, + title=f"[bold]{verse.verse_ref}[/bold]", + subtitle=f"[dim]{subtitle}[/dim]", + border_style="cyan", + padding=(1, 2), + )) + + +def _explain_in_context( + console: Console, + verse: Verse, + history_messages: list[dict], + cps: int = _RESPONSE_CPS, +): + """Call the LM to explain the verse in context of the last conversation turn.""" + if history_messages: + last = history_messages[-1] + context = ( + f"User: {last.get('user_question', '')}\n\n" + f"Advisor: {last.get('response', '')}" + ) + else: + context = "No prior conversation." + + bits = [] + if verse.translation: + bits.append(f"Translation: {verse.translation}") + if verse.sanskrit: + bits.append(f"Sanskrit: {verse.sanskrit}") + if verse.bhashya: + bits.append(f"Śaṅkara's commentary: {verse.bhashya[:600]}") + ev = verse if isinstance(verse, EnrichedVerse) else None + if ev and ev.paraphrase: + bits.append(f"Teaching: {ev.paraphrase}") + verse_content = "\n\n".join(bits) + + explainer = dspy.ChainOfThought(_ExplainInContext) + with console.status("[dim]expanding...[/dim]", spinner="dots"): + try: + result = explainer( + verse_ref=verse.verse_ref, + verse_content=verse_content, + conversation_context=context, + ) + explanation = result.explanation + except Exception as exc: + console.print(f"[red]Could not generate explanation: {exc}[/red]") + return + + console.print() + _stream_response(console, explanation, cps=cps) + + +# ── main loop ───────────────────────────────────────────────────────────────── +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--program", default=str(config.OPTIMIZED_PROGRAM_PATH)) + ap.add_argument("--debug", action="store_true", + help="Show intermediate pipeline state for each turn.") + ap.add_argument("--thinking", action="store_true", + help="Show full synthesis reasoning trace (default: first 6 lines).") + ap.add_argument("--no-thinking", action="store_true", dest="no_thinking", + help="Hide the reasoning trace entirely.") + args = ap.parse_args() + + config.configure_dspy() + advisor = load_optimized(args.program) + console = Console() + + with console.status("[dim]loading corpus...[/dim]", spinner="dots"): + verse_lookup = _load_verse_lookup() + + console.print(Panel.fit( + "[bold]Gītā Advisor[/bold]\n\n" + "Speak from where you actually are.\n" + "After a response: [italic]show [/italic] to read a cited verse · " + "[italic]explain [/italic] for contextual breakdown.\n" + "Type [italic]exit[/italic] or Ctrl-D to leave.", + border_style="cyan", + )) + + history = dspy.History(messages=[]) + last_pred = None + + while True: + try: + console.print() + console.print("[bold cyan]you:[/bold cyan] ", end="") + line = input().strip() + except (EOFError, KeyboardInterrupt): + console.print("\n[dim]नमस्ते।[/dim]") + return + + if not line: + continue + if line.lower() in {"exit", "quit", ":q"}: + console.print("[dim]नमस्ते।[/dim]") + return + + # ── source exploration commands ─────────────────────────────────────── + cmd_lower = line.lower() + if cmd_lower.startswith(("show ", "explain ")): + if last_pred is None: + console.print("[dim]No sources yet — ask a question first.[/dim]") + continue + cmd, _, arg = line.partition(" ") + ref = _resolve_ref(arg, last_pred.sources_cited) + verse = _find_verse(verse_lookup, ref) + if verse is None: + console.print(f"[dim]'{ref}' not found in corpus.[/dim]") + if last_pred.sources_cited: + hint = " ".join( + f"[{i+1}] {r}" for i, r in enumerate(last_pred.sources_cited) + ) + console.print(f"[dim]Available: {hint}[/dim]") + continue + _show_verse(console, verse) + if cmd.lower() == "explain": + _explain_in_context(console, verse, history.messages) + continue + + # ── normal question — run pipeline in background with live stage progress ── + pred = None + error = None + stage = ["initializing..."] + done = threading.Event() + + def run_advisor(): + nonlocal pred, error + try: + pred = advisor( + user_question=line, + history=history, + _stage_cb=lambda msg: stage.__setitem__(0, msg), + ) + except Exception as exc: + error = exc + finally: + done.set() + + threading.Thread(target=run_advisor, daemon=True).start() + + with Live(console=console, refresh_per_second=8) as live: + while not done.wait(timeout=0.12): + live.update(Text(f" ◌ {stage[0]}", style="dim")) + live.update(Text("")) + + if error: + console.print(f"[red]Error: {error}[/red]") + continue + + last_pred = pred + history.messages.append({ + "user_question": line, + "response": pred.response, + "sources_cited": pred.sources_cited, + }) + + # debug trace + if args.debug: + console.print(Rule("[dim]debug[/dim]", style="dim")) + console.print(f"[dim]felt:[/dim] {pred.felt_emotion}") + console.print(f"[dim]surface:[/dim] {pred.surface_concern}") + console.print(f"[dim]deeper:[/dim] {pred.deeper_concern}") + console.print(f"[dim]themes:[/dim] {', '.join(pred.vedantic_themes)}") + console.print(f"[dim]queries:[/dim] {pred.queries}") + console.print(f"[dim]selected:[/dim] {pred.selected_indices}") + for i in pred.selected_indices: + if 1 <= i <= len(pred.retrieved_passages): + h = pred.retrieved_passages[i - 1] + m = h["meta"] + console.print( + f" [dim]→ [{m['tier']}] {m['work']}" + f"{' — ' + m['section'] if m.get('section') else ''}" + f" (score {h['score']:.3f})[/dim]" + ) + console.print(Rule(style="dim")) + + # thinking section + if not args.no_thinking: + _show_thinking( + console, + getattr(pred, "synthesis_reasoning", ""), + full=args.thinking, + ) + + # stream the response + console.print() + _stream_response(console, pred.response) + + # source footer with hints + if pred.sources_cited: + numbered = " ".join( + f"[{i+1}] {r}" for i, r in enumerate(pred.sources_cited) + ) + console.print(f"\n[dim]sources: {numbered}[/dim]") + console.print( + "[dim] → show to read the verse · explain for contextual breakdown[/dim]" + ) + + +if __name__ == "__main__": + main() diff --git a/config.py b/config.py new file mode 100644 index 0000000000000000000000000000000000000000..d17cccbb1dff6c35a455ea4a4e69fa9a9005ec34 --- /dev/null +++ b/config.py @@ -0,0 +1,201 @@ +""" +config.py — central configuration for the Gītā Advisor. + +Three LMs are configured: + + - TASK_LM: the local model running in LM Studio. Used at inference + time (understanding, retrieval planning, advice synthesis). + + - ENRICH_LM: Claude Sonnet (API) for the offline enrichment pass. + The local 26B model truncates structured output at 1500 + tokens and drops fields. Claude handles all six fields + cleanly in one call and costs ~$12-15 for the full 701- + verse corpus (one-time). Set ANTHROPIC_API_KEY in env. + + - REFLECTION_LM: gpt-4o (OpenAI) for GEPA's reflection step. + GEPA asks the reflection LM to read metric feedback and + propose rewritten prompts — this scales strongly with + model quality. gpt-4o reasons well enough to handle + nuanced Advaita feedback without breaking the budget. + Same OPENAI_API_KEY as enrichment. +""" + +from __future__ import annotations +import os +import re +from pathlib import Path +import dspy +import dspy.adapters.chat_adapter as _chat_adapter_module +from dotenv import load_dotenv + +# Gemma (and some other local models) output `[[ ## field ]]` without the closing `##` +# that DSPy's ChatAdapter expects (`[[ ## field ## ]]`). Patch the module-level regex +# to accept both forms before any adapter is instantiated. +_chat_adapter_module.field_header_pattern = re.compile(r"\[\[ ## (\w+)(?:\s*##)? \]\]") + +load_dotenv(Path(__file__).parent / ".env") # explicit path; works from any cwd + +# ──────────────────────────── Paths ──────────────────────────── +ROOT = Path(__file__).parent.resolve() +SOURCES_DIR = ROOT / "sources" +DATA_DIR = ROOT / "data" +ARTIFACTS_DIR = ROOT / "artifacts" +CHROMA_DIR = ARTIFACTS_DIR / "chroma" + +for d in (SOURCES_DIR, DATA_DIR, ARTIFACTS_DIR, CHROMA_DIR): + d.mkdir(parents=True, exist_ok=True) + +DATASET_PATH = DATA_DIR / "synthetic_questions.jsonl" +OPTIMIZED_PROGRAM_PATH = ARTIFACTS_DIR / "optimized_advisor.json" + +# ──────────────────────────── Task LM — Gemini API (preferred) ─────────────────────────── +# When GEMINI_API_KEY is set, route the task LM through Google AI Studio. +# Same Gemma 4 26B weights, but no local GPU required and the free tier is +# sufficient for inference + GEPA optimization runs. +GEMINI_API_KEY = os.getenv("GEMINI_API_KEY", "") +GEMINI_TASK_MODEL = os.getenv("GEMINI_TASK_MODEL", "gemini/gemma-4-26b-a4b-it") + +GEMINI_TASK_LM_KWARGS = dict( + api_key=GEMINI_API_KEY, + temperature=0.6, + # Gemma 4 thinking tokens count against max_tokens in the Gemini API. + # Each pipeline call burns ~3-4k reasoning tokens before writing output, + # so 4096 gets truncated. 16384 gives comfortable headroom for both. + max_tokens=16384, + cache=True, +) + +# ──────────────────────────── Task LM — LM Studio fallback ─────────────────────────────── +LM_STUDIO_BASE = os.getenv("LM_STUDIO_BASE", "http://localhost:1234/v1") +LOCAL_MODEL = os.getenv("LOCAL_MODEL", "google/gemma-4-26b-a4b") + +# DSPy uses LiteLLM-style model strings. "openai/" prefix routes through the +# OpenAI-compatible client, which LM Studio speaks. +TASK_MODEL_STRING = f"openai/{LOCAL_MODEL}" + +TASK_LM_KWARGS = dict( + api_base=LM_STUDIO_BASE, + api_key=os.getenv("LM_STUDIO_KEY", "lm-studio"), # any non-empty string + temperature=0.6, + max_tokens=4096, # ChainOfThought reasoning + all output fields easily exceeds 2k + cache=True, +) + +# Which backend to use: "gemini" if the API key is present, else "lm_studio". +# Override with TASK_LM_BACKEND=lm_studio to force local even when the key is set. +TASK_LM_BACKEND: str = os.getenv("TASK_LM_BACKEND", "gemini" if GEMINI_API_KEY else "lm_studio") + + +# ──────────────────────────── Enrichment LM (OpenAI gpt-4o-mini, offline batch) ───────── +# gpt-4o-mini is reliable at structured JSON output and cheap enough that the +# full 701-verse corpus costs under $1 (one-time). +# +# Cost estimate (full 701-verse corpus): +# ~1800 input tokens/verse × 701 × $0.15/M ≈ $0.19 input +# ~900 output tokens/verse × 701 × $0.60/M ≈ $0.38 output +# Total ≈ $0.57 — effectively free at this scale. +# +# Key is read from .env (OPENAI_API_KEY). Override ENRICH_MODEL env var to +# swap in a different OpenAI model (e.g. "openai/gpt-4o" for harder cases). +ENRICH_MODEL = os.getenv("ENRICH_MODEL", "openai/gpt-4o-mini") + +ENRICH_LM_KWARGS = dict( + api_key=os.getenv("OPENAI_API_KEY", ""), + temperature=0.3, # lower than task LM — we want consistent structured output + max_tokens=3000, # enough headroom for all six fields + CoT reasoning + cache=True, # DSPy disk cache deduplicates identical calls on re-runs + response_format={"type": "text"}, # DSPy 3.x sends json_object by default; + # OpenAI now requires json_schema or text +) + + +# ──────────────────────────── Proxy Task LM (gpt-4o-mini, GEPA optimization only) ──────── +# When running GEPA with --proxy-task-lm, this model replaces Gemma 4 as the task LM +# during optimization. Prompts are model-agnostic text; they transfer back to Gemma 4 +# at inference time. gpt-4o-mini runs ~20x faster than Gemma 4 thinking mode, bringing +# --auto light from ~260 hours to ~2-3 hours. +PROXY_TASK_MODEL = os.getenv("PROXY_TASK_MODEL", "openai/gpt-4o-mini") + +PROXY_TASK_LM_KWARGS = dict( + api_key=os.getenv("OPENAI_API_KEY", ""), + temperature=0.6, + max_tokens=4096, + cache=True, + response_format={"type": "text"}, +) + +# ──────────────────────────── Reflection LM (gpt-4o, GEPA) ────────────────────────────── +# GEPA's reflection step reads metric feedback and proposes rewritten prompts. +# This scales strongly with model quality. gpt-4o is the right balance here: +# it reasons well enough to write meaningful prompt mutations from nuanced +# Advaita feedback, and is affordable on a small OpenAI credit balance. +# +# Cost estimate per GEPA run (reflection calls only): +# --auto light: ~50 calls × 6k tokens ≈ $1.50 +# --auto medium: ~250 calls × 6k tokens ≈ $7.50 +# +# gpt-4o-mini is too shallow for this task — it produces generic rewrites +# that ignore the tradition-specific feedback the metric provides. +# Same OPENAI_API_KEY as the enrichment LM. +REFLECTION_MODEL = os.getenv("REFLECTION_MODEL", "openai/gpt-4o") + +REFLECTION_LM_KWARGS = dict( + api_key=os.getenv("OPENAI_API_KEY", ""), + temperature=1.0, # GEPA wants diversity across reflection proposals + max_tokens=6000, # headroom for detailed critique + full rewritten prompt text + response_format={"type": "text"}, # same fix as enrichment LM — avoid json_object + cache=False, # reflection calls are intentionally diverse; caching defeats that +) + + +# ──────────────────────────── Configure helpers ─────────────────────────────────────── +def configure_dspy() -> tuple[dspy.LM, dspy.LM]: + """Configure DSPy for inference and return (task_lm, reflection_lm). + + Prefers Gemini API when GEMINI_API_KEY is set (same Gemma 4 26B weights, + hosted by Google, free tier). Falls back to LM Studio otherwise. + Override with TASK_LM_BACKEND=lm_studio env var to force local. + + ChatAdapter fallback to JSONAdapter is disabled in both paths because: + - LM Studio rejects json_object. + - Gemma outputs `[[ ## field ]]` (no closing ##); the field_header_pattern + patch at module load time makes ChatAdapter parse these correctly. + """ + if TASK_LM_BACKEND == "gemini": + task_lm = dspy.LM(model=GEMINI_TASK_MODEL, **GEMINI_TASK_LM_KWARGS) + print(f"Task LM backend: Gemini API ({GEMINI_TASK_MODEL})") + else: + task_lm = dspy.LM(model=TASK_MODEL_STRING, **TASK_LM_KWARGS) + print(f"Task LM backend: LM Studio ({TASK_MODEL_STRING} @ {LM_STUDIO_BASE})") + + reflection_lm = dspy.LM(model=REFLECTION_MODEL, **REFLECTION_LM_KWARGS) + # use_json_adapter_fallback=False: LM Studio rejects json_object, so we must never fall back + dspy.configure(lm=task_lm, adapter=dspy.ChatAdapter(use_json_adapter_fallback=False)) + return task_lm, reflection_lm + + +def configure_enrich_lm() -> dspy.LM: + """Configure DSPy globally with the Claude Sonnet enrichment LM and return it. + + Call this instead of configure_dspy() when running enrich_corpus.py. + Raises if ANTHROPIC_API_KEY is not set. + """ + key = os.getenv("OPENAI_API_KEY", "") + if not key: + raise SystemExit( + "OPENAI_API_KEY is not set. Add it to your .env file:\n" + " OPENAI_API_KEY=sk-proj-..." + ) + lm = dspy.LM(model=ENRICH_MODEL, **ENRICH_LM_KWARGS) + dspy.configure(lm=lm) + return lm + + +# ──────────────────────────── Embeddings ───────────────────────────────────────────── +# Local sentence-transformer for retrieval. BGE-small is a sweet spot for +# semantic philosophy text on a Mac without burning RAM. +EMBED_MODEL = os.getenv("EMBED_MODEL", "BAAI/bge-small-en-v1.5") +EMBED_DEVICE = os.getenv("EMBED_DEVICE", "mps") # "mps" on Apple Silicon, "cpu" otherwise + +TOP_K_RETRIEVE = 8 # passages to fetch per query +N_RETRIEVAL_QUERIES = 3 # the planner generates this many per user question diff --git a/corpus.py b/corpus.py new file mode 100644 index 0000000000000000000000000000000000000000..f122bd57dd9962fde851291572d3f518a62da900 --- /dev/null +++ b/corpus.py @@ -0,0 +1,224 @@ +""" +corpus.py — the data model and on-disk storage for the verse corpus. + +A note on dataclasses vs. plain dicts +------------------------------------- +We could have used dicts everywhere and saved keystrokes. We don't, because +the Verse type is the contract between five different modules — parsers, +enrichment, indexing, retrieval, and the metric — and a typed contract +catches mistakes that "I thought 'sources_cited' was a list" wouldn't. + +The pipeline lifecycle of a verse +--------------------------------- + parsers.* → Verse (no LLM-derived fields) + enrichment.py → EnrichedVerse (with LLM-derived fields) + knowledge_base → reads EnrichedVerse, writes 3 embeddings per verse + advisor.py → receives EnrichedVerse via retriever hits + metrics.py → uses verse_id for exact citation grounding + +Storage choice +-------------- +JSONL on disk. Each line is a verse. Why not Parquet, sqlite, etc.? +- Easy to grep +- Easy to diff in PRs +- Easy for a human to spot-check enrichment quality (the whole point) +- We never need to scan more than a few thousand lines, so format doesn't matter +""" + +from __future__ import annotations +import json +from dataclasses import dataclass, field, asdict, fields +from pathlib import Path +from typing import Iterable, Iterator + + +# ──────────────────────────── Verse: the raw record ──────────────────────────── +@dataclass +class Verse: + """A natural unit of scripture: one verse, one mantra, one sūtra. + + The required fields are minimal — every parser must produce at least these. + Optional fields (sanskrit, transliteration, bhashya, ...) are filled when + the source provides them. + + `verse_id` is the global unique key. Convention: + '__' + e.g. 'bhagavad_gita_02_47', 'mundaka_upanishad_2_1_3'. + + `verse_ref` is the human-readable citation form: + e.g. 'BG 2.47', 'Muṇḍaka Up. 2.1.3', 'Vivekacūḍāmaṇi 11'. + The advisor's response uses this exact string in citations. + """ + # Identity — required for every record + verse_id: str + work: str + work_display: str + verse_ref: str + tier: str # primary | shankara | supporting + + # Section/chapter info — required when the work has chapters + section: str = "" # 'chapter_02' + section_display: str = "" # 'Chapter 2: Sāṅkhya Yoga' + + # Content — at least one of {translation, bhashya} must be non-empty + translation: str = "" # English translation of the verse itself + translator: str = "" # who translated it (for attribution) + + sanskrit: str = "" # original Devanāgarī + transliteration: str = "" # IAST roman transliteration + word_meanings: str = "" # word-by-word gloss when present + + bhashya: str = "" # Śaṅkara's commentary on this verse, if any + bhashya_translator: str = "" # who translated the bhāṣya + + # Provenance for accountability and license display + source_key: str = "" # the registry key this came from + license: str = "" # license tag from registry + + def has_content(self) -> bool: + """Used by parsers/loaders to drop empty records before they pollute + the index. A 'verse' with only a verse_id and no actual text is junk.""" + return bool(self.translation.strip() or self.bhashya.strip()) + + +# ──────────────────────────── EnrichedVerse: with LLM extractions ──────────────── +@dataclass +class EnrichedVerse(Verse): + """A Verse + the structured fields produced by the offline LLM pass. + + Every list defaults to empty so a verse that fails enrichment can still + be stored (without enrichment, indexed only on its literal text/bhāṣya). + """ + # The plain-English statement of what the verse teaches. Ideally 1–2 + # sentences. This is what the synthesizer reads downstream. + paraphrase: str = "" + + # Vedānta concepts engaged by the verse. Tradition-native vocabulary. + # Examples: 'karma_yoga', 'vairagya', 'sakshi', 'two_truths', 'adhyasa'. + themes: list[str] = field(default_factory=list) + + # Mundane life situations where this verse would help. User-language. + # Examples: 'facing failure after sustained effort', 'watching a parent decline'. + life_situations: list[str] = field(default_factory=list) + + # Emotions addressed, from a small consistent vocabulary. + # See enrichment.py EMOTION_VOCAB for the closed set. + emotions_addressed: list[str] = field(default_factory=list) + + # What does this verse ask the seeker to do or shift? + practical_teaching: str = "" + + # Hypothetical questions a real person might bring to this verse. + # These are gold for retrieval; they bridge the language gap. + hypothetical_questions: list[str] = field(default_factory=list) + + # Quality / debugging + enrichment_model: str = "" # which LM produced these fields + enrichment_version: int = 1 # bump when the prompt changes substantively + + # ---- Derived "views" used at indexing time ---- + def literal_view(self) -> str: + """The literal English translation, lightly enriched with the Sanskrit + if available. Best for queries that share lexical features with the text.""" + parts = [] + if self.translation: + parts.append(self.translation.strip()) + if self.transliteration: + parts.append(f"({self.transliteration.strip()})") + return "\n".join(parts) + + def bhashya_view(self) -> str: + """Śaṅkara's commentary on this verse. Best for queries about the + Vedāntic explanation rather than the verse text itself.""" + return self.bhashya.strip() + + def advisor_view(self) -> str: + """The composed view that bridges the language gap. + + This is what makes the user-question-→-verse mapping work. A user who + types 'I feel hollow even though I got everything I wanted' will not + find anything in the Sanskrit. They will find a near-neighbor in this + view if the enrichment did its job. + """ + bits = [] + if self.paraphrase: + bits.append(f"Teaching: {self.paraphrase}") + if self.life_situations: + bits.append( + "Speaks to: " + "; ".join(self.life_situations) + ) + if self.emotions_addressed: + bits.append( + "Addresses: " + ", ".join(self.emotions_addressed) + ) + if self.themes: + bits.append( + "Themes: " + ", ".join(self.themes) + ) + if self.hypothetical_questions: + bits.append( + "Questions this answers:\n - " + + "\n - ".join(self.hypothetical_questions) + ) + if self.practical_teaching: + bits.append(f"Practical shift: {self.practical_teaching}") + return "\n".join(bits) + + def is_enriched(self) -> bool: + """Did enrichment populate at least the minimum-viable fields?""" + return bool(self.paraphrase) and bool(self.life_situations) and bool(self.hypothetical_questions) + + +# ──────────────────────────── On-disk JSONL ──────────────────────────── +def write_jsonl(records: Iterable[Verse], path: Path) -> int: + """Write a stream of records as JSONL. Returns count written.""" + path.parent.mkdir(parents=True, exist_ok=True) + n = 0 + with path.open("w", encoding="utf-8") as f: + for r in records: + f.write(json.dumps(asdict(r), ensure_ascii=False) + "\n") + n += 1 + return n + + +def read_jsonl_verses(path: Path) -> Iterator[Verse]: + """Read a JSONL file as Verse records. Skips lines we can't parse.""" + if not path.exists(): + return + with path.open(encoding="utf-8") as f: + for line_no, line in enumerate(f, start=1): + line = line.strip() + if not line: + continue + try: + d = json.loads(line) + yield _verse_from_dict(d, Verse) + except Exception as e: + print(f"[corpus] skipping malformed line {line_no} in {path}: {e}") + + +def read_jsonl_enriched(path: Path) -> Iterator[EnrichedVerse]: + """Read a JSONL file as EnrichedVerse records.""" + if not path.exists(): + return + with path.open(encoding="utf-8") as f: + for line_no, line in enumerate(f, start=1): + line = line.strip() + if not line: + continue + try: + d = json.loads(line) + yield _verse_from_dict(d, EnrichedVerse) + except Exception as e: + print(f"[corpus] skipping malformed line {line_no} in {path}: {e}") + + +def _verse_from_dict(d: dict, cls): + """Construct a Verse/EnrichedVerse, ignoring keys the dataclass doesn't know. + + This forward-compatibility matters: if a future version adds a field, old + JSONL files should still load. And if enrichment adds extra debug fields, + we don't want the dataclass to choke on them. + """ + valid = {f.name for f in fields(cls)} + return cls(**{k: v for k, v in d.items() if k in valid}) diff --git a/data/corpus_enriched.jsonl b/data/corpus_enriched.jsonl new file mode 100644 index 0000000000000000000000000000000000000000..9357664e320d10316e8d6752b68b604e7f57f193 --- /dev/null +++ b/data/corpus_enriched.jsonl @@ -0,0 +1,701 @@ +{"verse_id": "bhagavad_gita_01_01", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.1", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Dhritarashtra said, \"What did my people and the sons of Pandu do when they had assembled together, eager for battle, on the holy plain of Kurukshetra, O Sanjaya?\"", "translator": "Swami Sivananda", "sanskrit": "धृतराष्ट्र उवाच\n\nधर्मक्षेत्रे कुरुक्षेत्रे समवेता युयुत्सवः।\n\nमामकाः पाण्डवाश्चैव किमकुर्वत सञ्जय।।1.1।।", "transliteration": "dhṛitarāśhtra uvācha\ndharma-kṣhetre kuru-kṣhetre samavetā yuyutsavaḥ\nmāmakāḥ pāṇḍavāśhchaiva kimakurvata sañjaya", "word_meanings": "dhṛitarāśhtraḥ uvācha—Dhritarashtra said; dharma-kṣhetre—the land of dharma; kuru-kṣhetre—at Kurukshetra; samavetāḥ—having gathered; yuyutsavaḥ—desiring to fight; māmakāḥ—my sons; pāṇḍavāḥ—the sons of Pandu; cha—and; eva—certainly; kim—what; akurvata—did they do; sañjaya—Sanjay", "bhashya": "i i.. \n\n* World. Sentient beings.— A. \n\nf Sensual enjoyment is the supreme source of happiness j there is no \nsuch thing as the happiness of another world.— A« \n\nt The immeasurable care as to the means of acquiring and preserving \nthe innumerable objects of desire.— -A. \n\n9—14] SPIRITUALITY AND MATERIALISM. 421 \n\n12. Bound by hundreds of bands of hope, \ngiven over to lust and wrath, they strive to secure \nby unjust means hoards of wealth for sensual enjoy- \nment. \n\nThey are attracted here and there, bound by a hundred \nbands of false hopes. They secure wealth for sensual enjoy- \nment, not for (performing acts of) dharma. By unjust means: \nby robbing other men's wealth. \n\nThe materialist's aspirations. \n\nTheir aspiration is expressed as follows : \n\n13. This to-day has been gained by me ; this \ndesire I shall attain ; this is mine, and this wealth \nalso shall be mine in future. \n\nIn future : in the coming year this wealth also shall be \nmine, and thereby I shall be known to be a man of wealth. \n\n14. lt That enemy has been slain by me, and \n\nothers also shall I slay. I am a lord, I enjoy, I \n\nam successful, strong and healthy.\" \n\nThat unconquerable enemy, say Devadatta by name, \nhas been slain by me and others also shall 1 slay. What can \nthese poor men do ? There is none equal to me in any respect \n\n422 THE BHAGAVAD-GITA. [DlS. XVI. \n\n— How ? — I am a lord, I enjoy, I am successful in every way* \nblessed with children and grandchildren ; I am no ordinary \nman. I am alone strong and healthy. \n\nw& mmtfk Mv®t ^grafanfQor: si % * u \nmmt mww% ^crFcr ^sg^fr II \\% li \n\n15. \"I am rich and well-born. Who else is \nequal to me ? I will sacrifice, I will give, I will \nrejoice.\" Thus deluded by unwisdom. \n\n16. Bewildered by many a fancy, entangled \nin the snare of delusion, addicted to the gratifica- \ntion of lust, they fall into a foul hell. \n\nWelVbrnn : born in a family learned in the scriptures for \nseven generations. Even in this respect none is equal to me. \nI will surpass others even in respect of sacrificial rites. I \nwill give (money) to actors and obtain a high delight Mmy \na faney : such as those described above. Delusion is a \nsnare, as it is of the nature of an enclosure or envelope. \nThey are addicated to sensual gratification ; and with sins thus \naccumulated they fall into a foul hell, such as Vaitarawi. \n\nThe materialist's sacrificial rites. \n\n17. Self-honored, stubborn, filled with the \npride and intoxication of wealth, they perform \nsacrifices in name with hypocrisy, without regafd \nto ordinance. \n\n14—19] SPIRITUALITY AND MATERIALISM. 423 \n\nSelf-honored : Esteeming themselves as possessed of all \ngood qualities ; they are not esteemed as such by the \nrighteous. They perform sacrifices without regard to the \nseveral parts and obligations enjoined in the scriptural \nordinances. \nThe materialist's neglect of Divine Commandments. \n\n18. Given over to egotism, power, haughti- \nness, lust, and anger, these malicious people hate \nMe in their own and others' bodies. \n\nEgotism • they esteem themselves very high for qualities \nwhich they really possess and for those which they falsely \nattribute to themselves. This egotism is what is called \navidya; and it is the hardest thing (to overcome), the source \nof all perversitiss (doshas), of all evil acts. Power : accom- \npanied with lust and passion, and seeking to humiliate others. \nHaughtiness : when this arises one transgresses the path of \nvirtue ; it is a peculiar vice seated in the antafckarawa.. Jjusts \nsexual passion, and the like. Anger • at something unplea- \nsant. They are given over to these and other great vices. \nMoreover, they hate Me, the Isvara, abiding in their own and \nother bodies as the Witness of tijeir thoughts and actions. \nTo hate Me is to transgress My commands* They are \nmalicious, jealous of the virtue of those who tread the right \n\npath. \n\nThe materialist's fall. \n\n*Not caring to know and follow the isvara's commands as.embodied \nin the Sruti and the Smriti.— A. \n\n424 THE BHAGAVAD-GITA. [DlS. XVI. \n\ni9. These cruel haters, worst of men, I hurl \nthese evil-doers for ever in the worlds into the \nwombs of the demons only. \n\nThese : enemies of the' right path and haters of the \nrighteous. Worst: because they are guilty of unrighteous \ndeeds (a-dharma). Worlds : paths of samsara passing through \nmany a hell. Wombs of the demons: wombs of the most \ncruel beings such as tigers, lions and the like. \n\n20. Entering into demoniac wombs, the de- \nluded ones, in birth after birth, without ever \nreaching Me, O son of Kunti, pass into a condi- \ntion still lower than that. \n\nThese deluded.creatures are born, birth after birth, only \nin Tamasic wombs and pass into lower and lower states. \nWithout ever reaching Me, the Isvara, they fall into a condi- \ntion which is still lower (than they are in at present). Without \nreaching Me t Certainly there is no room whatever even for the \nsupposition. that they will ever reach Me. The meaning, there- \nfore, is, 'without ever attaining to the right path taught by Me.'* \nThe three Gates of Hell to be avoided. \n\nHere follows a surmnary of the whole demoniac (asuric) \nnature in which, in its three forms, the whole variety of \nasuric nature, though endless, is comprehended; which \nbeing avoided, the whole asuric nature becomes avoided, and \nwhich is the source of all evil. \n\n* The meaning on the whole is this, The asuric nature, as leading to \na series of evils, is inimical to all human progress. A man should, there- \nfore, try and shake it oft while he is yet a free agent, while he has not \nyet passed into a birth which would make him entirely dependent on \nothers.*— A. \n\n19—23] SPIRITUALITY AND MATERIALISM. 425 \n\n21. Triple is this, the gate to hell, destruc- \ntive of the self : lust, wrath, and greed. There- \nfore., these three, one should abandon. \n\nThe gate to hell •* the gate leading to hell (naraka). By \nmerely entering at the gate, the self is ruined, *. e.t is fit for \nno human end whatever. Since this gate is ruinous to the \nself, let every one abandon these three : lust, wrath and \ngreed- \n\nHere follows the praise of this abandonment. \n\n22. A man who is released from these, the \nthree gates to darkness, O son of Kunti, does good \nto the self, and thereby reaches the Supreme Goal. \n\nGates to darkness : leading to hell (naraka) which is full \nof pain and delusion. He who is released from lust, wrath \nand greed will act for the good of the self, because of the \nabsence of that by which obstructed he has not hitherto so \nacted. By so doing he even attains moksha. \n\nLet the Law guide thy Life. \n\nThe scripture (sastra) is the authority on which all this \nrenunciation of asuric nature and the observance of what is \ngood are based. One would engage in these only on the \nauthority of the scriptures (sastra), not otherwise. Therefore, \n\n426 THE BHAGAVAD-GITA. [DlS.", "bhashya_translator": "Alladi Mahadeva Sastry, 1897", "source_key": "gita_json_core+sastry_gita_bhashya", "license": "unlicense", "paraphrase": "The verse introduces a father, Dhritarashtra, who is anxious about the battle between his sons and their cousins, asking what they are doing as they prepare to fight on the sacred battlefield of Kurukshetra.", "themes": ["dharma", "karma", "family_duties", "moral_conflict"], "life_situations": ["worried about family conflicts", "facing a difficult decision between right and wrong", "feeling anxious about a major life event", "struggling with the consequences of family loyalty", "navigating moral dilemmas in competitive situations"], "emotions_addressed": ["anxiety", "confusion", "fear"], "practical_teaching": "pure ontology — no direct prescription", "hypothetical_questions": ["I'm torn between supporting my family and doing what's right — what should I do?", "How can I deal with the anxiety of a big decision that affects my loved ones?", "What if my duty to my family conflicts with my moral beliefs?", "I'm feeling overwhelmed by a situation where everyone is against each other — how do I find clarity?", "How do I handle the fear of loss in a competitive environment?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_02", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.2", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Sanjaya said: Having seen the army of the Pandavas drawn up in battle array, King Duryodhana approached his teacher, Drona, and spoke these words.", "translator": "Swami Sivananda", "sanskrit": "सञ्जय उवाच\n\nदृष्ट्वा तु पाण्डवानीकं व्यूढं दुर्योधनस्तदा।\n\nआचार्यमुपसङ्गम्य राजा वचनमब्रवीत्।।1.2।।", "transliteration": "sañjaya uvācha\ndṛiṣhṭvā tu pāṇḍavānīkaṁ vyūḍhaṁ duryodhanastadā\nāchāryamupasaṅgamya rājā vachanamabravīt", "word_meanings": "sanjayaḥ uvācha—Sanjay said; dṛiṣhṭvā—on observing; tu—but; pāṇḍava-anīkam—the Pandava army; vyūḍham—standing in a military formation; duryodhanaḥ—King Duryodhan; tadā—then; āchāryam—teacher; upasaṅgamya—approached; rājā—the king; vachanam—words; abravīt—spoke", "bhashya": "Again, having started with the words \" Elsewhere than \njn dharma and elsewhere than in a-dharma, tell me that thou \nseest ;\" (Katha-Upanisbed, 2-13), the sruti says, \"that goal \nwhich all the Vedas speak of (ue-, are intended for), which all \nthe austerities speak of, desiring which they lead the life of \nBrahmacharya (celibacy), that goal I tell thee in brevity : \nIt is this, the syllable ' Om.' \" (Ibid 2-14). \n\nIn such passages as these, the syllable ' Om ', regarded \neither as an expression of the Para- Brahman or as a symbol \nof Him like an idol, is intended for persons of dull and mid- \ndling intellects as a means of knowing the Para-Brahman ; \nand the contemplation of the ' Om * is said to produce moksha \nat a subsequent period. Now, the same contemplation \n(conjoined with firmness in Yoga) of the syllable ' Om/ \nproductive of mukti at a subsequent period — the * Om ' \nforming, as shown above, a means of knowing the Para- \nBrahman described here (viii. 9, 11) — has to be taught here \nas well as some minor matters connected with tbe main \nsubject. With this view, the Lord proceeds with the sequel ; \n\n11—14] ABHYASA YOGA. 229 \n\n**i swm m*\\i ^ «m% ww Tifan^ u 33 u \n\n12-13. Having closed all the gates, having \nconfined mind in the heart, having fixed his life- \nbreath in the head, engaged in firm Yoga, uttering \nBrahman, the one-syllabled 'Om,' thinking of Me3 \nwhoso departs, leaving the body, he reaches the \nSupreme Goal* \n\nHaving closed all the avenues of knowledge and having \nconcentrated thought in the lotus of the heart, and with \nthought thus controlled, he ascends by the Nadi which passes \n•upwards from the heart, and then fixing life-breath in the \nhead, he utters the syllable 'Om', the appellation of the \nBrahman, and meditates on Me. — ' Leaving the body, shows \nthe mode of departure. The departure takes place by the \nSelf leaving the body, not by the Self being destroyed. \n\nHo rebirth on attaining to the Divine Being. \n\nMoreover, \n\n^trt garart mh ikzvgsm Stftra: u ^ it \n\n14, Whoso constantly thinks of me and long, \nto him I am easily accessible, O son of Pritha, to \nthe ever-devout Yogin. \n\nHe who thinks of Me, the Supreme Lord, long— i>e-> not \nfor six months or a year, but uninterruptedly throughout* life* \n— to that Yogin who is ever steadfast in thought, I am vastly \n\n230 THE BBAGAVAD GITA. |DIS- VII. \n\naccessible. This being so, therefore, without thinking of \nanother, one should ever dwell steadfast in Me. \n\nIt may be asked, \"What if Thou art easily accessible ?\" — \nListen : I shall tell you of what use is My being thus easily \naccessible : \n\n15. Having attained to Me, they do not again \nattain birth, which is the seat of pain and is not \neternal, they having reached highest perfection. \n\nHaving attained to Me, the Isvara, 'having reached My \nbeing, they are not again subject to birth- Birth here is the \nseat of all pain arising from the body, etc-, and is of an ever* \nchanging nature. Having reached the highest stage called \nmoksha, they do not attain birth again. Those, on the other \nhand, who do not attain to Me, return again (to the earth). \n\nDo those again return who have reached any other being \nthan Thyself ?— -^isten : \n\n16. (All) worlds including the world of \nBrahma are subject to returning again, O Arjuna ; \nbut, on reaching Me, O son of Kunti, there is no \nrebirths \n\nThe Day and the Night of Brahma. \n\n\"Why are all the worlds including the world of Brahma \nsubject to returning ? — Because they are limited by time. — \nHow? \n\n14—18] ABHYASA YOGA. 231 \n\nim gnsff^Fm asgrcraraYT 5RT: \\\\ \\* II \n\n17. They — those people who know day and \nnight — know that the day of Brahma is a thousand \nyugas long and the night is a thousand yogas long. \n\nBrahma is the Prajapati, the Viraj. Those persons who \nknow how to compute Time know that Brahma's day is a \nthousand yugas long, and that His night is of the same \nduration as His day. Because the worlds are thus limited \nby time, therefore they return again. \n\nWhat takes place during the Prajapati's day and what \ntakes place during His night will now be described : \n\n18. From the Unmanifested all the mani- \nfestations proceed at the coming on of day ; at the \ncoming on of night they dissolve there only, in \nwhat is called the Unmanifested. \n\nThe Unmanifested (Avyakta) is the sleeping condition of \nthe Prajapati who is asleep. Out of That, all manifestations \n(vyaktis), all creatures unmoving and moving (sthavara and \njawgama), are manifested at the coming on of day, a.e., when \nBrahma awakes. So, at the coming on of night, i.ett when \nBrahma goes to sleep, all the manifestations dissolve there \nonly, in what is called Avyakta, the one already spoken of. \n\nWith a view to avoid the fallacious implication that a \n\nman reaps the fruits of what he has not done, or that he does \n\nnot reap the fruits of what he has done, with a view to show \n\nthat the teaching of the scripture concerning bondage Cbaridha) \n\nand liberation (moksha) has a purpose to serve, and with a \n\n.232 THE BHAGAVAD GITA. [DlS. VIIL \n\nview further to teach detachment from samsara by showing \nthat, as the effect of karma caused by avidya (nescience) and \nother sources of evil, all creatures involuntarily come into \nbeing again and again and dissolve, the Lord says : \n\n?jpm: b mm ^\\ *gm srafc& i \n\n19. This same multitude of beings having \ncome into being again and again, is dissolved at \nthe coming on of night, not of their will, O son \nof Pfitha, and comes forth at the coming on of day. \n\nThis multitude of beings comprising those that move as \nwell as those that do not— the same multitude that existed in \nthe preceding kalpa or age, and no other — involuntarily comes \ninto being at the coming on of day, and is dissolved again at \nthe coming on of night— at the close of the day, Again at the \ncoming on of day, it involuntarily comes into existance. \nThe Highest Goal— how reached. \n\nIn \"viii. 13, etc., has been shown the way, by which to \nreach the Imperishable CAkshara) described above. Now, \nwith a view to indicate the nature of the Akshara, with a view \nthus to specify that so and so is the thing to be reached by \nthis path of Yoga, the Lord proceeds as follows : \n\n'SgJ \n\n20. But that other eternal Unmanifested \nBeing, distinct from this Unmanifested (Avyakta), \n—He does not perish when all creatures perish. \n\n' But ' indicates that the Akshara who is to be described \nnow is distinct from the Avyakta. Being ; the Supreme, the \nPara-Brahman, called the Akshara. Though distinct from \n\n19—22] ABHYASA YOGA. 233 \n\nthe Avyakta, one may suppose that He is of the same nature \nas the Avyakta. To remove this impression, the Lord \nqualifies Him by ' other ', meaning thereby that He is of a \ndifferent nature from the Avyakta. He is unmanifested, \nimperceptible to the senses. He is distinnct from the Avyakta \nmentioned above, which is Avidya itself, the seed of the \nwhole multitude of created beings ; that is to say, He is of \nquite a different nature from the Avyakta. He does not \nperish when all beings from Brahma downwards perish. \n\n^ sncq- q \\km*% awl *m m u \\\\ w \n\n21. What is called the Unmanifested and \nthe Imperishable, That, they say, is the highest \ngoal ; which having reached none return. That is \nMy highest place. \n\nThat : that Avyakta which is called Akshara, the Impe- \nrishable, the Unmanifested Being. Having reached that state, \nnone has returned to sawsara, the mundane life- That is My \n(i.e.t Vishwu's) Supreme Abode. \n\nThe means of attaining to that state will now be pointed \n\nout \n\njp<*t € to qrl w$m\\ SHRwrawrar \\ \n\n22. Now, that Highest Purusha, O son of \nPntha, within Whom all beings dwell, by Whom \nall this is pervaded, is attainable by exclusive \ndevotion \n\nPurusha is so called because He rests in the body, or \nbecause He is full. Than Him none is higher. He is \nattained by exclusive devotion, by j«ana or knowledge of \n\n234 THE BHAGAVAD GITA. [DlS. VIIL \n\nthe Self. All the created beings abide within the Purusba ;. \nfor, every effect rests within its cause ; and by that Purusha \nthe whole world is pervaded. \n\nThe Paths of Light and Darkness. \n\nNow it is necessary to speak of the Uttaramarga, ' the \nNorthern Path *, the Path of Light by which the Yogins just \nspoken of attain to Brahman, — those Yogins who meditate \nhere on Brahman as inhering in the Prarcava, in the syllable \n' Om ', and who attain to moksha later on.* And this will be- \ntaught in the section beginning with viii. 23. The path of \nreturn is also described, only with a view to extol the other \npath. \n\nTO ^ WfffftsupBr %* srtnra:", "bhashya_translator": "Alladi Mahadeva Sastry, 1897", "source_key": "gita_json_core+sastry_gita_bhashya", "license": "unlicense", "paraphrase": "This verse introduces the scene where King Duryodhana, seeing the Pandava army prepared for battle, seeks counsel from his teacher Drona, illustrating the importance of seeking guidance in difficult times.", "themes": ["dharma", "teacher_disciple", "conflict", "guidance", "karma"], "life_situations": ["preparing for a major life decision", "facing a moral dilemma at work", "seeking advice before a big confrontation", "navigating family conflicts", "feeling overwhelmed by responsibilities"], "emotions_addressed": ["anxiety", "confusion", "fear"], "practical_teaching": "Seek guidance and clarity when faced with difficult choices.", "hypothetical_questions": ["I'm about to make a big decision and feel lost — should I consult someone?", "I have a conflict with a colleague and don't know how to approach it — what should I do?", "I'm overwhelmed by my responsibilities and unsure of my next step — how can I find clarity?", "I feel anxious about a confrontation with a family member — how can I prepare?", "I’m facing a moral dilemma at work and need advice — who should I turn to?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_03", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.3", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Behold, O Teacher! This mighty army of the sons of Pandu, arrayed by the son of Drupada, thy wise disciple.", "translator": "Swami Sivananda", "sanskrit": "पश्यैतां पाण्डुपुत्राणामाचार्य महतीं चमूम्।\n\nव्यूढां द्रुपदपुत्रेण तव शिष्येण धीमता।।1.3।।", "transliteration": "paśhyaitāṁ pāṇḍu-putrāṇām āchārya mahatīṁ chamūm\nvyūḍhāṁ drupada-putreṇa tava śhiṣhyeṇa dhīmatā", "word_meanings": "paśhya—behold; etām—this; pāṇḍu-putrāṇām—of the sons of Pandu; āchārya—respected teacher; mahatīm—mighty; chamūm—army; vyūḍhām—arrayed in a military formation; drupada-putreṇa—son of Drupad, Dhrishtadyumna; tava—by your; śhiṣhyeṇa—disciple; dhī-matā—intelligent", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "Arjuna points out to his teacher the powerful army of the Pandavas, led by his wise disciple, Drona, which emphasizes the gravity of the situation he faces in battle.", "themes": ["dharma", "karma_yoga", "teacher_student_relationship"], "life_situations": ["feeling overwhelmed by responsibilities", "facing a difficult decision that affects loved ones", "struggling with loyalty in a conflict", "dealing with the pressure of expectations from authority figures", "confronting moral dilemmas in professional life"], "emotions_addressed": ["confusion", "fear", "anxiety"], "practical_teaching": "pure ontology — no direct prescription", "hypothetical_questions": ["I feel torn between my duty and my family ties — how should I approach this?", "How do I handle the pressure from my teacher while feeling conflicted?", "I’m facing a tough decision that could hurt people I care about — what should I do?", "I’m overwhelmed by the expectations placed on me — how can I find clarity?", "What if my responsibilities conflict with my values — how do I resolve this?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_04", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.4", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Here are heroes, mighty archers, equal in battle to Bhima and Arjuna, Yuyudhana (Satyaki), Virata, and Drupada—all mighty warriors.", "translator": "Swami Sivananda", "sanskrit": "अत्र शूरा महेष्वासा भीमार्जुनसमा युधि।\n\nयुयुधानो विराटश्च द्रुपदश्च महारथः।।1.4।।", "transliteration": "atra śhūrā maheṣhvāsā bhīmārjuna-samā yudhi\nyuyudhāno virāṭaśhcha drupadaśhcha mahā-rathaḥ", "word_meanings": "atra—here; śhūrāḥ—powerful warriors; mahā-iṣhu-āsāḥ—great bowmen; bhīma-arjuna-samāḥ—equal to Bheem and Arjun; yudhi—in military prowess; yuyudhānaḥ—Yuyudhan; virāṭaḥ—Virat; cha—and; drupadaḥ—Drupad; cha—also; mahā-rathaḥ—warriors who could single handedly match the strength of ten thousand ordinary warriors;", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "This verse lists some of the strongest and most skilled warriors in the battle, showing that Arjuna faces serious opponents, which adds to his internal conflict about fighting.", "themes": ["dharma", "karma", "battle_of_life", "courage", "self_realization"], "life_situations": ["feeling overwhelmed by competition at work", "facing a difficult decision with significant consequences", "dealing with pressure from peers or family", "confronting fears in a challenging situation", "navigating a conflict with someone you respect"], "emotions_addressed": ["fear", "anxiety", "confusion"], "practical_teaching": "pure ontology — no direct prescription", "hypothetical_questions": ["I know I have to make a tough choice, but I'm scared of the consequences — how should I approach this?", "I'm facing strong competition and feel inadequate — how can I find my confidence?", "I respect my opponents but feel overwhelmed — how do I deal with this pressure?", "How can I overcome my fear of failure when the stakes are so high?", "I'm confused about my duty in this situation — how do I clarify my path?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_05", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.5", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Dhrishtaketu, Chekitana, the valiant king of Kasi, Purujit, Kuntibhoja, and Saibya—the best of men.", "translator": "Swami Sivananda", "sanskrit": "धृष्टकेतुश्चेकितानः काशिराजश्च वीर्यवान्।\n\nपुरुजित्कुन्तिभोजश्च शैब्यश्च नरपुङ्गवः।।1.5।।", "transliteration": "dhṛiṣhṭaketuśhchekitānaḥ kāśhirājaśhcha vīryavān\npurujit kuntibhojaśhcha śhaibyaśhcha nara-puṅgavaḥ\nyudhāmanyuśhcha vikrānta uttamaujāśhcha vīryavān", "word_meanings": "dhṛiṣhṭaketuḥ—Dhrishtaketu; chekitānaḥ—Chekitan; kāśhirājaḥ—Kashiraj; cha—and; vīrya-vān—heroic; purujit—Purujit; kuntibhojaḥ—Kuntibhoj; cha—and; śhaibyaḥ—Shaibya; cha—and; nara-puṅgavaḥ—best of men; yudhāmanyuḥ—Yudhamanyu; cha—and; vikrāntaḥ—courageous; uttamaujāḥ—Uttamauja; cha—and; vīrya-vān—gallant;", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "This verse introduces key warriors and leaders on the battlefield, showcasing their bravery and importance in the upcoming conflict.", "themes": ["dharma", "karma", "valor", "battlefield_dynamics"], "life_situations": ["feeling overwhelmed by competition at work", "facing a challenging decision with significant consequences", "dealing with pressure from peers in a group project", "navigating conflicts in a leadership role", "preparing for a major life challenge or confrontation"], "emotions_addressed": ["fear", "anxiety", "frustration"], "practical_teaching": "pure ontology — no direct prescription", "hypothetical_questions": ["I feel anxious about the competition I’m facing at work — how should I approach it?", "I’m overwhelmed by the pressure of an important decision — what should I consider?", "How do I deal with conflicts when leading a team?", "I’m nervous about a major challenge coming up in my life — how can I prepare myself?", "What should I do when I feel frustrated by my peers in a group project?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_06", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.6", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "The strong Yudhamanyu and the brave Uttamaujas, the son of Subhadra (Abhimanyu, the son of Subhadra and Arjuna), and the sons of Draupadi, all of them great charioteers (great heroes).\"", "translator": "Swami Sivananda", "sanskrit": "युधामन्युश्च विक्रान्त उत्तमौजाश्च वीर्यवान्।\n\nसौभद्रो द्रौपदेयाश्च सर्व एव महारथाः।।1.6।।", "transliteration": "saubhadro draupadeyāśhcha sarva eva mahā-rathāḥ", "word_meanings": "saubhadraḥ—the son of Subhadra; draupadeyāḥ—the sons of Draupadi; cha—and; sarve—all; eva—indeed; mahā-rathāḥ—warriors who could single handedly match the strength of ten thousand ordinary warriors", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "This verse highlights the powerful and brave warriors who are ready for battle, showing the strength of the opposing side and the seriousness of the conflict.", "themes": ["dharma", "karma", "battlefield_dilemma"], "life_situations": ["feeling overwhelmed by competition", "facing a significant challenge at work", "dealing with pressure from peers", "preparing for a major confrontation", "navigating family conflicts"], "emotions_addressed": ["fear", "anxiety", "confusion"], "practical_teaching": "pure ontology — no direct prescription", "hypothetical_questions": ["I see my colleagues as strong competitors — how do I handle this pressure?", "I'm facing a tough situation at work with powerful opponents — what should I focus on?", "How do I prepare myself mentally for a big confrontation?", "I feel anxious about the upcoming challenges — how can I manage this fear?", "In family disputes, how do I stand my ground against strong personalities?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_07", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.7", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Know also, O best among the twice-born! the names of those who are the most distinguished amongst ourselves, the leaders of my army; these I name to you for your information.", "translator": "Swami Sivananda", "sanskrit": "अस्माकं तु विशिष्टा ये तान्निबोध द्विजोत्तम।\n\nनायका मम सैन्यस्य संज्ञार्थं तान्ब्रवीमि ते।।1.7।।", "transliteration": "asmākaṁ tu viśhiṣhṭā ye tānnibodha dwijottama\nnāyakā mama sainyasya sanjñārthaṁ tānbravīmi te", "word_meanings": "asmākam—ours; tu—but; viśhiṣhṭāḥ—special; ye—who; tān—them; nibodha—be informed; dwija-uttama—best of Brahmnis; nāyakāḥ—principal generals; mama—our; sainyasya—of army; sanjñā-artham—for information; tān—them; bravīmi—I recount; te—unto you", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "Arjuna is pointing out the notable leaders in his army to Krishna, emphasizing the significance of these individuals as he prepares for battle.", "themes": ["dharma", "relationship_dynamics", "self_awareness", "conflict_resolution"], "life_situations": ["facing a difficult decision that involves family or friends", "struggling with loyalty in a competitive environment", "navigating complex relationships in a high-stakes situation", "feeling overwhelmed by the responsibilities of leadership", "grappling with the moral implications of a conflict"], "emotions_addressed": ["confusion", "anxiety", "doubt"], "practical_teaching": "Recognize the complexity of your relationships and the responsibilities that come with your roles in challenging situations.", "hypothetical_questions": ["I have to confront a family member in a business deal — how do I handle it?", "m torn between my duty to my team and my loyalty to my friends — what should I do?'", "I feel overwhelmed by the pressure of leadership and the expectations of others — how can I cope?", "How do I make a decision when it feels like I will hurt someone I care about?", "I’m anxious about the consequences of my choices in a conflict — how do I find clarity?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_08", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.8", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "\"Thou thyself, Bhishma, Karna, Kripa, the victorious in war, Asvatthama, Vikarna, and Bhurisrava, the son of Somadatta—all these are ready for battle.\"", "translator": "Swami Sivananda", "sanskrit": "भवान्भीष्मश्च कर्णश्च कृपश्च समितिञ्जयः।\n\nअश्वत्थामा विकर्णश्च सौमदत्तिस्तथैव च।।1.8।।", "transliteration": "bhavānbhīṣhmaśhcha karṇaśhcha kṛipaśhcha samitiñjayaḥ\naśhvatthāmā vikarṇaśhcha saumadattis tathaiva cha", "word_meanings": "bhavān—yourself; bhīṣhmaḥ—Bheeshma; cha—and; karṇaḥ—Karna; cha—and; kṛipaḥ—Kripa; cha—and; samitim-jayaḥ—victorious in battle; aśhvatthāmā—Ashvatthama; vikarṇaḥ—Vikarna; cha—and; saumadattiḥ—Bhurishrava; tathā—thus; eva—even; cha—also", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "This verse points out that Arjuna's opponents are not just ordinary soldiers; they are highly skilled and respected warriors, making the battle even more daunting for him.", "themes": ["dharma", "karma", "non_attachment", "conflict", "self_inquiry"], "life_situations": ["feeling overwhelmed by the challenges ahead", "struggling with difficult decisions involving loved ones", "facing a situation where you must oppose respected figures", "dealing with the pressure of expectations in a competitive environment", "navigating moral dilemmas in personal relationships"], "emotions_addressed": ["fear", "anxiety", "confusion"], "practical_teaching": "pure ontology — no direct prescription", "hypothetical_questions": ["I know I have to confront my family about a serious issue, but I'm terrified of the fallout — how do I handle this?", "I'm facing a tough competition against people I deeply respect — how do I prepare myself mentally?", "How can I reconcile my duty with my feelings for those I must oppose?", "I'm feeling lost about what to do when the stakes are so high — how can I find clarity?", "What should I do when the people I admire are on the opposite side of my beliefs?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_09", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.9", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "And also many other heroes, ready to give up their lives for my sake, armed with various weapons and missiles, all well-skilled in battle.", "translator": "Swami Sivananda", "sanskrit": "अन्ये च बहवः शूरा मदर्थे त्यक्तजीविताः।\n\nनानाशस्त्रप्रहरणाः सर्वे युद्धविशारदाः।।1.9।।", "transliteration": "anye cha bahavaḥ śhūrā madarthe tyaktajīvitāḥ\nnānā-śhastra-praharaṇāḥ sarve yuddha-viśhāradāḥ", "word_meanings": "anye—others; cha—also; bahavaḥ—many; śhūrāḥ—heroic warriors; mat-arthe—for my sake; tyakta-jīvitāḥ—prepared to lay down their lives; nānā-śhastra-praharaṇāḥ—equipped with various kinds of weapons; sarve—all; yuddha-viśhāradāḥ—skilled in the art of warfare", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "This verse illustrates Arjuna's awareness of the many brave warriors who are willing to die for their beliefs, making him question the righteousness of the battle he is about to engage in.", "themes": ["dharma", "non_attachment", "selflessness", "the_nature_of_duty"], "life_situations": ["feeling torn about fighting against loved ones", "struggling with the moral implications of a difficult decision", "questioning the value of loyalty in a conflict", "dealing with the pressure of expectations from others", "facing a situation where personal values clash with duty"], "emotions_addressed": ["confusion", "fear", "guilt"], "practical_teaching": "pure ontology — no direct prescription", "hypothetical_questions": ["How can I reconcile my duty with my feelings for those I have to oppose?", "I feel guilty about the possibility of hurting people I care about — what should I do?", "What if my values conflict with what others expect of me?", "How do I find clarity when faced with such difficult choices?", "Why does it feel so heavy to think about the consequences of my actions?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_10", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.10", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Our army, marshalled by Bhishma, is insufficient, whereas theirs, marshalled by Bhima, is sufficient.", "translator": "Swami Sivananda", "sanskrit": "अपर्याप्तं तदस्माकं बलं भीष्माभिरक्षितम्।\n\nपर्याप्तं त्विदमेतेषां बलं भीमाभिरक्षितम्।।1.10।।", "transliteration": "aparyāptaṁ tadasmākaṁ balaṁ bhīṣhmābhirakṣhitam\nparyāptaṁ tvidameteṣhāṁ balaṁ bhīmābhirakṣhitam", "word_meanings": "aparyāptam—unlimited; tat—that; asmākam—ours; balam—strength; bhīṣhma—by Grandsire Bheeshma; abhirakṣhitam—safely marshalled; paryāptam—limited; tu—but; idam—this; eteṣhām—their; balam—strength; bhīma—Bheem; abhirakṣhitam—carefully marshalled", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "Arjuna feels that his army is weak compared to the opposing side, which he believes is stronger and better led. This realization contributes to his hesitation about fighting.", "themes": ["self_doubt", "perceived_inadequacy", "conflict", "fear_of_loss"], "life_situations": ["doubting my abilities in a competitive environment", "feeling overwhelmed before an important decision", "questioning my support system in a crisis", "struggling with feelings of inadequacy in a team setting", "facing a significant challenge with perceived disadvantages"], "emotions_addressed": ["fear", "doubt", "anxiety"], "practical_teaching": "The verse encourages the seeker to confront feelings of inadequacy and recognize the strength within their own resources.", "hypothetical_questions": ["I feel like I'm not good enough compared to my peers — how do I overcome this?', 'What should I do when I doubt my team's capabilities before a big project?", "I’m facing a tough competition and feel overwhelmed — how can I regain my confidence?", "How do I deal with the fear of failing when I think others are better prepared?", "I’m struggling to believe in my support system during a crisis — what can I focus on?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_11", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.11", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Therefore, do all of you, stationed in your respective positions in the several divisions of the army, protect Bhishma alone.", "translator": "Swami Sivananda", "sanskrit": "अयनेषु च सर्वेषु यथाभागमवस्थिताः।\n\nभीष्ममेवाभिरक्षन्तु भवन्तः सर्व एव हि।।1.11।।", "transliteration": "ayaneṣhu cha sarveṣhu yathā-bhāgamavasthitāḥ\nbhīṣhmamevābhirakṣhantu bhavantaḥ sarva eva hi", "word_meanings": "ayaneṣhu—at the strategic points; cha—also; sarveṣhu—all; yathā-bhāgam—in respective position; avasthitāḥ—situated; bhīṣhmam—to Grandsire Bheeshma; eva—only; abhirakṣhantu—defend; bhavantaḥ—you; sarve—all; eva hi—even as", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "The verse teaches that in a challenging situation, everyone should concentrate their efforts on a common goal or leader, ensuring that they work together effectively.", "themes": ["dharma", "collective_effort", "leadership", "unity", "focus"], "life_situations": ["navigating a team project with a strong leader", "supporting a friend during a difficult time", "working towards a common goal in a community effort", "dealing with a crisis where one person is crucial", "balancing personal responsibilities while supporting a leader"], "emotions_addressed": ["anxiety", "confusion", "fear"], "practical_teaching": "Focus your energy on supporting a key person or goal in a challenging situation.", "hypothetical_questions": ["How can I best support my boss during this critical project?", "I'm feeling overwhelmed — how do I prioritize my efforts in a team?", "What should I do if I disagree with the leader's approach but want to help?", "How can I encourage my friends to unite for a common cause?", "In a crisis, how do I decide where to direct my support?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_12", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.12", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "His glorious grandsire, the oldest of the Kauravas, roared like a lion to cheer Duryodhana and blew his conch.", "translator": "Swami Sivananda", "sanskrit": "तस्य संजनयन्हर्षं कुरुवृद्धः पितामहः।\n\nसिंहनादं विनद्योच्चैः शङ्खं दध्मौ प्रतापवान्।।1.12।।", "transliteration": "tasya sañjanayan harṣhaṁ kuru-vṛiddhaḥ pitāmahaḥ\nsiṁha-nādaṁ vinadyochchaiḥ śhaṅkhaṁ dadhmau pratāpavān", "word_meanings": "tasya—his; sañjanayan—causing; harṣham—joy; kuru-vṛiddhaḥ—the grand old man of the Kuru dynasty (Bheeshma); pitāmahaḥ—grandfather; sinha-nādam—lion’s roar; vinadya—sounding; uchchaiḥ—very loudly; śhaṅkham—conch shell; dadhmau—blew; pratāpa-vān—the glorious", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "The verse illustrates how Bhishma, the oldest Kaurava, supports Duryodhana by blowing his conch, signaling the start of battle and rallying the troops.", "themes": ["dharma", "loyalty", "battle_preparation", "family_dynamics"], "life_situations": ["feeling pressured to support a family member in a difficult situation", "facing a conflict where loyalty is tested", "preparing for a major challenge or confrontation", "dealing with family expectations during a crisis"], "emotions_addressed": ["anxiety", "fear", "confusion"], "practical_teaching": "pure ontology — no direct prescription", "hypothetical_questions": ["I feel torn between my loyalty to my family and my own beliefs — what should I do?", "How do I handle the pressure to support someone in a conflict I don’t agree with?", "I’m anxious about facing a big challenge — how can I prepare myself mentally?", "What if my family expects me to take sides in a conflict I want to avoid?", "How do I find clarity when I feel confused about my role in a family dispute?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_13", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.13", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Then, suddenly, conches, kettledrums, tabors, drums, and cow horns blared forth from the Kaurava side, and the sound was tremendous.", "translator": "Swami Sivananda", "sanskrit": "ततः शङ्खाश्च भेर्यश्च पणवानकगोमुखाः।\n\nसहसैवाभ्यहन्यन्त स शब्दस्तुमुलोऽभवत्।।1.13।।", "transliteration": "tataḥ śhaṅkhāśhcha bheryaśhcha paṇavānaka-gomukhāḥ\nsahasaivābhyahanyanta sa śhabdastumulo ’bhavat", "word_meanings": "tataḥ—thereafter; śhaṅkhāḥ—conches; cha—and; bheryaḥ—bugles; cha—and; paṇava-ānaka—drums and kettledrums; go-mukhāḥ—trumpets; sahasā—suddenly; eva—indeed; abhyahanyanta—blared forth; saḥ—that; śhabdaḥ—sound; tumulaḥ—overwhelming; abhavat—was", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "This verse illustrates the dramatic buildup to battle, marked by the loud sounds of conches and drums, signaling the start of a major conflict and the emotions that come with it.", "themes": ["dharma_yuddha", "collective_action", "anticipation", "conflict"], "life_situations": ["preparing for a major life change", "facing a challenging decision", "entering a competitive environment", "experiencing heightened tension before an important event", "dealing with the pressure of expectations"], "emotions_addressed": ["anxiety", "anticipatory_grief", "fear"], "practical_teaching": "pure ontology — no direct prescription", "hypothetical_questions": ["I feel overwhelmed by the pressure before my big presentation — how can I manage this anxiety?", "I’m facing a tough decision and feel the weight of expectations — what should I do?", "How do I prepare myself mentally for an upcoming competition that I’m anxious about?", "I’m feeling a mix of excitement and fear about a major life change — how can I navigate these emotions?", "What can I do to calm my nerves before an important event?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_14", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.14", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Then, Madhava (Krishna) and the son of Pandu (Arjuna), seated in the magnificent chariot yoked with white horses, blew divine conches.", "translator": "Swami Sivananda", "sanskrit": "ततः श्वेतैर्हयैर्युक्ते महति स्यन्दने स्थितौ।\n\nमाधवः पाण्डवश्चैव दिव्यौ शङ्खौ प्रदध्मतुः।।1.14।।", "transliteration": "tataḥ śhvetairhayairyukte mahati syandane sthitau\nmādhavaḥ pāṇḍavaśhchaiva divyau śhaṅkhau pradadhmatuḥ", "word_meanings": "tataḥ—then; śhvetaiḥ—by white; hayaiḥ—horses; yukte—yoked; mahati—glorious; syandane—chariot; sthitau—seated; mādhavaḥ—Shree Krishna, the husband of the goddess of fortune, Lakshmi; pāṇḍavaḥ—Arjun; cha—and; eva—also; divyau—Divine; śhaṅkhau—conch shells; pradadhmatuḥ—blew", "bhashya": "Then: having seen Him. The God: putting on the \nUniversal Form. With joined palms : in order to bow down. \n\n282 THE BHAGAVAD GITA. [DlS. XL \n\nHow P — Arjuna declares his own experience, viz., that \nhe sees the Universal Form shewn by the Lord: \n\ni#a mi*pjti® nmn. II %** u \n\nArjtma said: \n\n15. I see all the Gods, O God, in thy body, \nas also hosts of various classes of beings : Brahma, \nthe Lord, seated on the lotus-seat, and all iftshis \nand heavenly serpents. \n\nVarious classes of beings: both animate and inanimate, \nand of various forms. Brahma : the Four-faced, the Lord of \ncreatures. He is seated in the centre of the Earth-Lotus, \non the Meru which forms the cup or seed-vessel as it were of \nthe Earth-Lotus. Bishis; such as Vasishflaa. Serpents: \nsuch as Vasuki. \n\n«?wm fMHrc fewr II \\§ 11 \n\n16. I see Thee of boundless form on every \nside with multitudinous arms, stomachs, mouths \nand eyes ; neither Thy end nor the middle nor the \nbeginning do I see, O Lord of the Universe, O \nUniversal Form. \n\nMiddle : what lies between two extremities. \n\n14—19] THE UNIVERSAL FORM. 283 \n\nMoreover, \n\n17. I see Thee with diadem, club, and discus; \na mass of splendour shining everywhere, very hard \nto look at, all around blazing like burning fire and \nsun, and immeasurable. \n\nImmeasurable : whose limits cannot be fixed. \n\nVishnu is one* with the Unconditioned. \n\nFrom this vision of Thy power of Yoga (wonder-working) \nI infer, \n\n?sfiT$jx m& ^%r©3*i ^fto ikw® it foreran 1 \n\n18.. Thou art the Imperishable, the Supreme \nBeing worthy to be known. Thou art the great \nAbode of this Universe ; Thou art the undying \nGuardian of the Eternal Dharma, Thou art the \nancient Purusha, I deem. \n\nTo be known : by seekers of liberation. \n\nThe Univeral Form (continued.) \nMoreover, \n\n^iNrcrT fsRmt wan IMS II \n\n284 THE BHAGAVAD GITA. [DlS.", "bhashya_translator": "Alladi Mahadeva Sastry, 1897", "source_key": "gita_json_core+sastry_gita_bhashya", "license": "unlicense", "paraphrase": "Krishna and Arjuna, seated in a grand chariot, sound their conches, signaling the start of an important battle. This moment represents the call to fulfill one's duty with divine support.", "themes": ["dharma", "karma_yoga", "divine_guidance", "righteous_action"], "life_situations": ["preparing for a significant challenge", "facing moral dilemmas in decision-making", "seeking guidance before taking action", "feeling overwhelmed by responsibilities", "needing encouragement to fulfill one's duties"], "emotions_addressed": ["anxiety", "fear", "confusion"], "practical_teaching": "The verse encourages the seeker to embrace their responsibilities with a sense of divine support and readiness.", "hypothetical_questions": ["I feel anxious about the responsibilities I have to face — how can I find strength in this moment?", "I'm unsure about making the right decision in a tough situation — how do I know I'm on the right path?", "I’m facing a big challenge and feel overwhelmed — how can I prepare myself mentally?", "How do I seek guidance when I feel lost in my duties?", "I’m afraid of failing in my responsibilities — what should I do to overcome this fear?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_15", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.15", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Hrishikesha blew the Panchajanya, Arjuna blew the Devadatta, and Bhima, the wolf-bellied doer of terrible deeds, blew the great conch Paundra.", "translator": "Swami Sivananda", "sanskrit": "पाञ्चजन्यं हृषीकेशो देवदत्तं धनंजयः।\n\nपौण्ड्रं दध्मौ महाशङ्खं भीमकर्मा वृकोदरः।।1.15।।", "transliteration": "pāñchajanyaṁ hṛiṣhīkeśho devadattaṁ dhanañjayaḥ\npauṇḍraṁ dadhmau mahā-śhaṅkhaṁ bhīma-karmā vṛikodaraḥ", "word_meanings": "pāñchajanyam—the conch shell named Panchajanya; hṛiṣhīka-īśhaḥ—Shree Krishna, the Lord of the mind and senses; devadattam—the conch shell named Devadutta; dhanam-jayaḥ—Arjun, the winner of wealth; pauṇḍram—the conch named Paundra; dadhmau—blew; mahā-śhaṅkham—mighty conch; bhīma-karmā—one who performs herculean tasks; vṛika-udaraḥ—Bheem, the voracious eater", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "The verse illustrates the moment before battle, where key warriors announce their readiness through the sound of conch shells, marking the start of a significant confrontation.", "themes": ["dharma", "battle_of_life", "readiness", "action", "collective_effort"], "life_situations": ["preparing for a major life challenge", "facing a difficult decision with others", "gathering support for a cause", "starting a new project with a team", "entering a competitive environment"], "emotions_addressed": ["anxiety", "anticipatory_grief", "fear", "confusion"], "practical_teaching": "Be prepared and declare your intentions clearly when facing significant challenges.", "hypothetical_questions": ["I feel overwhelmed about an upcoming competition — how can I gather my strength?", "How do I rally my team before a big project?", "I’m anxious about making a tough decision — what should I do first?", "What can I do to prepare myself mentally for a challenging situation?", "How can I ensure everyone is on the same page before we start?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_16", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.16", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "King Yudhishthira, the son of Kunti, blew the Anantavijaya; Nakula and Sahadeva blew the Sughosha and the Manipushpaka.", "translator": "Swami Sivananda", "sanskrit": "अनन्तविजयं राजा कुन्तीपुत्रो युधिष्ठिरः।\n\nनकुलः सहदेवश्च सुघोषमणिपुष्पकौ।।1.16।।", "transliteration": "anantavijayaṁ rājā kuntī-putro yudhiṣhṭhiraḥ\nnakulaḥ sahadevaśhcha sughoṣha-maṇipuṣhpakau", "word_meanings": "ananta-vijayam—the conch named Anantavijay; rājā—king; kuntī-putraḥ—son of Kunti; yudhiṣhṭhiraḥ—Yudhishthir; nakulaḥ—Nakul; sahadevaḥ—Sahadev; cha—and; sughoṣha-maṇipuṣhpakau—the conche shells named Sughosh and Manipushpak;", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "The verse illustrates the moment when the Pandava brothers prepare for battle by blowing their conch shells, signifying their commitment and readiness to confront the challenges ahead.", "themes": ["dharma", "courage", "unity", "action", "preparedness"], "life_situations": ["preparing for a significant challenge or competition", "facing a difficult decision that requires courage", "coming together with others to achieve a common goal", "feeling the pressure before an important event", "needing to assert oneself in a challenging situation"], "emotions_addressed": ["fear", "anxiety", "anticipatory_grief"], "practical_teaching": "Embrace the challenges ahead with determination and unity, preparing yourself mentally and emotionally for the tasks at hand.", "hypothetical_questions": ["I feel overwhelmed about an upcoming presentation — how can I gather my courage?", "My team is facing a big project deadline — how do we unite and stay focused?", "I’m anxious about a major life decision — how can I prepare myself to face it?", "I’m about to compete in a tournament and feel nervous — what should I do to calm my fears?", "How do I rally my friends to support me in a tough situation?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_17", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.17", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "The king of Kasi, an excellent archer, Sikhandi, the mighty car-warrior, Dhrishtadyumna, Virata, and Satyaki, the unconquered.", "translator": "Swami Sivananda", "sanskrit": "काश्यश्च परमेष्वासः शिखण्डी च महारथः।\n\nधृष्टद्युम्नो विराटश्च सात्यकिश्चापराजितः।।1.17।।", "transliteration": "kāśhyaśhcha parameṣhvāsaḥ śhikhaṇḍī cha mahā-rathaḥ\ndhṛiṣhṭadyumno virāṭaśhcha sātyakiśh chāparājitaḥ", "word_meanings": "kāśhyaḥ—King of Kashi; cha—and; parama-iṣhu-āsaḥ—the excellent archer; śhikhaṇḍī—Shikhandi; cha—also; mahā-rathaḥ—warriors who could single handedly match the strength of ten thousand ordinary warriors; dhṛiṣhṭadyumnaḥ—Dhrishtadyumna; virāṭaḥ—Virat; cha—and; sātyakiḥ—Satyaki; cha—and; aparājitaḥ—invincible;", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "This verse introduces important fighters in the battle, showing their strength and skills, which underscores the seriousness of the conflict ahead.", "themes": ["dharma_yuddha", "heroism", "courage", "unity", "identity"], "life_situations": ["preparing for a significant challenge", "facing a competitive situation", "dealing with pressure from peers", "navigating conflicts in a team", "understanding one's role in a larger cause"], "emotions_addressed": ["anxiety", "fear", "confusion"], "practical_teaching": "pure ontology — no direct prescription", "hypothetical_questions": ["I feel overwhelmed by the expectations of my role in this project — how do I manage that pressure?", "I'm facing tough competition at work and I'm not sure how to stand out — what should I focus on?", "How can I find my purpose in this conflict I'm involved in?", "I'm confused about my responsibilities in this team — how do I clarify my role?", "With so many strong personalities around me, how do I maintain my confidence?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_18", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.18", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Drupada and the sons of Draupadi, O Lord of the Earth, and the son of Subhadra, the mighty-armed, blew their conches each separately.", "translator": "Swami Sivananda", "sanskrit": "द्रुपदो द्रौपदेयाश्च सर्वशः पृथिवीपते।\n\nसौभद्रश्च महाबाहुः शङ्खान्दध्मुः पृथक्पृथक्।।1.18।।", "transliteration": "drupado draupadeyāśhcha sarvaśhaḥ pṛithivī-pate\nsaubhadraśhcha mahā-bāhuḥ śhaṅkhāndadhmuḥ pṛithak pṛithak", "word_meanings": "drupadaḥ—Drupad; draupadeyāḥ—the five sons of Draupadi; cha—and; sarvaśhaḥ—all; pṛithivī-pate—Ruler of the earth; saubhadraḥ—Abhimanyu, the son of Subhadra; cha—also; mahā-bāhuḥ—the mighty-armed; śhaṅkhān—conch shells; dadhmuḥ—blew; pṛithak pṛithak—individually", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "This verse illustrates the moment when key warriors prepare for battle by blowing their conches, signaling their readiness and unity in the face of conflict.", "themes": ["dharma", "karma", "unity", "preparation_for_battle"], "life_situations": ["preparing for an important competition or challenge", "facing a significant decision with multiple stakeholders", "gathering support for a cause", "entering a new phase of life with determination", "standing united with friends or family in a difficult situation"], "emotions_addressed": ["anticipatory_grief", "fear", "anxiety"], "practical_teaching": "pure ontology — no direct prescription", "hypothetical_questions": ["I feel overwhelmed as I prepare for a big presentation — how can I find my confidence?", "How do I rally my team when we face a tough challenge ahead?", "I’m anxious about the upcoming changes in my life — what should I focus on?", "What can I do to strengthen my resolve before a major decision?", "How can I ensure that my friends and I stay united during tough times?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_19", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.19", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "The tumultuous sound rent the hearts of Dhritarashtra's party, reverberating through both heaven and earth.", "translator": "Swami Sivananda", "sanskrit": "स घोषो धार्तराष्ट्राणां हृदयानि व्यदारयत्।\n\nनभश्च पृथिवीं चैव तुमुलो व्यनुनादयन्।।1.19।।", "transliteration": "sa ghoṣho dhārtarāṣhṭrāṇāṁ hṛidayāni vyadārayat\nnabhaśhcha pṛithivīṁ chaiva tumulo nunādayan", "word_meanings": "saḥ—that; ghoṣhaḥ—sound; dhārtarāṣhṭrāṇām—of Dhritarashtra’s sons; hṛidayāni—hearts; vyadārayat—shattered; nabhaḥ—the sky; cha—and; pṛithivīm—the earth; cha—and; eva—certainly; tumulaḥ—terrific sound; abhyanunādayan—thundering", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "The loud sound of conch shells filled the air, deeply affecting the hearts of Dhritarashtra's side, signaling the seriousness of the battle about to unfold.", "themes": ["fear", "anxiety", "karma_yoga", "dharma"], "life_situations": ["feeling overwhelmed by a challenging situation", "experiencing fear before a big decision", "facing a conflict with loved ones", "dealing with anxiety about the future", "preparing for a significant life change"], "emotions_addressed": ["fear", "anxiety"], "practical_teaching": "Recognize the intensity of your feelings in the face of challenges and prepare to confront them with clarity.", "hypothetical_questions": ["I'm about to face a big confrontation — how do I manage my fear?", "I feel overwhelmed by the pressure of my responsibilities — what should I do?", "How can I stay calm when everything feels chaotic around me?", "I'm anxious about making the right decision — how can I find clarity?", "What should I do when I feel my heart racing before a big event?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_20", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.20", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Then, seeing the people of Dhritarashtra's party standing arrayed and the discharge of weapons about to begin, Arjuna, the son of Pandu whose ensign was a monkey, took up his bow and said the following to Krishna, O Lord of the Earth.", "translator": "Swami Sivananda", "sanskrit": "अथ व्यवस्थितान् दृष्ट्वा धार्तराष्ट्रान्कपिध्वजः।\n\nप्रवृत्ते शस्त्रसंपाते धनुरुद्यम्य पाण्डवः।।1.20।।", "transliteration": "atha vyavasthitān dṛiṣhṭvā dhārtarāṣhṭrān kapi-dhwajaḥ\npravṛitte śhastra-sampāte dhanurudyamya pāṇḍavaḥ\nhṛiṣhīkeśhaṁ tadā vākyam idam āha mahī-pate", "word_meanings": "atha—thereupon; vyavasthitān—arrayed; dṛiṣhṭvā—seeing; dhārtarāṣhṭrān—Dhritarashtra’s sons; kapi-dwajaḥ—the Monkey Bannered; pravṛitte—about to commence; śhastra-sampāte—to use the weapons; dhanuḥ—bow; udyamya—taking up; pāṇḍavaḥ—Arjun, the son of Pandu; hṛiṣhīkeśham—to Shree Krishna; tadā—at that time; vākyam—words; idam—these; āha—said; mahī-pate—King", "bhashya": "\" O Achyuta (Immortal), place my chariot \nbetween the two armies, that I may just see those \nwho stand here desirous to fight, and know with \nwhom I must fight in this strife of battle. \n\n23. \" I will observe those who are assembled \nhere and are about to engage in battle desirous to \ndo service in war to the evil-minded son of \nDhritarashfra\" \n\nWl^Pf e$NJfr ?pr%iN vrrc^ I \n&ratw*tt&!3ir ^r#f^T wlwflt II Htf II \n\n^h m§ m^^F^mm^ww^f^ 11 ^h u \n\nSa?njaya said : \n24-25. O descendant of Bharata, Hrishike^a \n(Krishna) thus addressed by Guiakesa (Arjuna) \nstationed that excellent car betweeq the two armies \nin front of Bhishma and Dro^a and all the rulers \nof earth, and said : \" O son of PHtha, look at these \nassembled Kauravas*\" \n\n20—30] THE DESPONDENCY OF ARJUNA 13 \n\n^S^TFIf $k S^ritorikfir I \n\n26-27. Then the son of Pritha saw arrayed \nthere in both the armies fathers and grandfathers, \nteachers, maternal uncles, brothers, sons, grandsons \nand comrades, fathers-in-law and friends. \n\n^ <\\ \n\nsFOTflpr sr «prw: e«n»iw|jwreraT^ II ^ II \n\n27-28. When the son of Kunti saw all the \nkinsmen standing, he was overcome with deepest \npity and said thus in sorrow : \n\nAriuna's words of despondency \n\ns|* m^H w®t 3?PS «g., those who are \nengaged in karma or action. The latter are spoken of as \nYogins only by courtesy ; and they are so spoken of in iii. 3. \nI shall tell you, when dying the Yogins are not born again, \nand when dying they will be born again. \n\nHe speaks of that time : \n\n* At tbe end of tfc* kalpa. \n\n22—251 ABHYASA YOGA. 235 \n\n24. Fire, light, day-time, the bright fortnight,. \nthe six months of the northern solstice, — then \ndeparting, men who know Brahman reach Brahman. \n\n' Fire * is the deity presiding over time ; so also is * light * \na deity presiding over time.— Or, it may be that ' fire * and \nlight ' are the deities so called ; the reference, however, to \nthe path as a whole by the expressions * in what time * and \n* that time * being due to the predominance of the deities \npresiding over time.' — The * day-time ' is the deity presiding \nover the day-time, the ' bright fortnight ' is the deity presiding \nover the bright fortnight. The six months of the northern \nsolstice : here also, it is the deity that forms the path, The \nprinciple on which this interpretation of the passage is based \nhas been established elsewere.* Those who die, having been \nengaged in the contemplation of Brahman, reach Brahman by \nthis path. The expression u in course of time \" should be \nunderstood after ' reach *; for, those who are firm in devotion \nto right knowledge and attain to immediate liberation have no \nplace to go to or to return from. \n\n25. Smoke, night-time, and the dark fortnight, \nthe six months of the southern solstice,— attaining \nby these to the lunar light, the Yogin returns. \n\n1 Smoke,* ' night time,* the * dark fortnight,* and the 6 six \nmonths of the southern solstice,\" are all deities presiding over \nsmoke and periods of time spoken of. By this path, the \nYogin — the Karmin who performs sacrifices Cto Gods) and \nother works — attains to the lunar light, and on the exhaus- \ntion thereof, returns again to earth \n\n• Sarir&ka Mima»*sa, iv 3-4. \n\n236 THE BHAGAVAD GITA. [DlS.", "bhashya_translator": "Alladi Mahadeva Sastry, 1897", "source_key": "gita_json_core+sastry_gita_bhashya", "license": "unlicense", "paraphrase": "Arjuna is conflicted and wants to see who he will be fighting against, particularly those he considers to have bad intentions, which reflects his struggle with the idea of going into battle against his relatives.", "themes": ["dharma", "internal_conflict", "karma_yoga", "non_attachment"], "life_situations": ["feeling torn about a difficult decision involving family", "struggling with the morality of a competitive situation", "facing pressure to act against personal values", "dealing with conflicting loyalties in a challenging situation"], "emotions_addressed": ["confusion", "fear", "anxiety"], "practical_teaching": "The verse encourages the seeker to confront their inner conflicts and understand the implications of their actions in relation to their duties.", "hypothetical_questions": ["I feel guilty about fighting against my family — how do I reconcile this?", "What should I do when my duty conflicts with my personal beliefs?", "How can I find clarity when I'm anxious about the consequences of my actions?", "I'm struggling with the idea of competing against someone I care about — how do I handle this?", "How do I make a decision when I feel torn between loyalty and responsibility?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_24", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.24", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Sanjaya said, Thus addressed by Arjuna, Krishna stationed the best of chariots, O Dhritarashtra, in the midst of the two armies.", "translator": "Swami Sivananda", "sanskrit": "संजय उवाच\n\nएवमुक्तो हृषीकेशो गुडाकेशेन भारत।\n\nसेनयोरुभयोर्मध्ये स्थापयित्वा रथोत्तमम्।।1.24।।", "transliteration": "sañjaya uvācha\nevam ukto hṛiṣhīkeśho guḍākeśhena bhārata\nsenayor ubhayor madhye sthāpayitvā rathottamam", "word_meanings": "sañjayaḥ uvācha—Sanjay said; evam—thus; uktaḥ—addressed; hṛiṣhīkeśhaḥ—Shree Krishna, the Lord of the senses; guḍākeśhena—by Arjun, the conqueror of sleep; bhārata—descendant of Bharat; senayoḥ—armies; ubhayoḥ—the two; madhye—between; sthāpayitvā—having drawn; ratha-uttamam—magnificent chariot", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "Krishna places Arjuna's chariot in the center of the battlefield, preparing for the confrontation ahead and signaling the start of a significant moral and spiritual discussion.", "themes": ["dharma", "karma_yoga", "moral_conflict", "spiritual_guidance"], "life_situations": ["facing a difficult decision between right and wrong", "feeling overwhelmed by conflicting responsibilities", "preparing for a challenging confrontation", "seeking guidance in a moment of crisis", "navigating personal dilemmas in relationships"], "emotions_addressed": ["confusion", "anxiety", "fear"], "practical_teaching": "pure ontology — no direct prescription", "hypothetical_questions": ["I'm torn between my duty to my family and my principles — what should I do?", "How do I find clarity when I'm facing pressure from both sides?", "I feel anxious about the choices I have to make — how can I cope?", "What if I regret my decisions after the battle begins?", "How can I trust my instincts when everything feels so uncertain?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_25", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.25", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "In front of Bhishma and Drona, and all the rulers of the earth, he said: \"O Arjuna, son of Pritha, behold these Kurus gathered together.\"", "translator": "Swami Sivananda", "sanskrit": "भीष्मद्रोणप्रमुखतः सर्वेषां च महीक्षिताम्।\n\nउवाच पार्थ पश्यैतान्समवेतान्कुरूनिति।।1.25।।", "transliteration": "bhīṣhma-droṇa-pramukhataḥ sarveṣhāṁ cha mahī-kṣhitām\nuvācha pārtha paśhyaitān samavetān kurūn iti", "word_meanings": "bhīṣhma—Grandsire Bheeshma; droṇa—Dronacharya; pramukhataḥ—in the presence; sarveṣhām—all; cha—and; mahī-kṣhitām—other kings; uvācha—said; pārtha—Arjun, the son of Pritha; paśhya—behold; etān—these; samavetān—gathered; kurūn—descendants of Kuru; iti—thus", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "Arjuna is instructed to look at the assembled warriors on the battlefield, which includes his relatives and revered teachers, emphasizing the gravity of the conflict he is about to engage in.", "themes": ["dharma", "karma_yoga", "family_duties", "moral_conflict"], "life_situations": ["feeling overwhelmed by family expectations", "struggling with a difficult decision that affects loved ones", "facing a moral dilemma in a competitive environment", "dealing with pressure from authority figures", "navigating conflicts between personal beliefs and social obligations"], "emotions_addressed": ["anxiety", "confusion", "fear"], "practical_teaching": "Reflect on the responsibilities and relationships that weigh on your decisions.", "hypothetical_questions": ["I feel torn between my duty to my family and my personal beliefs — what should I do?", "How do I handle the pressure from my elders when I disagree with their views?", "I’m facing a tough choice that could hurt my loved ones — how can I find clarity?", "What if I have to fight against those I care about — how do I cope with that?", "I’m feeling anxious about the expectations placed on me by my family — how can I manage this?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_26", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.26", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "Then, Arjuna (son of Pritha) saw there (in the armies) stationed fathers, grandfathers, teachers, maternal uncles, brothers, sons, grandsons, and friends.", "translator": "Swami Sivananda", "sanskrit": "तत्रापश्यत्स्थितान्पार्थः पितृ़नथ पितामहान्।\n\nआचार्यान्मातुलान्भ्रातृ़न्पुत्रान्पौत्रान्सखींस्तथा।।1.26।।", "transliteration": "tatrāpaśhyat sthitān pārthaḥ pitṝīn atha pitāmahān\nāchāryān mātulān bhrātṝīn putrān pautrān sakhīṁs tathā\nśhvaśhurān suhṛidaśh chaiva senayor ubhayor api", "word_meanings": "tatra—there; apaśhyat—saw; sthitān—stationed; pārthaḥ—Arjun; pitṝīn—fathers; atha—thereafter; pitāmahān—grandfathers; āchāryān—teachers; mātulān—maternal uncles; bhrātṝīn—brothers; putrān—sons; pautrān—grandsons; sakhīn—friends; tathā—also; śhvaśhurān—fathers-in-law; suhṛidaḥ—well-wishers; cha—and; eva—indeed; senayoḥ—armies; ubhayoḥ—in both armies; api—also", "bhashya": "", "bhashya_translator": "", "source_key": "gita_json_core", "license": "unlicense", "paraphrase": "Arjuna sees his family and loved ones on the battlefield, which makes him question the morality of fighting against them.", "themes": ["dharma", "karma", "attachment", "family", "inner_conflict"], "life_situations": ["facing a moral dilemma about family obligations", "struggling with the consequences of a difficult decision", "feeling torn between duty and personal relationships", "dealing with the pressure of expectations from loved ones", "experiencing conflict in a competitive environment"], "emotions_addressed": ["fear", "anxiety", "confusion", "longing"], "practical_teaching": "The verse encourages the seeker to reflect on the complexities of duty and relationships when faced with challenging decisions.", "hypothetical_questions": ["How do I handle a situation where my responsibilities conflict with my love for my family?", "I feel torn about making a decision that could hurt my loved ones — what should I do?", "What if my duty requires me to act against those I care about?", "How can I find clarity when my emotions are clouding my judgment?", "I’m anxious about disappointing my family — how do I navigate this?"], "enrichment_model": "openai/gpt-4o-mini", "enrichment_version": 1} +{"verse_id": "bhagavad_gita_01_27", "work": "bhagavad_gita", "work_display": "Bhagavad Gītā", "verse_ref": "BG 1.27", "tier": "primary", "section": "chapter_01", "section_display": "Chapter 1: Arjuna Visada Yoga", "translation": "He saw fathers-in-law and friends in both the armies. The son of Kunti, Arjuna, seeing all those kinsmen thus standing arrayed, spoke sorrowfully, deeply filled with pity.", "translator": "Swami Sivananda", "sanskrit": "श्वशुरान्सुहृदश्चैव सेनयोरुभयोरपि।\n\nतान्समीक्ष्य स कौन्तेयः सर्वान्बन्धूनवस्थितान्।।1.27।।", "transliteration": "tān samīkṣhya sa kaunteyaḥ sarvān bandhūn avasthitān\nkṛipayā parayāviṣhṭo viṣhīdann idam abravīt", "word_meanings": "tān—these; samīkṣhya—on seeing; saḥ—they; kaunteyaḥ—Arjun, the son of Kunti; sarvān—all; bandhūn—relatives; avasthitān—present; kṛipayā—by compassion; parayā—great; āviṣhṭaḥ—overwhelmed; viṣhīdan—deep sorrow; idam—this; abravīt—spoke", "bhashya": "—28] MATTER AND SPIRIT. 371 \n\nHe who realises that the Is vara described in the last pre- \nceding verse is the same — *. e., he who sees that he dwells in \nall creatures alike — destroys not his own self by himself. \nBecause he does not destroy the self, he reaches the Supreme \nGoal, he attains moksha.* \n\n(Objection) : — No living being whatever destroys itself by \nitself. Where then is the necessity for the denial *' He \ndestroys not the self by the self,*' any more than for the \nprohibition f \" fire should be consecrated not on earth, not in \n•the sky, not in heaven \" (Tait. Sam. 5-2-7) ? \n\n(Answer) :—This objection does not apply here ; for, the \nnecessity may be explained on the ground that ignorant men \nare guilty of ignoring the Self. An ignorant man ignores the \nSelf who is quite manifest to all, self-manifested, and directly \nvisible, and he regards the not-Self (physical body, etc) as \nhimself. Having performed good and evil works (dharma \n•and a-dharma), he kills even this self (the physical body, etc) \nwhich he had accepted and accepts another new self ; he kills \nthis again and accepts another and' so on ; thus he goes on \nkilling every new self that he has accepted. An ignorant \nman is, accordingly, a slayer of the self. Even the real Self \nis always killed by avidya, inasmuch as there is no percep- \ntible effect of His existence. Thus, all ignorant men are but \n\n* Knowledge destroys ignorance, and with it all evil is destroyed. \nOn. the destruction of nescience (ajnana) and false knowledge