Self-hosted knowledge management for SMEs: a split-screen Markdown editor whose sections an LLM refines while you write, and RAG question answering over the documents that result. FastAPI + Postgres/pgvector on the back, SvelteKit on the front, everything OpenAI-compatible and self-hostable. Squashed into a single commit; the development history stays local. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CA43ZJda8Rbp2hKXNy8f6b
75 lines
2.0 KiB
Python
75 lines
2.0 KiB
Python
import pytest
|
|
from sqlalchemy import select, text
|
|
from sqlalchemy.exc import IntegrityError
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.models import (
|
|
EMBEDDING_DIM,
|
|
Chunk,
|
|
Document,
|
|
DocumentStatus,
|
|
)
|
|
|
|
|
|
async def _make_document(db: AsyncSession, content: str) -> Document:
|
|
document = Document(
|
|
title="Server maintenance",
|
|
status=DocumentStatus.published,
|
|
content_md=content,
|
|
)
|
|
db.add(document)
|
|
await db.flush()
|
|
return document
|
|
|
|
|
|
async def test_chunk_tsv_is_generated_with_german_config(db: AsyncSession) -> None:
|
|
document = await _make_document(db, "# Maintenance")
|
|
chunk = Chunk(
|
|
document_id=document.id,
|
|
chunk_index=0,
|
|
content="The servers are maintained and checked regularly.",
|
|
embedding=[0.1] * EMBEDDING_DIM,
|
|
)
|
|
db.add(chunk)
|
|
await db.commit()
|
|
|
|
# Same word in content and query stems identically under any config;
|
|
# real German retrieval assertions come with the M4 fixture corpus.
|
|
matches = (
|
|
await db.execute(
|
|
select(Chunk.id).where(
|
|
text("tsv @@ websearch_to_tsquery('german', 'maintained')")
|
|
)
|
|
)
|
|
).all()
|
|
assert len(matches) == 1
|
|
|
|
|
|
async def test_chunk_index_unique_per_document(db: AsyncSession) -> None:
|
|
document = await _make_document(db, "# Duplicate")
|
|
for _ in range(2):
|
|
db.add(
|
|
Chunk(
|
|
document_id=document.id,
|
|
chunk_index=0,
|
|
content="same index",
|
|
embedding=[0.0] * EMBEDDING_DIM,
|
|
)
|
|
)
|
|
with pytest.raises(IntegrityError):
|
|
await db.commit()
|
|
|
|
|
|
async def test_embedding_dimension_enforced(db: AsyncSession) -> None:
|
|
document = await _make_document(db, "# Dimension")
|
|
db.add(
|
|
Chunk(
|
|
document_id=document.id,
|
|
chunk_index=0,
|
|
content="wrong dimension",
|
|
embedding=[0.0] * (EMBEDDING_DIM - 1),
|
|
)
|
|
)
|
|
with pytest.raises(Exception, match="expected 1024 dimensions"):
|
|
await db.commit()
|