Skip to content

Commit 7bf688c

Browse files
committed
feat(python/sdk): add ability to purge LeMUR requests (#2046)
GitOrigin-RevId: 4f596802d9bc99741304bc51d5dc1bca9fb2d2b7
1 parent 34e1e3c commit 7bf688c

File tree

7 files changed

+164
-2
lines changed

7 files changed

+164
-2
lines changed

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,35 @@ print(result.response)
260260

261261
</details>
262262

263+
<details>
264+
<summary>Delete data previously sent to LeMUR</summary>
265+
266+
```python
267+
import assemblyai as aai
268+
269+
# Create a transcript and a corresponding LeMUR request that may contain senstive information.
270+
transcriber = aai.Transcriber()
271+
transcript_group = transcriber.transcribe_group(
272+
[
273+
"https://example.org/customer1.mp3",
274+
],
275+
)
276+
277+
result = transcript_group.lemur.summarize(
278+
context="Customers providing sensitive, personally identifiable information",
279+
answer_format="TLDR"
280+
)
281+
282+
# Get the request ID from the LeMUR response
283+
request_id = result.request_id
284+
285+
# Now we can delete the data about this request
286+
deletion_result = aai.Lemur.purge_request_data(request_id)
287+
print(deletion_result)
288+
```
289+
290+
</details>
291+
263292
---
264293

265294
### **Audio Intelligence Examples**

assemblyai/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
LemurActionItemsResponse,
2121
LemurError,
2222
LemurModel,
23+
LemurPurgeRequest,
24+
LemurPurgeResponse,
2325
LemurQuestion,
2426
LemurQuestionAnswer,
2527
LemurQuestionResponse,
@@ -81,6 +83,8 @@
8183
"LemurActionItemsResponse",
8284
"LemurError",
8385
"LemurModel",
86+
"LemurPurgeRequest",
87+
"LemurPurgeResponse",
8488
"LemurSource",
8589
"LemurSourceType",
8690
"LemurTranscriptSource",

assemblyai/api.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
ENDPOINT_TRANSCRIPT = "/v2/transcript"
99
ENDPOINT_UPLOAD = "/v2/upload"
10-
ENDPOINT_LEMUR = "/lemur/v3/generate"
10+
ENDPOINT_LEMUR_BASE = "/lemur/v3"
11+
ENDPOINT_LEMUR = f"{ENDPOINT_LEMUR_BASE}/generate"
1112

1213

1314
def _get_error_message(response: httpx.Response) -> str:
@@ -310,3 +311,21 @@ def lemur_task(
310311
)
311312

312313
return types.LemurTaskResponse.parse_obj(response.json())
314+
315+
316+
def lemur_purge_request_data(
317+
client: httpx.Client,
318+
request: types.LemurPurgeRequest,
319+
http_timeout: Optional[float],
320+
) -> types.LemurPurgeRequest:
321+
response = client.delete(
322+
f"{ENDPOINT_LEMUR_BASE}/{request.request_id}",
323+
timeout=http_timeout,
324+
)
325+
326+
if response.status_code != httpx.codes.ok:
327+
raise types.LemurError(
328+
f"Failed to purge LeMUR request data for provided request ID: {request.request_id}. Error: {_get_error_message(response)}"
329+
)
330+
331+
return types.LemurPurgeResponse.parse_obj(response.json())

assemblyai/lemur.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,26 @@ def task(
283283
timeout=timeout,
284284
temperature=temperature,
285285
)
286+
287+
@classmethod
288+
def purge_request_data(
289+
cls,
290+
request_id: str,
291+
timeout: Optional[float] = None,
292+
) -> types.LemurPurgeResponse:
293+
"""
294+
Purge sent LeMUR request data that was previously sent.
295+
296+
Args:
297+
request_id: The request ID that was returned to you from the original LeMUR request that should be purged.
298+
299+
Returns: A response saying whether the LeMUR request data was successfully purged.
300+
"""
301+
302+
return api.lemur_purge_request_data(
303+
client=_client.Client.get_default().http_client,
304+
request=types.LemurPurgeRequest(
305+
request_id=request_id,
306+
),
307+
http_timeout=timeout,
308+
)

assemblyai/types.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1829,6 +1829,25 @@ class LemurActionItemsResponse(BaseModel):
18291829
"The action items for your LeMUR request"
18301830

18311831

1832+
class LemurPurgeRequest(BaseModel):
1833+
request_id: str
1834+
1835+
1836+
class LemurPurgeResponse(BaseModel):
1837+
"""
1838+
The result of your LeMUR purge request.
1839+
"""
1840+
1841+
request_id: str
1842+
"The unique identifier of the LeMUR purge request"
1843+
1844+
request_id_to_purge: str
1845+
"The unique identifier of the LeMUR request nneds to be purged"
1846+
1847+
deleted: bool
1848+
"The result of the LeMUR purge request"
1849+
1850+
18321851
class RealtimeMessageTypes(str, Enum):
18331852
"""
18341853
The type of message received from the real-time API

tests/unit/factories.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,15 @@ class Meta:
193193
response = factory.Faker("text")
194194

195195

196+
class LemurPurgeResponse(factory.Factory):
197+
class Meta:
198+
model = types.LemurPurgeResponse
199+
200+
request_id = factory.Faker("uuid4")
201+
request_id_to_purge = factory.Faker("uuid4")
202+
deleted = True
203+
204+
196205
class WordSearchMatchFactory(factory.Factory):
197206
class Meta:
198207
model = types.WordSearchMatch

tests/unit/test_lemur.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
from pytest_httpx import HTTPXMock
66

77
import assemblyai as aai
8-
from assemblyai.api import ENDPOINT_LEMUR
8+
from assemblyai.api import (
9+
ENDPOINT_LEMUR,
10+
ENDPOINT_LEMUR_BASE,
11+
)
912
from tests.unit import factories
1013

1114
aai.settings.api_key = "test"
@@ -330,3 +333,59 @@ def test_lemur_ask_coach_fails(httpx_mock: HTTPXMock):
330333

331334
# check whether we mocked everything
332335
assert len(httpx_mock.get_requests()) == 1
336+
337+
338+
def test_lemur_purge_request_data_succeeds(httpx_mock: HTTPXMock):
339+
"""
340+
Tests whether LeMUR request purging succeeds.
341+
"""
342+
343+
# create a mock response of a LemurPurgeResponse
344+
mock_lemur_purge_response = factories.generate_dict_factory(
345+
factories.LemurPurgeResponse
346+
)()
347+
348+
mock_request_id: str = str(uuid.uuid4())
349+
350+
# mock the specific endpoints
351+
httpx_mock.add_response(
352+
url=f"{aai.settings.base_url}{ENDPOINT_LEMUR_BASE}/{mock_request_id}",
353+
status_code=httpx.codes.OK,
354+
method="DELETE",
355+
json=mock_lemur_purge_response,
356+
)
357+
358+
# mimic the usage of the SDK
359+
result = aai.Lemur.purge_request_data(request_id=mock_request_id)
360+
361+
# check the response
362+
assert isinstance(result, aai.LemurPurgeResponse)
363+
364+
# check whether we mocked everything
365+
assert len(httpx_mock.get_requests()) == 1
366+
367+
368+
def test_lemur_purge_request_data_fails(httpx_mock: HTTPXMock):
369+
"""
370+
Tests whether LeMUR request purging fails.
371+
"""
372+
373+
# create a mock response of a LemurPurgeResponse
374+
mock_lemur_purge_response = factories.generate_dict_factory(
375+
factories.LemurPurgeResponse
376+
)()
377+
378+
mock_request_id: str = str(uuid.uuid4())
379+
380+
# mock the specific endpoints
381+
httpx_mock.add_response(
382+
url=f"{aai.settings.base_url}{ENDPOINT_LEMUR_BASE}/{mock_request_id}",
383+
status_code=httpx.codes.INTERNAL_SERVER_ERROR,
384+
method="DELETE",
385+
json=mock_lemur_purge_response,
386+
)
387+
388+
with pytest.raises(aai.LemurError) as error:
389+
aai.Lemur.purge_request_data(mock_request_id)
390+
391+
assert len(httpx_mock.get_requests()) == 1

0 commit comments

Comments
 (0)