Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions assemblyai/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@
TTSWordBoundariesEvent,
)
from .types import (
ActionItem,
ActionItemsRequest,
ActionItemsResponse,
AssemblyAIError,
AutohighlightResponse,
AutohighlightResult,
Expand Down Expand Up @@ -145,6 +148,9 @@ def __getattr__(name: str):

__all__ = [
# types
"ActionItem",
"ActionItemsRequest",
"ActionItemsResponse",
"AssemblyAIError",
"AsyncClient",
"AsyncDictationTranscriber",
Expand Down
2 changes: 1 addition & 1 deletion assemblyai/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.9.0"
__version__ = "1.9.1"
50 changes: 49 additions & 1 deletion assemblyai/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,18 @@ class SummarizationRequest(BaseModel):
"How much effort to spend on this task (default: 'low')"


class ActionItemsRequest(BaseModel):
"""
Action items configuration for speech understanding
"""

include_decisions: Optional[bool] = None
"Also extract key decisions made during the conversation"

effort: Optional[Literal["low", "medium"]] = None
"How much effort to spend on this task (default: 'low')"


class SpeechUnderstandingFeatureRequests(BaseModel):
"""
Speech understanding feature requests
Expand All @@ -790,6 +802,9 @@ class SpeechUnderstandingFeatureRequests(BaseModel):
summarization: Optional[SummarizationRequest] = None
"Summarization configuration"

action_items: Optional[ActionItemsRequest] = None
"Action items configuration"


class SpeechUnderstandingRequest(BaseModel):
"""
Expand Down Expand Up @@ -890,6 +905,36 @@ class SummarizationResponse(BaseModel):
"The effort level that was used"


class ActionItem(BaseModel):
"""
An action item or decision extracted from the audio
"""

action_item: str
"The extracted action item or decision"

quote: Optional[str] = None
"The source quote from the audio"

timestamp: Optional[int] = None
"Timestamp in milliseconds from audio start"


class ActionItemsResponse(BaseModel):
"""
Action items response containing status and extracted items
"""

status: str
"Status of the action items feature"

effort: Optional[Literal["low", "medium"]] = None
"The effort level that was used"

items: Optional[List[ActionItem]] = None
"List of extracted action items"


class SpeechUnderstandingFeatureResponses(BaseModel):
"""
Speech understanding feature responses grouped together
Expand All @@ -907,6 +952,9 @@ class SpeechUnderstandingFeatureResponses(BaseModel):
summarization: Optional[SummarizationResponse] = None
"Summarization results"

action_items: Optional[ActionItemsResponse] = None
"Action items results including status and items"


class SpeechUnderstandingResponse(BaseModel):
"""
Expand Down Expand Up @@ -1253,7 +1301,7 @@ def __init__(
language_detection_options: Options for controlling the behavior or Automatic Language Detection.
speech_threshold: Reject audio files that contain less than this fraction of speech. Valid values are in the range [0,1] inclusive.
raw_transcription_config: Create the config from a `RawTranscriptionConfig`
speech_understanding: Speech understanding configuration for LLM Gateway features (speaker identification, translation, custom formatting)
speech_understanding: Speech understanding configuration for LLM Gateway features (speaker identification, translation, custom formatting, summarization, action items)
temperature: Change how deterministic the response is, with 0 being the most deterministic and 1 being the least deterministic.
remove_audio_tags: When set to 'all', removes all bracketed audio/speaker tags from the transcript. Only supported for Universal-3 Pro.
keyterms_prompt_options: Options for controlling keyterms boosting behavior when using `keyterms_prompt`.
Expand Down
138 changes: 138 additions & 0 deletions tests/unit/test_action_items.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
from pytest_httpx import HTTPXMock

import assemblyai as aai
import tests.unit.factories as factories
import tests.unit.unit_test_utils as test_utils

aai.settings.api_key = "test"


def test_action_items_request_model():
req = aai.ActionItemsRequest(
effort="low",
include_decisions=True,
)
assert req.effort == "low"
assert req.include_decisions is True


def test_action_items_request_defaults():
req = aai.ActionItemsRequest()
assert req.effort is None
assert req.include_decisions is None


def test_action_items_in_speech_understanding_request():
req = aai.SpeechUnderstandingRequest(
request=aai.SpeechUnderstandingFeatureRequests(
action_items=aai.ActionItemsRequest(
effort="medium",
include_decisions=False,
)
)
)
assert req.request is not None
assert req.request.action_items is not None
assert req.request.action_items.effort == "medium"
assert req.request.action_items.include_decisions is False


def test_action_items_dict_style_in_transcription_config():
config = aai.TranscriptionConfig(
speech_understanding={
"request": {
"action_items": {
"effort": "low",
"include_decisions": True,
}
}
}
)
assert config.speech_understanding is not None
assert config.speech_understanding.request is not None
assert config.speech_understanding.request.action_items is not None
assert config.speech_understanding.request.action_items.effort == "low"
assert config.speech_understanding.request.action_items.include_decisions is True


def test_action_items_response_model():
resp = aai.ActionItemsResponse(
status="success",
effort="low",
items=[
aai.ActionItem(
action_item="Send follow-up email",
quote="I will send follow-up email",
timestamp=124500,
)
],
)
assert resp.status == "success"
assert resp.effort == "low"
assert resp.items is not None
assert len(resp.items) == 1
assert resp.items[0].action_item == "Send follow-up email"
assert resp.items[0].quote == "I will send follow-up email"
assert resp.items[0].timestamp == 124500


def test_transcript_speech_understanding_action_items(httpx_mock: HTTPXMock):
mock_response = factories.generate_dict_factory(
factories.TranscriptCompletedResponseFactory
)()
mock_response["speech_understanding"] = {
"request": {
"action_items": {
"effort": "low",
"include_decisions": True,
}
},
"response": {
"action_items": {
"status": "success",
"effort": "low",
"items": [
{
"action_item": "Schedule sync meeting",
"quote": "Let's meet tomorrow at 10",
"timestamp": 45000,
}
],
}
},
}

request_body, transcript = test_utils.submit_mock_transcription_request(
httpx_mock,
mock_response,
config=aai.TranscriptionConfig(
speech_understanding={
"request": {
"action_items": {
"effort": "low",
"include_decisions": True,
}
}
}
),
)

# Check request payload serialization
assert request_body.get("speech_understanding") is not None
su_request = request_body["speech_understanding"]["request"]
assert su_request.get("action_items") is not None
assert su_request["action_items"]["effort"] == "low"
assert su_request["action_items"]["include_decisions"] is True

# Check parsed transcript response
assert transcript.speech_understanding is not None
assert transcript.speech_understanding.response is not None
assert transcript.speech_understanding.response.action_items is not None
ai_resp = transcript.speech_understanding.response.action_items
assert ai_resp.status == "success"
assert ai_resp.effort == "low"
assert ai_resp.items is not None
assert len(ai_resp.items) == 1
assert ai_resp.items[0].action_item == "Schedule sync meeting"
assert ai_resp.items[0].quote == "Let's meet tomorrow at 10"
assert ai_resp.items[0].timestamp == 45000
Loading