All articles
Build Guides

Build a Smart Clipboard That Summarizes and Translates with Cloudflare Workers AI

FDE Coach EditorialAugust 15, 20269 min read

What We're Building

A background desktop utility that monitors your system clipboard. Copy any text—a dense research paper paragraph, a foreign-language error message, a 500-word email—then hit a hotkey. The tool fires the text to a free Cloudflare Workers AI endpoint running Llama 3, returns a crisp summary or translation, and pastes the result right back into your clipboard. Zero cost. Zero context-switching to a browser tab.

Feature list:

  • Clipboard polling via a lightweight Python daemon (or AutoHotkey on Windows).
  • Dual-mode hotkeys: Ctrl+Shift+S for summarize, Ctrl+Shift+T for translate.
  • Free LLM inference using Cloudflare Workers AI (Llama 3 8B, 10k free requests/day).
  • Optional caching of recent results in Cloudflare R2 (10 GB free storage) to avoid re-processing identical text.
  • Cross-platform with minimal dependencies.
  • Privacy-respecting: text is encrypted in transit (HTTPS) and never logged on Cloudflare’s side when using Workers AI.

Architecture Overview

The daemon sits between your clipboard and the cloud. When you press a hotkey, it grabs the current clipboard content, sends it to a Cloudflare Worker, which optionally checks R2 for a cached result before calling Workers AI. The response flows back and overwrites the clipboard. Everything stays synchronous enough to feel instant.

Prerequisites and Free-Tier Setup

You need three things—all free:

  1. Cloudflare account with Workers AI enabled. Sign up at dash.cloudflare.com. Workers AI includes 10,000 free requests per day for Llama 3 8B. No credit card required for the free tier.
  2. Python 3.10+ installed locally (or AutoHotkey v2 if you’re on Windows and prefer it). We’ll use Python for cross-platform clarity.
  3. Wrangler CLI for deploying the Worker: npm install -g wrangler (Node.js 18+ required).

Optional: Cloudflare R2 bucket for caching. Free tier gives 10 GB storage, 1 million Class A operations/month, 10 million Class B operations/month. More than enough for a clipboard cache.

Step 1: Cloudflare Workers AI Backend

Create a new Worker project:

mkdir smart-clipboard-worker
cd smart-clipboard-worker
wrangler init

Replace src/index.js with the following:

export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const path = url.pathname;

    if (request.method !== 'POST') {
      return new Response('Method not allowed', { status: 405 });
    }

    const { text, mode, targetLang } = await request.json();

    if (!text || !mode) {
      return new Response('Missing text or mode', { status: 400 });
    }

    // Optional: check R2 cache
    const cacheKey = `${mode}:${targetLang || 'none'}:${hash(text)}`;
    if (env.CLIPBOARD_CACHE) {
      const cached = await env.CLIPBOARD_CACHE.get(cacheKey);
      if (cached) {
        return new Response(await cached.text(), {
          headers: { 'Content-Type': 'text/plain', 'X-Cache': 'HIT' },
        });
      }
    }

    // Build prompt
    let prompt;
    if (mode === 'summarize') {
      prompt = `Summarize the following text concisely in 2-3 sentences, preserving key facts and names. Output only the summary, no preamble.\n\n${text}`;
    } else if (mode === 'translate') {
      const lang = targetLang || 'English';
      prompt = `Translate the following text to ${lang}. Output only the translation, no preamble.\n\n${text}`;
    } else {
      return new Response('Invalid mode. Use summarize or translate.', { status: 400 });
    }

    // Call Workers AI
    const aiResponse = await env.AI.run('@cf/meta/llama-3-8b-instruct', {
      prompt,
      max_tokens: mode === 'summarize' ? 200 : 1000,
      temperature: 0.3,
    });

    const result = aiResponse.response.trim();

    // Cache in R2 if available
    if (env.CLIPBOARD_CACHE) {
      await env.CLIPBOARD_CACHE.put(cacheKey, result, {
        expirationTtl: 86400, // 24 hours
      });
    }

    return new Response(result, {
      headers: { 'Content-Type': 'text/plain', 'X-Cache': 'MISS' },
    });
  },
};

function hash(str) {
  // Simple hash for cache key (not cryptographic)
  let h = 0;
  for (let i = 0; i < str.length; i++) {
    h = (Math.imul(31, h) + str.charCodeAt(i)) | 0;
  }
  return h.toString(36);
}

Configure wrangler.toml:

name = "smart-clipboard"
main = "src/index.js"
compatibility_date = "2024-09-01"

[[r2_buckets]]
binding = "CLIPBOARD_CACHE"
bucket_name = "clipboard-cache"

[ai]
binding = "AI"

Create the R2 bucket (if using caching):

wrangler r2 bucket create clipboard-cache

Deploy:

wrangler deploy

Note the deployed URL (e.g., https://smart-clipboard.your-subdomain.workers.dev). You’ll hit this from the desktop client.

Step 2: Cloudflare R2 for Optional Caching

If you skip R2, remove the CLIPBOARD_CACHE references from the Worker code and wrangler.toml. The utility still works—you just lose the cache. With R2, identical text copied twice within 24 hours returns instantly without burning AI tokens.

To verify the cache works:

curl -X POST https://your-worker.workers.dev/summarize \
  -H "Content-Type: application/json" \
  -d '{"text":"Cloudflare Workers AI provides serverless GPU-accelerated inference.","mode":"summarize"}'

Run it twice. The second response includes X-Cache: HIT.

Step 3: Python Clipboard Daemon

Install dependencies:

pip install pyperclip keyboard requests

Create clipboard_daemon.py:

import pyperclip
import keyboard
import requests
import threading
import time
import json

WORKER_URL = "https://smart-clipboard.your-subdomain.workers.dev"
MODE = None  # 'summarize' or 'translate'
TARGET_LANG = "English"  # Change as needed

last_clipboard = ""

def poll_clipboard():
    global last_clipboard
    while True:
        try:
            current = pyperclip.paste()
            if current != last_clipboard:
                last_clipboard = current
        except Exception:
            pass
        time.sleep(0.3)

def process_text(mode):
    text = pyperclip.paste().strip()
    if not text:
        print("Clipboard empty.")
        return
    if len(text) < 10 and mode == 'summarize':
        print("Text too short to summarize.")
        return

    print(f"Processing ({mode})...")
    try:
        payload = {"text": text, "mode": mode, "targetLang": TARGET_LANG}
        resp = requests.post(WORKER_URL, json=payload, timeout=30)
        resp.raise_for_status()
        result = resp.text.strip()
        pyperclip.copy(result)
        print(f"Done. {'Cached' if resp.headers.get('X-Cache') == 'HIT' else 'Fresh'} result in clipboard.")
    except Exception as e:
        print(f"Error: {e}")

def on_summarize():
    process_text('summarize')

def on_translate():
    process_text('translate')

if __name__ == "__main__":
    # Start clipboard poller
    poller = threading.Thread(target=poll_clipboard, daemon=True)
    poller.start()

    # Register hotkeys
    keyboard.add_hotkey('ctrl+shift+s', on_summarize)
    keyboard.add_hotkey('ctrl+shift+t', on_translate)

    print("Smart Clipboard running. Ctrl+Shift+S: Summarize | Ctrl+Shift+T: Translate | Ctrl+C to exit")
    keyboard.wait('ctrl+c')

Step 4: Wiring the Hotkey Listener

On Windows, keyboard requires admin privileges for global hotkeys. Run your terminal as Administrator, or switch to AutoHotkey:

^+s::
    Run, pythonw.exe C:\path\to\clipboard_daemon.py --summarize, , Hide
    return
^+t::
    Run, pythonw.exe C:\path\to\clipboard_daemon.py --translate, , Hide
    return

Modify the Python script to accept a --summarize or --translate argument and process the clipboard immediately instead of polling. This avoids keeping a long-running Python process.

On macOS, pyperclip works out of the box. If hotkeys are flaky, use pynput instead of keyboard:

pip install pynput

Replace the keyboard calls with pynput’s global hotkey listener. The architecture stays identical.

Step 5: Running the Utility

python clipboard_daemon.py
  1. Copy any paragraph.
  2. Press Ctrl+Shift+S to summarize. The clipboard updates with a 2-3 sentence summary.
  3. Copy a foreign-language snippet, press Ctrl+Shift+T, and the translation overwrites the clipboard.

To run on startup:

  • Windows: Add a shortcut to clipboard_daemon.py in shell:startup.
  • macOS: Create a LaunchAgent plist.
  • Linux: Add to .xinitrc or use systemd user service.

Sensible Extensions

  • Multi-language translation: Extend targetLang to accept language codes (e.g., fr, de, ja). Add a third hotkey that cycles languages.
  • Clipboard history: Store the last 20 clipboard entries in a local SQLite database so you can recall previous copies. This pairs well with the FDE portfolio mindset—small utilities that solve real friction points.
  • Model fallback: If Workers AI rate-limits you (10k req/day), fall back to a local Ollama instance running Llama 3.2. Check out running production-grade LLMs locally for the setup.
  • Tone adjustment: Add modes like “make professional,” “make casual,” or “explain like I’m five” by tweaking the system prompt in the Worker.
  • Desktop notifications: Use plyer to show a toast when processing completes, so you’re not left wondering if the hotkey registered.

Common Pitfalls

  1. “Text too short” errors: Llama 3 needs context. Summarizing a single sentence returns garbage. Add a minimum character threshold (we used 50 chars above).
  2. Clipboard permission issues: On Wayland (Linux), pyperclip may fail. Use wl-clipboard as a backend or switch to subprocess.run(["wl-paste"]).
  3. Hotkey conflicts: Ctrl+Shift+S is “Save As” in many apps. Pick unoccupied combos like Ctrl+Shift+Alt+S. Test with keyboard-test.org.
  4. Workers AI cold starts: First request after deployment may take 2-3 seconds. Subsequent requests are sub-second. Keep the daemon alive to amortize.
  5. Token limits: Llama 3 8B on Workers AI has a 4096-token context window. For very long text, truncate before sending. The Worker code above doesn’t truncate—add text.slice(0, 3000) for safety.
  6. Security: The Worker is public. Anyone who discovers the URL can burn your free quota. Add a simple bearer token in the request header and validate it in the Worker. Even a hardcoded random string raises the bar significantly. This is a real concern—security engineers thinking about AI pipelines should understand why text watermarks don’t solve this class of problem.

FAQ

Q: Why not just use ChatGPT’s desktop app? A: Context-switching kills flow. This utility keeps you in your current window. Plus, Workers AI is free up to 10k requests/day—OpenAI’s API is not.

Q: Can I use a different model? A: Yes. Swap @cf/meta/llama-3-8b-instruct for any model in the Workers AI catalog. Mistral 7B and Gemma 2B work identically.

Q: What if I copy sensitive data? A: Text is transmitted over HTTPS. Cloudflare’s Workers AI inference does not log prompts or responses by default. For ultra-sensitive environments, run the model locally via Ollama and point the daemon at localhost:11434. The Llama.cpp deep dive covers this.

Q: How do I debug if nothing happens? A: Add print statements liberally. Check the Worker logs with wrangler tail. Verify the Worker URL with curl first. Test clipboard access with pyperclip.paste() in a Python REPL.

Q: Will this drain my laptop battery? A: The clipboard poller runs every 300ms—negligible CPU. The heavy lifting happens on Cloudflare’s GPUs. Battery impact is near zero.

Q: Can I make this a proper system tray app? A: Absolutely. Wrap it with pystray or PyQt5 for a tray icon with a right-click menu. This is a natural next step if you’re building a portfolio of shipped artifacts that demonstrate real user empathy—exactly what forward deployed engineering roles reward.


You now have a zero-cost, privacy-conscious clipboard AI that runs silently in the background. The entire stack—Workers AI, R2, Python—stays well within free tiers for personal use. Ship it, tweak it, and keep the context switches at bay.

#clipboard-tool#summarization#translation#cloudflare

Want to build like a Forward Deployed Engineer?

FDE Coach is a cohort-based program in frontend, backend, AWS, and AI. Build real products and get referred to 200+ hiring partners.

Explore the program

More build guides

August 15 · 0d left
Enroll Now