Note
Click here to download the full example code
REST API
Ragna was designed to help you quickly build custom RAG powered web applications. For this you can leverage the built-in REST API.
This tutorial walks you through basic steps of using Ragna's REST API.
Step 1: Start the REST API
Ragnas REST API is normally started from a terminal with
$ ragna deploy
For this tutorial we use our helper that does the equivalent just from Python.
Note
By default, the REST API is started from the ragna.toml
configuration file in
the current working directory. If you don't have a configuration file yet, you can
run
$ ragna init
to start an interactive wizard that helps you create one. The config that we'll be using for this tutorial is equivalent of picking the first option the wizard offers you, i.e. using only demo components.
import ragna._docs as ragna_docs
from ragna.deploy import Config
config = Config()
ragna_deploy = ragna_docs.RagnaDeploy(config=config)
Let's make sure the REST API is started correctly and can be reached.
import httpx
client = httpx.Client(base_url=f"http://{config.hostname}:{config.port}")
client.get("/health").raise_for_status()
Out:
<Response [200 OK]>
Step 2: Authentication
In order to use Ragna's REST API, we need to authenticate first. This is handled by
the ragna.deploy.Auth class, which can be overridden through the config. By
default, ragna.deploy.NoAuth is used. By hitting the /login
endpoint, we get a
session cookie, which is later used to authorize our requests.
client.get("/login", follow_redirects=True)
dict(client.cookies)
Out:
{'ragna': 'fd9331c8-55f0-4410-b028-1ebfae62eb96'}
Note
In a regular deployment, you'll have login through your browser and create an API key in your profile page. The API key is used as bearer token and can be set with
httpx.Client(..., headers={"Authorization": f"Bearer {RAGNA_API_KEY}"})
Step 3: Uploading documents
Before we start with the upload process, let's first have a look what kind of documents are supported.
import json
response = client.get("/api/components").raise_for_status()
print(json.dumps(response.json(), indent=2))
Out:
{
"documents": [
".docx",
".md",
".pdf",
".pptx",
".txt"
],
"source_storages": [
{
"properties": {},
"title": "Ragna/DemoSourceStorage",
"type": "object"
}
],
"assistants": [
{
"properties": {},
"title": "Ragna/DemoAssistant",
"type": "object"
}
]
}
For simplicity, let's use a demo document with some information about Ragna
from pathlib import Path
print(ragna_docs.SAMPLE_CONTENT)
document_path = Path.cwd() / "ragna.txt"
with open(document_path, "w") as file:
file.write(ragna_docs.SAMPLE_CONTENT)
Out:
Ragna is an open source project built by Quansight. It is designed to allow
organizations to explore the power of Retrieval-augmented generation (RAG) based
AI tools. Ragna provides an intuitive API for quick experimentation and built-in
tools for creating production-ready applications allowing you to quickly leverage
Large Language Models (LLMs) for your work.
The Ragna website is https://ragna.chat/. The source code is available at
https://github.com/Quansight/ragna under the BSD 3-Clause license.
The upload process in Ragna consists of two parts:
- Register the document in Ragna's database. This returns the document ID, which is needed for the upload.
response = client.post(
"/api/documents", json=[{"name": document_path.name}]
).raise_for_status()
documents = response.json()
print(json.dumps(documents, indent=2))
Out:
[
{
"id": "20234686-4e12-4320-b879-8bc6e83677f5",
"name": "ragna.txt",
"metadata": {
"path": "/tmp/tmp49gprz0s/documents/20234686-4e12-4320-b879-8bc6e83677f5"
}
}
]
- Perform the upload through a multipart request with the following parameters:
- The field is
documents
for all entries - The field name is the ID of the document returned by step 1.
- The field value is the binary content of the document.
client.put(
"/api/documents",
files=[("documents", (documents[0]["id"], open(document_path, "rb")))],
)
Out:
<Response [200 OK]>
Step 4: Select a source storage and assistant
The configuration we are using only supports demo components for the source storage and assistant and so we pick them here.
from ragna import source_storages, assistants
source_storage = source_storages.RagnaDemoSourceStorage.display_name()
assistant = assistants.RagnaDemoAssistant.display_name()
print(f"{source_storage=}, {assistant=}")
Out:
source_storage='Ragna/DemoSourceStorage', assistant='Ragna/DemoAssistant'
Step 5: Start chatting
Now that we have uploaded a document, and selected a source storage and assistant to be used, we can create a new chat.
response = client.post(
"/api/chats",
json={
"name": "Tutorial REST API",
"input": [document["id"] for document in documents],
"source_storage": source_storage,
"assistant": assistant,
},
).raise_for_status()
chat = response.json()
print(json.dumps(chat, indent=2))
Out:
{
"id": "c9b91008-9deb-48ec-a967-481f190af64f",
"name": "Tutorial REST API",
"metadata_filter": null,
"documents": [
{
"id": "20234686-4e12-4320-b879-8bc6e83677f5",
"name": "ragna.txt",
"metadata": {
"path": "/tmp/tmp49gprz0s/documents/20234686-4e12-4320-b879-8bc6e83677f5"
}
}
],
"source_storage": "Ragna/DemoSourceStorage",
"assistant": "Ragna/DemoAssistant",
"corpus_name": "default",
"params": {},
"messages": [],
"prepared": false
}
As can be seen by the "prepared": false
value in the chat
JSON object we still
need to prepare it.
client.post(f"/api/chats/{chat['id']}/prepare").raise_for_status()
Out:
<Response [200 OK]>
Finally, we can get answers to our questions.
response = client.post(
f"/api/chats/{chat['id']}/answer",
json={"prompt": "What is Ragna?"},
).raise_for_status()
answer = response.json()
print(json.dumps(answer, indent=2))
Out:
{
"id": "0f41f1c6-f82b-4956-b0f6-75e7cd2a2bef",
"content": "I'm a demo assistant and can be used to try Ragna's workflow.\nI will only mirror back my inputs. \n\nSo far I have received 1 messages.\n\nYour last prompt was:\n\n> What is Ragna?\n\nThese are the sources I was given:\n\n- ragna.txt: Ragna is an open source project built by Quansight. It is designed to allow organizations to [...]",
"role": "assistant",
"sources": [
{
"id": "16d2141a-bdd8-4130-9743-ff8575e90c28",
"document_id": "20234686-4e12-4320-b879-8bc6e83677f5",
"document_name": "ragna.txt",
"location": "",
"content": "Ragna is an open source project built by Quansight. It is designed to allow organizations to [...]",
"num_tokens": 17
}
],
"timestamp": "2025-02-03T10:22:20.478379Z"
}
print(answer["content"])
Out:
I'm a demo assistant and can be used to try Ragna's workflow.
I will only mirror back my inputs.
So far I have received 1 messages.
Your last prompt was:
> What is Ragna?
These are the sources I was given:
- ragna.txt: Ragna is an open source project built by Quansight. It is designed to allow organizations to [...]
Before we close the tutorial, let's terminate the REST API and have a look at what
would have printed in the terminal if we had started it with the ragna deploy
command.
ragna_deploy.terminate()
Out:
INFO: 127.0.0.1:55300 - "GET /health HTTP/1.1" 200 OK
INFO: 127.0.0.1:55316 - "GET /health HTTP/1.1" 200 OK
INFO: 127.0.0.1:55316 - "GET /login HTTP/1.1" 303 See Other
INFO: 127.0.0.1:55316 - "GET /oauth-callback HTTP/1.1" 303 See Other
INFO: 127.0.0.1:55316 - "GET / HTTP/1.1" 303 See Other
INFO: 127.0.0.1:55316 - "GET /docs HTTP/1.1" 200 OK
INFO: 127.0.0.1:55316 - "GET /api/components HTTP/1.1" 200 OK
INFO: 127.0.0.1:55316 - "POST /api/documents HTTP/1.1" 200 OK
INFO: 127.0.0.1:55316 - "PUT /api/documents HTTP/1.1" 200 OK
INFO: 127.0.0.1:55316 - "POST /api/chats HTTP/1.1" 200 OK
INFO: 127.0.0.1:55316 - "POST /api/chats/c9b91008-9deb-48ec-a967-481f190af64f/prepare HTTP/1.1" 200 OK
INFO: 127.0.0.1:55316 - "POST /api/chats/c9b91008-9deb-48ec-a967-481f190af64f/answer HTTP/1.1" 200 OK
Total running time of the script: ( 0 minutes 2.186 seconds)
Download Python source code: gallery_rest_api.py