Skip to content
Merged
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
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
STREAM_API_KEY=892s22ypvt6m
STREAM_API_SECRET=5cssrefv55rs3cnkk38kfjam2k7c2ykwn4h79dqh66ym89gm65cxy4h9jx4cypd6
STREAM_BASE_URL=http://127.0.0.1:3030
OPENAI_API_KEY=sk-your-openai-api-key
14 changes: 5 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,15 @@ jobs:
uses: actions/checkout@v4
- uses: chartboost/ruff-action@v1
continue-on-error: false
- name: Install poetry
run: pipx install poetry
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
- name: Install uv and set the python version
uses: astral-sh/setup-uv@v5
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true
cache: 'poetry'
- name: Install deps
run: poetry install
- name: Install the project
run: uv sync --all-extras --dev
- name: Run tests
env:
STREAM_BASE_URL: ${{ vars.STREAM_BASE_URL }}
STREAM_API_KEY: ${{ vars.STREAM_API_KEY }}
STREAM_API_SECRET: ${{ secrets.STREAM_API_SECRET }}
run: poetry run pytest tests/ getstream/
run: uv run pytest tests/ getstream/
10 changes: 6 additions & 4 deletions .github/workflows/initiate_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # gives the changelog generator access to all previous commits
- uses: actions/setup-python@v5
- name: Install uv and set the python version
uses: astral-sh/setup-uv@v5
with:
python-version: "3.12"
- name: Install poetry
run: pipx install poetry
- name: Update version.py and push release branch
env:
VERSION: ${{ github.event.inputs.version }}
run: |
poetry version $VERSION
# Update pyproject.toml with sed since uv doesn't have a version command
sed -i "s/^version = \".*\"/version = \"$VERSION\"/" pyproject.toml
# Update version.py directly
sed -i "s/^VERSION = \".*\"/VERSION = \"$VERSION\"/" getstream/version.py
# Configure git and push release branch
git config --global user.name 'github-actions'
git config --global user.email '[email protected]'
git checkout -q -b "release-$VERSION"
Expand Down
7 changes: 3 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,12 @@ jobs:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
- name: Install uv and set the python version
uses: astral-sh/setup-uv@v5
with:
python-version: "3.12"
- name: Install poetry
run: pipx install poetry
- name: Build project
run: poetry build
run: uv build
- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
- name: Create release on GitHub
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ bin/*
lib/*
shell.nix
pyrightconfig.json
.DS_Store
30 changes: 20 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,37 +95,47 @@ chat_instance = client.chat

## Development

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.
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.
To install the development dependencies, run the following command:

```sh
poetry install
uv venv --python 3.12.2
uv sync --all-extras --dev
pre-commit install
```

To activate the virtual environment, run the following command:

```sh
poetry shell
```

To run tests, create a `.env` using the `.env.example` and adjust it to have valid API credentials
```sh
poetry run pytest tests/ getstream/
uv run pytest tests/ getstream/
```

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

You can also run the code formatting yourself if needed:

```sh
poetry run ruff format getstream/ tests/
uv run ruff format getstream/ tests/
```

### Writing new tests

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`

#### Skipping Tests in CI

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:

```python
import pytest

@pytest.mark.skip_in_ci
def test_something():
# This test will be skipped when running in GitHub Actions
...
```

The test will run normally in local development environments but will be automatically skipped when running in GitHub Actions.

### Generate code from spec

To regenerate the Python source from OpenAPI, just run the `./generate.sh` script from this repo.
Expand Down
3 changes: 2 additions & 1 deletion getstream/chat/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@


class ChatClient(ChatRestClient):
def __init__(self, api_key: str, base_url, token, timeout):
def __init__(self, api_key: str, base_url, token, timeout, stream):
super().__init__(
api_key=api_key, base_url=base_url, token=token, timeout=timeout
)
self.stream = stream
2 changes: 2 additions & 0 deletions getstream/stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def video(self):
base_url=self.base_url,
token=self.token,
timeout=self.timeout,
stream=self,
)

@cached_property
Expand All @@ -66,6 +67,7 @@ def chat(self):
base_url=self.base_url,
token=self.token,
timeout=self.timeout,
stream=self,
)

def upsert_users(self, *users: UserRequest):
Expand Down
22 changes: 22 additions & 0 deletions getstream/video/call.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,28 @@ def _sync_from_response(self, data):
if hasattr(data, "call") and isinstance(data.call, CallResponse):
self.custom_data = data.call.custom

def connect_openai(self, openai_api_key, agent_user_id):
from .openai import get_openai_realtime_client, ConnectionManagerWrapper

client = get_openai_realtime_client(openai_api_key, self.client.base_url)
token = self.client.stream.create_token(agent_user_id)
connection_manager = client.beta.realtime.connect(
extra_query={
"call_type": self.call_type,
"call_id": self.id,
"api_key": self.client.api_key,
},
model="gpt-4o-realtime-preview",
extra_headers={
"Authorization": f"Bearer {openai_api_key}",
"OpenAI-Beta": "realtime=v1",
"Stream-Authorization": token,
},
)

# Wrap the connection manager to check for errors in the first message
return ConnectionManagerWrapper(connection_manager, self.call_type, self.id)

def get(
self,
members_limit: Optional[int] = None,
Expand Down
3 changes: 2 additions & 1 deletion getstream/video/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@


class VideoClient(VideoRestClient):
def __init__(self, api_key: str, base_url, token, timeout):
def __init__(self, api_key: str, base_url, token, timeout, stream):
"""
Initializes VideoClient with BaseClient instance
:param api_key: A string representing the client's API key
Expand All @@ -17,6 +17,7 @@ def __init__(self, api_key: str, base_url, token, timeout):
token=token,
timeout=timeout,
)
self.stream = stream

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