upp-python 0.1.0__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.
- upp/__init__.py +183 -0
- upp/backends/.gitkeep +0 -0
- upp/backends/__init__.py +23 -0
- upp/backends/ingest.py +122 -0
- upp/backends/ontology.py +41 -0
- upp/backends/retriever.py +79 -0
- upp/client.py +148 -0
- upp/models/.gitkeep +0 -0
- upp/models/__init__.py +38 -0
- upp/models/client.py +113 -0
- upp/models/enums.py +124 -0
- upp/models/events.py +124 -0
- upp/models/labels.py +71 -0
- upp/ontologies/__init__.py +0 -0
- upp/ontologies/user_v1.py +112 -0
- upp/py.typed +0 -0
- upp/rpc/.gitkeep +0 -0
- upp/rpc/__init__.py +137 -0
- upp/rpc/codec.py +112 -0
- upp/rpc/errors.py +127 -0
- upp/rpc/messages.py +354 -0
- upp/rpc/methods.py +73 -0
- upp_python-0.1.0.dist-info/METADATA +137 -0
- upp_python-0.1.0.dist-info/RECORD +25 -0
- upp_python-0.1.0.dist-info/WHEEL +4 -0
upp/__init__.py
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"""UPP — Universal Personalization Protocol Python Reference Implementation.
|
|
2
|
+
|
|
3
|
+
This package provides the Python reference implementation of the Universal
|
|
4
|
+
Personalization Protocol (UPP) data models, backend interfaces, JSON-RPC
|
|
5
|
+
support, and a high-level client.
|
|
6
|
+
|
|
7
|
+
Quick Start::
|
|
8
|
+
|
|
9
|
+
from upp import UPPClient, OntologyUserV1
|
|
10
|
+
from upp import Event, StoredEvent, LabelDefinition
|
|
11
|
+
from upp import EventStatus, SourceType, SensitivityTier
|
|
12
|
+
|
|
13
|
+
Backend Protocols::
|
|
14
|
+
|
|
15
|
+
from upp import IngestBackend, RetrieverBackend, OntologyBackend
|
|
16
|
+
|
|
17
|
+
All public types are re-exported from sub-packages for convenience.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from importlib.metadata import version as _pkg_version
|
|
21
|
+
|
|
22
|
+
__version__ = _pkg_version("upp-python")
|
|
23
|
+
|
|
24
|
+
# --- Backend Protocols ---
|
|
25
|
+
from upp.backends import (
|
|
26
|
+
IngestBackend,
|
|
27
|
+
OntologyBackend,
|
|
28
|
+
RetrieverBackend,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# --- Client ---
|
|
32
|
+
from upp.client import UPPClient
|
|
33
|
+
|
|
34
|
+
# --- Models ---
|
|
35
|
+
from upp.models import (
|
|
36
|
+
Cardinality,
|
|
37
|
+
ContextualizeResult,
|
|
38
|
+
Durability,
|
|
39
|
+
Event,
|
|
40
|
+
EventStatus,
|
|
41
|
+
LabelDefinition,
|
|
42
|
+
SensitivityTier,
|
|
43
|
+
SourceType,
|
|
44
|
+
StoredEvent,
|
|
45
|
+
TaskResult,
|
|
46
|
+
TaskStatus,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# --- Ontologies ---
|
|
50
|
+
from upp.ontologies.user_v1 import OntologyUserV1
|
|
51
|
+
|
|
52
|
+
# --- RPC ---
|
|
53
|
+
from upp.rpc import (
|
|
54
|
+
ALL_METHODS,
|
|
55
|
+
EXTRACTION_FAILED,
|
|
56
|
+
INGEST_FAILED,
|
|
57
|
+
INTERNAL_ERROR,
|
|
58
|
+
INVALID_PARAMS,
|
|
59
|
+
INVALID_REQUEST,
|
|
60
|
+
METHOD_NOT_FOUND,
|
|
61
|
+
ONTOLOGY_NOT_FOUND,
|
|
62
|
+
PARSE_ERROR,
|
|
63
|
+
UPP_CONTEXTUALIZE,
|
|
64
|
+
UPP_DELETE,
|
|
65
|
+
UPP_EVENTS,
|
|
66
|
+
UPP_EXPORT,
|
|
67
|
+
UPP_GET_TASKS,
|
|
68
|
+
UPP_IMPORT,
|
|
69
|
+
UPP_INFO,
|
|
70
|
+
UPP_INGEST,
|
|
71
|
+
UPP_LABELS,
|
|
72
|
+
UPP_RETRIEVE,
|
|
73
|
+
USER_NOT_FOUND,
|
|
74
|
+
ContextualizeRequest,
|
|
75
|
+
ContextualizeResponse,
|
|
76
|
+
DeleteRequest,
|
|
77
|
+
DeleteResponse,
|
|
78
|
+
EventsRequest,
|
|
79
|
+
EventsResponse,
|
|
80
|
+
ExportRequest,
|
|
81
|
+
ExportResponse,
|
|
82
|
+
GetTasksRequest,
|
|
83
|
+
GetTasksResponse,
|
|
84
|
+
ImportRequest,
|
|
85
|
+
ImportResponse,
|
|
86
|
+
InfoRequest,
|
|
87
|
+
InfoResponse,
|
|
88
|
+
IngestRequest,
|
|
89
|
+
IngestResponse,
|
|
90
|
+
JsonRpcError,
|
|
91
|
+
JsonRpcNotification,
|
|
92
|
+
JsonRpcRequest,
|
|
93
|
+
JsonRpcResponse,
|
|
94
|
+
LabelsRequest,
|
|
95
|
+
LabelsResponse,
|
|
96
|
+
RetrieveRequest,
|
|
97
|
+
RetrieveResponse,
|
|
98
|
+
UppError,
|
|
99
|
+
decode_request,
|
|
100
|
+
decode_response,
|
|
101
|
+
encode_request,
|
|
102
|
+
encode_response,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
__all__ = [
|
|
106
|
+
"__version__",
|
|
107
|
+
# Enumerations
|
|
108
|
+
"Cardinality",
|
|
109
|
+
"Durability",
|
|
110
|
+
"EventStatus",
|
|
111
|
+
"SensitivityTier",
|
|
112
|
+
"SourceType",
|
|
113
|
+
"TaskStatus",
|
|
114
|
+
# Core entities
|
|
115
|
+
"ContextualizeResult",
|
|
116
|
+
"Event",
|
|
117
|
+
"LabelDefinition",
|
|
118
|
+
"StoredEvent",
|
|
119
|
+
"TaskResult",
|
|
120
|
+
# Backend protocols
|
|
121
|
+
"OntologyBackend",
|
|
122
|
+
"RetrieverBackend",
|
|
123
|
+
"IngestBackend",
|
|
124
|
+
# RPC message types
|
|
125
|
+
"JsonRpcError",
|
|
126
|
+
"JsonRpcNotification",
|
|
127
|
+
"JsonRpcRequest",
|
|
128
|
+
"JsonRpcResponse",
|
|
129
|
+
# RPC operation models
|
|
130
|
+
"ContextualizeRequest",
|
|
131
|
+
"ContextualizeResponse",
|
|
132
|
+
"DeleteRequest",
|
|
133
|
+
"DeleteResponse",
|
|
134
|
+
"EventsRequest",
|
|
135
|
+
"EventsResponse",
|
|
136
|
+
"ExportRequest",
|
|
137
|
+
"ExportResponse",
|
|
138
|
+
"GetTasksRequest",
|
|
139
|
+
"GetTasksResponse",
|
|
140
|
+
"ImportRequest",
|
|
141
|
+
"ImportResponse",
|
|
142
|
+
"InfoRequest",
|
|
143
|
+
"InfoResponse",
|
|
144
|
+
"LabelsRequest",
|
|
145
|
+
"LabelsResponse",
|
|
146
|
+
"IngestRequest",
|
|
147
|
+
"IngestResponse",
|
|
148
|
+
"RetrieveRequest",
|
|
149
|
+
"RetrieveResponse",
|
|
150
|
+
# RPC method constants
|
|
151
|
+
"ALL_METHODS",
|
|
152
|
+
"UPP_CONTEXTUALIZE",
|
|
153
|
+
"UPP_DELETE",
|
|
154
|
+
"UPP_EVENTS",
|
|
155
|
+
"UPP_EXPORT",
|
|
156
|
+
"UPP_GET_TASKS",
|
|
157
|
+
"UPP_IMPORT",
|
|
158
|
+
"UPP_INFO",
|
|
159
|
+
"UPP_LABELS",
|
|
160
|
+
"UPP_INGEST",
|
|
161
|
+
"UPP_RETRIEVE",
|
|
162
|
+
# RPC error codes
|
|
163
|
+
"EXTRACTION_FAILED",
|
|
164
|
+
"INTERNAL_ERROR",
|
|
165
|
+
"INVALID_PARAMS",
|
|
166
|
+
"INVALID_REQUEST",
|
|
167
|
+
"METHOD_NOT_FOUND",
|
|
168
|
+
"ONTOLOGY_NOT_FOUND",
|
|
169
|
+
"INGEST_FAILED",
|
|
170
|
+
"PARSE_ERROR",
|
|
171
|
+
"USER_NOT_FOUND",
|
|
172
|
+
# Exception
|
|
173
|
+
"UppError",
|
|
174
|
+
# Codec
|
|
175
|
+
"decode_request",
|
|
176
|
+
"decode_response",
|
|
177
|
+
"encode_request",
|
|
178
|
+
"encode_response",
|
|
179
|
+
# Client
|
|
180
|
+
"UPPClient",
|
|
181
|
+
# Ontology
|
|
182
|
+
"OntologyUserV1",
|
|
183
|
+
]
|
upp/backends/.gitkeep
ADDED
|
File without changes
|
upp/backends/__init__.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""UPP Backend Interfaces.
|
|
2
|
+
|
|
3
|
+
This package defines the abstract backend protocols for the Universal
|
|
4
|
+
Personalization Protocol. Each backend is a :class:`typing.Protocol`
|
|
5
|
+
decorated with :func:`typing.runtime_checkable`.
|
|
6
|
+
|
|
7
|
+
Backend Protocols:
|
|
8
|
+
IngestBackend — Persists and retrieves stored events.
|
|
9
|
+
RetrieverBackend — Intelligent retrieval of relevant context.
|
|
10
|
+
OntologyBackend — Label definitions and server metadata.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from upp.backends.ingest import IngestBackend
|
|
16
|
+
from upp.backends.ontology import OntologyBackend
|
|
17
|
+
from upp.backends.retriever import RetrieverBackend
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"OntologyBackend",
|
|
21
|
+
"RetrieverBackend",
|
|
22
|
+
"IngestBackend",
|
|
23
|
+
]
|
upp/backends/ingest.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""UPP Ingest Backend Protocol.
|
|
2
|
+
|
|
3
|
+
Defines the :class:`IngestBackend` protocol for extracting and persisting
|
|
4
|
+
personal events from free text. The backend manages the full lifecycle of
|
|
5
|
+
events following an immutable event-sourcing pattern.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Protocol, runtime_checkable
|
|
11
|
+
|
|
12
|
+
from upp.models.events import Event, StoredEvent, TaskResult
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"IngestBackend",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@runtime_checkable
|
|
20
|
+
class IngestBackend(Protocol):
|
|
21
|
+
"""Protocol for pluggable event ingestion.
|
|
22
|
+
|
|
23
|
+
An ingest backend receives free text, extracts relevant personal
|
|
24
|
+
facts, classifies them with ontology labels, handles supersession
|
|
25
|
+
for singular-cardinality labels, and persists the resulting events.
|
|
26
|
+
|
|
27
|
+
Implementations may use any extraction strategy (LLM, NLP, rules)
|
|
28
|
+
and any backing storage (in-memory, SQLite, PostgreSQL, Redis, etc.).
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
async def ingest(
|
|
32
|
+
self,
|
|
33
|
+
entity_key: str,
|
|
34
|
+
text: str,
|
|
35
|
+
) -> list[StoredEvent]:
|
|
36
|
+
"""Extract and persist events from free text.
|
|
37
|
+
|
|
38
|
+
The backend MUST:
|
|
39
|
+
|
|
40
|
+
1. Analyze the input text and extract relevant personal facts.
|
|
41
|
+
2. Classify each fact with one or more ontology labels.
|
|
42
|
+
3. Assign a UUID v4 ``id`` and a UTC ``created_at`` timestamp.
|
|
43
|
+
4. For singular-cardinality labels, mark existing valid events
|
|
44
|
+
with the same label as superseded.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
entity_key: Unique identifier of the user.
|
|
48
|
+
text: Free text from which to extract events.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
A list of :class:`StoredEvent` objects with server-assigned metadata.
|
|
52
|
+
"""
|
|
53
|
+
...
|
|
54
|
+
|
|
55
|
+
async def delete_events(
|
|
56
|
+
self,
|
|
57
|
+
entity_key: str,
|
|
58
|
+
event_ids: list[str] | None = None,
|
|
59
|
+
) -> int:
|
|
60
|
+
"""Delete events for a user.
|
|
61
|
+
|
|
62
|
+
If ``event_ids`` is ``None``, deletes ALL events for the user
|
|
63
|
+
(right to erasure). Otherwise, deletes only the specified events.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
entity_key: Unique identifier of the user.
|
|
67
|
+
event_ids: Optional list of specific event IDs to delete.
|
|
68
|
+
If ``None``, all events for the user are deleted.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
Number of events deleted.
|
|
72
|
+
"""
|
|
73
|
+
...
|
|
74
|
+
|
|
75
|
+
async def import_events(
|
|
76
|
+
self,
|
|
77
|
+
entity_key: str,
|
|
78
|
+
events: list[Event],
|
|
79
|
+
) -> list[StoredEvent]:
|
|
80
|
+
"""Import events for a user.
|
|
81
|
+
|
|
82
|
+
Persists events that were previously exported from another
|
|
83
|
+
UPP-compatible server.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
entity_key: Unique identifier of the user.
|
|
87
|
+
events: Events to import.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
A list of :class:`StoredEvent` objects with server-assigned metadata.
|
|
91
|
+
"""
|
|
92
|
+
...
|
|
93
|
+
|
|
94
|
+
async def schedule_ingest(
|
|
95
|
+
self,
|
|
96
|
+
entity_key: str,
|
|
97
|
+
text: str,
|
|
98
|
+
) -> str:
|
|
99
|
+
"""Schedule an ingest operation to run in the background.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
entity_key: Unique identifier of the user.
|
|
103
|
+
text: Free text from which to extract events.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
A task_id that can be used with get_tasks to check status.
|
|
107
|
+
"""
|
|
108
|
+
...
|
|
109
|
+
|
|
110
|
+
async def get_tasks(
|
|
111
|
+
self,
|
|
112
|
+
task_ids: list[str],
|
|
113
|
+
) -> list[TaskResult]:
|
|
114
|
+
"""Check the status of background tasks.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
task_ids: One or more task IDs to check.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
A list of TaskResult objects with status and results.
|
|
121
|
+
"""
|
|
122
|
+
...
|
upp/backends/ontology.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""UPP Ontology Backend Protocol.
|
|
2
|
+
|
|
3
|
+
Defines the :class:`OntologyBackend` protocol for accessing ontology
|
|
4
|
+
metadata, label definitions, and server information.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Protocol, runtime_checkable
|
|
10
|
+
|
|
11
|
+
from upp.models.labels import LabelDefinition
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"OntologyBackend",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@runtime_checkable
|
|
19
|
+
class OntologyBackend(Protocol):
|
|
20
|
+
"""Protocol for pluggable ontology backends.
|
|
21
|
+
|
|
22
|
+
An ontology backend provides access to label definitions, the
|
|
23
|
+
ontology identifier, and server information for the ``upp/info``
|
|
24
|
+
operation.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def get_labels(self) -> list[LabelDefinition]:
|
|
28
|
+
"""Return all label definitions for the ontology.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
A list of :class:`LabelDefinition` objects.
|
|
32
|
+
"""
|
|
33
|
+
...
|
|
34
|
+
|
|
35
|
+
def get_version(self) -> str:
|
|
36
|
+
"""Return the ontology identifier for this server instance.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
The ontology identifier string (e.g., ``"user/v1"``).
|
|
40
|
+
"""
|
|
41
|
+
...
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""UPP Retriever Backend Protocol.
|
|
2
|
+
|
|
3
|
+
Defines the :class:`RetrieverBackend` protocol for retrieving relevant
|
|
4
|
+
structured context given a free-text query. The retriever is responsible
|
|
5
|
+
for scoring, ranking, and selecting the most relevant events.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Protocol, runtime_checkable
|
|
11
|
+
|
|
12
|
+
from upp.models.events import StoredEvent
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"RetrieverBackend",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@runtime_checkable
|
|
20
|
+
class RetrieverBackend(Protocol):
|
|
21
|
+
"""Protocol for pluggable intelligent retrieval.
|
|
22
|
+
|
|
23
|
+
A retriever takes a user key and a free-text query, then returns
|
|
24
|
+
the most relevant events ranked by the implementation's scoring
|
|
25
|
+
algorithm.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
async def retrieve(
|
|
29
|
+
self,
|
|
30
|
+
entity_key: str,
|
|
31
|
+
query: str,
|
|
32
|
+
) -> list[StoredEvent]:
|
|
33
|
+
"""Retrieve relevant events for a user given a query.
|
|
34
|
+
|
|
35
|
+
The retriever MUST interpret the query and return events
|
|
36
|
+
ranked by relevance.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
entity_key: Unique identifier of the user.
|
|
40
|
+
query: Free-text query describing what information is needed.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
A list of :class:`StoredEvent` objects ranked by relevance.
|
|
44
|
+
"""
|
|
45
|
+
...
|
|
46
|
+
|
|
47
|
+
async def get_events(
|
|
48
|
+
self,
|
|
49
|
+
entity_key: str,
|
|
50
|
+
) -> list[StoredEvent]:
|
|
51
|
+
"""Get all stored events for a user.
|
|
52
|
+
|
|
53
|
+
Returns events of all statuses for transparency.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
entity_key: Unique identifier of the user.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
All stored events for the user.
|
|
60
|
+
"""
|
|
61
|
+
...
|
|
62
|
+
|
|
63
|
+
async def export_events(
|
|
64
|
+
self,
|
|
65
|
+
entity_key: str,
|
|
66
|
+
) -> list[StoredEvent]:
|
|
67
|
+
"""Export all events for a user.
|
|
68
|
+
|
|
69
|
+
Returns events of all statuses (valid, staged, superseded) to
|
|
70
|
+
provide a complete audit trail suitable for migration between
|
|
71
|
+
vendors.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
entity_key: Unique identifier of the user.
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
All stored events for export.
|
|
78
|
+
"""
|
|
79
|
+
...
|
upp/client.py
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""UPP Client — High-Level Protocol Client.
|
|
2
|
+
|
|
3
|
+
Provides :class:`UPPClient`, the primary entry point for the UPP Python
|
|
4
|
+
reference implementation. The client accepts pluggable backends and
|
|
5
|
+
exposes methods for all ten UPP operations.
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
from importlib.metadata import version as _pkg_version
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from upp.backends.ingest import IngestBackend
|
|
16
|
+
from upp.backends.ontology import OntologyBackend
|
|
17
|
+
from upp.backends.retriever import RetrieverBackend
|
|
18
|
+
from upp.models.client import UPPClientProtocol
|
|
19
|
+
from upp.models.events import ContextualizeResult, Event, StoredEvent, TaskResult
|
|
20
|
+
from upp.models.labels import LabelDefinition
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"UPPClient",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class UPPClient(UPPClientProtocol):
|
|
30
|
+
"""High-level UPP protocol client.
|
|
31
|
+
|
|
32
|
+
Orchestrates backend interfaces to implement all ten UPP
|
|
33
|
+
operations. The client is backend-agnostic — any combination of
|
|
34
|
+
backends satisfying the respective Protocol interfaces can be
|
|
35
|
+
injected.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
*,
|
|
41
|
+
ingest: IngestBackend,
|
|
42
|
+
retriever: RetrieverBackend,
|
|
43
|
+
ontology: OntologyBackend,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Initialize the UPP client with pluggable backends.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
ingest: Backend for event ingestion.
|
|
49
|
+
retriever: Backend for intelligent retrieval.
|
|
50
|
+
ontology: Backend for ontology access and server metadata.
|
|
51
|
+
"""
|
|
52
|
+
self._ingest = ingest
|
|
53
|
+
self._retriever = retriever
|
|
54
|
+
self._ontology = ontology
|
|
55
|
+
|
|
56
|
+
# ── Core (write) ─────────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
async def ingest(
|
|
59
|
+
self,
|
|
60
|
+
entity_key: str,
|
|
61
|
+
text: str,
|
|
62
|
+
) -> list[StoredEvent]:
|
|
63
|
+
"""upp/ingest — Extract and ingest events from text."""
|
|
64
|
+
logger.info(f"Ingesting text for entity '{entity_key}'")
|
|
65
|
+
return await self._ingest.ingest(entity_key, text)
|
|
66
|
+
|
|
67
|
+
async def delete_events(
|
|
68
|
+
self,
|
|
69
|
+
entity_key: str,
|
|
70
|
+
event_ids: list[str] | None = None,
|
|
71
|
+
) -> int:
|
|
72
|
+
"""upp/delete_events — Delete events (GDPR/CCPA compliance)."""
|
|
73
|
+
logger.info(f"Deleting events for entity '{entity_key}' with event_ids={event_ids}")
|
|
74
|
+
return await self._ingest.delete_events(entity_key, event_ids)
|
|
75
|
+
|
|
76
|
+
# ── Core (read) ──────────────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
async def retrieve(
|
|
79
|
+
self,
|
|
80
|
+
entity_key: str,
|
|
81
|
+
query: str,
|
|
82
|
+
) -> list[StoredEvent]:
|
|
83
|
+
"""upp/retrieve — Intelligent search for relevant events."""
|
|
84
|
+
logger.info(f"Retrieving events for entity '{entity_key}'")
|
|
85
|
+
return await self._retriever.retrieve(entity_key, query)
|
|
86
|
+
|
|
87
|
+
async def get_events(
|
|
88
|
+
self,
|
|
89
|
+
entity_key: str,
|
|
90
|
+
) -> list[StoredEvent]:
|
|
91
|
+
"""upp/get_events — Raw listing of stored events."""
|
|
92
|
+
logger.info(f"Getting events for entity '{entity_key}'")
|
|
93
|
+
return await self._retriever.get_events(entity_key)
|
|
94
|
+
|
|
95
|
+
async def contextualize(
|
|
96
|
+
self,
|
|
97
|
+
entity_key: str,
|
|
98
|
+
text: str,
|
|
99
|
+
) -> ContextualizeResult:
|
|
100
|
+
"""upp/contextualize — Retrieve context and ingest in the background."""
|
|
101
|
+
logger.info(f"Contextualizing text for entity '{entity_key}'")
|
|
102
|
+
# Retrieve existing relevant events synchronously
|
|
103
|
+
events = await self._retriever.retrieve(entity_key, text)
|
|
104
|
+
# Schedule background ingest and get task reference
|
|
105
|
+
task_id = await self._ingest.schedule_ingest(entity_key, text)
|
|
106
|
+
return ContextualizeResult(events=events, task_id=task_id)
|
|
107
|
+
|
|
108
|
+
# ── Discovery ────────────────────────────────────────────────────
|
|
109
|
+
|
|
110
|
+
def info(self) -> dict[str, Any]:
|
|
111
|
+
"""upp/info — Server metadata and capabilities."""
|
|
112
|
+
logger.info("Fetching server info")
|
|
113
|
+
return {
|
|
114
|
+
"protocol_version": _pkg_version("upp-python"),
|
|
115
|
+
"ontology": self._ontology.get_version(),
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
def get_labels(self) -> list[LabelDefinition]:
|
|
119
|
+
"""upp/get_labels — Available labels in the ontology."""
|
|
120
|
+
logger.info("Fetching label definitions from ontology")
|
|
121
|
+
return self._ontology.get_labels()
|
|
122
|
+
|
|
123
|
+
async def get_tasks(
|
|
124
|
+
self,
|
|
125
|
+
task_ids: list[str],
|
|
126
|
+
) -> list[TaskResult]:
|
|
127
|
+
"""upp/get_tasks — Check status of background tasks."""
|
|
128
|
+
logger.info(f"Getting task status for {len(task_ids)} task(s)")
|
|
129
|
+
return await self._ingest.get_tasks(task_ids)
|
|
130
|
+
|
|
131
|
+
# ── Portability ──────────────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
async def export_events(
|
|
134
|
+
self,
|
|
135
|
+
entity_key: str,
|
|
136
|
+
) -> list[StoredEvent]:
|
|
137
|
+
"""upp/export_events — Export events for migration."""
|
|
138
|
+
logger.info(f"Exporting events for entity '{entity_key}'")
|
|
139
|
+
return await self._retriever.export_events(entity_key)
|
|
140
|
+
|
|
141
|
+
async def import_events(
|
|
142
|
+
self,
|
|
143
|
+
entity_key: str,
|
|
144
|
+
events: list[Event],
|
|
145
|
+
) -> list[StoredEvent]:
|
|
146
|
+
"""upp/import_events — Import events from another server."""
|
|
147
|
+
logger.info(f"Importing {len(events)} events for entity '{entity_key}'")
|
|
148
|
+
return await self._ingest.import_events(entity_key, events)
|
upp/models/.gitkeep
ADDED
|
File without changes
|
upp/models/__init__.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""UPP Data Models.
|
|
2
|
+
|
|
3
|
+
This package contains all data model definitions for the Universal
|
|
4
|
+
Personalization Protocol (UPP) Python reference implementation.
|
|
5
|
+
|
|
6
|
+
Enumerations:
|
|
7
|
+
EventStatus, SourceType, SensitivityTier, Cardinality, Durability
|
|
8
|
+
|
|
9
|
+
Core Entities:
|
|
10
|
+
Event, StoredEvent, LabelDefinition
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from upp.models.enums import (
|
|
14
|
+
Cardinality,
|
|
15
|
+
Durability,
|
|
16
|
+
EventStatus,
|
|
17
|
+
SensitivityTier,
|
|
18
|
+
SourceType,
|
|
19
|
+
TaskStatus,
|
|
20
|
+
)
|
|
21
|
+
from upp.models.events import ContextualizeResult, Event, StoredEvent, TaskResult
|
|
22
|
+
from upp.models.labels import LabelDefinition
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
# Enumerations
|
|
26
|
+
"Cardinality",
|
|
27
|
+
"Durability",
|
|
28
|
+
"EventStatus",
|
|
29
|
+
"SensitivityTier",
|
|
30
|
+
"SourceType",
|
|
31
|
+
"TaskStatus",
|
|
32
|
+
# Core entities
|
|
33
|
+
"ContextualizeResult",
|
|
34
|
+
"Event",
|
|
35
|
+
"LabelDefinition",
|
|
36
|
+
"StoredEvent",
|
|
37
|
+
"TaskResult",
|
|
38
|
+
]
|