mdb-engine 0.1.7__py3-none-any.whl → 0.2.1__py3-none-any.whl
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.
- mdb_engine/__init__.py +71 -10
- mdb_engine/auth/ARCHITECTURE.md +112 -0
- mdb_engine/auth/README.md +125 -11
- mdb_engine/auth/__init__.py +7 -1
- mdb_engine/auth/base.py +252 -0
- mdb_engine/auth/casbin_factory.py +258 -59
- mdb_engine/auth/dependencies.py +10 -5
- mdb_engine/auth/integration.py +23 -7
- mdb_engine/auth/oso_factory.py +2 -2
- mdb_engine/auth/provider.py +263 -143
- mdb_engine/core/engine.py +307 -6
- mdb_engine/core/manifest.py +35 -15
- mdb_engine/database/README.md +28 -1
- mdb_engine/dependencies.py +426 -0
- mdb_engine/di/__init__.py +34 -0
- mdb_engine/di/container.py +248 -0
- mdb_engine/di/providers.py +205 -0
- mdb_engine/di/scopes.py +139 -0
- mdb_engine/embeddings/README.md +54 -24
- mdb_engine/embeddings/__init__.py +22 -23
- mdb_engine/embeddings/dependencies.py +37 -152
- mdb_engine/repositories/__init__.py +34 -0
- mdb_engine/repositories/base.py +325 -0
- mdb_engine/repositories/mongo.py +233 -0
- mdb_engine/repositories/unit_of_work.py +166 -0
- {mdb_engine-0.1.7.dist-info → mdb_engine-0.2.1.dist-info}/METADATA +42 -14
- {mdb_engine-0.1.7.dist-info → mdb_engine-0.2.1.dist-info}/RECORD +31 -20
- {mdb_engine-0.1.7.dist-info → mdb_engine-0.2.1.dist-info}/WHEEL +0 -0
- {mdb_engine-0.1.7.dist-info → mdb_engine-0.2.1.dist-info}/entry_points.txt +0 -0
- {mdb_engine-0.1.7.dist-info → mdb_engine-0.2.1.dist-info}/licenses/LICENSE +0 -0
- {mdb_engine-0.1.7.dist-info → mdb_engine-0.2.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Service Providers for Dependency Injection
|
|
3
|
+
|
|
4
|
+
Providers are responsible for creating and managing service instances
|
|
5
|
+
according to their configured scope.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import inspect
|
|
9
|
+
import logging
|
|
10
|
+
from abc import ABC, abstractmethod
|
|
11
|
+
from typing import TYPE_CHECKING, Any, Callable, Dict, Generic, Optional, Type, TypeVar
|
|
12
|
+
|
|
13
|
+
from .scopes import Scope, ScopeManager
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from .container import Container
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
T = TypeVar("T")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Provider(ABC, Generic[T]):
|
|
24
|
+
"""
|
|
25
|
+
Abstract base class for service providers.
|
|
26
|
+
|
|
27
|
+
Providers know how to create instances of a service and manage
|
|
28
|
+
their lifecycle according to the configured scope.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
service_type: Type[T],
|
|
34
|
+
scope: Scope,
|
|
35
|
+
factory: Optional[Callable[..., T]] = None,
|
|
36
|
+
):
|
|
37
|
+
self.service_type = service_type
|
|
38
|
+
self.scope = scope
|
|
39
|
+
self._factory = factory or service_type
|
|
40
|
+
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def get(self, container: "Container") -> T:
|
|
43
|
+
"""
|
|
44
|
+
Get or create a service instance.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
container: The DI container for resolving dependencies
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Service instance
|
|
51
|
+
"""
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
def _create_instance(self, container: "Container") -> T:
|
|
55
|
+
"""
|
|
56
|
+
Create a new instance, injecting dependencies.
|
|
57
|
+
|
|
58
|
+
Inspects the factory/constructor signature and resolves
|
|
59
|
+
any type-hinted parameters from the container.
|
|
60
|
+
"""
|
|
61
|
+
# Get constructor signature
|
|
62
|
+
sig = inspect.signature(self._factory)
|
|
63
|
+
kwargs: Dict[str, Any] = {}
|
|
64
|
+
|
|
65
|
+
for param_name, param in sig.parameters.items():
|
|
66
|
+
if param_name == "self":
|
|
67
|
+
continue
|
|
68
|
+
|
|
69
|
+
# Check if parameter has a type annotation
|
|
70
|
+
if param.annotation != inspect.Parameter.empty:
|
|
71
|
+
param_type = param.annotation
|
|
72
|
+
|
|
73
|
+
# Skip primitive types and Optional markers
|
|
74
|
+
if param_type in (str, int, float, bool, type(None)):
|
|
75
|
+
continue
|
|
76
|
+
|
|
77
|
+
# Handle Optional[X] - extract X
|
|
78
|
+
origin = getattr(param_type, "__origin__", None)
|
|
79
|
+
if origin is type(None):
|
|
80
|
+
continue
|
|
81
|
+
|
|
82
|
+
# Try to resolve from container
|
|
83
|
+
try:
|
|
84
|
+
kwargs[param_name] = container.resolve(param_type)
|
|
85
|
+
except KeyError:
|
|
86
|
+
# If not registered and has default, skip
|
|
87
|
+
if param.default != inspect.Parameter.empty:
|
|
88
|
+
continue
|
|
89
|
+
# If not registered and no default, re-raise
|
|
90
|
+
raise
|
|
91
|
+
|
|
92
|
+
return self._factory(**kwargs)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class SingletonProvider(Provider[T]):
|
|
96
|
+
"""
|
|
97
|
+
Provider that creates a single instance shared across the application.
|
|
98
|
+
|
|
99
|
+
The instance is created lazily on first request and cached forever.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
def __init__(
|
|
103
|
+
self,
|
|
104
|
+
service_type: Type[T],
|
|
105
|
+
factory: Optional[Callable[..., T]] = None,
|
|
106
|
+
):
|
|
107
|
+
super().__init__(service_type, Scope.SINGLETON, factory)
|
|
108
|
+
self._instance: Optional[T] = None
|
|
109
|
+
|
|
110
|
+
def get(self, container: "Container") -> T:
|
|
111
|
+
if self._instance is None:
|
|
112
|
+
self._instance = self._create_instance(container)
|
|
113
|
+
logger.debug(f"Created singleton: {self.service_type.__name__}")
|
|
114
|
+
return self._instance
|
|
115
|
+
|
|
116
|
+
def reset(self) -> None:
|
|
117
|
+
"""Reset the singleton (useful for testing)."""
|
|
118
|
+
self._instance = None
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class RequestProvider(Provider[T]):
|
|
122
|
+
"""
|
|
123
|
+
Provider that creates one instance per request.
|
|
124
|
+
|
|
125
|
+
Uses ScopeManager to cache instances within the request scope.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
def __init__(
|
|
129
|
+
self,
|
|
130
|
+
service_type: Type[T],
|
|
131
|
+
factory: Optional[Callable[..., T]] = None,
|
|
132
|
+
):
|
|
133
|
+
super().__init__(service_type, Scope.REQUEST, factory)
|
|
134
|
+
|
|
135
|
+
def get(self, container: "Container") -> T:
|
|
136
|
+
return ScopeManager.get_or_create(
|
|
137
|
+
self.service_type, lambda: self._create_instance(container)
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class TransientProvider(Provider[T]):
|
|
142
|
+
"""
|
|
143
|
+
Provider that creates a new instance every time.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
def __init__(
|
|
147
|
+
self,
|
|
148
|
+
service_type: Type[T],
|
|
149
|
+
factory: Optional[Callable[..., T]] = None,
|
|
150
|
+
):
|
|
151
|
+
super().__init__(service_type, Scope.TRANSIENT, factory)
|
|
152
|
+
|
|
153
|
+
def get(self, container: "Container") -> T:
|
|
154
|
+
instance = self._create_instance(container)
|
|
155
|
+
logger.debug(f"Created transient: {self.service_type.__name__}")
|
|
156
|
+
return instance
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class FactoryProvider(Provider[T]):
|
|
160
|
+
"""
|
|
161
|
+
Provider that uses a custom factory function.
|
|
162
|
+
|
|
163
|
+
The factory is called with the container as the first argument,
|
|
164
|
+
allowing manual dependency resolution.
|
|
165
|
+
|
|
166
|
+
Usage:
|
|
167
|
+
def create_user_service(container: Container) -> UserService:
|
|
168
|
+
db = container.resolve(Database)
|
|
169
|
+
return UserService(db, custom_config=...)
|
|
170
|
+
|
|
171
|
+
container.register_factory(UserService, create_user_service, Scope.REQUEST)
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
def __init__(
|
|
175
|
+
self,
|
|
176
|
+
service_type: Type[T],
|
|
177
|
+
factory: Callable[["Container"], T],
|
|
178
|
+
scope: Scope,
|
|
179
|
+
):
|
|
180
|
+
super().__init__(service_type, scope, None)
|
|
181
|
+
self._custom_factory = factory
|
|
182
|
+
self._singleton_instance: Optional[T] = None
|
|
183
|
+
|
|
184
|
+
def get(self, container: "Container") -> T:
|
|
185
|
+
if self.scope == Scope.SINGLETON:
|
|
186
|
+
if self._singleton_instance is None:
|
|
187
|
+
self._singleton_instance = self._custom_factory(container)
|
|
188
|
+
return self._singleton_instance
|
|
189
|
+
|
|
190
|
+
elif self.scope == Scope.REQUEST:
|
|
191
|
+
return ScopeManager.get_or_create(
|
|
192
|
+
self.service_type, lambda: self._custom_factory(container)
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
else: # TRANSIENT
|
|
196
|
+
return self._custom_factory(container)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
__all__ = [
|
|
200
|
+
"Provider",
|
|
201
|
+
"SingletonProvider",
|
|
202
|
+
"RequestProvider",
|
|
203
|
+
"TransientProvider",
|
|
204
|
+
"FactoryProvider",
|
|
205
|
+
]
|
mdb_engine/di/scopes.py
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Service Scopes for Dependency Injection
|
|
3
|
+
|
|
4
|
+
Defines service lifetime scopes following enterprise patterns:
|
|
5
|
+
- SINGLETON: Created once, shared across all requests
|
|
6
|
+
- REQUEST: Created once per HTTP request, disposed after
|
|
7
|
+
- TRANSIENT: Created fresh on every injection
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
from contextvars import ContextVar
|
|
12
|
+
from enum import Enum
|
|
13
|
+
from typing import Any, Dict, Optional
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
# Context variable for request-scoped instances
|
|
18
|
+
_request_scope: ContextVar[Optional[Dict[type, Any]]] = ContextVar("request_scope", default=None)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Scope(Enum):
|
|
22
|
+
"""
|
|
23
|
+
Service lifetime scopes.
|
|
24
|
+
|
|
25
|
+
SINGLETON: One instance for the entire application lifetime.
|
|
26
|
+
Use for: Database connections, configuration, caches.
|
|
27
|
+
|
|
28
|
+
REQUEST: One instance per HTTP request. Automatically disposed
|
|
29
|
+
when the request ends.
|
|
30
|
+
Use for: Unit of Work, request context, user session.
|
|
31
|
+
|
|
32
|
+
TRANSIENT: New instance created every time it's requested.
|
|
33
|
+
Use for: Stateless services, utilities.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
SINGLETON = "singleton"
|
|
37
|
+
REQUEST = "request"
|
|
38
|
+
TRANSIENT = "transient"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ScopeManager:
|
|
42
|
+
"""
|
|
43
|
+
Manages request-scoped instance lifecycles.
|
|
44
|
+
|
|
45
|
+
Usage with FastAPI middleware:
|
|
46
|
+
@app.middleware("http")
|
|
47
|
+
async def scope_middleware(request: Request, call_next):
|
|
48
|
+
async with ScopeManager.request_scope():
|
|
49
|
+
response = await call_next(request)
|
|
50
|
+
return response
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def begin_request(cls) -> Dict[type, Any]:
|
|
55
|
+
"""
|
|
56
|
+
Begin a new request scope.
|
|
57
|
+
|
|
58
|
+
Returns the scope dictionary for manual management if needed.
|
|
59
|
+
"""
|
|
60
|
+
scope_dict: Dict[type, Any] = {}
|
|
61
|
+
_request_scope.set(scope_dict)
|
|
62
|
+
logger.debug("Request scope started")
|
|
63
|
+
return scope_dict
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def end_request(cls) -> None:
|
|
67
|
+
"""
|
|
68
|
+
End the current request scope and cleanup instances.
|
|
69
|
+
|
|
70
|
+
Calls dispose() on any instances that have it.
|
|
71
|
+
"""
|
|
72
|
+
scope_dict = _request_scope.get()
|
|
73
|
+
if scope_dict:
|
|
74
|
+
for instance in scope_dict.values():
|
|
75
|
+
if hasattr(instance, "dispose"):
|
|
76
|
+
try:
|
|
77
|
+
instance.dispose()
|
|
78
|
+
except (AttributeError, RuntimeError, TypeError) as e:
|
|
79
|
+
logger.warning(f"Error disposing {type(instance).__name__}: {e}")
|
|
80
|
+
scope_dict.clear()
|
|
81
|
+
_request_scope.set(None)
|
|
82
|
+
logger.debug("Request scope ended")
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def get_request_scope(cls) -> Optional[Dict[type, Any]]:
|
|
86
|
+
"""Get the current request scope dictionary."""
|
|
87
|
+
return _request_scope.get()
|
|
88
|
+
|
|
89
|
+
@classmethod
|
|
90
|
+
def get_or_create(cls, key: type, factory: callable) -> Any:
|
|
91
|
+
"""
|
|
92
|
+
Get an existing instance from request scope or create one.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
key: The type to use as cache key
|
|
96
|
+
factory: Callable to create a new instance if not cached
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
The cached or newly created instance
|
|
100
|
+
|
|
101
|
+
Raises:
|
|
102
|
+
RuntimeError: If called outside a request scope
|
|
103
|
+
"""
|
|
104
|
+
scope_dict = _request_scope.get()
|
|
105
|
+
if scope_dict is None:
|
|
106
|
+
raise RuntimeError(
|
|
107
|
+
"No active request scope. Ensure ScopeManager.begin_request() "
|
|
108
|
+
"was called (usually via middleware)."
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
if key not in scope_dict:
|
|
112
|
+
scope_dict[key] = factory()
|
|
113
|
+
logger.debug(f"Created request-scoped instance: {key.__name__}")
|
|
114
|
+
|
|
115
|
+
return scope_dict[key]
|
|
116
|
+
|
|
117
|
+
@classmethod
|
|
118
|
+
async def request_scope(cls):
|
|
119
|
+
"""
|
|
120
|
+
Async context manager for request scope.
|
|
121
|
+
|
|
122
|
+
Usage:
|
|
123
|
+
async with ScopeManager.request_scope():
|
|
124
|
+
# Request-scoped services available here
|
|
125
|
+
pass
|
|
126
|
+
"""
|
|
127
|
+
return _RequestScopeContext()
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class _RequestScopeContext:
|
|
131
|
+
"""Async context manager for request scope."""
|
|
132
|
+
|
|
133
|
+
async def __aenter__(self):
|
|
134
|
+
ScopeManager.begin_request()
|
|
135
|
+
return self
|
|
136
|
+
|
|
137
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
138
|
+
ScopeManager.end_request()
|
|
139
|
+
return False
|
mdb_engine/embeddings/README.md
CHANGED
|
@@ -9,6 +9,7 @@ Semantic text splitting and embedding generation for MDB_ENGINE applications.
|
|
|
9
9
|
- **Token-Aware**: Never exceeds model token limits
|
|
10
10
|
- **Batch Processing**: Efficient batch embedding generation
|
|
11
11
|
- **MongoDB Integration**: Built-in support for storing embeddings with metadata
|
|
12
|
+
- **Request-Scoped Dependencies**: Clean FastAPI integration via `mdb_engine.dependencies`
|
|
12
13
|
|
|
13
14
|
## Installation
|
|
14
15
|
|
|
@@ -38,7 +39,44 @@ Enable embedding service in your `manifest.json`:
|
|
|
38
39
|
|
|
39
40
|
## Usage
|
|
40
41
|
|
|
41
|
-
### 1.
|
|
42
|
+
### 1. FastAPI Routes (Recommended)
|
|
43
|
+
|
|
44
|
+
Use request-scoped dependencies from `mdb_engine.dependencies`:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
from fastapi import Depends
|
|
48
|
+
from mdb_engine import MongoDBEngine
|
|
49
|
+
from mdb_engine.dependencies import get_embedding_service, get_scoped_db
|
|
50
|
+
|
|
51
|
+
engine = MongoDBEngine(mongo_uri=..., db_name=...)
|
|
52
|
+
app = engine.create_app(slug="my_app", manifest=Path("manifest.json"))
|
|
53
|
+
|
|
54
|
+
@app.post("/embed")
|
|
55
|
+
async def embed_endpoint(
|
|
56
|
+
db=Depends(get_scoped_db),
|
|
57
|
+
embedding_service=Depends(get_embedding_service),
|
|
58
|
+
):
|
|
59
|
+
# Services are automatically bound to the current app
|
|
60
|
+
result = await embedding_service.process_and_store(
|
|
61
|
+
text_content="Hello world",
|
|
62
|
+
source_id="doc_1",
|
|
63
|
+
collection=db.knowledge_base,
|
|
64
|
+
)
|
|
65
|
+
return {"chunks_created": result["chunks_created"]}
|
|
66
|
+
|
|
67
|
+
@app.post("/search")
|
|
68
|
+
async def search(
|
|
69
|
+
query: str,
|
|
70
|
+
db=Depends(get_scoped_db),
|
|
71
|
+
embedding_service=Depends(get_embedding_service),
|
|
72
|
+
):
|
|
73
|
+
# Generate query embedding
|
|
74
|
+
vectors = await embedding_service.embed_chunks([query])
|
|
75
|
+
# Use vectors for vector search...
|
|
76
|
+
return {"query_vector_dims": len(vectors[0])}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 2. Basic Usage (Standalone)
|
|
42
80
|
|
|
43
81
|
```python
|
|
44
82
|
from mdb_engine.embeddings import EmbeddingService
|
|
@@ -56,7 +94,7 @@ chunks = await embedding_service.chunk_text(
|
|
|
56
94
|
vectors = await embedding_service.embed_chunks(chunks, model="text-embedding-3-small")
|
|
57
95
|
```
|
|
58
96
|
|
|
59
|
-
###
|
|
97
|
+
### 3. Process and Store in MongoDB
|
|
60
98
|
|
|
61
99
|
```python
|
|
62
100
|
from mdb_engine.embeddings import EmbeddingService
|
|
@@ -75,36 +113,28 @@ result = await embedding_service.process_and_store(
|
|
|
75
113
|
print(f"Created {result['chunks_created']} chunks")
|
|
76
114
|
```
|
|
77
115
|
|
|
78
|
-
###
|
|
116
|
+
### 4. Utility Function (Background Tasks/CLI)
|
|
117
|
+
|
|
118
|
+
For use outside of FastAPI request handlers:
|
|
79
119
|
|
|
80
120
|
```python
|
|
81
|
-
from mdb_engine.embeddings import
|
|
121
|
+
from mdb_engine.embeddings.dependencies import get_embedding_service_for_app
|
|
82
122
|
|
|
83
|
-
#
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
123
|
+
# In a background task or CLI tool
|
|
124
|
+
service = get_embedding_service_for_app("my_app", engine)
|
|
125
|
+
if service:
|
|
126
|
+
embeddings = await service.embed_chunks(["Hello world"])
|
|
87
127
|
```
|
|
88
128
|
|
|
89
|
-
###
|
|
129
|
+
### 5. Explicit Provider
|
|
90
130
|
|
|
91
131
|
```python
|
|
92
|
-
from
|
|
93
|
-
from mdb_engine.embeddings.dependencies import get_embedding_service_dependency
|
|
94
|
-
from mdb_engine.embeddings import EmbeddingService
|
|
95
|
-
|
|
96
|
-
app = FastAPI()
|
|
97
|
-
|
|
98
|
-
# Set global engine during startup
|
|
99
|
-
from mdb_engine.embeddings.dependencies import set_global_engine
|
|
100
|
-
set_global_engine(engine, app_slug="my_app")
|
|
132
|
+
from mdb_engine.embeddings import EmbeddingService, OpenAIEmbeddingProvider, EmbeddingProvider
|
|
101
133
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
)
|
|
106
|
-
embeddings = await embedding_service.embed_chunks(["Hello world"])
|
|
107
|
-
return {"embeddings": embeddings}
|
|
134
|
+
# Use OpenAI explicitly
|
|
135
|
+
openai_provider = OpenAIEmbeddingProvider(default_model="text-embedding-3-small")
|
|
136
|
+
provider = EmbeddingProvider(embedding_provider=openai_provider)
|
|
137
|
+
embedding_service = EmbeddingService(embedding_provider=provider)
|
|
108
138
|
```
|
|
109
139
|
|
|
110
140
|
## Environment Variables
|
|
@@ -7,6 +7,22 @@ Examples should implement their own LLM clients directly using the OpenAI SDK.
|
|
|
7
7
|
For memory functionality, use mdb_engine.memory.Mem0MemoryService which
|
|
8
8
|
handles embeddings and LLM via environment variables (.env).
|
|
9
9
|
|
|
10
|
+
FastAPI Dependency Injection:
|
|
11
|
+
# RECOMMENDED: Use request-scoped dependencies
|
|
12
|
+
from mdb_engine.dependencies import get_embedding_service
|
|
13
|
+
|
|
14
|
+
@app.post("/embed")
|
|
15
|
+
async def embed_text(embedding_service=Depends(get_embedding_service)):
|
|
16
|
+
embeddings = await embedding_service.embed_chunks(["Hello world"])
|
|
17
|
+
return {"embeddings": embeddings}
|
|
18
|
+
|
|
19
|
+
Standalone Usage:
|
|
20
|
+
from mdb_engine.embeddings import EmbeddingService, get_embedding_service
|
|
21
|
+
|
|
22
|
+
# Auto-detects OpenAI or Azure from environment variables
|
|
23
|
+
service = get_embedding_service(config={"default_embedding_model": "text-embedding-3-small"})
|
|
24
|
+
embeddings = await service.embed_chunks(["Hello world"])
|
|
25
|
+
|
|
10
26
|
Example LLM implementation:
|
|
11
27
|
from openai import AzureOpenAI
|
|
12
28
|
from dotenv import load_dotenv
|
|
@@ -24,25 +40,9 @@ Example LLM implementation:
|
|
|
24
40
|
model=os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME"),
|
|
25
41
|
messages=[...]
|
|
26
42
|
)
|
|
27
|
-
|
|
28
|
-
Example EmbeddingService usage:
|
|
29
|
-
from mdb_engine.embeddings import EmbeddingService, get_embedding_service
|
|
30
|
-
|
|
31
|
-
# In FastAPI route
|
|
32
|
-
@app.post("/embed")
|
|
33
|
-
async def embed_text(embedding_service: EmbeddingService = Depends(get_embedding_service)):
|
|
34
|
-
embeddings = await embedding_service.embed_chunks(["Hello world"])
|
|
35
|
-
return {"embeddings": embeddings}
|
|
36
43
|
"""
|
|
37
44
|
|
|
38
|
-
from .dependencies import
|
|
39
|
-
create_embedding_dependency,
|
|
40
|
-
get_embedding_service_dep,
|
|
41
|
-
get_embedding_service_dependency,
|
|
42
|
-
get_embedding_service_for_app,
|
|
43
|
-
get_global_engine,
|
|
44
|
-
set_global_engine,
|
|
45
|
-
)
|
|
45
|
+
from .dependencies import get_embedding_service_for_app
|
|
46
46
|
from .service import (
|
|
47
47
|
AzureOpenAIEmbeddingProvider,
|
|
48
48
|
BaseEmbeddingProvider,
|
|
@@ -54,17 +54,16 @@ from .service import (
|
|
|
54
54
|
)
|
|
55
55
|
|
|
56
56
|
__all__ = [
|
|
57
|
+
# Core service classes
|
|
57
58
|
"EmbeddingService",
|
|
58
59
|
"EmbeddingServiceError",
|
|
60
|
+
"EmbeddingProvider",
|
|
61
|
+
# Embedding providers
|
|
59
62
|
"BaseEmbeddingProvider",
|
|
60
63
|
"OpenAIEmbeddingProvider",
|
|
61
64
|
"AzureOpenAIEmbeddingProvider",
|
|
62
|
-
|
|
65
|
+
# Factory function
|
|
63
66
|
"get_embedding_service",
|
|
67
|
+
# Utility for standalone usage
|
|
64
68
|
"get_embedding_service_for_app",
|
|
65
|
-
"create_embedding_dependency",
|
|
66
|
-
"set_global_engine",
|
|
67
|
-
"get_global_engine",
|
|
68
|
-
"get_embedding_service_dependency",
|
|
69
|
-
"get_embedding_service_dep",
|
|
70
69
|
]
|