AI Chat with your Notes using LogSeq and Open WebUI
Unlock the full potential of Logseq by integrating it with AI tools like OpenWebUI! Learn how to seamlessly chat with your notes, aggregate information, and manage your to-dos—all from your chat window. This step-by-step guide walks you through setting up API access, creating prompts, and testing...


Logseq is an amazing open source note-taking and journaling tool with powerful search capabilities. However, navigating a complex document base and gathering information from multiple locations can be challenging.
This is where AI comes in.
Imagine a scenario where you can seamlessly integrate your Logseq notes with the power of OpenWebUI or similar open source tools, all from the comfort of your chat window. This integration allows you to:
- Aggregate information: Combine your notes with external web information to create a unified knowledge base.
- Ask questions: Query your notes without leaving the chat window, getting relevant information instantly.Create notes: Create new notes from web content or AI-generated insights.
The possibilities are endless!
In this blog post we will integrate Logseq with Open WebUI and LLama3.1 (or OpenAI) and end up being able to chat with our Logseq notes and todos.
Steps
- Create a Test Page with To-dos in Logseq
- Enable the Logseq API
- Set a Secure Auth Token
- Create a Tool in OpenWebUI
- Configure the Tool in OpenWebUI
- Create a Prompt Template for Querying To-dos
- Test the Setup
Let's go.
1. Create a Test Page with To-dos in Logseq
First, let's start by creating a test page with some to-dos we want to query later from OpenWebUI.

2. Enable the Logseq API
Now we need to enable the API for Logseq to give OpenWebUI access for the chat.

3. Set a Secure Auth Token
Set a secure auth token.

4. Create a Tool in OpenWebUI
Next, let's create a tool in OpenWebUI that will interact with the Logseq API.

In the tool window:

Enter this code and give it a useful name, for example, "Logseq API."
import requests
import json
import logging
from pydantic import BaseModel, Field
class Tools:
class Valves(BaseModel):
LOGSEQ_BASE_URL: str = Field(
default="http://host.docker.internal:12315",
description="Logseq API base URL",
)
LOGSEQ_TOKEN: str = Field(default="", description="Logseq API token")
def __init__(self):
"""
Initialize the Tools class with Logseq API configuration and set up logging.
"""
self.valves = self.Valves()
self._setup_logging()
def _setup_logging(self):
"""
Set up logging configuration for the Tools class.
"""
log_file = "/tmp/logseq_api_tools.log"
logging.basicConfig(
filename=log_file,
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
)
self.logger = logging.getLogger(__name__)
self.logger.info(f"Logging initialized. Log file: {log_file}")
def _make_request(self, method, args):
"""
Make a request to the Logseq API.
:param method: The Logseq API method to call.
:param args: A list of arguments to pass to the method.
:return: The JSON string response from the API or an error JSON string.
"""
url = f"{self.valves.LOGSEQ_BASE_URL}/api"
headers = {
"Authorization": f"Bearer {self.valves.LOGSEQ_TOKEN}",
"Content-Type": "application/json",
}
payload = {"method": method, "args": args}
self.logger.info(f"Making request to Logseq API: {method}")
try:
response = requests.post(url, headers=headers, json=payload)
response.raise_for_status()
self.logger.info(f"Successful API call to {method}")
return json.dumps(response.json())
except requests.RequestException as e:
self.logger.error(f"Error in API call to {method}: {str(e)}")
return json.dumps({"error": str(e)})
def query_todos(self):
"""
Query all TODO items in the Logseq graph.
:return: JSON string of TODO items or an error JSON string.
"""
self.logger.info("Querying todos")
return self._make_request("logseq.db.q", ["(task TODO)"])
def add_block(self, page_name, content, properties=None):
"""
Add a new block to a Logseq page.
:param page_name: Name of the page to add the block to.
:param content: Content of the new block.
:param properties: Optional dict of block properties.
:return: JSON string of the inserted block data or an error JSON string.
"""
self.logger.info(f"Adding block to page: {page_name}")
return self._make_request(
"logseq.Editor.insertBlock",
[page_name, content, properties or {}],
)
def delete_block(self, block_id):
"""
Delete a block from the Logseq graph.
:param block_id: ID of the block to delete.
:return: JSON string of the deletion operation result or an error JSON string.
"""
self.logger.info(f"Deleting block: {block_id}")
return self._make_request("logseq.Editor.removeBlock", [block_id])
def get_page(self, page_name):
"""
Get a page from the Logseq graph.
:param page_name: Name of the page to retrieve.
:return: JSON string of the page data or an error JSON string.
"""
self.logger.info(f"Getting page: {page_name}")
return self._make_request("logseq.Editor.getPage", [page_name])
def create_page(self, page_name, properties=None):
"""
Create a new page in the Logseq graph.
:param page_name: Name of the new page.
:param properties: Optional dict of page properties.
:return: JSON string of the created page data or an error JSON string.
"""
self.logger.info(f"Creating page: {page_name}")
return self._make_request(
"logseq.Editor.createPage", [page_name, properties or {}]
)
def query(self, search_string):
"""
Logseq query for a given string
:param search_string: A simple string to search for in the Logseq graph.
:return: JSON string of the query results or an error JSON string.
"""
datalog_query = search_string
self.logger.info(f"Executing query for: {search_string}")
self.logger.debug(f"Datalog query: {datalog_query}")
return self._make_request("logseq.app.search", [datalog_query])
def delete_page(self, page_name):
"""
Delete a page from the Logseq graph.
:param page_name: Name of the page to delete.
:return: JSON string of the deletion operation result or an error JSON string.
"""
self.logger.info(f"Deleting page: {page_name}")
return self._make_request("logseq.Editor.deletePage", [page_name])
# Usage:
# tools = Tools()
# Set the Logseq API token and base URL in the valves:
# tools.valves.LOGSEQ_TOKEN = "your_logseq_api_token_here"
# tools.valves.LOGSEQ_BASE_URL = "http://host.docker.internal:12315" # Change if needed
# todos = tools.query_todos()
# new_block = tools.add_block('My Page', 'New block content', {'priority': 'high'})
# tools.delete_block('block_id_here')
# page = tools.get_page('My Page')
# new_page = tools.create_page('New Page', {'tags': ['project', 'important']})
# tools.delete_page('Page to Delete')
5. Configure the Tool in OpenWebUI
Now, configure the auth token key you set above for Logseq:

Enter in the settings for the tool the Logseq token and the API URL.
Note: The default URL is valid only if you have Logseq running on your host and OpenWebUI running in a Docker container (the same as for Ollama and OpenWebUI). If you have a different setup, please make sure to test the URL from OpenWebUI before you test it to avoid connection errors when the tool tries to reach Logseq.

6. Create a Prompt Template for Querying To-dos
Now let's create a prompt template for querying the to-dos.

Enter the following prompt. This will filter by whatever you enter, e.g., "TODO buy" or just "TODO," etc.
QUERY THE LOGSEQ for "[Query]" and return the result as is from the context just adapting to user request.
7. Test the Setup
Now we are all set. Let's try it out in a new chat with a model that supports tools, like llama3.1 or gpt-4o-mini.
First, you need to activate this tool for the selected model as follows:

Then select the prompt template we defined earlier:

Now enter a query parameter, e.g., TODO buy
If all went well, you should now see the to-dos we entered above:
buy milk
buy apples

Now that we have the information we want, we can transform and present it in any way we like, such as clustering or sorting in a table like this

And that's it! You've now set up a tool in OpenWEBUI to interact with the Logseq API. This means that you can easily manage your to-dos and pages in Logseq directly from OpenWEBUI. You can also use the tool to create and delete notes. Happy organising!