yoga1290.rag 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. yoga1290_rag-0.1.0/PKG-INFO +7 -0
  2. yoga1290_rag-0.1.0/pyproject.toml +16 -0
  3. yoga1290_rag-0.1.0/setup.cfg +4 -0
  4. yoga1290_rag-0.1.0/yoga1290/rag/api/main.py +48 -0
  5. yoga1290_rag-0.1.0/yoga1290/rag/application/__init__.py +0 -0
  6. yoga1290_rag-0.1.0/yoga1290/rag/application/pipelines/__init__.py +7 -0
  7. yoga1290_rag-0.1.0/yoga1290/rag/application/pipelines/indexing_pipeline.py +34 -0
  8. yoga1290_rag-0.1.0/yoga1290/rag/application/pipelines/ingestion_pipeline.py +54 -0
  9. yoga1290_rag-0.1.0/yoga1290/rag/application/pipelines/retrieval_pipeline.py +84 -0
  10. yoga1290_rag-0.1.0/yoga1290/rag/application/services/__init__.py +0 -0
  11. yoga1290_rag-0.1.0/yoga1290/rag/application/services/document_service.py +15 -0
  12. yoga1290_rag-0.1.0/yoga1290/rag/application/services/search_service.py +25 -0
  13. yoga1290_rag-0.1.0/yoga1290/rag/config/__init__.py +0 -0
  14. yoga1290_rag-0.1.0/yoga1290/rag/config/settings.py +12 -0
  15. yoga1290_rag-0.1.0/yoga1290/rag/domain/__init__.py +0 -0
  16. yoga1290_rag-0.1.0/yoga1290/rag/domain/models/__init__.py +20 -0
  17. yoga1290_rag-0.1.0/yoga1290/rag/domain/models/chunk.py +13 -0
  18. yoga1290_rag-0.1.0/yoga1290/rag/domain/models/classification.py +20 -0
  19. yoga1290_rag-0.1.0/yoga1290/rag/domain/models/document.py +21 -0
  20. yoga1290_rag-0.1.0/yoga1290/rag/domain/models/extracted_data.py +15 -0
  21. yoga1290_rag-0.1.0/yoga1290/rag/domain/models/parsed_document.py +30 -0
  22. yoga1290_rag-0.1.0/yoga1290/rag/domain/models/rag_result.py +17 -0
  23. yoga1290_rag-0.1.0/yoga1290/rag/domain/models/search_document.py +16 -0
  24. yoga1290_rag-0.1.0/yoga1290/rag/domain/models/search_result.py +12 -0
  25. yoga1290_rag-0.1.0/yoga1290/rag/domain/ports/__init__.py +21 -0
  26. yoga1290_rag-0.1.0/yoga1290/rag/domain/ports/document_classifier.py +31 -0
  27. yoga1290_rag-0.1.0/yoga1290/rag/domain/ports/document_extractor.py +17 -0
  28. yoga1290_rag-0.1.0/yoga1290/rag/domain/ports/document_parser.py +30 -0
  29. yoga1290_rag-0.1.0/yoga1290/rag/domain/ports/document_source.py +29 -0
  30. yoga1290_rag-0.1.0/yoga1290/rag/domain/ports/embedder.py +66 -0
  31. yoga1290_rag-0.1.0/yoga1290/rag/domain/ports/llm.py +11 -0
  32. yoga1290_rag-0.1.0/yoga1290/rag/domain/ports/retriever.py +16 -0
  33. yoga1290_rag-0.1.0/yoga1290/rag/domain/ports/search_preparer.py +25 -0
  34. yoga1290_rag-0.1.0/yoga1290/rag/domain/ports/vector_store.py +46 -0
  35. yoga1290_rag-0.1.0/yoga1290/rag/domain/schemas/__init__.py +0 -0
  36. yoga1290_rag-0.1.0/yoga1290/rag/domain/schemas/classification_schema.py +10 -0
  37. yoga1290_rag-0.1.0/yoga1290/rag/domain/schemas/extraction_schema.py +50 -0
  38. yoga1290_rag-0.1.0/yoga1290/rag/factories/__init__.py +5 -0
  39. yoga1290_rag-0.1.0/yoga1290/rag/factories/ai_provider.py +4 -0
  40. yoga1290_rag-0.1.0/yoga1290/rag/factories/llm_factory.py +48 -0
  41. yoga1290_rag-0.1.0/yoga1290/rag/factories/pipeline_factory.py +4 -0
  42. yoga1290_rag-0.1.0/yoga1290/rag/factories/storage_provider.py +4 -0
  43. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/__init__.py +0 -0
  44. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/databricks/__init__.py +0 -0
  45. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/databricks/classifier.py +8 -0
  46. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/databricks/extractor.py +9 -0
  47. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/databricks/parser.py +9 -0
  48. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/databricks/search_preparer.py +8 -0
  49. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/databricks/spark_session.py +4 -0
  50. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/embeddings/__init__.py +5 -0
  51. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/embeddings/gte_embedder.py +12 -0
  52. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/embeddings/llama_cpp_embedder.py +72 -0
  53. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/embeddings/qwen_embedder.py +12 -0
  54. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/__init__.py +0 -0
  55. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/classification/__init__.py +0 -0
  56. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/classification/qwen_classifier.py +6 -0
  57. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/extraction/__init__.py +5 -0
  58. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/extraction/llama_cpp_document_extractor.py +181 -0
  59. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/llm/__init__.py +5 -0
  60. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/llm/llama_cpp_llm.py +31 -0
  61. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/llm/qwen.py +3 -0
  62. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/llm/vllm.py +3 -0
  63. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/parsing/__init__.py +5 -0
  64. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/parsing/local_document_parser.py +54 -0
  65. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/search/__init__.py +0 -0
  66. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/search/local_search_preparer.py +31 -0
  67. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/search/recursive_character_search_preparer.py +62 -0
  68. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/local/sources/csv_document_source.py +62 -0
  69. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/vectorstores/__init__.py +7 -0
  70. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/vectorstores/databricks_vector_search.py +14 -0
  71. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/vectorstores/milvus.py +14 -0
  72. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/vectorstores/pgvector/__init__.py +7 -0
  73. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/vectorstores/pgvector/pgvector_retriever.py +43 -0
  74. yoga1290_rag-0.1.0/yoga1290/rag/infrastructure/vectorstores/pgvector/pgvector_store.py +165 -0
  75. yoga1290_rag-0.1.0/yoga1290/rag/yoga1290.rag.egg-info/PKG-INFO +7 -0
  76. yoga1290_rag-0.1.0/yoga1290/rag/yoga1290.rag.egg-info/SOURCES.txt +76 -0
  77. yoga1290_rag-0.1.0/yoga1290/rag/yoga1290.rag.egg-info/dependency_links.txt +1 -0
  78. yoga1290_rag-0.1.0/yoga1290/rag/yoga1290.rag.egg-info/top_level.txt +6 -0
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: yoga1290.rag
3
+ Version: 0.1.0
4
+ Summary: Document AI and RAG application
5
+ Project-URL: Homepage, https://github.com/yoga1290/rag
6
+ Project-URL: Issues, https://github.com/yoga1290/rag/issues
7
+ Requires-Python: >=3.11
@@ -0,0 +1,16 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "yoga1290.rag"
7
+ version = "0.1.0"
8
+ description = "Document AI and RAG application"
9
+ requires-python = ">=3.11"
10
+
11
+ [tool.setuptools.packages.find]
12
+ where = ["yoga1290/rag"]
13
+
14
+ [project.urls]
15
+ Homepage = "https://github.com/yoga1290/rag"
16
+ Issues = "https://github.com/yoga1290/rag/issues"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,48 @@
1
+ from fastapi import FastAPI, File, HTTPException, Query, UploadFile
2
+ from pathlib import Path
3
+ from uuid import uuid4
4
+
5
+ app = FastAPI()
6
+
7
+ UPLOAD_DIR = Path("uploads")
8
+ UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
9
+
10
+
11
+ @app.post("/embed")
12
+ async def upload_file(
13
+ user_id: str = Query(...),
14
+ file: UploadFile = File(...),
15
+ ):
16
+ try:
17
+ # Preserve the original file extension
18
+ extension = Path(file.filename).suffix
19
+
20
+ # Generate a unique filename
21
+ unique_filename = f"{uuid4()}{extension}"
22
+
23
+ # Optionally organize files by user
24
+ user_dir = UPLOAD_DIR / user_id
25
+ user_dir.mkdir(parents=True, exist_ok=True)
26
+
27
+ destination = user_dir / unique_filename
28
+
29
+ with destination.open("wb") as buffer:
30
+ while chunk := await file.read(1024 * 1024):
31
+ buffer.write(chunk)
32
+
33
+ return {
34
+ "user_id": user_id,
35
+ "filename": unique_filename,
36
+ "original_filename": file.filename,
37
+ "content_type": file.content_type,
38
+ "path": str(destination),
39
+ }
40
+
41
+ except Exception as e:
42
+ raise HTTPException(
43
+ status_code=500,
44
+ detail=f"Failed to upload file: {e}",
45
+ )
46
+
47
+ finally:
48
+ await file.close()
@@ -0,0 +1,7 @@
1
+ from .ingestion_pipeline import IngestionPipeline
2
+ from .retrieval_pipeline import RetrievalPipeline
3
+
4
+ __all__ = [
5
+ "IngestionPipeline",
6
+ "RetrievalPipeline",
7
+ ]
@@ -0,0 +1,34 @@
1
+ from yoga1290.rag.domain.ports.embedder import Embedder
2
+ from yoga1290.rag.domain.ports.vector_store import VectorStore
3
+
4
+ class IndexingPipeline:
5
+ def __init__(
6
+ self,
7
+ embedder: Embedder,
8
+ vector_store: VectorStore,
9
+ ) -> None:
10
+ self.embedder = embedder
11
+ self.vector_store = vector_store
12
+
13
+ def index(self, search_document):
14
+ chunks = list(search_document.chunks)
15
+ texts = [chunk.text for chunk in chunks]
16
+ embeddings = self.embedder.embed_batch(texts)
17
+
18
+ indexed_chunks = [
19
+ chunk.__class__(
20
+ id=chunk.id,
21
+ document_id=chunk.document_id,
22
+ text=chunk.text,
23
+ index=chunk.index,
24
+ embedding=embedding,
25
+ metadata=chunk.metadata,
26
+ )
27
+ for chunk, embedding in zip(
28
+ chunks,
29
+ embeddings,
30
+ strict=True,
31
+ )
32
+ ]
33
+
34
+ self.vector_store.upsert(indexed_chunks)
@@ -0,0 +1,54 @@
1
+ from yoga1290.rag.domain.models import (
2
+ Document,
3
+ ParsedDocument,
4
+ SearchDocument)
5
+ from yoga1290.rag.domain.ports import (
6
+ DocumentParser,
7
+ DocumentExtractor,
8
+ DocumentClassifier,
9
+ SearchPreparer,
10
+ VectorStore,)
11
+ from collections.abc import Sequence
12
+
13
+ class IngestionPipeline:
14
+ def __init__(
15
+ self,
16
+ parser: DocumentParser,
17
+ extractor: DocumentExtractor,
18
+ classifier: DocumentClassifier,
19
+ search_preparer: SearchPreparer,
20
+ vectorstore: VectorStore,
21
+ ) -> None:
22
+ self.parser = parser
23
+ self.extractor = extractor
24
+ self.classifier = classifier
25
+ self.search_preparer = search_preparer
26
+ self.vectorstore = vectorstore
27
+
28
+ def process(self,
29
+ documents: Sequence[Document],
30
+ # extraction_schema,
31
+ # classification_schema,
32
+ ):
33
+ search_documents = []
34
+ for document in documents:
35
+ parsed_document: ParsedDocument = (
36
+ self.parser.parse(document))
37
+ search_document: SearchDocument = (
38
+ self.search_preparer.prepare(parsed_document))
39
+ search_documents.append(search_document)
40
+ self.vectorstore.add_documents(search_documents)
41
+
42
+ return {
43
+ # "parsed": parsed,
44
+ # "extracted": extracted,
45
+ # "classification": classification,
46
+ "search_document": search_documents,
47
+ }
48
+
49
+
50
+ # extracted = self.extractor.extract(parsed, extraction_schema)
51
+ # classification = self.classifier.classify(
52
+ # parsed,
53
+ # classification_schema,
54
+ # )
@@ -0,0 +1,84 @@
1
+ from yoga1290.rag.domain.models.rag_result import (
2
+ RagResult,
3
+ Source,
4
+ )
5
+ from yoga1290.rag.domain.ports import (
6
+ LLM,
7
+ Retriever, )
8
+
9
+
10
+ class RetrievalPipeline:
11
+
12
+ def __init__(
13
+ self,
14
+ llm: LLM,
15
+ retriever: Retriever,
16
+ top_k: int = 2,
17
+ ) -> None:
18
+ self._llm = llm
19
+ self._retriever = retriever
20
+ self._top_k = top_k
21
+
22
+ def run(self, question: str) -> RagResult:
23
+
24
+ import time
25
+
26
+ start = time.perf_counter()
27
+
28
+ chunks = self._retriever.retrieve(
29
+ question,
30
+ top_k=self._top_k,
31
+ )
32
+
33
+ context = self._build_context(chunks)
34
+
35
+ prompt = self._build_prompt(
36
+ question=question,
37
+ context=context,
38
+ )
39
+
40
+ answer = self._llm.generate(prompt)
41
+
42
+ duration = time.perf_counter() - start
43
+
44
+ sources = tuple(
45
+ Source(
46
+ document_id=chunk.document_id,
47
+ chunk_id=chunk.id,
48
+ metadata=chunk.metadata,
49
+ )
50
+ for chunk in chunks
51
+ )
52
+
53
+ return RagResult(
54
+ question=question,
55
+ answer=answer,
56
+ sources=sources,
57
+ duration_seconds=duration,
58
+ )
59
+
60
+ @staticmethod
61
+ def _build_context(chunks) -> str:
62
+
63
+ return "\n\n".join(
64
+ chunk.text
65
+ for chunk in chunks
66
+ )
67
+
68
+ @staticmethod
69
+ def _build_prompt(
70
+ question: str,
71
+ context: str,
72
+ ) -> str:
73
+
74
+ return f"""
75
+ Use the following context to answer the question.
76
+
77
+ Context:
78
+ {context}
79
+
80
+ Question:
81
+ {question}
82
+
83
+ Answer:
84
+ """.strip()
@@ -0,0 +1,15 @@
1
+ from yoga1290.rag.domain.ports.document_parser import DocumentParser
2
+ from yoga1290.rag.domain.ports.document_source import DocumentSource
3
+
4
+ class DocumentService:
5
+ def __init__(
6
+ self,
7
+ source: DocumentSource,
8
+ parser: DocumentParser,
9
+ ) -> None:
10
+ self.source = source
11
+ self.parser = parser
12
+
13
+ def process(self, document_id: str):
14
+ document = self.source.get(document_id)
15
+ return self.parser.parse(document)
@@ -0,0 +1,25 @@
1
+ from yoga1290.rag.domain.ports.embedder import Embedder
2
+ from yoga1290.rag.domain.ports.vector_store import VectorStore
3
+
4
+ class SearchService:
5
+ def __init__(
6
+ self,
7
+ embedder: Embedder,
8
+ vector_store: VectorStore,
9
+ ) -> None:
10
+ self.embedder = embedder
11
+ self.vector_store = vector_store
12
+
13
+ def search(
14
+ self,
15
+ query: str,
16
+ *,
17
+ top_k: int = 10,
18
+ filters: dict[str, object] | None = None,
19
+ ):
20
+ embedding = self.embedder.embed(query)
21
+ return self.vector_store.search(
22
+ embedding,
23
+ top_k=top_k,
24
+ filters=filters,
25
+ )
File without changes
@@ -0,0 +1,12 @@
1
+ from dataclasses import dataclass
2
+
3
+ @dataclass(frozen=True)
4
+ class Settings:
5
+ app_env: str = "local"
6
+ ai_provider: str = "local"
7
+ parser_provider: str = "docling"
8
+ extractor_provider: str = "qwen"
9
+ classifier_provider: str = "qwen"
10
+ search_preparer_provider: str = "local"
11
+ embedding_provider: str = "qwen"
12
+ vector_store_provider: str = "pgvector"
File without changes
@@ -0,0 +1,20 @@
1
+ from .document import Document
2
+ from .parsed_document import ParsedDocument, ParsedPage, ParsedTable
3
+ from .extracted_data import ExtractedData
4
+ from .classification import Classification, ClassificationLabel
5
+ from .search_document import SearchDocument
6
+ from .chunk import Chunk
7
+ from .search_result import SearchResult
8
+
9
+ __all__ = [
10
+ "Document",
11
+ "ParsedDocument",
12
+ "ParsedPage",
13
+ "ParsedTable",
14
+ "ExtractedData",
15
+ "Classification",
16
+ "ClassificationLabel",
17
+ "SearchDocument",
18
+ "Chunk",
19
+ "SearchResult",
20
+ ]
@@ -0,0 +1,13 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Mapping, Sequence
5
+
6
+ @dataclass(frozen=True, slots=True)
7
+ class Chunk:
8
+ id: str
9
+ document_id: str
10
+ text: str
11
+ index: int
12
+ embedding: Sequence[float] | None = None
13
+ metadata: Mapping[str, object] = field(default_factory=dict)
@@ -0,0 +1,20 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Mapping, Sequence
5
+
6
+ @dataclass(frozen=True, slots=True)
7
+ class ClassificationLabel:
8
+ name: str
9
+ confidence: float | None = None
10
+ metadata: Mapping[str, object] = field(default_factory=dict)
11
+
12
+ @dataclass(frozen=True, slots=True)
13
+ class Classification:
14
+ document_id: str
15
+ labels: Sequence[ClassificationLabel]
16
+ provider: str | None = None
17
+
18
+ @property
19
+ def primary_label(self) -> ClassificationLabel | None:
20
+ return self.labels[0] if self.labels else None
@@ -0,0 +1,21 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from datetime import datetime
5
+ from pathlib import Path
6
+ from typing import Mapping
7
+
8
+ @dataclass(frozen=True, slots=True)
9
+ class Document:
10
+ id: str | None = None
11
+ size_bytes: int | None = None
12
+ uri: str | None = None
13
+ content: bytes | None = None
14
+ filename: str = None
15
+ content_type: str = None
16
+ metadata: Mapping[str, object] = field(default_factory=dict)
17
+ created_at: datetime | None = None
18
+
19
+ @property
20
+ def suffix(self) -> str:
21
+ return Path(self.filename).suffix.lower()
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from datetime import datetime
5
+ from typing import Generic, TypeVar
6
+
7
+ T = TypeVar("T")
8
+
9
+ @dataclass(frozen=True, slots=True)
10
+ class ExtractedData(Generic[T]):
11
+ document_id: str
12
+ data: T
13
+ confidence: float | None = None
14
+ provider: str | None = None
15
+ extracted_at: datetime | None = None
@@ -0,0 +1,30 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Mapping, Sequence
5
+
6
+ @dataclass(frozen=True, slots=True)
7
+ class ParsedPage:
8
+ page_number: int
9
+ text: str
10
+ metadata: Mapping[str, object] = field(default_factory=dict)
11
+
12
+ @dataclass(frozen=True, slots=True)
13
+ class ParsedTable:
14
+ table_id: str
15
+ page_number: int | None
16
+ headers: Sequence[str] = field(default_factory=tuple)
17
+ rows: Sequence[Sequence[object]] = field(default_factory=tuple)
18
+ metadata: Mapping[str, object] = field(default_factory=dict)
19
+
20
+ @dataclass(frozen=True, slots=True)
21
+ class ParsedDocument:
22
+ document_id: str
23
+ text: str
24
+ pages: Sequence[ParsedPage] = field(default_factory=tuple)
25
+ tables: Sequence[ParsedTable] = field(default_factory=tuple)
26
+ metadata: Mapping[str, object] = field(default_factory=dict)
27
+
28
+ @property
29
+ def page_count(self) -> int:
30
+ return len(self.pages)
@@ -0,0 +1,17 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any
3
+
4
+
5
+ @dataclass(frozen=True, slots=True)
6
+ class Source:
7
+ document_id: str
8
+ chunk_id: str
9
+ metadata: dict[str, Any]
10
+
11
+
12
+ @dataclass(frozen=True, slots=True)
13
+ class RagResult:
14
+ question: str
15
+ answer: str
16
+ sources: tuple[Source, ...]
17
+ duration_seconds: float
@@ -0,0 +1,16 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Mapping, Sequence
5
+
6
+ from .chunk import Chunk
7
+
8
+ @dataclass(frozen=True, slots=True)
9
+ class SearchDocument:
10
+ document_id: str
11
+ chunks: Sequence[Chunk] = field(default_factory=tuple)
12
+ metadata: Mapping[str, object] = field(default_factory=dict)
13
+
14
+ @property
15
+ def chunk_count(self) -> int:
16
+ return len(self.chunks)
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Mapping
5
+
6
+ @dataclass(frozen=True, slots=True)
7
+ class SearchResult:
8
+ chunk_id: str
9
+ document_id: str
10
+ text: str
11
+ score: float
12
+ metadata: Mapping[str, object] = field(default_factory=dict)
@@ -0,0 +1,21 @@
1
+ from .document_classifier import DocumentClassifier
2
+ from .document_extractor import DocumentExtractor
3
+ from .document_parser import DocumentParser
4
+ from .document_source import DocumentSource
5
+ from .embedder import Embedder
6
+ from .search_preparer import SearchPreparer
7
+ from .vector_store import VectorStore
8
+ from .llm import LLM
9
+ from .retriever import Retriever
10
+
11
+ __all__ = [
12
+ "DocumentSource",
13
+ "DocumentParser",
14
+ "DocumentExtractor",
15
+ "DocumentClassifier",
16
+ "SearchPreparer",
17
+ "Embedder",
18
+ "LLM",
19
+ "VectorStore",
20
+ "Retriever",
21
+ ]
@@ -0,0 +1,31 @@
1
+ from yoga1290.rag.domain.models.classification import Classification
2
+ from yoga1290.rag.domain.models.parsed_document import ParsedDocument
3
+ from yoga1290.rag.domain.schemas.classification_schema import ClassificationSchema
4
+
5
+
6
+ class DocumentClassifier():
7
+ """
8
+ Classifies a document according to a domain-defined classification schema.
9
+
10
+ Implementations may use:
11
+ - Databricks ai_classify
12
+ - Qwen
13
+ - BERT
14
+ - Other classifiers
15
+ """
16
+ def classify(
17
+ self,
18
+ document: ParsedDocument,
19
+ schema: ClassificationSchema,
20
+ ) -> Classification:
21
+ """
22
+ Classify a document.
23
+
24
+ Args:
25
+ document: Parsed document.
26
+ schema: Allowed categories and classification configuration.
27
+
28
+ Returns:
29
+ Classification result.
30
+ """
31
+ raise NotImplementedError
@@ -0,0 +1,17 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Generic, TypeVar
3
+
4
+ from yoga1290.rag.domain.models.extracted_data import ExtractedData
5
+ from yoga1290.rag.domain.models.parsed_document import ParsedDocument
6
+ from yoga1290.rag.domain.schemas.extraction_schema import ExtractionSchema
7
+
8
+ T = TypeVar("T")
9
+
10
+ class DocumentExtractor(ABC, Generic[T]):
11
+ @abstractmethod
12
+ def extract(
13
+ self,
14
+ document: ParsedDocument,
15
+ schema: ExtractionSchema[T],
16
+ ) -> ExtractedData[T]:
17
+ raise NotImplementedError
@@ -0,0 +1,30 @@
1
+ from yoga1290.rag.domain.models.document import Document
2
+ from yoga1290.rag.domain.models.parsed_document import ParsedDocument
3
+
4
+ class DocumentParser():
5
+ """
6
+ Converts a raw document into a normalized ParsedDocument.
7
+
8
+ Implementations may use:
9
+ - Databricks ai_parse_document
10
+ - Docling
11
+ - PyMuPDF
12
+ - OCR
13
+ - Other document parsing engines
14
+ """
15
+ def parse(self, document: Document) -> ParsedDocument:
16
+ """
17
+ Parse a document into a normalized representation.
18
+
19
+ Args:
20
+ document: Raw document metadata and content reference.
21
+
22
+ Returns:
23
+ ParsedDocument containing normalized text, pages,
24
+ tables, images, metadata, etc.
25
+
26
+ Raises:
27
+ DocumentParseError: If the document cannot be parsed.
28
+ """
29
+ raise NotImplementedError
30
+
@@ -0,0 +1,29 @@
1
+ from collections.abc import Iterator
2
+ from abc import ABC, abstractmethod
3
+ from yoga1290.rag.domain.models.document import Document
4
+
5
+
6
+ class DocumentSource:
7
+ """
8
+ Port for retrieving documents from an external source.
9
+
10
+ Implementations may read from:
11
+ - Local filesystem
12
+ - S3
13
+ - Azure Blob Storage
14
+ - Google Cloud Storage
15
+ - Databricks Volumes
16
+ - Database
17
+ - Message queue
18
+ - HTTP/API
19
+ """
20
+
21
+ @abstractmethod
22
+ def __iter__(self) -> Iterator[Document]:
23
+ """
24
+ Iterate over documents available from the source.
25
+
26
+ Returns:
27
+ Iterator of Document objects.
28
+ """
29
+ raise NotImplementedError