Skip to content

Commit 6e965e4

Browse files
authored
feat!: add Action Items LeMUR GA feature (#29)
add Action Items LeMUR GA feature
1 parent 1a8b675 commit 6e965e4

File tree

8 files changed

+194
-2
lines changed

8 files changed

+194
-2
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,26 @@ for q in result.response:
218218
print(f"Answer: {q.answer}")
219219
```
220220

221+
</details>
222+
223+
<details>
224+
<summary>Use LeMUR to Ask for Action Items from a Single Transcript</summary>
225+
226+
```python
227+
import assemblyai as aai
228+
229+
transcriber = aai.Transcriber()
230+
transcript = transcriber.transcribe("https://example.org/customer.mp3")
231+
232+
result = transcript.lemur.action_items(
233+
context="Customers asking for help with resolving their problem",
234+
answer_format="Three bullet points",
235+
)
236+
237+
print(result.response)
238+
```
239+
240+
221241
</details>
222242

223243
<details>

assemblyai/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
IABResponse,
1818
IABResult,
1919
LanguageCode,
20+
LemurActionItemsResponse,
2021
LemurError,
2122
LemurModel,
2223
LemurQuestion,
@@ -77,6 +78,7 @@
7778
"IABResult",
7879
"LanguageCode",
7980
"Lemur",
81+
"LemurActionItemsResponse",
8082
"LemurError",
8183
"LemurModel",
8284
"LemurSource",

assemblyai/api.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,27 @@ def lemur_summarize(
270270
return types.LemurSummaryResponse.parse_obj(response.json())
271271

272272

273+
def lemur_action_items(
274+
client: httpx.Client,
275+
request: types.LemurActionItemsRequest,
276+
http_timeout: Optional[float],
277+
) -> types.LemurActionItemsResponse:
278+
response = client.post(
279+
f"{ENDPOINT_LEMUR}/action-items",
280+
json=request.dict(
281+
exclude_none=True,
282+
),
283+
timeout=http_timeout,
284+
)
285+
286+
if response.status_code != httpx.codes.ok:
287+
raise types.LemurError(
288+
f"failed to call Lemur action items: {_get_error_message(response)}"
289+
)
290+
291+
return types.LemurActionItemsResponse.parse_obj(response.json())
292+
293+
273294
def lemur_task(
274295
client: httpx.Client,
275296
request: types.LemurTaskRequest,

assemblyai/lemur.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,28 @@ def summarize(
5858

5959
return response
6060

61+
def action_items(
62+
self,
63+
context: Optional[Union[str, Dict[str, Any]]],
64+
answer_format: Optional[str],
65+
final_model: Optional[types.LemurModel],
66+
max_output_size: Optional[int],
67+
timeout: Optional[float],
68+
) -> types.LemurActionItemsResponse:
69+
response = api.lemur_action_items(
70+
client=self._client.http_client,
71+
request=types.LemurActionItemsRequest(
72+
sources=self._sources,
73+
context=context,
74+
answer_format=answer_format,
75+
final_model=final_model,
76+
max_output_size=max_output_size,
77+
),
78+
http_timeout=timeout,
79+
)
80+
81+
return response
82+
6183
def task(
6284
self,
6385
prompt: str,
@@ -175,6 +197,40 @@ def summarize(
175197
timeout=timeout,
176198
)
177199

200+
def action_items(
201+
self,
202+
context: Optional[Union[str, Dict[str, Any]]] = None,
203+
answer_format: Optional[str] = None,
204+
final_model: Optional[types.LemurModel] = None,
205+
max_output_size: Optional[int] = None,
206+
timeout: Optional[float] = None,
207+
) -> types.LemurActionItemsResponse:
208+
"""
209+
Action Items allows you to generate action items from one or many transcripts.
210+
211+
You can provide the model with a context to get more pinpoint results while outputting the
212+
results in a variety of formats described in human language.
213+
214+
See also Best Practices on LeMUR: https://www.assemblyai.com/docs/Guides/lemur_best_practices
215+
216+
Args:
217+
context: An optional context on the transcript.
218+
answer_format: The preferred format for the result action items.
219+
final_model: The model that is used for the final prompt after compression is performed (options: "basic" and "default").
220+
max_output_size: Max output size in tokens
221+
timeout: The timeout in seconds to wait for the action items response.
222+
223+
Returns: The action items as a string.
224+
"""
225+
226+
return self._impl.action_items(
227+
context=context,
228+
answer_format=answer_format,
229+
final_model=final_model,
230+
max_output_size=max_output_size,
231+
timeout=timeout,
232+
)
233+
178234
def task(
179235
self,
180236
prompt: str,

assemblyai/types.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1781,6 +1781,23 @@ class LemurSummaryResponse(BaseModel):
17811781
"The summary of your LeMUR request"
17821782

17831783

1784+
class LemurActionItemsRequest(BaseLemurRequest):
1785+
context: Optional[Union[str, Dict[str, Any]]]
1786+
answer_format: Optional[str]
1787+
1788+
1789+
class LemurActionItemsResponse(BaseModel):
1790+
"""
1791+
The result of your Action Items LeMUR request.
1792+
"""
1793+
1794+
request_id: str
1795+
"The unique identifier of your LeMUR request"
1796+
1797+
response: str
1798+
"The action items for your LeMUR request"
1799+
1800+
17841801
class RealtimeMessageTypes(str, Enum):
17851802
"""
17861803
The type of message received from the real-time API

setup.py

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

88
setup(
99
name="assemblyai",
10-
version="0.14.0",
10+
version="0.15.0",
1111
description="AssemblyAI Python SDK",
1212
author="AssemblyAI",
1313
author_email="[email protected]",

tests/unit/factories.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,14 @@ class Meta:
177177
response = factory.Faker("text")
178178

179179

180+
class LemurActionItemsResponse(factory.Factory):
181+
class Meta:
182+
model = types.LemurActionItemsResponse
183+
184+
request_id = factory.Faker("uuid4")
185+
response = factory.Faker("text")
186+
187+
180188
class LemurTaskResponse(factory.Factory):
181189
class Meta:
182190
model = types.LemurTaskResponse

tests/unit/test_lemur.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,9 @@ def test_lemur_summarize_succeeds(httpx_mock: HTTPXMock):
152152
"""
153153

154154
# create a mock response of a LemurSummaryResponse
155-
mock_lemur_summary = factories.generate_dict_factory(factories.LemurTaskResponse)()
155+
mock_lemur_summary = factories.generate_dict_factory(
156+
factories.LemurSummaryResponse
157+
)()
156158

157159
# mock the specific endpoints
158160
httpx_mock.add_response(
@@ -204,6 +206,72 @@ def test_lemur_summarize_fails(httpx_mock: HTTPXMock):
204206
assert len(httpx_mock.get_requests()) == 1
205207

206208

209+
def test_lemur_action_items_succeeds(httpx_mock: HTTPXMock):
210+
"""
211+
Tests whether generating action items for a transcript via LeMUR succeeds.
212+
"""
213+
214+
# create a mock response of a LemurActionItemsResponse
215+
mock_lemur_action_items = factories.generate_dict_factory(
216+
factories.LemurActionItemsResponse
217+
)()
218+
219+
# mock the specific endpoints
220+
httpx_mock.add_response(
221+
url=f"{aai.settings.base_url}{ENDPOINT_LEMUR}/action-items",
222+
status_code=httpx.codes.OK,
223+
method="POST",
224+
json=mock_lemur_action_items,
225+
)
226+
227+
# mimic the usage of the SDK
228+
transcript = aai.Transcript(str(uuid.uuid4()))
229+
230+
lemur = aai.Lemur(sources=[aai.LemurSource(transcript)])
231+
result = lemur.action_items(
232+
context="Customers asking for help with resolving their problem",
233+
answer_format="Three bullet points",
234+
)
235+
236+
assert isinstance(result, aai.LemurActionItemsResponse)
237+
238+
action_items = result.response
239+
240+
# check the response
241+
assert action_items == mock_lemur_action_items["response"]
242+
243+
# check whether we mocked everything
244+
assert len(httpx_mock.get_requests()) == 1
245+
246+
247+
def test_lemur_action_items_fails(httpx_mock: HTTPXMock):
248+
"""
249+
Tests whether generating action items for a transcript via LeMUR fails.
250+
"""
251+
252+
# mock the specific endpoints
253+
httpx_mock.add_response(
254+
url=f"{aai.settings.base_url}{ENDPOINT_LEMUR}/action-items",
255+
status_code=httpx.codes.INTERNAL_SERVER_ERROR,
256+
method="POST",
257+
json={"error": "something went wrong"},
258+
)
259+
260+
# mimic the usage of the SDK
261+
transcript = aai.Transcript(str(uuid.uuid4()))
262+
263+
lemur = aai.Lemur(sources=[aai.LemurSource(transcript)])
264+
265+
with pytest.raises(aai.LemurError):
266+
lemur.action_items(
267+
context="Customers asking for help with resolving their problem",
268+
answer_format="Three bullet points",
269+
)
270+
271+
# check whether we mocked everything
272+
assert len(httpx_mock.get_requests()) == 1
273+
274+
207275
def test_lemur_task_succeeds(httpx_mock: HTTPXMock):
208276
"""
209277
Tests whether creating a task request succeeds.

0 commit comments

Comments
 (0)