API Notes
November 15, 2025 · View on GitHub
Existing Pages:
- Transcribe/Analyze/Ingestion
- Video Transcription + Summarization
- Audio File Transcription + Summarization
- Podcast
- Ebook Files
- Import Plain Text & .docx files
- Import XML Files
- Website Scraping
- PDF Ingestion
- Re-Summarize
- Live Recording & Transcription
- Audio Generation Playground
- Arxiv Search & Ingest
- Semantic Scholar Search
- RAG Chat/Search
- RAG Search
- RAG QA Chat (Chat + notes)
- Notes Management
- Chat Management
- Chat with an LLM
- Remote LLM Chat (Horizontal)
- Remote LLM Chat (Vertical)
- One prompt, multiple APIs
- Four independent API Chats
- Chat workflows
- Web Search & Review
- Web Search & Review
- Character Chat
- Chat with a character card
- Character Chat Management
- Create a New Character Card
- Validate a Character Card
- Multi-Character Chat
- Writing Tools
- Writing Feedback
- Grammar & Style Checker
- Tone Analyzer & Editor
- Creative Writing Assistant
- Mikupad
- Search / View DB Items
- Media DB Search/ Detailed View
- Media DB Search/View Title + Summary
- View all MediaDB Items
- View Media Database Entries
- Search MediaDB by keyword
- View all RAG notes/Conversation items
- View RAG DB Entries
- View RAG Notes/Conversations by keyword
- Prompts
- View Prompt Database
- Search Prompts
- Add & Edit Prompts
- Clone & Edit prompts
- Add & Edito prompts
- Export Prompts
- Clone & Edit prompts
- Prompt Suggestion/Creation
- Export Prompts
- Manage DB Items
- Edit existing items in the Media DB
- Edit/Manage DB Items
- Clone and edit existing items in the media DB
- Embeddings Management
- Create Embeddings
- View/Update Embeddings
- Purge Embeddings
- Keywords
- View MediaDB Keywords
- Add MediaDB Keywords
- Delete MediaDB Keywords
- Export MEdiaDB Keywords
- Character Keywords
- RAG QA Keywords
- Meta-Keywords
- Prompt Keywords
- Import
- Import Markdown/Text Files
- Import Obsidian Vault
- Import a Prompt
- Import multiple prompts
- MediaWiki Import
- MediaWiki import config
- Import RAG chats
- Export
- Media DB Export
- RAG Conversations Export
- RAG Notes Export
- Export Prompts
- Export Prompts
- DB Mgmt
- Media DB
- RAG Chat DB
- Character Chat DB
- Utils
- MindMap Gen
- Youtube vid downloader
- Youtube audio downloader
- Youtube timestamp URL gen
- Anki
- Anki Deck Generator
- Anki Flash Card Validator
- Local LLM
- Local LLM with Llamafile
- Ollama Model Serving
- Trashcan
- Search and mark as trash
- View trash
- Delete DB Item
- Empty trash
- Evals
- G-Eval
- Infinite Bench
- Intro/Help
- Intro/Help Page
- Config Editor
- Config Editor
Old
Here’s the important part. We’ll create:
A global asyncio.Queue of “write tasks.”
A WriteTask class that holds the SQL, parameters, and an asyncio.Future to signal completion.
A background worker (writer_worker) that pops tasks from the queue, executes them, and sets the result in the Future.
Endpoints that push a WriteTask onto the queue, then await the Future before returning.
# main.py
import asyncio
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import Any, Tuple, Union
from database import get_db_connection
app = FastAPI()
# -----------------------------
# 1) A global queue + task class
# -----------------------------
class WriteTask:
"""Holds SQL, parameters, and a Future to let the enqueuing code wait for completion."""
def __init__(self, sql: str, params: tuple[Any, ...]):
self.sql = sql
self.params = params
self.future: asyncio.Future = asyncio.get_event_loop().create_future()
write_queue: asyncio.Queue[WriteTask] = asyncio.Queue()
# -----------------------------
# 2) The background worker
# -----------------------------
async def writer_worker():
"""Continuously processes write tasks from the queue, one at a time."""
while True:
task: WriteTask = await write_queue.get()
try:
# Perform the write
with get_db_connection() as conn:
conn.execute(task.sql, task.params)
conn.commit()
# If success, set the result of the Future
task.future.set_result(True)
except Exception as e:
# If failure, set the exception so the caller can handle it
task.future.set_exception(e)
finally:
write_queue.task_done()
# -----------------------------
# 3) Start the worker on startup
# -----------------------------
@app.on_event("startup")
async def startup_event():
# Launch the writer worker as a background task
asyncio.create_task(writer_worker())
# -----------------------------
# 4) Pydantic model for input
# -----------------------------
class ItemCreate(BaseModel):
name: str
# -----------------------------
# 5) Write endpoint (POST)
# -----------------------------
@app.post("/items")
async def create_item(item: ItemCreate):
"""Queue a write to the database, then wait for its completion."""
# Cross-backend placeholder guidance:
# - Prefer Postgres-style placeholders (\$1,\$2,...) in examples; SQLite adapters will translate $N→?
# - If you are using raw sqlite3 without the project adapters, use: "VALUES (?)"
sql = "INSERT INTO items (name) VALUES (\$1)"
params = (item.name,)
# Create a WriteTask
write_task = WriteTask(sql, params)
# Put the task in the queue
await write_queue.put(write_task)
# Wait for the task to complete
try:
result = await write_task.future # This will be True if successful
return {"status": "success", "name": item.name}
except Exception as exc:
# If the DB write failed for some reason, raise a 500
raise HTTPException(status_code=500, detail=str(exc))
# -----------------------------
# 6) Read endpoint (GET)
# -----------------------------
@app.get("/items")
def read_items():
"""Simple read operation that does not need the queue."""
with get_db_connection() as conn:
cursor = conn.cursor()
cursor.execute("SELECT id, name FROM items")
rows = cursor.fetchall()
return [{"id": row[0], "name": row[1]} for row in rows]
Explanation
WriteTask stores (sql, params, future). The future is how we pass success/failure back to the original request.
When a request hits POST /items, we:
Construct a WriteTask.
put() it on the write_queue.
Immediately await write_task.future. We don’t return until the DB operation is done.
The writer_worker loop picks tasks in FIFO order and executes them one-by-one, guaranteeing no concurrency for writes (thus avoiding locks).
On success, task.future.set_result(True) is called. On failure, task.future.set_exception(e).
The awaiting endpoint sees either a success (and returns HTTP 200) or an exception (and returns HTTP 500).
This pattern means each request is effectively serialized for writes, but the user still gets a definitive success/failure response in the same request/response cycle.
To Do:
- Add API endpoint for video download from URL, storing as temp file for X time before auto-deletion.
- Add API endpoint for status of media file processing - Can query endpoint with media_id to get status of processing.
- Config file option/check for default user agent
- Add XML to document ingestion pipeline0
- Global variables in Video library - currently uses global variables for paths. This needs to be refactored to instead take/return file paths per-user.
- Add 'rolling_summarization' option to processing pipelines
- VAD Use and
store_in_dboptions are hardcoded when callingprocess_videos- re-examine, so can use process_videos without perm storage - Regex in confab check Issue: The process_videos function uses a regular expression to extract the summary text from a formatted string (all_summaries) for the run_geval check. This relies heavily on the exact string format and can easily break if the format changes. Recommendation: Make process_single_video return a structured dictionary like {"video_input": ..., "status": ..., "transcript": ..., "summary": ..., "db_id": ...}. Then, process_videos can collect these dictionaries in its results list. When running the confabulation check, iterate through the results list and directly access item['transcript'] and item['summary'] to pass to run_geval. This avoids fragile string parsing.
- Set proper paths for model files in config.txt