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...

"""
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})
Comments ()