Skip to content

feat: add YouTube knowledge source ingestion and retrieval - #60

Open
chaudharyvinay4 wants to merge 4 commits into
mosip:developfrom
chaudharyvinay4:issue-48-youtube-clean
Open

feat: add YouTube knowledge source ingestion and retrieval#60
chaudharyvinay4 wants to merge 4 commits into
mosip:developfrom
chaudharyvinay4:issue-48-youtube-clean

Conversation

@chaudharyvinay4

@chaudharyvinay4 chaudharyvinay4 commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR adds YouTube as a new knowledge source to MOSIP Nexus, enabling relevant MOSIP YouTube video transcripts to be indexed, retrieved, and used during RAG response generation.

Changes

YouTube Ingestion

  • Added a YouTube crawler to collect video metadata and transcripts.
  • Added an ingestion pipeline for processing YouTube content.
  • Chunked and embedded transcripts into a dedicated pgvector collection.

Retrieval

  • Integrated YouTube into the unified retrieval pipeline.
  • Included YouTube results in the retrieval context used for answer generation.
  • Added YouTube source attribution in the UI.

Configuration

  • Added configuration required for YouTube ingestion and retrieval.
  • Added sample YouTube dataset for indexing.

Testing

  • Successfully indexed YouTube transcripts.
  • Verified retrieval returns relevant YouTube content.
  • Verified RAG responses include YouTube as a cited source.
  • Confirmed existing knowledge sources continue to work correctly.

Summary by CodeRabbit

  • New Features

    • Added YouTube channel crawling, transcript extraction, and ingestion.
    • YouTube videos can now appear in search results, source citations, chat exports, and source filters.
    • Added YouTube configuration for API access and channel selection.
  • Improvements

    • The Groq API key is now loaded securely from environment settings.
    • Reduced the amount of retrieved content used to generate responses for more focused results.
    • Added YouTube source labels and icons across the interface.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds YouTube crawling, transcript chunking, pgvector retrieval, response attribution, and UI support. Groq configuration is loaded from environment settings, and the maximum LLM context document count is reduced.

Changes

YouTube knowledge-source integration

Layer / File(s) Summary
YouTube configuration and dependencies
MosipNexus/.env.example, MosipNexus/config/settings.py, MosipNexus/pyproject.toml
Adds YouTube credentials, channel and storage settings, YouTube client dependencies, and reduces MAX_CONTEXT_DOCS from 40 to 10.
YouTube crawl and transcript chunking
MosipNexus/crawler/youtube_crawler.py, MosipNexus/ingestion/ingest_youtube.py
Crawls channel videos, retrieves transcripts with fallback handling, writes video documents to JSON, and creates overlapping transcript chunks.
YouTube retrieval and response attribution
MosipNexus/retrieval/retriever.py, MosipNexus/chain/query_engine.py
Loads the optional YouTube collection, includes YouTube results in retrieval and scoring, and adds YouTube source classification and attribution.
Application configuration and source UI
MosipNexus/app/app.py, MosipNexus/app/pages/settings.py
Loads the Groq key from configuration, disables interactive API-key editing, and adds YouTube source labels, icons, and sidebar entries.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant YouTubeDataAPI
  participant youtube_crawler
  participant ingest_youtube
  participant retriever
  participant query_engine
  YouTubeDataAPI->>youtube_crawler: video metadata and transcripts
  youtube_crawler->>ingest_youtube: JSON video documents
  ingest_youtube->>retriever: transcript chunks in YouTube collection
  retriever->>query_engine: YouTube and other retrieved chunks
  query_engine-->>retriever: source classification and attributions
Loading

Possibly related issues

Suggested reviewers: mohanachandran-s

Poem

Videos drift into the knowledge stream,
Transcripts weave a searchable dream.
Chunks align and vectors glow,
YouTube sources now join the show.
Groq keys rest in .env bright—
MOSIP answers take new flight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding YouTube as a knowledge source with ingestion and retrieval.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@MosipNexus/.env.example`:
- Line 40: Replace the real credential assigned to YOUTUBE_API_KEY in the
environment template with a clearly fake placeholder value, preserving the
variable name and configuration format.

In `@MosipNexus/app/pages/settings.py`:
- Around line 253-260: Remove the plaintext GROQ_API_KEY from the st.text_input
value in the settings UI; display only a non-secret masked placeholder or empty
value while retaining the disabled password field and explanatory help text.
Keep api_key server-side for backend use without passing the secret to the
client DOM.

In `@MosipNexus/ingestion/ingest_youtube.py`:
- Around line 66-83: Update the ingestion flow after loading videos to iterate
over every video, chunk each transcript, generate embeddings, and persist the
resulting chunks and metadata into the dedicated pgvector collection. Replace
the single-video console-only handling around first, chunk_transcript, and the
print statements with database ingestion while preserving the existing
transcript chunking behavior and collection configuration.

In `@MosipNexus/pyproject.toml`:
- Around line 27-28: Update the dependencies list in pyproject.toml to restore
the runtime packages mcp, langchain-anthropic, and langchain-openai. Keep the
existing dependency declarations intact and add these packages so the imports
used by query_engine.py and server.py resolve at runtime.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: eea6ea44-ec83-4b6e-a40b-5d03854bb651

📥 Commits

Reviewing files that changed from the base of the PR and between 2efd597 and 72be2d3.

⛔ Files ignored due to path filters (1)
  • MosipNexus/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • MosipNexus/.env.example
  • MosipNexus/app/app.py
  • MosipNexus/app/pages/settings.py
  • MosipNexus/chain/query_engine.py
  • MosipNexus/config/settings.py
  • MosipNexus/crawler/youtube_crawler.py
  • MosipNexus/data/mosip_youtube.json
  • MosipNexus/ingestion/ingest_youtube.py
  • MosipNexus/pyproject.toml
  • MosipNexus/retrieval/retriever.py

Comment thread MosipNexus/.env.example Outdated
Comment thread MosipNexus/app/pages/settings.py Outdated
Comment on lines +66 to +83
with open(YOUTUBE_FILE, encoding="utf-8") as f:
videos = json.load(f)

print(f"Loaded {len(videos)} videos")

first = videos[0]

chunks = chunk_transcript(first["transcript"])

print()

print(first["title"])

print(f"Chunks: {len(chunks)}")

print(chunks[0]["start"])

print(chunks[0]["text"][:250]) No newline at end of file

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🔴 Critical | 🏗️ Heavy lift

Implement full ingestion and database embedding.

The script currently only processes the first video (videos[0]) and prints the output to the console. It does not iterate over all videos or embed them into the pgvector collection. Failing to embed the data violates MOSIP data integrity standards by leaving the knowledge base unpopulated. As per PR objectives, transcript chunking and embedding into a dedicated pgvector collection is required.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@MosipNexus/ingestion/ingest_youtube.py` around lines 66 - 83, Update the
ingestion flow after loading videos to iterate over every video, chunk each
transcript, generate embeddings, and persist the resulting chunks and metadata
into the dedicated pgvector collection. Replace the single-video console-only
handling around first, chunk_transcript, and the print statements with database
ingestion while preserving the existing transcript chunking behavior and
collection configuration.

Comment thread MosipNexus/pyproject.toml
Comment on lines +27 to +28
"google-api-python-client>=2.100.0",
"youtube-transcript-api>=0.6.2",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check if langchain or mcp dependencies are still present in pyproject.toml

rg -e "langchain" -e "mcp" pyproject.toml

Repository: mosip/mosip-labs

Length of output: 209


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate pyproject.toml files and inspect the relevant one(s)
git ls-files | rg '(^|/)pyproject\.toml$'

# Show the relevant section for each candidate without reading too much
for f in $(git ls-files | rg '(^|/)pyproject\.toml$'); do
  echo "===== $f ====="
  wc -l "$f"
  sed -n '1,120p' "$f"
done

Repository: mosip/mosip-labs

Length of output: 1118


🏁 Script executed:

#!/bin/bash
set -euo pipefail

git ls-files | rg '(^|/)pyproject\.toml$'
for f in $(git ls-files | rg '(^|/)pyproject\.toml$'); do
  echo "===== $f ====="
  wc -l "$f"
  sed -n '1,120p' "$f"
done

Repository: mosip/mosip-labs

Length of output: 1118


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the repository path that contains the targeted pyproject.toml
fd -a --hidden --glob 'pyproject.toml' .

# If MosipNexus/pyproject.toml exists, print the relevant dependency block
if [ -f MosipNexus/pyproject.toml ]; then
  echo "===== MosipNexus/pyproject.toml ====="
  wc -l MosipNexus/pyproject.toml
  sed -n '1,120p' MosipNexus/pyproject.toml
fi

Repository: mosip/mosip-labs

Length of output: 1137


🏁 Script executed:

#!/bin/bash
set -euo pipefail

cd MosipNexus

echo "== package refs =="
rg -n --hidden -S '\b(mcp|langchain-anthropic|langchain-openai)\b' .

echo "== langchain provider imports =="
rg -n --hidden -S 'from langchain_(anthropic|openai)|import langchain_(anthropic|openai)' .

Repository: mosip/mosip-labs

Length of output: 3715


🏁 Script executed:

#!/bin/bash
set -euo pipefail

cd MosipNexus

# Inspect the query engine around the provider imports and fallback logic
wc -l chain/query_engine.py
sed -n '1,160p' chain/query_engine.py

# Also inspect the MCP server entrypoint imports to see if the MCP package is required directly
wc -l mcp_server/server.py
sed -n '1,120p' mcp_server/server.py

Repository: mosip/mosip-labs

Length of output: 11058


Restore the missing runtime dependencies MosipNexus/pyproject.toml no longer declares mcp, langchain-anthropic, or langchain-openai, but chain/query_engine.py and mcp_server/server.py import them directly. That breaks the MCP server and Anthropic/OpenAI provider paths at runtime.

dependencies = [
  ...
  "mcp",
  "langchain-anthropic",
  "langchain-openai",
]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@MosipNexus/pyproject.toml` around lines 27 - 28, Update the dependencies list
in pyproject.toml to restore the runtime packages mcp, langchain-anthropic, and
langchain-openai. Keep the existing dependency declarations intact and add these
packages so the imports used by query_engine.py and server.py resolve at
runtime.

Signed-off-by: Vinay Kumar <chaudharyvinay44477@gmail.com>
Signed-off-by: Vinay Kumar <chaudharyvinay44477@gmail.com>
@chaudharyvinay4
chaudharyvinay4 force-pushed the issue-48-youtube-clean branch from 72be2d3 to 7ec9ec3 Compare July 15, 2026 19:27
Signed-off-by: Vinay Kumar <chaudharyvinay44477@gmail.com>
Signed-off-by: Vinay Kumar <chaudharyvinay44477@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (2)
MosipNexus/ingestion/ingest_youtube.py (1)

66-83: 🗄️ Data Integrity & Integration | 🔴 Critical | 🏗️ Heavy lift

Ingestion pipeline still doesn't embed anything — unresolved from prior review.

Same gap flagged previously: this script only loads videos[0], chunks its transcript, and prints debug output — no loop over all videos, no embeddings, no writes to the pgvector YOUTUBE_COLLECTION. As per PR objectives, transcript chunking and embedding into a dedicated pgvector collection is required, but nothing is persisted here.

Also, this runs unconditionally at module import time (no if __name__ == "__main__": guard) — worth wrapping in a main()/guard as part of the rewrite so the module can be safely imported by an orchestrator without side effects.

if __name__ == "__main__":
    main()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@MosipNexus/ingestion/ingest_youtube.py` around lines 66 - 83, Rewrite the
module-level ingestion flow around YOUTUBE_FILE so a main() function processes
every video, chunks each transcript, generates embeddings, and persists the
resulting chunks to the pgvector YOUTUBE_COLLECTION instead of only printing
videos[0] debug data. Preserve the existing chunk_transcript behavior and
collection configuration, and invoke main() only under an if __name__ ==
"__main__": guard so importing the module has no side effects.
MosipNexus/pyproject.toml (1)

27-28: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

Runtime deps still missing: mcp, langchain-anthropic, langchain-openai.

This is the same gap flagged in a previous review: those packages were dropped and this diff again modifies the same block without restoring them, while chain/query_engine.py and mcp_server/server.py import them directly.

🔧 Proposed fix
 dependencies = [
+    "mcp",
+    "langchain-anthropic",
+    "langchain-openai",
     "google-api-python-client>=2.100.0",
     "youtube-transcript-api>=0.6.2",
 ]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@MosipNexus/pyproject.toml` around lines 27 - 28, Restore the missing runtime
dependencies in the project dependency list: add mcp, langchain-anthropic, and
langchain-openai alongside the existing entries. Ensure the versions are
compatible with the direct imports used by chain/query_engine.py and
mcp_server/server.py.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@MosipNexus/app/pages/settings.py`:
- Around line 253-260: Fix the syntax error in the API key widget arguments by
adding the missing comma after the value argument in the settings page, before
the type argument. Keep the existing disabled password-field configuration and
GROQ_API_KEY assignment unchanged.

In `@MosipNexus/config/settings.py`:
- Line 59: Increase MAX_CONTEXT_DOCS from 10 or add per-source minimum
reservations before the global deduplication slice, ensuring YouTube results
cannot crowd out existing prod-code, docs, community, GitHub, and demo-code
context; preserve the final context limit and existing source-priority behavior
where applicable.

In `@MosipNexus/ingestion/ingest_youtube.py`:
- Around line 7-11: Update the chunk_transcript call in the ingestion flow to
pass the imported CHUNK_SIZE and CHUNK_OVERLAP configuration values explicitly,
replacing reliance on its hardcoded defaults. Keep the existing transcript and
chunking flow unchanged.

---

Duplicate comments:
In `@MosipNexus/ingestion/ingest_youtube.py`:
- Around line 66-83: Rewrite the module-level ingestion flow around YOUTUBE_FILE
so a main() function processes every video, chunks each transcript, generates
embeddings, and persists the resulting chunks to the pgvector YOUTUBE_COLLECTION
instead of only printing videos[0] debug data. Preserve the existing
chunk_transcript behavior and collection configuration, and invoke main() only
under an if __name__ == "__main__": guard so importing the module has no side
effects.

In `@MosipNexus/pyproject.toml`:
- Around line 27-28: Restore the missing runtime dependencies in the project
dependency list: add mcp, langchain-anthropic, and langchain-openai alongside
the existing entries. Ensure the versions are compatible with the direct imports
used by chain/query_engine.py and mcp_server/server.py.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7af049d1-32b4-44db-84aa-baf36fe13124

📥 Commits

Reviewing files that changed from the base of the PR and between 72be2d3 and 094ad98.

⛔ Files ignored due to path filters (1)
  • MosipNexus/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • MosipNexus/.env.example
  • MosipNexus/app/app.py
  • MosipNexus/app/pages/settings.py
  • MosipNexus/chain/query_engine.py
  • MosipNexus/config/settings.py
  • MosipNexus/crawler/youtube_crawler.py
  • MosipNexus/data/mosip_youtube.json
  • MosipNexus/ingestion/ingest_youtube.py
  • MosipNexus/pyproject.toml
  • MosipNexus/retrieval/retriever.py

Comment on lines +253 to +260
value="Loaded from .env"
type="password",
placeholder=key_placeholder,
key="_api_key_widget",
on_change=_sync_api_key,
disabled=True,
label_visibility="collapsed",
help="API key is loaded from the .env file."
)
api_key = st.session_state.get("llm_api_key", "")

api_key = GROQ_API_KEY

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Fix the syntax error.

The missing comma after the value argument causes a SyntaxError that crashes the application. Such service outages violate MOSIP operational availability and compliance baselines.

🐛 Proposed fix
-            value="Loaded from .env"
+            value="Loaded from .env",
             type="password",
             disabled=True,  
             label_visibility="collapsed",
             help="API key is loaded from the .env file."
         )
 
         api_key = GROQ_API_KEY
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
value="Loaded from .env"
type="password",
placeholder=key_placeholder,
key="_api_key_widget",
on_change=_sync_api_key,
disabled=True,
label_visibility="collapsed",
help="API key is loaded from the .env file."
)
api_key = st.session_state.get("llm_api_key", "")
api_key = GROQ_API_KEY
value="Loaded from .env",
type="password",
disabled=True,
label_visibility="collapsed",
help="API key is loaded from the .env file."
)
api_key = GROQ_API_KEY
🧰 Tools
🪛 Ruff (0.15.21)

[warning] 254-254: Expected ,, found type

(invalid-syntax)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@MosipNexus/app/pages/settings.py` around lines 253 - 260, Fix the syntax
error in the API key widget arguments by adding the missing comma after the
value argument in the settings page, before the type argument. Keep the existing
disabled password-field configuration and GROQ_API_KEY assignment unchanged.

Source: Linters/SAST tools

RETRIEVAL_K = 8 # final chunks returned per collection
RETRIEVAL_FETCH_K = 30 # MMR candidate pool
MAX_CONTEXT_DOCS = 40 # hard cap on total docs passed to LLM (prevents context overflow)
MAX_CONTEXT_DOCS = 10

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

MAX_CONTEXT_DOCS cut 75% (40→10) while adding a 5th competing source.

Per retriever.py, the final context is _deduped[:MAX_CONTEXT_DOCS] over the concatenation of prod-code, docs, community, github, youtube, and demo-code results — there's no per-source floor. Dropping the cap to 10 at the same time YouTube is added as a new competitor for that slice risks starving existing sources (docs/community/github/code) of context, potentially degrading answer quality/citations for previously working queries.

Consider either a higher cap or per-source minimums (e.g., reserve N slots per collection before the global truncation) so YouTube doesn't crowd out existing sources.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@MosipNexus/config/settings.py` at line 59, Increase MAX_CONTEXT_DOCS from 10
or add per-source minimum reservations before the global deduplication slice,
ensuring YouTube results cannot crowd out existing prod-code, docs, community,
GitHub, and demo-code context; preserve the final context limit and existing
source-priority behavior where applicable.

Comment on lines +7 to +11
from config.settings import (
YOUTUBE_FILE,
CHUNK_SIZE,
CHUNK_OVERLAP,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

CHUNK_SIZE/CHUNK_OVERLAP imported but unused — chunking silently ignores configured values.

chunk_transcript keeps its hardcoded defaults (chunk_size=500, overlap=50); the imported CHUNK_SIZE/CHUNK_OVERLAP from config.settings are never passed in at the call site (Line 73), so this ingestion path diverges from the shared chunking config used elsewhere.

🔧 Proposed fix
-chunks = chunk_transcript(first["transcript"])
+chunks = chunk_transcript(first["transcript"], chunk_size=CHUNK_SIZE, overlap=CHUNK_OVERLAP)

Also applies to: 13-13

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@MosipNexus/ingestion/ingest_youtube.py` around lines 7 - 11, Update the
chunk_transcript call in the ingestion flow to pass the imported CHUNK_SIZE and
CHUNK_OVERLAP configuration values explicitly, replacing reliance on its
hardcoded defaults. Keep the existing transcript and chunking flow unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant