-
Notifications
You must be signed in to change notification settings - Fork 349
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into instructions
- Loading branch information
Showing
30 changed files
with
989 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,67 @@ | ||
from enum import Enum | ||
|
||
import marvin | ||
from gh_util.functions import add_labels_to_issue, fetch_repo_labels | ||
from gh_util.types import GitHubIssueEvent | ||
from gh_util.types import GitHubIssueEvent, GitHubLabel | ||
from prefect import flow, task | ||
from prefect.events.schemas import DeploymentTrigger | ||
|
||
|
||
@flow(log_prints=True) | ||
async def label_issues( | ||
event_body_str: str, | ||
): # want to do {{ event.payload.body | from_json }} but not supported | ||
"""Label issues based on their action""" | ||
issue_event = GitHubIssueEvent.model_validate_json(event_body_str) | ||
print( | ||
f"Issue '#{issue_event.issue.number} - {issue_event.issue.title}' was {issue_event.action}" | ||
@task | ||
async def get_appropriate_labels( | ||
issue_body: str, label_options: set[GitHubLabel], existing_labels: set[GitHubLabel] | ||
) -> set[str]: | ||
LabelOption = Enum( | ||
"LabelOption", | ||
{label.name: label.name for label in label_options.union(existing_labels)}, | ||
) | ||
|
||
issue_body = issue_event.issue.body | ||
@marvin.fn | ||
async def get_labels( | ||
body: str, existing_labels: list[GitHubLabel] | ||
) -> set[LabelOption]: # type: ignore | ||
"""Return appropriate labels for a GitHub issue based on its body. | ||
If existing labels are sufficient, return them. | ||
""" | ||
|
||
return {i.value for i in await get_labels(issue_body, existing_labels)} | ||
|
||
|
||
@flow(log_prints=True) | ||
async def label_issues(event_body_json: str): | ||
"""Label issues based on incoming webhook events from GitHub.""" | ||
event = GitHubIssueEvent.model_validate_json(event_body_json) | ||
|
||
print(f"Issue '#{event.issue.number} - {event.issue.title}' was {event.action}") | ||
|
||
owner, repo = event.repository.owner.login, event.repository.name | ||
|
||
owner, repo = issue_event.repository.owner.login, issue_event.repository.name | ||
label_options = await task(fetch_repo_labels)(owner, repo) | ||
|
||
repo_labels = await task(fetch_repo_labels)(owner, repo) | ||
labels = await get_appropriate_labels( | ||
issue_body=event.issue.body, | ||
label_options=label_options, | ||
existing_labels=set(event.issue.labels), | ||
) | ||
|
||
label = task(marvin.classify)( | ||
issue_body, labels=[label.name for label in repo_labels] | ||
await task(add_labels_to_issue)( | ||
owner=owner, | ||
repo=repo, | ||
issue_number=event.issue.number, | ||
new_labels=labels, | ||
) | ||
|
||
await task(add_labels_to_issue)(owner, repo, issue_event.issue.number, {label}) | ||
print(f"Labeled issue with {' | '.join(labels)!r}") | ||
|
||
|
||
print(f"Labeled issue with '{label}'") | ||
if __name__ == "__main__": | ||
label_issues.serve( | ||
name="Label GitHub Issues", | ||
triggers=[ | ||
DeploymentTrigger( | ||
expect={"marvin.issue*"}, | ||
parameters={"event_body_json": "{{ event.payload.body }}"}, | ||
) | ||
], | ||
) |
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
# Recording audio | ||
|
||
Marvin has utilities for working with audio data beyond generating speech and transcription. To use these utilities, you must install Marvin with the `audio` extra: | ||
|
||
```bash | ||
pip install marvin[audio] | ||
``` | ||
|
||
## Audio objects | ||
|
||
The `Audio` object gives users a simple way to work with audio data that is compatible with all of Marvin's audio abilities. You can create an `Audio` object from a file path or by providing audio bytes directly. | ||
|
||
|
||
### From a file path | ||
```python | ||
from marvin.audio import Audio | ||
audio = Audio.from_path("fancy_computer.mp3") | ||
``` | ||
### From data | ||
```python | ||
audio = Audio(data=audio_bytes) | ||
``` | ||
|
||
### Playing audio | ||
You can play audio from an `Audio` object using the `play` method: | ||
|
||
```python | ||
audio.play() | ||
``` | ||
|
||
## Recording audio | ||
|
||
Marvin can record audio from your computer's microphone. There are a variety of options for recording audio in order to match your specific use case. | ||
|
||
|
||
|
||
### Recording for a set duration | ||
|
||
The basic `record` function records audio for a specified duration. The duration is provided in seconds. | ||
|
||
```python | ||
import marvin.audio | ||
|
||
# record 5 seconds of audio | ||
audio = marvin.audio.record(duration=5) | ||
audio.play() | ||
``` | ||
|
||
### Recording a phrase | ||
|
||
The `record_phrase` function records audio until a pause is detected. This is useful for recording a phrase or sentence. | ||
|
||
```python | ||
import marvin.audio | ||
|
||
audio = marvin.audio.record_phrase() | ||
audio.play() | ||
``` | ||
|
||
There are a few keyword arguments that can be used to customize the behavior of `record_phrase`: | ||
- `after_phrase_silence`: The duration of silence to consider the end of a phrase. The default is 0.8 seconds. | ||
- `timeout`: The maximum time to wait for speech to start before giving up. The default is no timeout. | ||
- `max_phrase_duration`: The maximum duration for recording a phrase. The default is no limit. | ||
- `adjust_for_ambient_noise`: Whether to adjust the recognizer sensitivity to ambient noise before starting recording. The default is `True`, but note that this introduces a minor latency between the time the function is called and the time recording starts. A log message will be printed to indicate when the calibration is complete. | ||
|
||
### Recording continuously | ||
|
||
The `record_background` function records audio continuously in the background. This is useful for recording audio while doing other tasks or processing audio in real time. | ||
|
||
The result of `record_background` is a `BackgroundAudioRecorder` object, which can be used to control the recording (including stopping it) and to access the recorded audio as a stream. | ||
|
||
By default, the audio is recorded as a series of phrases, meaning a new `Audio` object is created each time a phase is detected. Audio objects are queued and can be accessed by iterating over the recorder's `stream` method. | ||
|
||
```python | ||
import marvin | ||
import marvin.audio | ||
|
||
recorder = marvin.audio.record_background() | ||
|
||
counter = 0 | ||
for audio in recorder.stream(): | ||
counter += 1 | ||
# process each audio phrase | ||
marvin.transcribe(audio) | ||
|
||
# stop recording | ||
if counter == 3: | ||
recorder.stop() | ||
``` |
Oops, something went wrong.