pipecatcloud 0.0.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. pipecatcloud-0.0.6/.github/workflows/python-publish.yml +98 -0
  2. pipecatcloud-0.0.6/.gitignore +92 -0
  3. pipecatcloud-0.0.6/CHANGELOG.md +28 -0
  4. pipecatcloud-0.0.6/PKG-INFO +13 -0
  5. pipecatcloud-0.0.6/README.md +51 -0
  6. pipecatcloud-0.0.6/dev-requirements.txt +8 -0
  7. pipecatcloud-0.0.6/pipecat-cloud.png +0 -0
  8. pipecatcloud-0.0.6/pyproject.toml +34 -0
  9. pipecatcloud-0.0.6/setup.cfg +4 -0
  10. pipecatcloud-0.0.6/src/pipecatcloud/__init__.py +12 -0
  11. pipecatcloud-0.0.6/src/pipecatcloud/__main__.py +9 -0
  12. pipecatcloud-0.0.6/src/pipecatcloud/__version__.py +6 -0
  13. pipecatcloud-0.0.6/src/pipecatcloud/_utils/__init__.py +0 -0
  14. pipecatcloud-0.0.6/src/pipecatcloud/_utils/agent_utils.py +9 -0
  15. pipecatcloud-0.0.6/src/pipecatcloud/_utils/async_utils.py +20 -0
  16. pipecatcloud-0.0.6/src/pipecatcloud/_utils/auth_utils.py +26 -0
  17. pipecatcloud-0.0.6/src/pipecatcloud/_utils/console_utils.py +25 -0
  18. pipecatcloud-0.0.6/src/pipecatcloud/_utils/deploy_utils.py +18 -0
  19. pipecatcloud-0.0.6/src/pipecatcloud/_utils/http_utils.py +43 -0
  20. pipecatcloud-0.0.6/src/pipecatcloud/agent.py +83 -0
  21. pipecatcloud-0.0.6/src/pipecatcloud/cli/__init__.py +3 -0
  22. pipecatcloud-0.0.6/src/pipecatcloud/cli/agent.py +405 -0
  23. pipecatcloud-0.0.6/src/pipecatcloud/cli/auth.py +274 -0
  24. pipecatcloud-0.0.6/src/pipecatcloud/cli/deploy.py +230 -0
  25. pipecatcloud-0.0.6/src/pipecatcloud/cli/entry_point.py +83 -0
  26. pipecatcloud-0.0.6/src/pipecatcloud/cli/init.py +0 -0
  27. pipecatcloud-0.0.6/src/pipecatcloud/cli/organizations.py +351 -0
  28. pipecatcloud-0.0.6/src/pipecatcloud/cli/run.py +28 -0
  29. pipecatcloud-0.0.6/src/pipecatcloud/cli/secrets.py +426 -0
  30. pipecatcloud-0.0.6/src/pipecatcloud/config.py +158 -0
  31. pipecatcloud-0.0.6/src/pipecatcloud/errors.py +11 -0
  32. pipecatcloud-0.0.6/src/pipecatcloud/exception.py +55 -0
  33. pipecatcloud-0.0.6/src/pipecatcloud.egg-info/PKG-INFO +13 -0
  34. pipecatcloud-0.0.6/src/pipecatcloud.egg-info/SOURCES.txt +36 -0
  35. pipecatcloud-0.0.6/src/pipecatcloud.egg-info/dependency_links.txt +1 -0
  36. pipecatcloud-0.0.6/src/pipecatcloud.egg-info/entry_points.txt +3 -0
  37. pipecatcloud-0.0.6/src/pipecatcloud.egg-info/requires.txt +9 -0
  38. pipecatcloud-0.0.6/src/pipecatcloud.egg-info/top_level.txt +1 -0
@@ -0,0 +1,98 @@
1
+ # This workflow will upload a Python Package to PyPI when a release is created
2
+ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3
+
4
+ # This workflow uses actions that are not certified by GitHub.
5
+ # They are provided by a third-party and are governed by
6
+ # separate terms of service, privacy policy, and support
7
+ # documentation.
8
+
9
+ name: Upload Python Package
10
+
11
+ on:
12
+ release:
13
+ types: [published]
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ release-build:
20
+ runs-on: ubuntu-latest
21
+
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+
25
+ - uses: actions/setup-python@v5
26
+ with:
27
+ python-version: '3.10'
28
+ - name: Setup virtual environment
29
+ run: |
30
+ python -m venv .venv
31
+ - name: Install basic Python dependencies
32
+ run: |
33
+ source .venv/bin/activate
34
+ python -m pip install --upgrade pip
35
+ pip install -r dev-requirements.txt
36
+ - name: Build project
37
+ run: |
38
+ source .venv/bin/activate
39
+ python -m build
40
+ - name: Install project and other Python dependencies
41
+ run: |
42
+ source .venv/bin/activate
43
+ pip install --editable .
44
+ - name: Upload distributions
45
+ uses: actions/upload-artifact@v4
46
+ with:
47
+ name: release-dists
48
+ path: dist/
49
+
50
+ pypi-publish:
51
+ runs-on: ubuntu-latest
52
+ needs:
53
+ - release-build
54
+ permissions:
55
+ id-token: write
56
+ contents: read
57
+
58
+ environment:
59
+ name: pypi
60
+ url: https://pypi.org/p/pipecatcloud
61
+
62
+ steps:
63
+ - uses: actions/checkout@v4
64
+
65
+ - name: Retrieve release distributions
66
+ uses: actions/download-artifact@v4
67
+ with:
68
+ name: release-dists
69
+ path: dist/
70
+
71
+ - name: Publish release distributions to PyPI
72
+ uses: pypa/gh-action-pypi-publish@release/v1
73
+ with:
74
+ packages-dir: dist/
75
+
76
+ - name: Read CHANGELOG
77
+ id: changelog
78
+ run: |
79
+ if [ -f "CHANGELOG.md" ]; then
80
+ echo "CHANGELOG_CONTENT<<EOF" >> $GITHUB_ENV
81
+ cat CHANGELOG.md >> $GITHUB_ENV
82
+ echo "EOF" >> $GITHUB_ENV
83
+ else
84
+ echo "CHANGELOG_CONTENT=No changelog available." >> $GITHUB_ENV
85
+ fi
86
+
87
+ - name: Create GitHub Release
88
+ uses: softprops/action-gh-release@v2
89
+ with:
90
+ tag_name: ${{ github.ref }}
91
+ name: Release ${{ github.ref_name }}
92
+ body: |
93
+ ${{ env.CHANGELOG_CONTENT }}
94
+ draft: false
95
+ prerelease: false
96
+ files: |
97
+ dist/*.tar.gz
98
+ dist/*.whl
@@ -0,0 +1,92 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ dist/
9
+ *.egg-info/
10
+ *.egg
11
+ *.egg-info
12
+ .installed.cfg
13
+ .eggs/
14
+ downloads/
15
+ lib/
16
+ lib64/
17
+ parts/
18
+ sdist/
19
+ var/
20
+ wheels/
21
+ share/python-wheels/
22
+ MANIFEST
23
+
24
+ # Virtual Environments
25
+ venv/
26
+ env/
27
+ .env
28
+ .venv/
29
+ ENV/
30
+ env.bak/
31
+ venv.bak/
32
+
33
+ # IDE
34
+ .idea/
35
+ .vscode/
36
+ .spyderproject
37
+ .spyproject
38
+ .ropeproject
39
+
40
+ # Testing and Coverage
41
+ .coverage
42
+ .coverage.*
43
+ htmlcov/
44
+ .pytest_cache/
45
+ .tox/
46
+ .nox/
47
+ .cache
48
+ nosetests.xml
49
+ coverage.xml
50
+ *.cover
51
+ .hypothesis/
52
+ cover/
53
+
54
+ # Logs and Databases
55
+ *.log
56
+ *.db
57
+ db.sqlite3
58
+ db.sqlite3-journal
59
+ pip-log.txt
60
+
61
+ # System Files
62
+ .DS_Store
63
+ Thumbs.db
64
+ desktop.ini
65
+ *.swp
66
+ *.swo
67
+ *.bak
68
+ *.tmp
69
+ *~
70
+
71
+ # Build and Documentation
72
+ docs/_build/
73
+ .pybuilder/
74
+ target/
75
+ instance/
76
+ .webassets-cache
77
+ .pdm.toml
78
+ .pdm-python
79
+ .pdm-build/
80
+ __pypackages__/
81
+
82
+ # Other
83
+ *.mo
84
+ *.pot
85
+ *.sage.py
86
+ .mypy_cache/
87
+ .dmypy.json
88
+ dmypy.json
89
+ .pyre/
90
+ .pytype/
91
+ cython_debug/
92
+ .ipynb_checkpoints
@@ -0,0 +1,28 @@
1
+ # Changelog
2
+
3
+ All notable changes to **Pipecat Cloud** will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.0.6] - 2025-02-01
9
+
10
+ ### Added
11
+
12
+ - `pipecatcloud.agent` module for working with agents via Python scripts
13
+ - `start_agent` method for starting an agent
14
+
15
+ ### Backlog
16
+
17
+ - `deploy` make image pull secrets non-optional, but allow for bypassing
18
+ - Fix: update docs to assert that the bot method must be async
19
+ - Fix: Secrets are not upserting (overriding each time, which may be preferrable?)
20
+ - Fix: deployment process needs better output
21
+ - `organizations keys create` should ask if you'd like to set the created key as default after creation (if org matches)
22
+ - Sense check image parameter of the deploy command (does it have a tag, etc)
23
+ - `agent logs` paginate / filter / sort and tidy up display for logs
24
+ - Fix: start command should clear the live text
25
+ - Secrets from .env method
26
+ - Fix: .pcc-deploy.toml should read correctly
27
+ - New conveience method to add account associated Daily API Key to a secret set
28
+ - Add: concurrency support for agent deployments
@@ -0,0 +1,13 @@
1
+ Metadata-Version: 2.2
2
+ Name: pipecatcloud
3
+ Version: 0.0.6
4
+ Requires-Python: >=3.10
5
+ Requires-Dist: aiohttp~=3.10.10
6
+ Requires-Dist: fastapi~=0.115.5
7
+ Requires-Dist: loguru~=0.7.2
8
+ Requires-Dist: python-dotenv~=1.0.1
9
+ Requires-Dist: uvicorn~=0.32.0
10
+ Requires-Dist: typer~=0.13.0
11
+ Requires-Dist: synchronicity~=0.7.6
12
+ Requires-Dist: toml~=0.10.2
13
+ Requires-Dist: questionary~=2.1.0
@@ -0,0 +1,51 @@
1
+
2
+ <h1><div align="center">
3
+ <img alt="pipecat cloud" width="500px" height="auto" src="./pipecat-cloud.png">
4
+ </div></h1>
5
+
6
+
7
+ [![Docs](https://img.shields.io/badge/documentation-blue)](https://docs.pipecat.cloud)
8
+ [![PyPI](https://img.shields.io/pypi/v/pipecat-cloud)](https://pypi.org/project/pipecat-cloud)
9
+
10
+ # Pipecat Cloud
11
+
12
+ Python module and CLI for interacting with [Pipecat Cloud](https://pipecat.cloud).
13
+
14
+ ### Requirements
15
+
16
+ - Python 3.10+
17
+ - Docker and a Docker repository (e.g. Docker Hub)
18
+ - Active [Pipecat Cloud](https://dashboard.pipecat.cloud)
19
+ account
20
+
21
+ ### Documentation
22
+
23
+ Documentation for Pipecat Cloud is available [here](https://docs.pipecat.cloud).
24
+
25
+ ### Installation
26
+
27
+ ```shell
28
+ pip install pipecatcloud
29
+
30
+ # Note: you can use `pipecat` or `pcc` interchangeably
31
+
32
+ pipecat --help
33
+ pipecat --version
34
+ ```
35
+
36
+ ! All CLI commands have a `--help` flag that will display the command usage and options.
37
+
38
+ ## Usage
39
+
40
+ 1. Create an account at [Pipecat Cloud](https://pipecat.cloud)
41
+
42
+ 2. Login to your account `pipecat auth login`
43
+
44
+ 3. (Optional): Clone the starter agent [here](https://github.com/pipecat-ai/pipecat-cloud-starter-agent)
45
+
46
+ 4. Build your agent `docker build --platform linux/arm64 -t your-agent-name .`
47
+
48
+ 5. Push your Docker image to your repository `docker push your-repository/your-agent-name:0.1`
49
+
50
+ 6. Deploy your agent `pipecat deploy starter-agent your-repository/your-agent-name:0.1`
51
+
@@ -0,0 +1,8 @@
1
+ build~=1.2.1
2
+ grpcio-tools~=1.62.2
3
+ pip-tools~=7.4.1
4
+ pyright~=1.1.376
5
+ pytest~=8.3.2
6
+ ruff~=0.6.7
7
+ setuptools~=72.2.0
8
+ setuptools_scm~=8.1.0
Binary file
@@ -0,0 +1,34 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "setuptools_scm>=8"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pipecatcloud"
7
+ version = "0.0.6"
8
+ requires-python = ">=3.10"
9
+ dependencies = [
10
+ "aiohttp~=3.10.10",
11
+ "fastapi~=0.115.5",
12
+ "loguru~=0.7.2",
13
+ "python-dotenv~=1.0.1",
14
+ "uvicorn~=0.32.0",
15
+ "typer~=0.13.0",
16
+ "synchronicity~=0.7.6",
17
+ "toml~=0.10.2",
18
+ "questionary~=2.1.0",
19
+ ]
20
+
21
+ [project.scripts]
22
+ pcc = "pipecatcloud.__main__:main"
23
+ pipecat = "pipecatcloud.__main__:main"
24
+
25
+ [tool.setuptools]
26
+ package-dir = {"" = "src"}
27
+
28
+ [tool.setuptools.packages.find]
29
+ where = ["src"]
30
+ include = ["pipecatcloud*"]
31
+
32
+ [tool.ruff]
33
+ exclude = ["*_pb2.py"]
34
+ line-length = 100
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,12 @@
1
+ import os
2
+ import sys
3
+
4
+ from loguru import logger
5
+
6
+ PIPECAT_CLI_NAME = "pcc"
7
+ PIPECAT_CREDENTIALS_PATH = "~/.pipecatcloud.toml"
8
+ PIPECAT_DEPLOY_CONFIG_PATH = ".pcc-deploy.toml"
9
+
10
+
11
+ logger.remove()
12
+ logger.add(sys.stderr, level=str(os.getenv("PCC_LOG_LEVEL", "INFO")))
@@ -0,0 +1,9 @@
1
+ from pipecatcloud.cli.entry_point import entrypoint_cli
2
+
3
+
4
+ def main():
5
+ entrypoint_cli()
6
+
7
+
8
+ if __name__ == "__main__":
9
+ main()
@@ -0,0 +1,6 @@
1
+ from pathlib import Path
2
+
3
+ import toml
4
+
5
+ pyproject_path = Path(__file__).parent.parent.parent / "pyproject.toml"
6
+ version = toml.load(pyproject_path)["project"]["version"]
File without changes
@@ -0,0 +1,9 @@
1
+ def handle_agent_start_error(response_code: int) -> str:
2
+ if response_code == 404:
3
+ return "PCC-1005"
4
+ elif response_code == 400:
5
+ return "PCC-1004"
6
+ elif response_code == 401:
7
+ return "PCC-1006"
8
+ else:
9
+ return "PCC-1000"
@@ -0,0 +1,20 @@
1
+ import inspect
2
+ from typing import (
3
+ TypeVar,
4
+ )
5
+
6
+ import synchronicity
7
+
8
+ synchronizer = synchronicity.Synchronizer()
9
+
10
+
11
+ def synchronize_api(obj, target_module=None):
12
+ if inspect.isclass(obj) or inspect.isfunction(obj):
13
+ blocking_name = obj.__name__.lstrip("_")
14
+ elif isinstance(obj, TypeVar):
15
+ blocking_name = "_BLOCKING_" + obj.__name__
16
+ else:
17
+ blocking_name = None
18
+ if target_module is None:
19
+ target_module = obj.__module__
20
+ return synchronizer.create_blocking(obj, blocking_name, target_module=target_module)
@@ -0,0 +1,26 @@
1
+ import functools
2
+
3
+ from rich.console import Console
4
+ from rich.panel import Panel
5
+
6
+ from pipecatcloud import PIPECAT_CLI_NAME
7
+ from pipecatcloud.cli import PANEL_TITLE_ERROR
8
+ from pipecatcloud.config import config
9
+
10
+
11
+ def requires_login(func):
12
+ @functools.wraps(func)
13
+ def wrapper(*args, **kwargs):
14
+ console = Console()
15
+ org = config.get("org")
16
+ token = config.get("token")
17
+ if org is None or token is None:
18
+ console.print(Panel(
19
+ f"You are not logged in. Please run `{PIPECAT_CLI_NAME} auth login` first.",
20
+ title=f"[red]{PANEL_TITLE_ERROR}[/red]",
21
+ title_align="left",
22
+ border_style="red",
23
+ ))
24
+ return
25
+ return func(*args, **kwargs)
26
+ return wrapper
@@ -0,0 +1,25 @@
1
+
2
+ from typing import Optional
3
+
4
+ from rich.console import Console
5
+ from rich.panel import Panel
6
+
7
+ from pipecatcloud.cli import PANEL_TITLE_ERROR
8
+ from pipecatcloud.errors import ERROR_CODES
9
+
10
+ console = Console()
11
+
12
+
13
+ def print_api_error(error_code: Optional[str], title: str):
14
+ error_message = "Unknown error" if not error_code else ERROR_CODES.get(
15
+ error_code, "Unknown error")
16
+
17
+ console.print(Panel(
18
+ f"[red]{title}[/red]\n\n"
19
+ f"[dim]Error message:[/dim]\n{error_message}",
20
+ title=f"[bold red]{PANEL_TITLE_ERROR} - {error_code}[/bold red]",
21
+ subtitle=f"[dim]Docs: https://docs.pipecat.cloud/troubleshooting/#{error_code}[/dim]",
22
+ title_align="left",
23
+ subtitle_align="left",
24
+ border_style="red"
25
+ ))
@@ -0,0 +1,18 @@
1
+ from loguru import logger
2
+
3
+
4
+ def load_deploy_config_file() -> dict | None:
5
+ import os
6
+
7
+ import toml
8
+
9
+ from pipecatcloud.config import deploy_config_path
10
+
11
+ logger.info(f"Deploy config path: {deploy_config_path}")
12
+ logger.info(f"Deploy config path exists: {os.path.exists(deploy_config_path)}")
13
+
14
+ try:
15
+ with open(deploy_config_path, "r") as f:
16
+ return toml.load(f)
17
+ except Exception:
18
+ return None
@@ -0,0 +1,43 @@
1
+ import contextlib
2
+ import logging
3
+ import socket
4
+
5
+ from aiohttp.web import Application
6
+ from aiohttp.web_runner import AppRunner, SockSite
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ @contextlib.asynccontextmanager
12
+ async def run_temporary_http_server(app: Application):
13
+ sock = socket.socket()
14
+ try:
15
+ sock.bind(("", 0))
16
+ port = sock.getsockname()[1]
17
+ host = f"http://127.0.0.1:{port}"
18
+
19
+ runner = AppRunner(app)
20
+ await runner.setup()
21
+ site = SockSite(runner, sock=sock)
22
+ await site.start()
23
+ try:
24
+ yield host
25
+ finally:
26
+ await runner.cleanup()
27
+ except Exception as e:
28
+ logger.error(f"Error setting up temporary HTTP server: {e}")
29
+ raise
30
+ finally:
31
+ sock.close()
32
+
33
+
34
+ def construct_api_url(path: str) -> str:
35
+ from pipecatcloud.config import config
36
+
37
+ if not config.get("server_url", ""):
38
+ raise ValueError("Server URL is not set")
39
+
40
+ if not config.get(path, ""):
41
+ raise ValueError(f"Endpoint {path} is not set")
42
+
43
+ return f"{config.get('server_url', '')}{config.get(path, '')}"
@@ -0,0 +1,83 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+
4
+ import aiohttp
5
+ from loguru import logger
6
+
7
+ from pipecatcloud._utils.agent_utils import handle_agent_start_error
8
+ from pipecatcloud._utils.http_utils import construct_api_url
9
+ from pipecatcloud.exception import AgentStartError
10
+
11
+
12
+ @dataclass
13
+ class AgentParams:
14
+ data: Optional[dict] = None
15
+ use_daily: Optional[bool] = False
16
+
17
+
18
+ class Agent:
19
+ def __init__(
20
+ self,
21
+ agent_name: str,
22
+ organization: str,
23
+ api_key: str,
24
+ params: Optional[AgentParams] = None,
25
+ ):
26
+ self.agent_name = agent_name
27
+ self.api_key = api_key
28
+ self.organization = organization
29
+
30
+ if not self.organization or not self.agent_name:
31
+ raise ValueError("Organization and agent name are required")
32
+
33
+ self.params = params or AgentParams()
34
+
35
+ async def start(self) -> bool:
36
+ if not self.api_key:
37
+ raise AgentStartError(error_code="PCC-1002")
38
+
39
+ # @TODO: Public route not yet implemented
40
+ """
41
+ # Check deployment heath
42
+ error_code = None
43
+ agent_data = None
44
+
45
+ try:
46
+ async with aiohttp.ClientSession() as session:
47
+ response = await session.get(
48
+ f"{construct_api_url('services_path').format(org=self.organization)}/{self.agent_name}",
49
+ headers={"Authorization": f"Bearer {self.api_key}"},
50
+ )
51
+ if response.status != 200:
52
+ error_code = str(response.status)
53
+ response.raise_for_status()
54
+ agent_data = await response.json()
55
+ if agent_data is None or not agent_data["ready"]:
56
+ raise AgentNotHealthyError(error_code=error_code)
57
+ except Exception as e:
58
+ raise Exception(f"Error checking agent health: {e}")
59
+ """
60
+
61
+ logger.debug(f"Starting agent {self.agent_name}")
62
+
63
+ start_error_code = None
64
+ try:
65
+ async with aiohttp.ClientSession() as session:
66
+ response = await session.post(
67
+ f"{construct_api_url('start_path').format(service=self.agent_name)}",
68
+ headers={"Authorization": f"Bearer {self.api_key}"},
69
+ json={
70
+ "createDailyRoom": bool(self.params.use_daily),
71
+ "body": self.params.data
72
+ }
73
+ )
74
+ if response.status != 200:
75
+ start_error_code = handle_agent_start_error(response.status)
76
+ response.raise_for_status()
77
+ else:
78
+ logger.debug(f"Agent {self.agent_name} started successfully")
79
+ except Exception as e:
80
+ logger.error(f"Error starting agent {self.agent_name}: {e}")
81
+ raise AgentStartError(error_code=start_error_code)
82
+
83
+ return True
@@ -0,0 +1,3 @@
1
+ PANEL_TITLE_ERROR = "ᓚᘏᗢ Error"
2
+ PANEL_TITLE_SUCCESS = "ᓚᘏᗢ Success"
3
+ PANEL_TITLE_NOT_IMPLEMENTED = "ᓚᘏᗢ Not yet implemented"