Merge pull request #800 from pipecat-ai/mb/autogen-docs
Auto-generate API reference docs
This commit is contained in:
47
.github/workflows/generate_docs.yaml
vendored
Normal file
47
.github/workflows/generate_docs.yaml
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
name: Generate API Documentation
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published] # Run on new release
|
||||||
|
workflow_dispatch: # Manual trigger
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update-docs:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.12'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install -r docs/api/requirements.txt
|
||||||
|
pip install .
|
||||||
|
|
||||||
|
- name: Generate API documentation
|
||||||
|
run: |
|
||||||
|
cd docs/api
|
||||||
|
python generate_docs.py
|
||||||
|
|
||||||
|
- name: Create Pull Request
|
||||||
|
uses: peter-evans/create-pull-request@v5
|
||||||
|
with:
|
||||||
|
commit-message: 'docs: Update API documentation'
|
||||||
|
title: 'docs: Update API documentation'
|
||||||
|
body: |
|
||||||
|
Automated PR to update API documentation.
|
||||||
|
|
||||||
|
- Generated using `docs/api/generate_docs.py`
|
||||||
|
- Triggered by: ${{ github.event_name }}
|
||||||
|
branch: update-api-docs
|
||||||
|
delete-branch: true
|
||||||
|
labels: |
|
||||||
|
documentation
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -32,3 +32,7 @@ fly.toml
|
|||||||
|
|
||||||
# Example files
|
# Example files
|
||||||
pipecat/examples/twilio-chatbot/templates/streams.xml
|
pipecat/examples/twilio-chatbot/templates/streams.xml
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
docs/api/_build/
|
||||||
|
docs/api/api
|
||||||
15
.readthedocs.yaml
Normal file
15
.readthedocs.yaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
version: 2
|
||||||
|
|
||||||
|
build:
|
||||||
|
os: ubuntu-22.04
|
||||||
|
tools:
|
||||||
|
python: '3.12'
|
||||||
|
|
||||||
|
sphinx:
|
||||||
|
configuration: docs/api/conf.py
|
||||||
|
|
||||||
|
python:
|
||||||
|
install:
|
||||||
|
- requirements: docs/api/requirements.txt
|
||||||
|
- method: pip
|
||||||
|
path: .
|
||||||
20
docs/api/Makefile
Normal file
20
docs/api/Makefile
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Minimal makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line, and also
|
||||||
|
# from the environment for the first two.
|
||||||
|
SPHINXOPTS ?=
|
||||||
|
SPHINXBUILD ?= sphinx-build
|
||||||
|
SOURCEDIR = .
|
||||||
|
BUILDDIR = _build
|
||||||
|
|
||||||
|
# Put it first so that "make" without argument is like "make help".
|
||||||
|
help:
|
||||||
|
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
|
|
||||||
|
.PHONY: help Makefile
|
||||||
|
|
||||||
|
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||||
|
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||||
|
%: Makefile
|
||||||
|
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||||
41
docs/api/conf.py
Normal file
41
docs/api/conf.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Add source directory to path
|
||||||
|
docs_dir = Path(__file__).parent
|
||||||
|
project_root = docs_dir.parent
|
||||||
|
sys.path.insert(0, str(project_root / "src"))
|
||||||
|
|
||||||
|
# Project information
|
||||||
|
project = "pipecat-ai"
|
||||||
|
copyright = "2024, Daily"
|
||||||
|
author = "Daily"
|
||||||
|
|
||||||
|
# General configuration
|
||||||
|
extensions = [
|
||||||
|
"sphinx.ext.autodoc",
|
||||||
|
"sphinx.ext.napoleon",
|
||||||
|
"sphinx.ext.viewcode",
|
||||||
|
"sphinx.ext.intersphinx",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Napoleon settings
|
||||||
|
napoleon_google_docstring = True
|
||||||
|
napoleon_numpy_docstring = False
|
||||||
|
napoleon_include_init_with_doc = True
|
||||||
|
|
||||||
|
# AutoDoc settings
|
||||||
|
autodoc_default_options = {
|
||||||
|
"members": True,
|
||||||
|
"member-order": "bysource",
|
||||||
|
"special-members": "__init__",
|
||||||
|
"undoc-members": True,
|
||||||
|
"exclude-members": "__weakref__",
|
||||||
|
"no-index": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
# HTML output settings
|
||||||
|
html_theme = "sphinx_rtd_theme"
|
||||||
|
html_static_path = ["_static"]
|
||||||
|
autodoc_typehints = "description"
|
||||||
|
html_show_sphinx = False # Remove "Built with Sphinx"
|
||||||
104
docs/api/generate_docs.py
Normal file
104
docs/api/generate_docs.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(command: list[str]) -> None:
|
||||||
|
"""Run a command and exit if it fails."""
|
||||||
|
print(f"Running: {' '.join(command)}")
|
||||||
|
try:
|
||||||
|
subprocess.run(command, check=True)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Warning: Command failed: {' '.join(command)}")
|
||||||
|
print(f"Error: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
docs_dir = Path(__file__).parent
|
||||||
|
project_root = docs_dir.parent.parent
|
||||||
|
|
||||||
|
# Install documentation requirements
|
||||||
|
requirements_file = docs_dir / "requirements.txt"
|
||||||
|
run_command(["pip", "install", "-r", str(requirements_file)])
|
||||||
|
|
||||||
|
# Install from project root, not docs directory
|
||||||
|
run_command(["pip", "install", "-e", str(project_root)])
|
||||||
|
|
||||||
|
# Install all service dependencies
|
||||||
|
services = [
|
||||||
|
"anthropic",
|
||||||
|
"assemblyai",
|
||||||
|
"aws",
|
||||||
|
"azure",
|
||||||
|
"canonical",
|
||||||
|
"cartesia",
|
||||||
|
# "daily",
|
||||||
|
"deepgram",
|
||||||
|
"elevenlabs",
|
||||||
|
"fal",
|
||||||
|
"fireworks",
|
||||||
|
"gladia",
|
||||||
|
"google",
|
||||||
|
"grok",
|
||||||
|
"groq",
|
||||||
|
"langchain",
|
||||||
|
# "livekit",
|
||||||
|
"lmnt",
|
||||||
|
"moondream",
|
||||||
|
"nim",
|
||||||
|
"noisereduce",
|
||||||
|
"openai",
|
||||||
|
"openpipe",
|
||||||
|
"playht",
|
||||||
|
"silero",
|
||||||
|
"soundfile",
|
||||||
|
"websocket",
|
||||||
|
"whisper",
|
||||||
|
]
|
||||||
|
|
||||||
|
extras = ",".join(services)
|
||||||
|
try:
|
||||||
|
run_command(["pip", "install", "-e", f"{str(project_root)}[{extras}]"])
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Warning: Some dependencies failed to install: {e}")
|
||||||
|
|
||||||
|
# Clean old files
|
||||||
|
api_dir = docs_dir / "api"
|
||||||
|
build_dir = docs_dir / "_build"
|
||||||
|
for dir in [api_dir, build_dir]:
|
||||||
|
if dir.exists():
|
||||||
|
shutil.rmtree(dir)
|
||||||
|
|
||||||
|
# Generate API documentation
|
||||||
|
run_command(
|
||||||
|
[
|
||||||
|
"sphinx-apidoc",
|
||||||
|
"-f", # Force overwrite
|
||||||
|
"-e", # Put each module on its own page
|
||||||
|
"-M", # Put module documentation before submodule
|
||||||
|
"--no-toc", # Don't generate modules.rst (cleaner structure)
|
||||||
|
"-o",
|
||||||
|
str(api_dir), # Output directory
|
||||||
|
str(project_root / "src/pipecat"),
|
||||||
|
# Exclude problematic files and directories
|
||||||
|
str(project_root / "src/pipecat/processors/gstreamer"), # Optional gstreamer
|
||||||
|
str(project_root / "src/pipecat/transports/network"), # Pydantic issues
|
||||||
|
str(project_root / "src/pipecat/transports/services"), # Pydantic issues
|
||||||
|
str(project_root / "src/pipecat/transports/local"), # Optional dependencies
|
||||||
|
str(project_root / "src/pipecat/services/to_be_updated"), # Exclude to_be_updated
|
||||||
|
"**/test_*.py", # Test files
|
||||||
|
"**/tests/*.py", # Test files
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Build HTML documentation
|
||||||
|
run_command(["sphinx-build", "-b", "html", str(docs_dir), str(build_dir / "html")])
|
||||||
|
|
||||||
|
print("\nDocumentation generated successfully!")
|
||||||
|
print(f"HTML docs: {build_dir}/html/index.html")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
77
docs/api/index.rst
Normal file
77
docs/api/index.rst
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
Pipecat API Reference Docs
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Welcome to Pipecat's API reference documentation!
|
||||||
|
|
||||||
|
Pipecat is an open source framework for building voice and multimodal assistants.
|
||||||
|
It provides a flexible pipeline architecture for connecting various AI services,
|
||||||
|
audio processing, and transport layers.
|
||||||
|
|
||||||
|
Quick Links
|
||||||
|
-----------
|
||||||
|
|
||||||
|
* `GitHub Repository <https://github.com/pipecat-ai/pipecat>`_
|
||||||
|
* `Website <https://pipecat.ai>`_
|
||||||
|
|
||||||
|
|
||||||
|
API Reference
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Core Components
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* :mod:`pipecat.frames`
|
||||||
|
* :mod:`pipecat.processors`
|
||||||
|
* :mod:`pipecat.pipeline`
|
||||||
|
|
||||||
|
Audio Processing
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* :mod:`pipecat.audio`
|
||||||
|
* :mod:`pipecat.vad`
|
||||||
|
|
||||||
|
Services
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
* :mod:`pipecat.services`
|
||||||
|
|
||||||
|
Transport & Serialization
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
* :mod:`pipecat.transports`
|
||||||
|
* :mod:`pipecat.serializers`
|
||||||
|
|
||||||
|
Utilities
|
||||||
|
~~~~~~~~~
|
||||||
|
|
||||||
|
* :mod:`pipecat.clocks`
|
||||||
|
* :mod:`pipecat.metrics`
|
||||||
|
* :mod:`pipecat.sync`
|
||||||
|
* :mod:`pipecat.transcriptions`
|
||||||
|
* :mod:`pipecat.utils`
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
:caption: API Reference
|
||||||
|
:hidden:
|
||||||
|
|
||||||
|
api/pipecat.audio
|
||||||
|
api/pipecat.clocks
|
||||||
|
api/pipecat.frames
|
||||||
|
api/pipecat.metrics
|
||||||
|
api/pipecat.pipeline
|
||||||
|
api/pipecat.processors
|
||||||
|
api/pipecat.serializers
|
||||||
|
api/pipecat.services
|
||||||
|
api/pipecat.sync
|
||||||
|
api/pipecat.transcriptions
|
||||||
|
api/pipecat.transports
|
||||||
|
api/pipecat.utils
|
||||||
|
api/pipecat.vad
|
||||||
|
|
||||||
|
Indices and tables
|
||||||
|
==================
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`modindex`
|
||||||
|
* :ref:`search`
|
||||||
35
docs/api/make.bat
Normal file
35
docs/api/make.bat
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
|
||||||
|
pushd %~dp0
|
||||||
|
|
||||||
|
REM Command file for Sphinx documentation
|
||||||
|
|
||||||
|
if "%SPHINXBUILD%" == "" (
|
||||||
|
set SPHINXBUILD=sphinx-build
|
||||||
|
)
|
||||||
|
set SOURCEDIR=.
|
||||||
|
set BUILDDIR=_build
|
||||||
|
|
||||||
|
%SPHINXBUILD% >NUL 2>NUL
|
||||||
|
if errorlevel 9009 (
|
||||||
|
echo.
|
||||||
|
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||||
|
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||||
|
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||||
|
echo.may add the Sphinx directory to PATH.
|
||||||
|
echo.
|
||||||
|
echo.If you don't have Sphinx installed, grab it from
|
||||||
|
echo.https://www.sphinx-doc.org/
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "" goto help
|
||||||
|
|
||||||
|
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||||
|
goto end
|
||||||
|
|
||||||
|
:help
|
||||||
|
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||||
|
|
||||||
|
:end
|
||||||
|
popd
|
||||||
5
docs/api/requirements.txt
Normal file
5
docs/api/requirements.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
sphinx>=8.1.3
|
||||||
|
sphinx-rtd-theme
|
||||||
|
sphinx-markdown-builder
|
||||||
|
sphinx-autodoc-typehints
|
||||||
|
toml
|
||||||
@@ -62,7 +62,7 @@ moondream = [ "einops~=0.8.0", "timm~=1.0.8", "transformers~=4.44.0" ]
|
|||||||
nim = [ "openai~=1.50.2" ]
|
nim = [ "openai~=1.50.2" ]
|
||||||
noisereduce = [ "noisereduce~=3.0.3" ]
|
noisereduce = [ "noisereduce~=3.0.3" ]
|
||||||
openai = [ "openai~=1.50.2", "websockets~=13.1", "python-deepcompare~=1.0.1" ]
|
openai = [ "openai~=1.50.2", "websockets~=13.1", "python-deepcompare~=1.0.1" ]
|
||||||
openpipe = [ "openpipe~=4.24.0" ]
|
openpipe = [ "openpipe~=4.38.0" ]
|
||||||
playht = [ "pyht~=0.1.4", "websockets~=13.1" ]
|
playht = [ "pyht~=0.1.4", "websockets~=13.1" ]
|
||||||
silero = [ "onnxruntime~=1.19.2" ]
|
silero = [ "onnxruntime~=1.19.2" ]
|
||||||
soundfile = [ "soundfile~=0.12.1" ]
|
soundfile = [ "soundfile~=0.12.1" ]
|
||||||
@@ -84,3 +84,10 @@ fallback_version = "0.0.0-dev"
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
exclude = ["*_pb2.py"]
|
exclude = ["*_pb2.py"]
|
||||||
line-length = 100
|
line-length = 100
|
||||||
|
|
||||||
|
select = [
|
||||||
|
"D", # Docstring rules
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.ruff.pydocstyle]
|
||||||
|
convention = "google"
|
||||||
@@ -8,7 +8,7 @@ from abc import abstractmethod
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic.main import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from pipecat.audio.utils import calculate_audio_volume, exp_smoothing
|
from pipecat.audio.utils import calculate_audio_volume, exp_smoothing
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import uuid
|
|||||||
from typing import AsyncGenerator, List, Optional, Union
|
from typing import AsyncGenerator, List, Optional, Union
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic.main import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
BotStoppedSpeakingFrame,
|
BotStoppedSpeakingFrame,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from typing import AsyncGenerator, Optional
|
|||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic.main import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
CancelFrame,
|
CancelFrame,
|
||||||
|
|||||||
@@ -22,14 +22,6 @@ class NimLLMService(OpenAILLMService):
|
|||||||
base_url (str, optional): The base URL for NIM API. Defaults to "https://integrate.api.nvidia.com/v1"
|
base_url (str, optional): The base URL for NIM API. Defaults to "https://integrate.api.nvidia.com/v1"
|
||||||
model (str, optional): The model identifier to use. Defaults to "nvidia/llama-3.1-nemotron-70b-instruct"
|
model (str, optional): The model identifier to use. Defaults to "nvidia/llama-3.1-nemotron-70b-instruct"
|
||||||
**kwargs: Additional keyword arguments passed to OpenAILLMService
|
**kwargs: Additional keyword arguments passed to OpenAILLMService
|
||||||
|
|
||||||
Example:
|
|
||||||
```python
|
|
||||||
service = NimLLMService(
|
|
||||||
api_key="your-api-key",
|
|
||||||
model="nvidia/llama-3.1-nemotron-70b-instruct"
|
|
||||||
)
|
|
||||||
```
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|||||||
@@ -379,14 +379,25 @@ class OpenAIImageGenService(ImageGenService):
|
|||||||
|
|
||||||
|
|
||||||
class OpenAITTSService(TTSService):
|
class OpenAITTSService(TTSService):
|
||||||
"""This service uses the OpenAI TTS API to generate audio from text.
|
"""OpenAI Text-to-Speech service that generates audio from text.
|
||||||
The returned audio is PCM encoded at 24kHz. When using the DailyTransport, set the sample rate in the DailyParams accordingly:
|
|
||||||
```
|
This service uses the OpenAI TTS API to generate PCM-encoded audio at 24kHz.
|
||||||
|
When using with DailyTransport, configure the sample rate in DailyParams
|
||||||
|
as shown below:
|
||||||
|
|
||||||
DailyParams(
|
DailyParams(
|
||||||
audio_out_enabled=True,
|
audio_out_enabled=True,
|
||||||
audio_out_sample_rate=24_000,
|
audio_out_sample_rate=24_000,
|
||||||
)
|
)
|
||||||
```
|
|
||||||
|
Args:
|
||||||
|
api_key: OpenAI API key. Defaults to None.
|
||||||
|
voice: Voice ID to use. Defaults to "alloy".
|
||||||
|
model: TTS model to use ("tts-1" or "tts-1-hd"). Defaults to "tts-1".
|
||||||
|
sample_rate: Output audio sample rate in Hz. Defaults to 24000.
|
||||||
|
**kwargs: Additional keyword arguments passed to TTSService.
|
||||||
|
|
||||||
|
The service returns PCM-encoded audio at the specified sample rate.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from typing import AsyncGenerator, Optional
|
|||||||
import aiohttp
|
import aiohttp
|
||||||
import websockets
|
import websockets
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic.main import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
BotStoppedSpeakingFrame,
|
BotStoppedSpeakingFrame,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from abc import ABC, abstractmethod
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from pydantic import ConfigDict
|
from pydantic import ConfigDict
|
||||||
from pydantic.main import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from pipecat.audio.filters.base_audio_filter import BaseAudioFilter
|
from pipecat.audio.filters.base_audio_filter import BaseAudioFilter
|
||||||
from pipecat.audio.mixers.base_audio_mixer import BaseAudioMixer
|
from pipecat.audio.mixers.base_audio_mixer import BaseAudioMixer
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import typing
|
|||||||
import wave
|
import wave
|
||||||
|
|
||||||
from typing import Awaitable, Callable
|
from typing import Awaitable, Callable
|
||||||
from pydantic.main import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
Frame,
|
Frame,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import time
|
|||||||
import wave
|
import wave
|
||||||
|
|
||||||
from typing import Awaitable, Callable
|
from typing import Awaitable, Callable
|
||||||
from pydantic.main import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
CancelFrame,
|
CancelFrame,
|
||||||
|
|||||||
Reference in New Issue
Block a user