An advanced AI agent that processes YouTube video transcripts to analyze claims across multiple perspectives, detect bias and potential deception, and output a rich "truth profile" per claim.
In the age of algorithmic feeds, users are often trapped in filter bubbles where they only encounter information that reinforces their existing beliefs. Misinformation spreads rapidly on video platforms like YouTube, where verifying claims requires significant effort (cross-referencing sources, checking scientific consensus, etc.). Most users simply don't have the time or expertise to fact-check every video they watch.
Perspective Prism is an AI agent that acts as an automated, multi-perspective fact-checker. It analyzes YouTube video transcripts to identify verifiable claims, retrieves supporting or refuting evidence from trusted sources, evaluates bias and credibility, and presents a comprehensive "Truth Profile" to help users make informed decisions about the content they consume.
Perspective Prism operates as a pipeline of specialized sub-agents:
- Claim Extractor: Uses an LLM to parse YouTube transcripts and identify distinct, verifiable claims.
- Evidence Retriever: Dynamically queries the Google Custom Search API to find external evidence.
- Analysis Engine: Synthesizes the claim and retrieved evidence to determine support/refutation and detects bias.
- AI Engine: Utilizes Gemini API (
gemini-3.5-flash-lite) via thegoogle-genaiSDK and thegoogle-adkframework for structured outputs. - Reliability Layer: Features a custom
google-genaicircuit breaker that automatically falls back togemini-3.1-flash-liteduring transient API errors (e.g. 429, 500, 503).
- AI Engine: Utilizes Gemini API (
- Truth Profiler: Aggregates these insights into a user-friendly "Truth Profile".
Perspective Prism offers:
- Enhanced Claim Analysis: The system supports a configurable claim limit (default: 15 claims) via the
MAX_CLAIMS_PER_ANALYSISsetting, allowing flexibility based on video complexity and API constraints. - Extended Transcript Coverage: Supports transcript processing up to 100k characters, enabling comprehensive analysis of long-form content (lectures, long-form podcasts, and documentaries).
The Perspective Prism multi-agent system is equipped with custom-built tools designed to ensure security, quality, and effectiveness throughout the analysis pipeline.
A critical security tool that protects against Large Language Model (LLM) prompt injection attacks, backed by a high-performance compiled Rust extension (prism_sanitizer_rs integrated via PyO3 and Maturin). Before any user-provided data (YouTube URLs, transcript text, or claims) is interpolated into LLM prompts, the sanitizer performs comprehensive validation. It detects and blocks suspicious patterns like ignore previous instructions, system:, <|im_start|>, and other common injection techniques. The tool employs multiple defense layers: high-speed control character detection, regex pattern matching against a blocklist, character escaping, and length enforcement. Additionally, it wraps user data in clearly delimited sections using ===USER DATA START=== and ===USER DATA END=== markers to optimize Gemini's implicit context caching.
A benchmarking framework that validates the entire analysis pipeline against a curated set of test videos containing verifiable factual claims. The evaluator measures three key performance metrics: Success Rate (percentage of successful analyses without errors), Latency (time breakdown for claim extraction vs. evidence analysis), and Output Quality (validation that Truth Profiles contain properly structured perspectives and bias indicators). It runs automated tests on videos spanning diverse topicsβTED Talks on data science, Bill Gates' pandemic preparedness presentation, and NASA's Artemis program announcementsβensuring the system can handle scientific, public health, and engineering claims. The benchmark script integrates directly with the ClaimExtractor, EvidenceRetriever, and AnalysisService to measure end-to-end performance, providing detailed timing breakdowns and failure diagnostics to support continuous improvement.
A sophisticated multi-perspective search tool that queries the Google Custom Search API to gather external evidence for each extracted claim. Rather than performing a single generic search, the Evidence Retriever executes perspective-specific queriesβtailoring search terms to find scientific studies (site:nih.gov OR site:nature.com), journalistic sources (site:nytimes.com OR site:reuters.com), and partisan viewpoints. It handles API quota limits gracefully, implements exponential backoff retry logic for transient failures, and normalizes search results into a consistent format (title, snippet, URL). The retriever also performs relevance filtering, discarding results that don't contain claim-related keywords, ensuring the AnalysisService receives only high-quality evidence. This tool is essential for transforming subjective claims into fact-checkable assertions backed by authoritative external sources.
Perspective Prism addresses the core problem of filter bubbles and misinformation by automating the fact-checking process that most users don't have time to perform manually. When a user submits a YouTube video URL, the system retrieves the video's transcript and initiates a sophisticated multi-agent workflow. The Claim Extractor agent uses large language models to intelligently parse the transcript, identifying specific claims that can be verified rather than opinions or subjective statements. Each extracted claim is then passed to the Evidence Retriever agent, which conducts targeted searches across trusted external sources using the Google Custom Search API. The Analysis Engine synthesizes this evidence with the original claim, evaluating the degree of support or refutation while simultaneously detecting logical fallacies, emotional manipulation tactics, and other bias indicators. Finally, the Truth Profiler aggregates these multi-perspective analyses into a comprehensive report that presents users with a balanced viewβshowing not just whether claims are true or false, but how different perspectives (scientific, journalistic, partisan) interpret the same information. This automated pipeline transforms hours of manual research into seconds of computational analysis, empowering users to escape their filter bubbles and make informed decisions about the content they consume.
In an era where video content increasingly shapes public opinion and political discourse, the ability to quickly verify claims and detect bias is not just convenientβit's essential for a healthy democracy. Perspective Prism democratizes access to multi-perspective fact-checking, a capability typically reserved for professional journalists and researchers. By surfacing bias indicators and presenting evidence from multiple viewpoints, the system helps users develop critical thinking skills and resist manipulation. The project demonstrates how AI agents can be harnessed not to replace human judgment, but to augment it with comprehensive, rapid analysis that would be impractical to conduct manually.
I used Perspective Prism to analyze claims from a political commentary video, discovering that 3 out of 7 major claims lacked credible supporting evidence and exhibited strong emotional manipulation tactics. Armed with this Truth Profile, I was able to disuade an acquaintance from taking the video's claims at face value, which would have otherwise reinforced their existing beliefs.
Perspective Prism features a Manifest V3 Chrome Extension modernized and hardened under the extension-security-and-vertexai-migration track:
- Native Chrome Side Panel Integration (
chrome.sidePanel)- Renders progressive claim streams, stance chips, and deception ratings exclusively in Chrome's native side panel without creating or mounting in-page floating DOM overlays (
#pp-analysis-panelexcised).
- Renders progressive claim streams, stance chips, and deception ratings exclusively in Chrome's native side panel without creating or mounting in-page floating DOM overlays (
- BYOK & Sensitive Data Storage Isolation (
chrome.storage.local)- Stores all user credentials, backend URL settings, and consent flags exclusively in
chrome.storage.local, isolating sensitive secrets fromchrome.storage.syncwith automatic one-time upgrade migration.
- Stores all user credentials, backend URL settings, and consent flags exclusively in
- Service Worker IPC Origin Validation
- Background service worker verifies
sender.id === chrome.runtime.idfor all message listeners, rejecting untrusted external origin calls with structuredUNAUTHORIZEDerror responses.
- Background service worker verifies
- Strict Content Security Policy & Manifest MV3 Hardening
- Enforces
script-src 'self'; object-src 'none';CSP, replaces legacytabspermission withactiveTab, and removes localhost HTTP host permissions.
- Enforces
- DOMPurify HTML & Link Sanitization
- Dynamically sanitizes all claim text, stance badges, tags, and evidence URLs (
sanitizeTextandsanitizeUrl) using vendored DOMPurify, rendering plain text<span>elements for empty/invalid source URLs.
- Dynamically sanitizes all claim text, stance badges, tags, and evidence URLs (
- Optimistic UI & Zero-Latency Feedback
- Displays instant animated CSS shimmer loader cards (<50ms) upon analysis start before backend streaming begins.
- Content-Hashed Local Storage Caching
- Caches analysis results locally (
cache_${videoId}_${contentHash}) with 10MB LRU storage pruning, enabling instant (<20ms) cache-hit loads.
- Caches analysis results locally (
- Comprehensive Quality Assurance & E2E Testing
- Vitest Unit Test Suite: Vitest unit tests covering key extension modules (
npm test), with coverage validation (npm run test:coverage). - Playwright E2E Integration Suite: End-to-end integration tests passing via persistent browser extension context (
npm run test:integration). - FastAPI Pytest Backend Suite: Complete backend test suite covering API endpoints, claim extraction, and reliability circuit breakers (
pytest).
- Vitest Unit Test Suite: Vitest unit tests covering key extension modules (
- AI Code Review & Quality Gates (Qodo)
- Automated PR reviews and hard compliance checks configured via .qodo.yaml and pr_compliance_checklist.yaml.
- Chrome Web Store Submission Disclosure
- Full metadata, privacy disclosure, CSP compliance, and permission justifications documented in CHROMEWEBSTORE.md.
We include a comprehensive evaluation suite integrated with Weights & Biases Weave to track agent performance, latency, and extraction quality across a curated set of test videos containing verifiable claims.
To run the evaluation, execute the benchmark script:
python .benchmarks/evaluate_agents.py- Weights & Biases Weave Mode (Cloud): If Weights & Biases credentials are configured in your environment (e.g.,
WANDB_API_KEY, netrc, or global W&B settings), the script initializes Weave under the project name"perspective-prism-evals". It logs full LLM trace details, latencies, and custom scores using Weave'sModel,Dataset, andScorerAPIs. - Local Fallback Mode: If no W&B credentials are found, the script automatically sets
WEAVE_DISABLED=trueto bypass cloud-logging. It runs a clean local fallback benchmarking loop in your terminal without displaying blocking login prompts, printing detailed per-video results and performance averages.
The suite checks your Gemini API Tier via the GEMINI_TIER environment variable:
GEMINI_TIER=free(Default): Concurrency is restricted (WEAVE_PARALLELISM=1) and artificial sleep delays are injected to respect the Gemini free-tier 15 RPM rate limits.GEMINI_TIER=paid: Concurrency is optimized (WEAVE_PARALLELISM=10) for rapid evaluation execution.
Perspective Prism's backend is designed to be deployed to Modal Labs using their serverless infrastructure.
Important Note on Capacity: This project is primarily a portfolio project, not a commercial product. The backend relies on the $30/month free tier of compute credits provided by Modal Labs. Based on standard usage (1 claim analysis per user per day), this free tier can only handle around ~2,000 monthly users.
Since there are no funds allocated to scale this extension further, the extension is planned to fail gracefully. In a future release, if the monthly compute credits run out, the Chrome extension will detect the server exhaustion and display a message directing users to self-host the backend locally. You can find instructions on how to run it yourself in the Setup & Installation section below.
- Backend: FastAPI, Python 3.13, Rust (
prism_sanitizer_rsPyO3 extension) - AI/LLM:
- Framework: Agent Development Kit (ADK) 2.x
- Primary: Gemini API (
gemini-3.5-flash-liteviagoogle-genaiSDK) - Backup:
gemini-3.1-flash-litewith transient-error circuit breaker fallback
- Search: Google Custom Search API
- Frontend: React, TypeScript, Vite, Tailwind CSS
- Security: Rust-accelerated input sanitizer (
prism_sanitizer_rsregex/control character validation)
- Operating System: macOS, Linux, or Windows (via WSL2)
- Runtime & Toolchain:
- Python 3.10 or higher
- Rust compiler (
cargo,rustcvia rustup) &maturinfor compiling the input sanitizer - Node.js 18+ (LTS) or 20+
- API Keys:
- Gemini API Key: Required for claim extraction and perspective analysis.
- Google Custom Search JSON API Key: Required for evidence retrieval.
- Google Search Engine ID: A programmable search engine configured to search the entire web (or specific trusted sites).
- Browser: Google Chrome, Brave, or Microsoft Edge (for the extension).
-
Navigate to the backend directory:
cd backend -
Create and activate a virtual environment:
python3 -m venv venv source venv/bin/activate -
Install dependencies:
pip install -r requirements.txt
Copy .env.example to .env in the backend/ directory:
cp backend/.env.example backend/.envTo run the full analysis, configure your GCP Vertex AI credentials in .env (utilizing GCP billing credits for 300+ RPM high-throughput quota):
- Link GCP Billing Account: Ensure your GCP project has an active Billing Account attached in Google Cloud Console.
- Enable Vertex AI API:
gcloud services enable aiplatform.googleapis.com - Authenticate via ADC (Application Default Credentials):
gcloud auth application-default login
Configure .env with your project ID:
GCP_PROJECT=your_gcp_project_id_here
GCP_LOCATION=global
GEMINI_TIER=paid
LLM_MODEL=gemini-3.5-flash-lite
BACKUP_LLM_MODEL=gemini-3.1-flash-liteAdditional configuration:
GOOGLE_API_KEY: Google Custom Search JSON API keyGOOGLE_CSE_ID: Google Custom Search Engine IDCHROME_EXTENSION_IDS: List of allowed extension IDs.
For production backend deployments:
- HTTPS Enforcement: All external client-to-backend API communication MUST use HTTPS. Cleartext HTTP is restricted to
localhost/127.0.0.1environments. - TLS 1.3 Ingress Termination: Production reverse proxies or ingress gateways (e.g., Cloud Run Ingress, Nginx, Caddy) MUST enforce TLS 1.3 encryption.
Audit your local environment setup and high-throughput quota using the diagnostic scripts:
# Verify ADC setup, project linkage, and Gemini 3.5 connectivity
python3 verify_environment.py
# Run mocked parallel burst test (20 concurrent requests) to verify tier limits
PYTHONPATH=backend python3 backend/scripts/burst_test.py 20- Run the server:
The API will be available at
uvicorn app.main:app --reload
http://localhost:8000.
-
Navigate to the frontend directory:
cd frontend -
Install dependencies:
npm install
-
Configure environment variables: Copy
.env.exampleto.env:cp .env.example .env
Ensure
VITE_API_URLmatches your backend URL (default:http://localhost:8000). -
Run the development server:
npm run dev
The app will be available at
http://localhost:5173.
- Install extension development dependencies:
cd chrome-extension npm install - Load the unpacked extension in Chrome:
- Open Google Chrome and navigate to
chrome://extensions/. - Enable Developer mode via the toggle switch in the top-right corner.
- Click the Load unpacked button.
- Select the
chrome-extensiondirectory from this repository.
- Open Google Chrome and navigate to
For distribution or release testing, compile and package the extension:
- Run the build command:
This command runs Vite (
cd chrome-extension npm run buildvite buildviavite.config.js) to bundle entry points, minify JavaScript (stripping developmentconsole.logstatements via Terser) and CSS files, copy static assets, and generate a production-readydist/directory. - Load the production build:
- Navigate to
chrome://extensions/. - Click Load unpacked and select the
chrome-extension/distdirectory.
- Navigate to
To allow the extension to communicate with your local Perspective Prism Backend:
- Load the extension in Chrome and note its Extension ID (e.g.,
amnjngnkcgooljnblcejpmkdhpikcdlp). - Open
backend/app/core/config.py. - Add the Extension ID to the
CHROME_EXTENSION_IDSlist:CHROME_EXTENSION_IDS: list[str] = [ "your-extension-id-here", ]
- Restart the backend server to apply the configuration.
Access settings by right-clicking the extension icon and selecting Options:
- Backend URL: Endpoint for the Perspective Prism backend (HTTPS required for external servers, HTTP allowed for localhost/127.0.0.1).
- Cache Settings: Enable/disable cache and configure the cache duration (defaults to 7 days, using content-hashed storage keys
cache_${videoId}_${contentHash}with 10MB auto-LRU eviction). - Privacy Notice & Consent: Review the current privacy policy and grant or revoke analysis consent. Revoking consent instantly clears all local caches, aborts pending jobs, and deletes background alarms.
To run the backend test suite:
cd backend
# Run all tests
pytest
# Run specific reliability tests
pytest tests/test_reliability.pyThe Chrome Extension has unit tests using Vitest and integration tests using Playwright.
cd chrome-extension
# Install testing dependencies
npm install
# Run unit tests
npm run test
# Run ESLint to check for code quality and global variable definitions
npm run lint
# Run unit tests with coverage validation (requires 15% coverage)
npm run test:coverage
# Run Playwright end-to-end integration tests
npm run test:integration| Issue | Possible Cause | Solution |
|---|---|---|
| 401 Unauthorized | Missing or invalid Gemini API Key | Check .env file. Ensure GEMINI_API_KEY is set and valid. |
| 429 Too Many Requests | LLM/Google API quota exceeded | Check your API usage limits in the respective provider dashboards. |
| 500 Internal Server Error | Unexpected backend crash | Check the terminal output where uvicorn is running for stack traces. |
| CORS Error | Frontend origin not allowed | Distinguish the request origin: For Chrome extension requests, add the extension ID to CHROME_EXTENSION_IDS in .env or config.py. For standalone web applications (e.g., React app), add the origin (e.g., http://localhost:5173) to BACKEND_CORS_ORIGINS in .env or config.py. |
| Issue | Possible Cause | Solution |
|---|---|---|
| "Analysis Failed" | Backend not reachable | Ensure backend is running at http://localhost:8000. Check VITE_API_URL. |
| "No claims found" | Transcript unavailable or poor quality | The video may be private, a livestream, lack captions, or have auto-generated captions with poor quality. Try another video. |
| Button not showing | Content script failed to inject | Refresh the YouTube page. Ensure the extension is enabled in chrome://extensions/. Check extension ID in config.py. |
- Restart the Backend: Whenever you change
.envorconfig.py. - Reload Extension: Click the refresh icon in
chrome://extensions/after code changes. - Clear Cache: If the frontend behaves oddly, try Hard Reload (Cmd+Shift+R).
This project implements strict input sanitization to protect against Large Language Model (LLM) prompt injection attacks.
- Pattern Matching: Blocks known injection patterns (e.g., "Ignore previous instructions").
- Delimiters: Uses strict delimiters to separate user data from system instructions.
- Validation: Enforces length limits and character whitelisting.
See backend/app/utils/input_sanitizer.py for implementation details.
- Minimal Transmission: The extension transmits the full YouTube Video URL via the
urlfield to the backend to retrieve the video transcript and perform claim extraction. Unrelated data such as browsing history, search queries, user identifiers, or personal information is never collected or transmitted. - Strict HTTPS: All communications with external backends enforce HTTPS encryption. Cleartext HTTP is restricted to localhost (
127.0.0.1andlocalhost). - Local Storage: Analysis cache, settings, and statistics are stored locally within the browser context (
chrome.storage.localandchrome.storage.sync). - No Third-Party Scripts: The extension is self-contained and does not load third-party scripts, trackers, or analytics packages.
The project is organized as follows:
- backend/: The main Python backend for the analysis system
app/main.py: Defines the FastAPI application and orchestrates the analysis pipelineapp/services/: Contains the individual agent services, each responsible for a specific taskclaim_extractor.py: Extracts verifiable claims from YouTube video transcripts using LLMsevidence_retriever.py: Queries Google Custom Search API to find external evidence for claimsanalysis_service.py: Synthesizes evidence and analyzes claims from multiple perspectives
app/models/: Defines Pydantic data models for requests and responsesapp/utils/: Contains shared utility modulesinput_sanitizer.py: Rust-accelerated input sanitization (prompt injection defense)llm_utils.py: Shared ADK agent execution (get_validated_api_key,execute_adk_agent)prompt_helpers.py: Standardized prompt formatting with===USER DATA START===/===USER DATA END===delimitersvideo_utils.py: Extracts YouTube Video IDs from various URL formats
tests/: Integration and unit tests for the backend services
- frontend/: React + TypeScript + Vite frontend application
src/: Contains React components, API clients, and application logicsrc/components/: Reusable UI components for displaying Truth Profilessrc/services/: API client for communicating with the backendsrc/utils/time.ts: Time formatting utilities for video timestamps
- .benchmarks/: Contains the agent evaluation framework
evaluate_agents.py: Benchmark script measuring success rate, latency, and output quality
- chrome-extension/: YouTube Chrome Extension (Manifest V3) - Nearly Complete Implementation
- Core Components:
manifest.json: Extension configuration with Manifest V3 permissions (sidePanel,storage), content scripts, and background service workerbackground.js: Service worker handling message passing, lazy API client initialization (getClient()), native Side Panel triggering (OPEN_SIDE_PANEL), and extension lifecycle resiliencecontent.js: Injected script that detects YouTube videos, injects action button, handles SPA navigation, and dispatches side panel open requestsclient.js: API client with async job polling, retry logic, content-hashed local cache management, and MV3 persistence
- UI Pages:
sidepanel.html/js/css: Native Chrome Side Panel UI showing claim timeline, progressive perspective streams, and truth profilespopup.html/js/css: Extension popup showing analysis status and cache statisticsoptions.html/js/css: Settings page for backend URL configuration, cache controls, and privacy settingswelcome.html/js/css: Onboarding page for first-time usersprivacy.html: Privacy policy with data handling disclosure
- Utilities:
config.js: Configuration validation and managementconsent.js: Privacy consent flow with versioning supportquota-manager.js: Chrome storage quota monitoring and LRU cache evictionmetrics-tracker.js: Performance metrics collection (cache hits, API latency)memory-monitor.js: Memory profiling for extension performancevideo-utils.js / video-utils-script.js: Shared video URL validation and extraction logic
- Accessibility:
ClaimNavigatorclass for keyboard navigation (Arrow keys, Home/End)- Screen reader announcements (ARIA live regions)
- Roving tabindex focus management
- Testing Infrastructure:
tests/unit/: Vitest unit tests for cache, config, API client, and Service Worker resilience (background-resilience.test.js)tests/integration/: Integration tests for end-to-end flowstests/manual_qa/: Manual QA test guides and regression scenarios- Multiple test HTML pages for component validation and performance benchmarking
- Core Components:
The Perspective Prism analysis pipeline follows this workflow:
-
Input Validation: User submits a YouTube video URL through the frontend. The backend validates the URL format and checks for required API credentials.
-
Transcript Retrieval: The Claim Extractor service extracts the video ID from the URL and fetches the video transcript using the YouTube Transcript API. If no transcript is available, the analysis fails gracefully with an error message.
-
Claim Extraction: The Claim Extractor uses the ADK 2.0
ExtractorAgent(Gemini) to parse the transcript and extract distinct, verifiable claims conforming to a strict Pydantic output schema. It places raw transcript text first within the required===USER DATA START===and===USER DATA END===untrusted-data delimiters to leverage implicit context caching. -
Evidence Gathering: For each extracted claim, the Evidence Retriever performs targeted searches across multiple perspectives (scientific, journalistic, partisan left/right) using the Google Custom Search API. It collects relevant articles, studies, and sources for each perspective.
-
Perspective & Bias Analysis: The Analysis Service evaluates each claim against the retrieved evidence and context using ADK 2.0
AnalysisAgentinstances. It analyzes the claim from each perspective (stance, confidence, explanation) and performs bias/deception detection (detecting fallacies, emotional appeals, and a deception rating). Moderate deception ratings downgrade the overall assessment, while high deception ratings trigger an immediate short-circuit to "Suspicious/Deceptive". -
Truth Profile Generation: The system aggregates all perspective analyses and bias indicators into a comprehensive "Truth Profile" for each claim, showing users a balanced view across multiple viewpoints.
-
Response: The backend returns the complete analysis (video metadata, claims, and Truth Profiles) to the frontend, which renders an interactive UI displaying the results with expandable claims, color-coded confidence bars, and detailed evidence citations.
