Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,31 @@

Synapse is a Vite + React + TypeScript application that turns complex content into accessible experiences using Chrome's built-in AI APIs. The application provides interactive demos and practical implementations of Chrome's Rewriter, Translator, and Prompt APIs with robust error handling, streaming support, and production-ready service wrappers.

## Getting Started
## Prerequisites

- Node.js 18+ (LTS recommended) and npm 9+
- Chrome Canary/Dev 130+ with the Chrome Built-in AI origin trial enabled
- Valid Origin Trial token configured in `.env` (`VITE_CHROME_AI_ORIGIN_TRIAL_TOKEN`)
- `chrome://flags/#optimization-guide-on-device-model` set to **Enabled**

## Setup

1. **Install dependencies**
```bash
npm install
```
2. **Configure Chrome AI origin trial**
- Request a token from [Chrome Origin Trials](https://developer.chrome.com/origintrials/#/trials/active).
- Create a `.env` file based on `.env.example` and paste the token in `VITE_CHROME_AI_ORIGIN_TRIAL_TOKEN`.
3. **Run the dev server**
2. **Create environment file**
```bash
cp .env.example .env
```
3. **Configure Chrome AI origin trial**
- Request a token from [Chrome Origin Trials](https://developer.chrome.com/origintrials/#/trials/active)
- Paste the token into `.env` under `VITE_CHROME_AI_ORIGIN_TRIAL_TOKEN`
4. **Run the dev server**
```bash
npm run dev
```
4. **Open in Chrome Canary** at the URL printed in the terminal (default `http://localhost:5173`). Ensure the matching origin trial flag is enabled.
5. **Open in Chrome Canary/Dev** at the printed URL (default `http://localhost:5173`). Ensure the origin trial flag remains enabled and the token is valid for the local domain.

## User Documentation

Expand Down Expand Up @@ -119,6 +130,8 @@ npm run test:e2e:ui # E2E interactive mode
- **Local storage:** Namespaced helpers (`createLocalStorageNamespace`) and `preferencesStorage` wrapper
- **Chrome AI readiness:** Origin trial token support via `<meta>` tag with comprehensive capability detection

For diagrams and deeper explanations of each layer, read [`docs/architecture.md`](docs/architecture.md).

## Project Structure

```
Expand Down Expand Up @@ -162,7 +175,9 @@ Each demo includes:
- Browser compatibility checks
- Comprehensive diagnostics

## Scripts
## Developer Workflow

Use the npm scripts below while iterating. Build and lint commands should pass before you open a pull request.

- `npm run dev` – Start Vite dev server.
- `npm run build` – Type-check and build for production.
Expand Down Expand Up @@ -524,3 +539,8 @@ You can verify our privacy claims by:
- Implement Writer & Proofreader API demos
- Integrate state management (Zustand) for cross-component state
- Add visual regression testing (Percy/Chromatic)

## Additional Documentation
- [`docs/architecture.md`](docs/architecture.md) – Layer breakdown, data flow, and diagrams.
- [`docs/chrome-ai-apis.md`](docs/chrome-ai-apis.md) – Chrome AI service contracts, initialization steps, and troubleshooting.
- [`docs/adr`](docs/adr) – Architecture decision records for foundational choices.
82 changes: 82 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Architecture Overview

Synapse is a single-page application built with Vite, React, and TypeScript. The frontend keeps all business logic on the client and wraps Chrome's built-in AI APIs with a resilient service layer that exposes ergonomic hooks to the UI. This document explains how the pieces fit together so new contributors can reason about data flow quickly.

## High-Level Flow

```mermaid
graph TD
subgraph UI
Routes[React Router<br/>Route Tree]
Components[UI Components<br/>Pages & Layouts]
end
subgraph State
Hooks[Custom React Hooks]
Storage[Preferences Storage<br/>Local Storage Namespace]
end
subgraph Services
Wrapper[Chrome AI Service Layer]
Utils[Validation & Sanitization<br/>File Processing Utilities]
Errors[Global Error Reporting]
end
subgraph Platform
ChromeAPIs[Chrome Built-in AI APIs<br/>Prompt · Rewriter · Translator · Writing Tools]
end

Routes --> Components
Components --> Hooks
Hooks --> Wrapper
Wrapper --> ChromeAPIs
ChromeAPIs --> Wrapper
Wrapper --> Hooks
Hooks --> Components
Hooks --> Storage
Utils --> Wrapper
Wrapper --> Errors
```

### Layers

- **Routing & Layout (`src/routes`, `src/components/layout`)**: `AppLayout` composes global chrome (header/footer) while `React Router` v7 mounts feature pages such as the Workspace and Demos hub. Each route is wrapped in the `RouteErrorBoundary` to surface Chrome AI failures.
- **UI Components (`src/components`)**: Feature-specific components (file uploaders, writing tool panes) depend on hooks for state and never call Chrome AI APIs directly.
- **Hooks (`src/hooks`)**: Hooks encapsulate state management, orchestration, and side-effects. They call service classes, expose request state, and consolidate analytics / logging. Examples include `useWritingTools`, `useRewriter`, and `useContentExtraction`.
- **Service Layer (`src/lib/chrome-ai/services`)**: TypeScript classes (`PromptService`, `RewriterService`, `TranslatorService`, `WritingToolsService`) manage API sessions, retries, streaming, and structured outputs. They depend on shared utilities for validation (`src/lib/chrome-ai/utils`) and sanitize user-provided input before passing it to the browser APIs.
- **Error Handling (`src/lib/errors`)**: Central utilities (`reportError`, `registerGlobalHandlers`, `AppErrorBoundary`) normalize errors from Chrome AI APIs, chunking pipelines, and network calls. Services wrap low-level exceptions into domain-specific error classes with actionable messages.
- **Platform Integration (`src/lib/chrome-ai`)**: Capability detection, origin trial injection, and browser compatibility messaging reside here. `detectChromeAiCapabilities` and `browserCompatibility` helpers drive the badges and warnings rendered in the UI.

## Workspace Data Flow

1. **Input Acquisition**
Users provide text by typing, uploading TXT/PDF/DOCX files, or extracting content from URLs. `useTextInput`, `useFileUpload`, and `useContentExtraction` own these flows. File uploads run through MIME checks, magic number validation, and asynchronous extraction (PDF.js, Mammoth) before sanitized text hits application state.

2. **Capability Negotiation**
When a user triggers an AI operation, hooks call `detectChromeAiCapabilities` to verify the requested API is available. Results feed UI affordances (disabled buttons, tooltips) and error boundaries.

3. **Service Invocation**
Hooks call the corresponding service method (`RewriterService.simplify`, `TranslatorService.translateStream`, `PromptService.prompt`, etc.). Services:
- Initialize the Chrome AI session on demand (with retries and progress monitoring).
- Validate input length / content and sanitize untrusted strings.
- Stream results back via async iterators where available, emitting partial responses to the UI.

4. **Result Presentation**
Hooks update React state with incremental or final payloads. Components render formatted diffs, translation tables, or streaming transcripts while showing timing/status indicators. Errors are surfaced through standardized toasts and inline callouts.

5. **Persistence & Preferences**
`preferencesStorage` (namespaced local storage) keeps track of user theme, last-used writing tool, and workspace settings. Hooks read/write preferences via the helper to avoid key collisions.

## Build & Deployment Pipeline

- **Vite + TypeScript** compile client code to ES modules served by the dev server or bundled for production (`npm run build`).
- **Tailwind CSS** generates scoped utility classes via PostCSS. Theme tokens are configured in `tailwind.config.js`.
- **ESLint & TypeScript** enforce code quality (`npm run lint`). Build scripts fail fast on type errors because `tsc -b` runs before bundling.
- **Service Worker** registration happens in production builds to allow future offline support, but the worker is optional during local development.

## Key Architectural Decisions

Existing Architecture Decision Records live under `docs/adr`. Review them before making cross-cutting changes:

- `0001-foundational-stack.md` – Explains the Vite + React + Tailwind selection.
- `0002-error-handling-and-storage.md` – Details the shared error reporting surface and local-storage namespacing pattern.

Refer to the [Chrome AI API Integration Guide](./chrome-ai-apis.md) for protocol-level details, request lifecycles, and troubleshooting flow charts.

76 changes: 76 additions & 0 deletions docs/chrome-ai-apis.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Chrome AI API Integration Guide

This document dives into how Synapse integrates Chrome's built-in AI APIs so you can extend or debug the service layer confidently. The application uses the Origin Trial versions of the Prompt, Rewriter, Translator, Language Detector, Writer, and Proofreader APIs (where available).

## Browser Requirements

- **Chrome 130+ (Canary/Dev/Beta)** with the "Built-in AI" origin trial token applied through the `<meta http-equiv="origin-trial">` tag injected at runtime by `injectChromeAiOriginTrial`.
- **Origin Trial Token** stored in `.env` as `VITE_CHROME_AI_ORIGIN_TRIAL_TOKEN`. Tokens are domain-specific and expire; generate a new one from the [Chrome Origin Trials dashboard](https://developer.chrome.com/origintrials/#/trials/active) as needed.
- **Feature Flags**: Ensure the matching Chrome flag is enabled (`chrome://flags/#optimization-guide-on-device-model`). The docs site surfaces compatibility warnings when detection fails.

## Capability Detection

All entry points check API availability via `detectChromeAiCapabilities` and `detectChromeAiAvailabilityStatus` (`src/lib/chrome-ai/capabilities.ts`). These helpers:

1. Inspect the global `self` object to confirm each API is present.
2. Call the `availability()` methods exposed by Chrome to verify the model is either `available` or `downloadable`.
3. Emit semantic booleans used by UI badges and guard clauses in the hooks.

When you add new integrations, extend the detection maps so the UI can reflect their state automatically.

## Service Layer Overview

Each Chrome API is wrapped with a dedicated service class that normalizes inputs, handles retries, and exposes streaming iterators where supported. Services live in `src/lib/chrome-ai/services` and share common utilities:

- **Validation** (`utils/validator.ts`) ensures character counts and banned content rules are respected before hitting the API.
- **Sanitization** (`utils/sanitizer.ts`) strips untrusted HTML and zero-width characters to avoid model hallucination issues.
- **Retry Logic** (`utils/retryHandler.ts`) replays transient failures (e.g., `MODEL_NOT_READY`) with exponential backoff.
- **Error Types** (`errors/*.ts`) wrap native exceptions in domain-specific errors surfaced by the UI and error telemetry.

### Prompt API (`PromptService`)

- **Initialization**: `PromptService.initialize` creates a `LanguageModel` session. Optional hooks configure `initialPrompts`, `temperature`, `topK`, expected input/output schemas, and download monitoring callbacks.
- **Prompting**: `prompt` sends a single message and returns the response string. Use `promptStream` to iterate over streaming chunks (async generator). The service tracks conversation history, so successive calls preserve context unless you call `reset`.
- **Session Management**: `cloneSession` enables lightweight branching, while `destroy` tears down the model to release memory. Hooks call `destroy` on unmount to avoid leaking sessions in Chrome.

### Rewriter API (`RewriterService`)

- **Simplification & Tone**: `simplify`, `simplifyProgressively`, and `adjustTone` wrap the multi-level rewriting APIs. The service supports chunked inputs through `enableChunking`, retrying failed chunks automatically.
- **Streaming**: `rewriteStream` exposes partial results so the UI can show incremental updates.
- **Content Safety**: Input validation enforces length and banned phrase requirements before they are forwarded to Chrome.

### Translator API (`TranslatorService`)

- **Initialization**: `translator.initialize(sourceLang, targetLang)` returns a session configured for specific languages. The service auto-detects source language if `null` and exposes `setLanguages` to pivot during a session.
- **Usage**: `translate` returns the full translation. `translateStream` yields incremental `TranslatorResponseChunk` payloads to power the UI's streaming table.
- **Fallbacks**: When the API reports `downloadable`, the service surfaces progress events via the `monitor` callback and shows actionable messages in the UI.

### Writing Tools (`WritingToolsService`)

The writing tools facade composes both Prompt and Rewriter services to deliver higher-level operations:

- **Proofreading**: Uses the Prompt API with structured output to return a `ProofreadResult` containing corrections, statistics, and diff-ready change objects.
- **Tone Adjustment & Summaries**: Leverage the Rewriter API for tone transformations and summarization with chunked inputs.
- **Key Points & Suggestions**: High-level prompts that transform model output into typed arrays for the UI to render (importance tagging, categories, priority).

The service memoizes initialization via an internal promise so concurrent requests do not race. It sanitizes and validates inputs, then aggregates final responses from both underlying services.

### Format & Image Analysis

Supporting services (`FormatTransformService`, `ImageAnalysisService`) handle experimental APIs behind feature flags. They are structured the same way—initialize -> process -> stream—and are safe extension points for future Chrome releases.

## Error Handling & Telemetry

- `reportError` routes enriched error objects to console logging today, but it is built to integrate with telemetry providers. Always wrap low-level exceptions so we can react to specific Chrome error codes.
- User-cancelled operations throw `AbortError` instances wrapped by custom error classes. Hooks translate these into friendly UI notifications.
- Chrome often returns `downloadable` before the model finishes downloading. The service layer surfaces `AIModelDownloadProgress` events through optional `monitor` callbacks so the UI can display progress bars.

## Debugging Tips

1. **Inspect Capabilities**: Visit `/demos` and open DevTools → Console to see the structured capability object printed whenever detection runs.
2. **Reset Sessions**: If you suspect a stale session, call the relevant service's `destroy()` method and initialize again.
3. **Verbose Logging**: Temporarily add `console.debug` inside service catch blocks while iterating; the retry helper swallows some errors by design after max attempts.
4. **Origin Trial Issues**: If every capability reports `unavailable`, confirm the token is valid, matches the hostname, and has not expired.

Refer back to [docs/architecture.md](./architecture.md) for an overview of how these services connect to the rest of the application.

7 changes: 5 additions & 2 deletions src/lib/chrome-ai/services/RewriterService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,8 @@ export class RewriterService {
}

private mergeContextSegments(...segments: Array<string | undefined>): string | undefined {
// Chrome's rewriter context becomes unstable beyond ~1k characters, so we clamp combined hints
// to keep prompts deterministic even when multiple sections contribute extra instructions.
const cleaned = segments
.map((segment) => segment?.trim())
.filter((segment): segment is string => Boolean(segment))
Expand Down Expand Up @@ -658,15 +660,16 @@ export class RewriterService {
options?: AIRewriteOptions,
onProgress?: (current: number, total: number) => void
): Promise<string> {
// Split into chunks
// Chrome's Rewriter API enforces payload caps (~8k tokens); chunkText() slices input into
// ordered segments with overlap so we can process long documents without hitting hard limits.
const chunks = chunkText(content)
const processedChunks: TextChunk[] = []

// Process each chunk
for (let i = 0; i < chunks.length; i++) {
const chunk = chunks[i]

// Build options with chunk context
// Preserve continuity by threading the previous chunk summary into the context payload.
const chunkOptions: AIRewriteOptions = {
...options,
context: this.mergeContextSegments(
Expand Down