Readwise AI Highlighter

Explore the powerful Readwise API integration with tools for retrieving highlights, adding new ones, and generating insightful daily reviews and quizzes. This guide details how to configure your token, customize your queries, and enhance your reading experience through structured data. Get starte...

Readwise AI Highlighter
"""
title: Readwise 
author: airabbit
author_url: https://airabbit.blog
funding_url: https://buymeacoffee.com/airabbit
version: 0.1.1
description: Readwise API Integration 
requirements:
    - pydantic>=2.0.0
    - requests>=2.25.0


from pydantic import BaseModel, Field
from typing import Dict, List, Any, Optional
import requests
from datetime import datetime, timedelta
import logging
import json


class Tools:
    class Valves(BaseModel):
        READWISE_TOKEN: str = Field(default="", description="Your Readwise API token")

    class UserValves(BaseModel):
        pass

    def __init__(self) -> None:
        self.name = "Readwise Integration"
        self.valves = self.Valves()

    def get_recent_highlights(
        self, limit: str = "10", category: str = "", source: str = "", book_id: str = ""
    ) -> str:
        """
        Get recent highlights with optional filtering
        """
        limit = str(min(int(limit), 100))

        print("\n=== get_recent_highlights ===")
        print("INPUT:")
        print(f"  limit: {limit}")
        print(f"  category: {category}")
        print(f"  source: {source}")
        print(f"  book_id: {book_id}\n")

        if not self.valves.READWISE_TOKEN:
            error = "⚠️ Readwise API token not configured"
            print("ERROR:")
            print(f"  {error}")
            print("========================\n")
            return json.dumps({"error": error})

        try:
            params = {"page_size": limit}
            if category:
                params["category"] = category
            if source:
                params["source"] = source
            if book_id:
                params["book_id"] = book_id

            headers = {"Authorization": f"Token {self.valves.READWISE_TOKEN}"}
            response = requests.get(
                "https://readwise.io/api/v2/highlights/", headers=headers, params=params
            )

            print("API RESPONSE:")
            print(f"  {response.text}\n")

            data = response.json()["results"]
            results = []

            for item in data:
                results.append(
                    {
                        "text": item["text"],
                        "note": item.get("note", ""),
                        "location": item["location"],
                    }
                )

            final_response = json.dumps({"highlights": results})
            print("OUTPUT:")
            print(f"  {final_response}")
            print("========================\n")
            return final_response

        except Exception as e:
            error = f"Error getting highlights: {str(e)}"
            print("ERROR:")
            print(f"  {error}")
            print("========================\n")
            return json.dumps({"error": error})

    def create_highlight(
        self,
        text: str,
        title: str,
        author: str,
        source_url: str,
        note: str = "",
    ) -> str:
        """
        Create a new memo or highlight in readwise. All fields are mandatory, including Title, Author and source_url
        """
        print("\n=== create_highlight ===")
        print("INPUT:")
        print(f"  text: {text}")
        print(f"  title: {title}")
        print(f"  author: {author}")
        print(f"  source_url: {source_url}")
        print(f"  note: {note}\n")

        if not self.valves.READWISE_TOKEN:
            error = "⚠️ Readwise API token not configured"
            print("ERROR:")
            print(f"  {error}")
            print("========================\n")
            return json.dumps({"error": error})

        try:
            headers = {"Authorization": f"Token {self.valves.READWISE_TOKEN}"}
            data = {
                "highlights": [
                    {
                        "text": text,
                        "title": title,
                        "author": "OpenWebUI",
                        "source_url": "https://openwebui.com/",
                        "note": "-",
                        "category": "articles",
                    }
                ]
            }

            response = requests.post(
                "https://readwise.io/api/v2/highlights/", headers=headers, json=data
            )

            print("API RESPONSE:")
            print(f"  {response.text}\n")

            final_response = json.dumps({"created": response.json()})
            print("OUTPUT:")
            print(f"  {final_response}")
            print("========================\n")

            prompt = f"""
            Inform the user that the highlight was created successfully 
            and format the field in a proper markdown format : {final_response}
            """
            return prompt

        except Exception as e:
            error = f"Error creating highlight: {str(e)}"
            print("ERROR:")
            print(f"  {error}")
            print("========================\n")
            return json.dumps({"error": error})

    def get_daily_review(self) -> str:
        """
        daily review highlights.


        """
        print("\n=== get_daily_review ===")
        print("INPUT: None\n")

        if not self.valves.READWISE_TOKEN:
            error = "⚠️ Readwise API token not configured"
            print("ERROR:")
            print(f"  {error}")
            print("========================\n")
            return json.dumps({"error": error})

        try:
            headers = {"Authorization": f"Token {self.valves.READWISE_TOKEN}"}
            response = requests.get(
                "https://readwise.io/api/v2/review/", headers=headers
            )

            print("API RESPONSE:")
            print(f"  {response.text}\n")

            final_response = json.dumps(response.json())
            print("OUTPUT:")
            print(f"  {final_response}")
            print("========================\n")
            return final_response

        except Exception as e:
            error = f"Error getting daily review: {str(e)}"
            print("ERROR:")
            print(f"  {error}")
            print("========================\n")
            return json.dumps({"error": error})

    def dailyquiz(self) -> str:
        """
        Create a quiz from the readwise daily review highlights
        """
        print("\n=== dailyquiz ===")
        print("INPUT: None\n")

        if not self.valves.READWISE_TOKEN:
            error = "⚠️ Readwise API token not configured"
            print("ERROR:")
            print(f"  {error}")
            print("========================\n")
            return json.dumps({"error": error})

        try:
            headers = {"Authorization": f"Token {self.valves.READWISE_TOKEN}"}
            response = requests.get(
                "https://readwise.io/api/v2/review/", headers=headers
            )

            print("API RESPONSE:")
            print(f"  {response.text}\n")

            highlights = response.json().get("highlights", [])
            highlight_texts = [highlight["text"] for highlight in highlights]

            quiz_prompt = (
                f"Make a quiz of the Highlights list {highlight_texts}, "
                "focusing on the content of the highlighted text, "
                "not the metadata or titles, one question at a time, "
                "and say right or wrong after each question."
            )

            print("OUTPUT:")
            print(f"  {quiz_prompt}")
            print("========================\n")
            return quiz_prompt

        except Exception as e:
            error = f"Error creating quiz: {str(e)}"
            print("ERROR:")
            print(f"  {error}")
            print("========================\n")
            return json.dumps({"error": error})
Data Privacy | Imprint