Skip to content

Commit 2eb5bdb

Browse files
authored
Merge pull request #67 from GetStream/openai-integration
OpenAI Realtime integration
2 parents 08e3a72 + e17bc4d commit 2eb5bdb

File tree

18 files changed

+1908
-677
lines changed

18 files changed

+1908
-677
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
STREAM_API_KEY=892s22ypvt6m
22
STREAM_API_SECRET=5cssrefv55rs3cnkk38kfjam2k7c2ykwn4h79dqh66ym89gm65cxy4h9jx4cypd6
33
STREAM_BASE_URL=http://127.0.0.1:3030
4+
OPENAI_API_KEY=sk-your-openai-api-key

.github/workflows/ci.yml

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,15 @@ jobs:
2323
uses: actions/checkout@v4
2424
- uses: chartboost/ruff-action@v1
2525
continue-on-error: false
26-
- name: Install poetry
27-
run: pipx install poetry
28-
- name: Set up Python ${{ matrix.python-version }}
29-
uses: actions/setup-python@v5
26+
- name: Install uv and set the python version
27+
uses: astral-sh/setup-uv@v5
3028
with:
3129
python-version: ${{ matrix.python-version }}
32-
allow-prereleases: true
33-
cache: 'poetry'
34-
- name: Install deps
35-
run: poetry install
30+
- name: Install the project
31+
run: uv sync --all-extras --dev
3632
- name: Run tests
3733
env:
3834
STREAM_BASE_URL: ${{ vars.STREAM_BASE_URL }}
3935
STREAM_API_KEY: ${{ vars.STREAM_API_KEY }}
4036
STREAM_API_SECRET: ${{ secrets.STREAM_API_SECRET }}
41-
run: poetry run pytest tests/ getstream/
37+
run: uv run pytest tests/ getstream/

.github/workflows/initiate_release.yml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,19 @@ jobs:
1515
- uses: actions/checkout@v4
1616
with:
1717
fetch-depth: 0 # gives the changelog generator access to all previous commits
18-
- uses: actions/setup-python@v5
18+
- name: Install uv and set the python version
19+
uses: astral-sh/setup-uv@v5
1920
with:
2021
python-version: "3.12"
21-
- name: Install poetry
22-
run: pipx install poetry
2322
- name: Update version.py and push release branch
2423
env:
2524
VERSION: ${{ github.event.inputs.version }}
2625
run: |
27-
poetry version $VERSION
26+
# Update pyproject.toml with sed since uv doesn't have a version command
27+
sed -i "s/^version = \".*\"/version = \"$VERSION\"/" pyproject.toml
28+
# Update version.py directly
2829
sed -i "s/^VERSION = \".*\"/VERSION = \"$VERSION\"/" getstream/version.py
30+
# Configure git and push release branch
2931
git config --global user.name 'github-actions'
3032
git config --global user.email '[email protected]'
3133
git checkout -q -b "release-$VERSION"

.github/workflows/release.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,12 @@ jobs:
2323
- uses: actions/checkout@v4
2424
with:
2525
fetch-depth: 0
26-
- uses: actions/setup-python@v5
26+
- name: Install uv and set the python version
27+
uses: astral-sh/setup-uv@v5
2728
with:
2829
python-version: "3.12"
29-
- name: Install poetry
30-
run: pipx install poetry
3130
- name: Build project
32-
run: poetry build
31+
run: uv build
3332
- name: Publish package distributions to PyPI
3433
uses: pypa/gh-action-pypi-publish@release/v1
3534
- name: Create release on GitHub

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ bin/*
2222
lib/*
2323
shell.nix
2424
pyrightconfig.json
25+
.DS_Store

README.md

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -95,37 +95,47 @@ chat_instance = client.chat
9595

9696
## Development
9797

98-
We use poetry to manage dependencies and run tests. It's a package manager for Python that allows you to declare the libraries your project depends on and manage them.
98+
We use [uv](https://github.com/astral-sh/uv) to manage dependencies and run tests. It's a package manager for Python that allows you to declare the libraries your project depends on and manage them.
9999
To install the development dependencies, run the following command:
100100

101101
```sh
102-
poetry install
102+
uv venv --python 3.12.2
103+
uv sync --all-extras --dev
103104
pre-commit install
104105
```
105106

106-
To activate the virtual environment, run the following command:
107-
108-
```sh
109-
poetry shell
110-
```
111-
112107
To run tests, create a `.env` using the `.env.example` and adjust it to have valid API credentials
113108
```sh
114-
poetry run pytest tests/ getstream/
109+
uv run pytest tests/ getstream/
115110
```
116111

117112
Before pushing changes make sure to have git hooks installed correctly, so that you get linting done locally `pre-commit install`
118113

119114
You can also run the code formatting yourself if needed:
120115

121116
```sh
122-
poetry run ruff format getstream/ tests/
117+
uv run ruff format getstream/ tests/
123118
```
124119

125120
### Writing new tests
126121

127122
pytest is used to run tests and to inject fixtures, simple tests can be written as simple python functions making assert calls. Make sure to have a look at the available test fixtures under `tests/fixtures.py`
128123

124+
#### Skipping Tests in CI
125+
126+
Some tests may not be suitable for running in a CI environment (GitHub Actions). To skip a test in CI, use the `@pytest.mark.skip_in_ci` decorator:
127+
128+
```python
129+
import pytest
130+
131+
@pytest.mark.skip_in_ci
132+
def test_something():
133+
# This test will be skipped when running in GitHub Actions
134+
...
135+
```
136+
137+
The test will run normally in local development environments but will be automatically skipped when running in GitHub Actions.
138+
129139
### Generate code from spec
130140

131141
To regenerate the Python source from OpenAPI, just run the `./generate.sh` script from this repo.

getstream/chat/client.py

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

33

44
class ChatClient(ChatRestClient):
5-
def __init__(self, api_key: str, base_url, token, timeout):
5+
def __init__(self, api_key: str, base_url, token, timeout, stream):
66
super().__init__(
77
api_key=api_key, base_url=base_url, token=token, timeout=timeout
88
)
9+
self.stream = stream

getstream/stream.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def video(self):
5353
base_url=self.base_url,
5454
token=self.token,
5555
timeout=self.timeout,
56+
stream=self,
5657
)
5758

5859
@cached_property
@@ -66,6 +67,7 @@ def chat(self):
6667
base_url=self.base_url,
6768
token=self.token,
6869
timeout=self.timeout,
70+
stream=self,
6971
)
7072

7173
def upsert_users(self, *users: UserRequest):

getstream/video/call.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,28 @@ def _sync_from_response(self, data):
1616
if hasattr(data, "call") and isinstance(data.call, CallResponse):
1717
self.custom_data = data.call.custom
1818

19+
def connect_openai(self, openai_api_key, agent_user_id):
20+
from .openai import get_openai_realtime_client, ConnectionManagerWrapper
21+
22+
client = get_openai_realtime_client(openai_api_key, self.client.base_url)
23+
token = self.client.stream.create_token(agent_user_id)
24+
connection_manager = client.beta.realtime.connect(
25+
extra_query={
26+
"call_type": self.call_type,
27+
"call_id": self.id,
28+
"api_key": self.client.api_key,
29+
},
30+
model="gpt-4o-realtime-preview",
31+
extra_headers={
32+
"Authorization": f"Bearer {openai_api_key}",
33+
"OpenAI-Beta": "realtime=v1",
34+
"Stream-Authorization": token,
35+
},
36+
)
37+
38+
# Wrap the connection manager to check for errors in the first message
39+
return ConnectionManagerWrapper(connection_manager, self.call_type, self.id)
40+
1941
def get(
2042
self,
2143
members_limit: Optional[int] = None,

getstream/video/client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44

55
class VideoClient(VideoRestClient):
6-
def __init__(self, api_key: str, base_url, token, timeout):
6+
def __init__(self, api_key: str, base_url, token, timeout, stream):
77
"""
88
Initializes VideoClient with BaseClient instance
99
:param api_key: A string representing the client's API key
@@ -17,6 +17,7 @@ def __init__(self, api_key: str, base_url, token, timeout):
1717
token=token,
1818
timeout=timeout,
1919
)
20+
self.stream = stream
2021

2122
def call(self, call_type: str, id: str) -> Call:
2223
return Call(self, call_type, id)

0 commit comments

Comments
 (0)