From 1f16ffd5b677558f397b7877e0342901e17d7494 Mon Sep 17 00:00:00 2001 From: Shingirayi Mandebvu Date: Wed, 22 Oct 2025 16:30:24 +0200 Subject: [PATCH 1/2] feat: introduce Writing Enhancement features and components - Added Writing Enhancement capabilities, including grammar correction, tone adjustment, key point extraction, text expansion, and writing suggestions. - Implemented WritingEnhancementService to manage enhancements using the Writer and Proofreader APIs. - Created WritingEnhancementPanel for user interaction and WritingEnhancementTest for manual testing of features. - Updated WorkspacePage to include a new input mode for writing enhancement. - Enhanced README.md with detailed descriptions of the new Writing Enhancement features and usage examples. This commit significantly improves the writing assistance functionality of the application, providing users with comprehensive tools for enhancing their text. --- README.md | 61 +- .../test/WritingEnhancementTest.tsx | 594 +++++++++++++ .../writing/WritingEnhancementPanel.tsx | 483 ++++++++++ src/hooks/useProofreader.ts | 237 +++++ src/hooks/useWriter.ts | 282 ++++++ src/hooks/useWritingEnhancement.ts | 350 ++++++++ src/lib/chrome-ai/capabilities.ts | 33 +- .../chrome-ai/errors/ProofreaderError.d.ts | 22 + src/lib/chrome-ai/errors/ProofreaderError.js | 47 + src/lib/chrome-ai/errors/WriterError.d.ts | 22 + src/lib/chrome-ai/errors/WriterError.js | 47 + src/lib/chrome-ai/errors/errorMessages.ts | 20 + src/lib/chrome-ai/errors/index.ts | 22 + .../errors/proofreaderErrorGuards.ts | 92 ++ src/lib/chrome-ai/errors/writerErrorGuards.ts | 92 ++ src/lib/chrome-ai/index.ts | 69 ++ src/lib/chrome-ai/proofreader.ts | 268 ++++++ src/lib/chrome-ai/services/PromptService.ts | 3 +- .../chrome-ai/services/ProofreaderService.ts | 381 ++++++++ src/lib/chrome-ai/services/WriterService.ts | 427 +++++++++ .../services/WritingEnhancementService.ts | 824 ++++++++++++++++++ src/lib/chrome-ai/services/index.ts | 24 + src/lib/chrome-ai/types.ts | 259 ++++++ src/lib/chrome-ai/writer.ts | 286 ++++++ src/pages/test/WritingEnhancementTestPage.tsx | 5 + src/pages/workspace/WorkspacePage.tsx | 106 ++- src/routes/app-router.tsx | 2 + 27 files changed, 5018 insertions(+), 40 deletions(-) create mode 100644 src/components/test/WritingEnhancementTest.tsx create mode 100644 src/components/writing/WritingEnhancementPanel.tsx create mode 100644 src/hooks/useProofreader.ts create mode 100644 src/hooks/useWriter.ts create mode 100644 src/hooks/useWritingEnhancement.ts create mode 100644 src/lib/chrome-ai/errors/ProofreaderError.d.ts create mode 100644 src/lib/chrome-ai/errors/ProofreaderError.js create mode 100644 src/lib/chrome-ai/errors/WriterError.d.ts create mode 100644 src/lib/chrome-ai/errors/WriterError.js create mode 100644 src/lib/chrome-ai/errors/proofreaderErrorGuards.ts create mode 100644 src/lib/chrome-ai/errors/writerErrorGuards.ts create mode 100644 src/lib/chrome-ai/proofreader.ts create mode 100644 src/lib/chrome-ai/services/ProofreaderService.ts create mode 100644 src/lib/chrome-ai/services/WriterService.ts create mode 100644 src/lib/chrome-ai/services/WritingEnhancementService.ts create mode 100644 src/lib/chrome-ai/writer.ts create mode 100644 src/pages/test/WritingEnhancementTestPage.tsx diff --git a/README.md b/README.md index 6950dc4..28a1596 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,12 @@ Synapse is a Vite + React + TypeScript application that turns complex content in - **Rewriter API**: Text simplification with reading level control, tone adjustment (formal/casual), length modification, and streaming support - **Translator API**: Multi-language translation (20+ languages) with automatic language detection and format preservation - **Prompt API**: Conversational AI with temperature control, system prompts, and streaming responses +- **Writing Enhancement**: Comprehensive writing assistance combining multiple APIs: + - Grammar and spelling correction (Proofreader API) + - Tone adjustment (Writer + Rewriter APIs) + - Key point extraction for summaries (Prompt API) + - Text expansion and elaboration (Writer API) + - Actionable writing improvement suggestions (Prompt API) - **Service Layer**: Production-ready wrappers with error handling, retry logic, content validation, and sanitization ### UI Components @@ -44,11 +50,12 @@ Synapse is a Vite + React + TypeScript application that turns complex content in - **Status Indicators**: Visual feedback for API availability, processing state, and elapsed time tracking ### Developer Experience -- **Comprehensive Error Handling**: Type-safe error guards for Rewriter, Translator, and Prompt APIs -- **React Hooks**: `useRewriter`, `useTranslator`, `usePrompt`, `useTextInput`, `useFileUpload`, and `useContentExtraction` for state management +- **Comprehensive Error Handling**: Type-safe error guards for Rewriter, Translator, Prompt, Writer, and Proofreader APIs +- **React Hooks**: `useRewriter`, `useTranslator`, `usePrompt`, `useWritingEnhancement`, `useTextInput`, `useFileUpload`, and `useContentExtraction` for state management - **Browser Compatibility**: Automatic detection and user-friendly warnings for unsupported browsers - **Capability Detection**: Runtime checks for API availability with graceful degradation - **File Processing**: Secure local PDF.js worker, content validation, and robust extraction pipeline +- **Test Infrastructure**: Dedicated test pages for all Chrome AI APIs with real-time diagnostics and event logging ## Tooling & Architecture @@ -93,6 +100,7 @@ Access interactive demos at `/demos`: - **Rewriter API Demo** (`/demos/rewriter`): Test text simplification with various options - **Translator API Demo** (`/demos/translator`): Translate between 20+ languages with streaming - **Prompt API Demo** (`/demos/prompt`): Conversational AI with advanced configuration +- **Writing Enhancement Demo** (`/demos/writing-enhancement`): Test comprehensive writing assistance features Each demo includes: - Real-time API status indicators @@ -100,6 +108,7 @@ Each demo includes: - Error handling demonstrations - Browser compatibility checks - Comprehensive diagnostics +- Event logging for debugging ## Scripts @@ -213,12 +222,15 @@ clear() - **Chrome Canary 137+** (or Dev channel) - **Chrome AI flags enabled**: Navigate to `chrome://flags` and enable: - - `#optimization-guide-on-device-model` - - `#prompt-api-for-gemini-nano` - - `#translation-api` - - `#rewriter-api` + - `#optimization-guide-on-device-model` (required for model download) + - `#prompt-api-for-gemini-nano` (for Prompt API and writing suggestions) + - `#translation-api` (for Translator API) + - `#rewriter-api` (for Rewriter API and tone simplification) + - `#writer-api` (for Writer and Proofreader APIs - grammar correction, text expansion) - **AI model downloaded**: ~2GB download occurs automatically on first use +For detailed setup instructions with screenshots, see the **[Writing Enhancement Setup Guide](./docs/SETUP.md)**. + ## File Upload Configuration ### Security Features @@ -261,10 +273,45 @@ The URL extraction feature uses Mozilla Readability to extract clean article con - **Supported Sites**: Works best with article-based content (blogs, news sites, documentation) - **Content Sanitization**: All extracted HTML is sanitized with DOMPurify to prevent XSS attacks +### Writing Enhancement Service +```typescript +import { WritingEnhancementService } from '@/lib/chrome-ai/services' + +const service = new WritingEnhancementService() +await service.initialize() + +// Grammar and spelling correction +const corrected = await service.correctGrammar('Text with erors and mistakes') +console.log(corrected.stats) // { totalCorrections: 2, grammarErrors: 1, spellingErrors: 1, ... } + +// Adjust tone +const professional = await service.adjustTone('hey whats up!', 'professional') +const simple = await service.adjustTone('The algorithm utilizes...', 'simple') + +// Extract key points +const keyPoints = await service.extractKeyPoints('Long article text...') +console.log(keyPoints) // [{ point: "Main idea", importance: "primary" }, ...] + +// Get writing suggestions +const suggestions = await service.getWritingSuggestions('Text to improve') +console.log(suggestions) // [{ category: "clarity", issue: "...", suggestion: "...", priority: "high" }, ...] + +// Expand brief text +const expanded = await service.expandText('Brief intro', 'medium') + +// Run multiple enhancements at once +const enhanced = await service.enhanceText('Text to enhance', { + correctGrammar: true, + extractKeyPoints: true, + getSuggestions: true, + adjustTone: 'professional' +}) +``` + ## Next Steps - Expand Workspace page with multi-API processing pipelines - Add Summarizer and Language Detector API integrations -- Implement Writer & Proofreader API demos - Add automated tests (Vitest + React Testing Library) - Integrate state management (Zustand) for cross-component state +- Add quality scoring and telemetry for Writing Enhancement diff --git a/src/components/test/WritingEnhancementTest.tsx b/src/components/test/WritingEnhancementTest.tsx new file mode 100644 index 0000000..3b131ce --- /dev/null +++ b/src/components/test/WritingEnhancementTest.tsx @@ -0,0 +1,594 @@ +import { useState, useRef, useEffect, useCallback } from 'react' +import { WritingEnhancementService, type AIModelDownloadProgress } from '@/lib/chrome-ai' +import type { + WritingSuggestion, + KeyPoint, + WritingEnhancementResult, +} from '@/lib/chrome-ai/services/WritingEnhancementService' +import type { EnhancedProofreadResult } from '@/lib/chrome-ai/services/ProofreaderService' +import { ChromeAiDiagnostics } from './ChromeAiDiagnostics' +import { + InlineSpinner, + ModelDownloadProgress, + DownloadStatus, +} from '@/components/ui' + +/** + * Test component for Chrome Writing Enhancement APIs + * This component allows manual testing of all WritingEnhancementService features + */ +export const WritingEnhancementTest = () => { + const [serviceStatus, setServiceStatus] = useState<'idle' | 'initializing' | 'ready' | 'error'>('idle') + const [isProcessing, setIsProcessing] = useState(false) + const [inputText, setInputText] = useState(DEFAULT_TEST_TEXT) + const [selectedTone, setSelectedTone] = useState<'professional' | 'casual' | 'academic' | 'simple'>('professional') + const [error, setError] = useState(null) + const [logs, setLogs] = useState([]) + const [downloadProgress, setDownloadProgress] = useState(null) + const [downloadStatus, setDownloadStatus] = useState(DownloadStatus.CHECKING) + + // Results for individual operations + const [grammarResult, setGrammarResult] = useState(null) + const [toneResult, setToneResult] = useState(null) + const [keyPointsResult, setKeyPointsResult] = useState(null) + const [expandedResult, setExpandedResult] = useState(null) + const [suggestionsResult, setSuggestionsResult] = useState(null) + const [combinedResult, setCombinedResult] = useState(null) + + const serviceRef = useRef(null) + + const addLog = (message: string) => { + const timestamp = new Date().toLocaleTimeString() + setLogs((prev) => [`[${timestamp}] ${message}`, ...prev].slice(0, 30)) + } + + const clearResults = () => { + setGrammarResult(null) + setToneResult(null) + setKeyPointsResult(null) + setExpandedResult(null) + setSuggestionsResult(null) + setCombinedResult(null) + } + + const handleInitialize = async () => { + try { + setServiceStatus('initializing') + setError(null) + setDownloadProgress(null) + setDownloadStatus(DownloadStatus.CHECKING) + clearResults() + addLog('Initializing WritingEnhancementService...') + + const service = new WritingEnhancementService() + + await service.initialize() + serviceRef.current = service + + setDownloadStatus(DownloadStatus.READY) + setDownloadProgress(null) + setServiceStatus('ready') + addLog('✓ WritingEnhancementService initialized successfully') + } catch (err) { + const errorMsg = err instanceof Error ? err.message : 'Unknown error' + setServiceStatus('error') + setDownloadStatus(DownloadStatus.FAILED) + setDownloadProgress(null) + setError(errorMsg) + addLog(`✗ Initialization failed: ${errorMsg}`) + } + } + + const handleCorrectGrammar = async () => { + if (!serviceRef.current) { + setError('Service not initialized') + return + } + + try { + setIsProcessing(true) + setError(null) + setGrammarResult(null) + addLog('Starting grammar correction...') + + const result = await serviceRef.current.correctGrammar(inputText) + + setGrammarResult(result) + addLog(`✓ Grammar correction complete (${result.stats.totalCorrections} corrections found)`) + } catch (err) { + const errorMsg = err instanceof Error ? err.message : 'Unknown error' + setError(errorMsg) + addLog(`✗ Grammar correction failed: ${errorMsg}`) + } finally { + setIsProcessing(false) + } + } + + const handleAdjustTone = async () => { + if (!serviceRef.current) { + setError('Service not initialized') + return + } + + try { + setIsProcessing(true) + setError(null) + setToneResult(null) + addLog(`Starting tone adjustment to ${selectedTone}...`) + + const result = await serviceRef.current.adjustTone(inputText, selectedTone) + + setToneResult(result) + addLog(`✓ Tone adjustment complete (${result.length} characters)`) + } catch (err) { + const errorMsg = err instanceof Error ? err.message : 'Unknown error' + setError(errorMsg) + addLog(`✗ Tone adjustment failed: ${errorMsg}`) + } finally { + setIsProcessing(false) + } + } + + const handleExtractKeyPoints = async () => { + if (!serviceRef.current) { + setError('Service not initialized') + return + } + + try { + setIsProcessing(true) + setError(null) + setKeyPointsResult(null) + addLog('Extracting key points...') + + const result = await serviceRef.current.extractKeyPoints(inputText) + + setKeyPointsResult(result) + addLog(`✓ Key point extraction complete (${result.length} points found)`) + } catch (err) { + const errorMsg = err instanceof Error ? err.message : 'Unknown error' + setError(errorMsg) + addLog(`✗ Key point extraction failed: ${errorMsg}`) + } finally { + setIsProcessing(false) + } + } + + const handleExpandText = async () => { + if (!serviceRef.current) { + setError('Service not initialized') + return + } + + try { + setIsProcessing(true) + setError(null) + setExpandedResult(null) + addLog('Expanding text...') + + const result = await serviceRef.current.expandText(inputText, 'medium') + + setExpandedResult(result) + addLog(`✓ Text expansion complete (${inputText.length} → ${result.length} characters)`) + } catch (err) { + const errorMsg = err instanceof Error ? err.message : 'Unknown error' + setError(errorMsg) + addLog(`✗ Text expansion failed: ${errorMsg}`) + } finally { + setIsProcessing(false) + } + } + + const handleGetSuggestions = async () => { + if (!serviceRef.current) { + setError('Service not initialized') + return + } + + try { + setIsProcessing(true) + setError(null) + setSuggestionsResult(null) + addLog('Getting writing suggestions...') + + const result = await serviceRef.current.getWritingSuggestions(inputText) + + setSuggestionsResult(result) + addLog(`✓ Writing suggestions complete (${result.length} suggestions found)`) + } catch (err) { + const errorMsg = err instanceof Error ? err.message : 'Unknown error' + setError(errorMsg) + addLog(`✗ Writing suggestions failed: ${errorMsg}`) + } finally { + setIsProcessing(false) + } + } + + const handleEnhanceAll = async () => { + if (!serviceRef.current) { + setError('Service not initialized') + return + } + + try { + setIsProcessing(true) + setError(null) + setCombinedResult(null) + addLog('Running all enhancements...') + + const result = await serviceRef.current.enhanceText(inputText, { + correctGrammar: true, + extractKeyPoints: true, + getSuggestions: true, + adjustTone: selectedTone, + expand: false, // Skip expansion in combined test + }) + + setCombinedResult(result) + addLog(`✓ All enhancements complete`) + } catch (err) { + const errorMsg = err instanceof Error ? err.message : 'Unknown error' + setError(errorMsg) + addLog(`✗ Combined enhancement failed: ${errorMsg}`) + } finally { + setIsProcessing(false) + } + } + + const handleDestroy = useCallback(() => { + if (serviceRef.current) { + serviceRef.current.destroy() + serviceRef.current = null + setServiceStatus('idle') + clearResults() + addLog('Service destroyed') + } + }, []) + + // Cleanup on unmount + useEffect(() => { + return () => { + handleDestroy() + } + }, [handleDestroy]) + + return ( +
+ {/* Header */} +
+

Writing Enhancement Test Suite

+

+ Test the Chrome Writing Enhancement APIs (Writer, Proofreader, Prompt, Rewriter) +

+
+ + {/* Diagnostics */} +
+ +
+ + {/* Service Status */} +
+
+
+

Service Status

+

+ Status:{' '} + + {serviceStatus} + +

+
+
+ + +
+
+ + {/* Download Progress */} + {serviceStatus === 'initializing' && downloadProgress && ( +
+ +
+ )} + + {/* Initialization Status (no download) */} + {serviceStatus === 'initializing' && !downloadProgress && ( +
+ + {downloadStatus} +
+ )} + + {error && ( +
+ Error: {error} +
+ )} +
+ + {/* Input Section */} +
+

Input Text

+