diff --git a/examples/open-telemetry-tracing-langfuse/README.md b/examples/open-telemetry-tracing-langfuse/README.md deleted file mode 100644 index 266c62757..000000000 --- a/examples/open-telemetry-tracing-langfuse/README.md +++ /dev/null @@ -1,140 +0,0 @@ -# Langfuse Tracing for Pipecat via OpenTelemetry - -This demo showcases [Langfuse](https://langfuse.com) tracing integration for Pipecat services via OpenTelemetry, allowing you to visualize service calls, performance metrics, and dependencies. - -This is a fork of the [OpenTelemetry Tracing for Pipecat](../open-telemetry-tracing) demo, but uses Langfuse instead of Jaeger. In contrast to the original demo, this demo uses the `opentelemetry-exporter-otlp-proto-http` exporter as the `grpc` exporter is not supported by Langfuse. - -Pipecat trace in Langfuse: - -https://github.com/user-attachments/assets/13dd7431-bf5e-42e3-8d6d-2ed84c51195d - -## Features - -- **Hierarchical Tracing**: Track entire conversations, turns, and service calls -- **Service Tracing**: Detailed spans for TTS, STT, and LLM services with rich context -- **TTFB Metrics**: Capture Time To First Byte metrics for latency analysis -- **Usage Statistics**: Track character counts for TTS and token usage for LLMs - -## Trace Structure - -Traces are organized hierarchically: - -``` -Conversation (conversation-uuid) -├── turn-1 -│ ├── stt_deepgramsttservice -│ ├── llm_openaillmservice -│ └── tts_cartesiattsservice -└── turn-2 - ├── stt_deepgramsttservice - ├── llm_openaillmservice - └── tts_cartesiattsservice - turn-N - └── ... -``` - -This organization helps you track conversation-to-conversation and turn-to-turn. - -## Setup Instructions - -### 1. Create a Langfuse Project and get API keys - -[Self-host](https://langfuse.com/self-hosting) Langfuse or create a free [Langfuse Cloud](https://cloud.langfuse.com) account. -Create a new project and get the API keys. - -### 2. Environment Configuration - -Base64 encode your Langfuse public and secret key: - -```bash -echo -n "pk-lf-1234567890:sk-lf-1234567890" | base64 -``` - -Create a `.env` file with your API keys to enable tracing: - -``` -ENABLE_TRACING=true -# OTLP endpoint (defaults to localhost:4317 if not set) -OTEL_EXPORTER_OTLP_ENDPOINT=http://cloud.langfuse.com/api/public/otel -OTEL_EXPORTER_OTLP_HEADERS=Authorization=Basic%20 -# Set to any value to enable console output for debugging -# OTEL_CONSOLE_EXPORT=true -``` - -### 3. Configure Your Pipeline Task - -Enable tracing in your Pipecat application: - -```python -# Initialize OpenTelemetry with your chosen exporter -from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter - -# Configured automatically from .env -exporter = OTLPSpanExporter() - -setup_tracing( - service_name="pipecat-demo", - exporter=exporter, - console_export=os.getenv("OTEL_CONSOLE_EXPORT", "false").lower() == "true", -) - -# Enable tracing in your PipelineTask -task = PipelineTask( - pipeline, - params=PipelineParams( - allow_interruptions=True, - enable_metrics=True, # Required for some service metrics - ), - enable_tracing=True, # Enables both turn and conversation tracing - conversation_id="customer-123", # Optional - will auto-generate if not provided -) -``` - -### 4. Install Dependencies - -```bash -pip install -r requirements.txt -``` - -### 5. Run the Demo - -```bash -python bot.py -``` - -### 6. View Traces in Langfuse - -Open your browser to [https://cloud.langfuse.com](https://cloud.langfuse.com) to view traces. - -## Understanding the Traces - -- **Conversation Spans**: The top-level span representing an entire conversation -- **Turn Spans**: Child spans of conversations that represent each turn in the dialog -- **Service Spans**: Detailed service operations nested under turns -- **Service Attributes**: Each service includes rich context about its operation: - - **TTS**: Voice ID, character count, service type - - **STT**: Transcription text, language, model - - **LLM**: Messages, tokens used, model, service configuration -- **Metrics**: Performance data like `metrics.ttfb_ms` and processing durations - -## How It Works - -The tracing system consists of: - -1. **TurnTrackingObserver**: Detects conversation turns -2. **TurnTraceObserver**: Creates spans for turns and conversations -3. **Service Decorators**: `@traced_tts`, `@traced_stt`, `@traced_llm` for service-specific tracing -4. **Context Providers**: Share context between different parts of the pipeline - -## Troubleshooting - -- **No Traces in Langfuse**: Ensure that your credentials are correct and follow this [troubleshooting guide](https://langfuse.com/faq/all/missing-traces) -- **Debugging Traces**: Set `OTEL_CONSOLE_EXPORT=true` to print traces to the console for debugging -- **Missing Metrics**: Check that `enable_metrics=True` in PipelineParams -- **Connection Errors**: Verify network connectivity to Langfuse -- **Exporter Issues**: Try the Console exporter (`OTEL_CONSOLE_EXPORT=true`) to verify tracing works - -## References - -- [OpenTelemetry Python Documentation](https://opentelemetry-python.readthedocs.io/) -- [Langfuse OpenTelemetry Documentation](https://langfuse.com/docs/opentelemetry/get-started) diff --git a/examples/open-telemetry-tracing/README.md b/examples/open-telemetry-tracing/README.md deleted file mode 100644 index 8695a8751..000000000 --- a/examples/open-telemetry-tracing/README.md +++ /dev/null @@ -1,176 +0,0 @@ -# OpenTelemetry Tracing for Pipecat - -This demo showcases OpenTelemetry tracing integration for Pipecat services, allowing you to visualize service calls, performance metrics, and dependencies in a Jaeger dashboard. - -## Features - -- **Hierarchical Tracing**: Track entire conversations, turns, and service calls -- **Service Tracing**: Detailed spans for TTS, STT, and LLM services with rich context -- **TTFB Metrics**: Capture Time To First Byte metrics for latency analysis -- **Usage Statistics**: Track character counts for TTS and token usage for LLMs -- **Flexible Exporters**: Use Jaeger, Zipkin, or any OpenTelemetry-compatible backend - -## Trace Structure - -Traces are organized hierarchically: - -``` -Conversation (conversation-uuid) -├── turn-1 -│ ├── stt_deepgramsttservice -│ ├── llm_openaillmservice -│ └── tts_cartesiattsservice -└── turn-2 - ├── stt_deepgramsttservice - ├── llm_openaillmservice - └── tts_cartesiattsservice - turn-N - └── ... -``` - -This organization helps you track conversation-to-conversation and turn-to-turn. - -## Setup Instructions - -### 1. Start the Jaeger Container - -Run Jaeger in Docker to collect and visualize traces: - -```bash -docker run -d --name jaeger \ - -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \ - -p 16686:16686 \ - -p 4317:4317 \ - -p 4318:4318 \ - jaegertracing/all-in-one:latest -``` - -### 2. Environment Configuration - -Create a `.env` file with your API keys and enable tracing: - -``` -ENABLE_TRACING=true -OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 # Point to your preferred backend -# OTEL_CONSOLE_EXPORT=true # Set to any value for debug output to console - -# Service API keys -DEEPGRAM_API_KEY=your_key_here -CARTESIA_API_KEY=your_key_here -OPENAI_API_KEY=your_key_here -``` - -### 3. Configure Your Pipeline Task - -Enable tracing in your Pipecat application: - -```python -# Initialize OpenTelemetry with your chosen exporter -from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter - -exporter = OTLPSpanExporter( - endpoint="http://localhost:4317", # Jaeger OTLP endpoint - insecure=True, -) - -setup_tracing( - service_name="pipecat-demo", - exporter=exporter, - console_export=os.getenv("OTEL_CONSOLE_EXPORT", "false").lower() == "true", -) - -# Enable tracing in your PipelineTask -task = PipelineTask( - pipeline, - params=PipelineParams( - allow_interruptions=True, - enable_metrics=True, # Required for some service metrics - ), - enable_tracing=True, # Enables both turn and conversation tracing - conversation_id="customer-123", # Optional - will auto-generate if not provided -) -``` - -### 4. Exporter Options - -While this demo uses Jaeger, you can configure any OpenTelemetry-compatible exporter: - -#### Jaeger (Default for the demo) - -```python -from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter - -exporter = OTLPSpanExporter( - endpoint="http://localhost:4317", # Jaeger OTLP endpoint - insecure=True, -) -``` - -#### Cloud Providers - -Many cloud providers offer OpenTelemetry-compatible observability services: - -- AWS X-Ray -- Google Cloud Trace -- Azure Monitor -- Datadog APM - -See the OpenTelemetry documentation for specific exporter configurations: -https://opentelemetry.io/ecosystem/vendors/ - -#### LLM Tracing and Evaluation Providers - -Many LLM-focused tracing and evaluation projects support OpenTelemetry, for example: - -- Langfuse ([integration example](../open-telemetry-tracing-langfuse/)) -- Arize Phoenix - -### 5. Install Dependencies - -```bash -pip install -r requirements.txt -``` - -### 6. Run the Demo - -```bash -python bot.py -``` - -### 7. View Traces in Jaeger - -Open your browser to [http://localhost:16686](http://localhost:16686) and select the "pipecat-demo" service to view traces. - -## Understanding the Traces - -- **Conversation Spans**: The top-level span representing an entire conversation -- **Turn Spans**: Child spans of conversations that represent each turn in the dialog -- **Service Spans**: Detailed service operations nested under turns -- **Service Attributes**: Each service includes rich context about its operation: - - **TTS**: Voice ID, character count, service type - - **STT**: Transcription text, language, model - - **LLM**: Messages, tokens used, model, service configuration -- **Metrics**: Performance data like `metrics.ttfb_ms` and processing durations - -## How It Works - -The tracing system consists of: - -1. **TurnTrackingObserver**: Detects conversation turns -2. **TurnTraceObserver**: Creates spans for turns and conversations -3. **Service Decorators**: `@traced_tts`, `@traced_stt`, `@traced_llm` for service-specific tracing -4. **Context Providers**: Share context between different parts of the pipeline - -## Troubleshooting - -- **No Traces in Jaeger**: Ensure the Docker container is running and the OTLP endpoint is correct -- **Debugging Traces**: Set `OTEL_CONSOLE_EXPORT=true` to print traces to the console for debugging -- **Missing Metrics**: Check that `enable_metrics=True` in PipelineParams -- **Connection Errors**: Verify network connectivity to the Jaeger container -- **Exporter Issues**: Try the Console exporter (`OTEL_CONSOLE_EXPORT=true`) to verify tracing works -- **Other Backends**: If using a different backend, ensure you've configured the correct exporter and endpoint - -## References - -- [OpenTelemetry Python Documentation](https://opentelemetry-python.readthedocs.io/) -- [Jaeger Documentation](https://www.jaegertracing.io/docs/latest/) diff --git a/examples/open-telemetry-tracing/run.py b/examples/open-telemetry-tracing/run.py deleted file mode 100644 index e7012c9e9..000000000 --- a/examples/open-telemetry-tracing/run.py +++ /dev/null @@ -1,205 +0,0 @@ -# -# Copyright (c) 2024–2025, Daily -# -# SPDX-License-Identifier: BSD 2-Clause License -# - -import argparse -import asyncio -import importlib.util -import os -import sys -from contextlib import asynccontextmanager -from inspect import iscoroutinefunction, signature -from typing import Any, Callable, Dict, Optional, Tuple - -import uvicorn -from dotenv import load_dotenv -from fastapi import BackgroundTasks, FastAPI -from fastapi.responses import RedirectResponse -from loguru import logger -from pipecat_ai_small_webrtc_prebuilt.frontend import SmallWebRTCPrebuiltUI - -from pipecat.transports.network.webrtc_connection import IceServer, SmallWebRTCConnection - -# Load environment variables -load_dotenv(override=True) - -app = FastAPI() - -# Store connections by pc_id -pcs_map: Dict[str, SmallWebRTCConnection] = {} - -ice_servers = [ - IceServer( - urls="stun:stun.l.google.com:19302", - ) -] - -# Mount the frontend at / -app.mount("/client", SmallWebRTCPrebuiltUI) - -# Store program arguments -args: argparse.Namespace = argparse.Namespace() - -# Store the bot module and function info -bot_module: Any = None -run_bot_func: Optional[Callable] = None -is_webrtc_bot: bool = True - - -def import_bot_file(file_path: str) -> Tuple[Any, Callable, bool]: - """Dynamically import the bot file and determine how to run it. - - Returns: - tuple: (module, run_function, is_webrtc_bot) - - module: The imported module - - run_function: Either run_bot or main function - - is_webrtc_bot: True if run_bot function exists and accepts a WebRTC connection - """ - if not os.path.exists(file_path): - raise FileNotFoundError(f"Bot file not found: {file_path}") - - # Extract module name without extension - module_name = os.path.splitext(os.path.basename(file_path))[0] - - # Load the module - spec = importlib.util.spec_from_file_location(module_name, file_path) - if not spec or not spec.loader: - raise ImportError(f"Could not load spec for {file_path}") - - module = importlib.util.module_from_spec(spec) - sys.modules[module_name] = module - spec.loader.exec_module(module) - - # Check for run_bot function first - if hasattr(module, "run_bot"): - run_func = module.run_bot - # Check if the function accepts a WebRTC connection - sig = signature(run_func) - is_webrtc = len(sig.parameters) > 0 - return module, run_func, is_webrtc - - # Fall back to main function - if hasattr(module, "main") and iscoroutinefunction(module.main): - return module, module.main, False - - raise AttributeError(f"No run_bot or async main function found in {file_path}") - - -@app.get("/", include_in_schema=False) -async def root_redirect(): - return RedirectResponse(url="/client/") - - -@app.post("/api/offer") -async def offer(request: dict, background_tasks: BackgroundTasks): - global run_bot_func, is_webrtc_bot - - if not run_bot_func: - raise RuntimeError("No bot file has been loaded") - - if not is_webrtc_bot: - return { - "error": "This bot doesn't support WebRTC connections, it's running in standalone mode" - } - - pc_id = request.get("pc_id") - - if pc_id and pc_id in pcs_map: - pipecat_connection = pcs_map[pc_id] - logger.info(f"Reusing existing connection for pc_id: {pc_id}") - await pipecat_connection.renegotiate( - sdp=request["sdp"], type=request["type"], restart_pc=request.get("restart_pc", False) - ) - else: - pipecat_connection = SmallWebRTCConnection(ice_servers) - await pipecat_connection.initialize(sdp=request["sdp"], type=request["type"]) - - @pipecat_connection.event_handler("closed") - async def handle_disconnected(webrtc_connection: SmallWebRTCConnection): - logger.info(f"Discarding peer connection for pc_id: {webrtc_connection.pc_id}") - pcs_map.pop(webrtc_connection.pc_id, None) - - # We've already checked that run_bot_func exists - assert run_bot_func is not None - background_tasks.add_task(run_bot_func, pipecat_connection, args) - - answer = pipecat_connection.get_answer() - # Updating the peer connection inside the map - pcs_map[answer["pc_id"]] = pipecat_connection - - return answer - - -@asynccontextmanager -async def lifespan(app: FastAPI): - yield # Run app - coros = [pc.close() for pc in pcs_map.values()] - await asyncio.gather(*coros) - pcs_map.clear() - - -async def run_standalone_bot() -> None: - """Run a standalone bot that doesn't require WebRTC""" - global run_bot_func - if run_bot_func is not None: - await run_bot_func() - else: - raise RuntimeError("No bot function available to run") - - -def main(parser: Optional[argparse.ArgumentParser] = None): - global args - - if not parser: - parser = argparse.ArgumentParser(description="Pipecat Bot Runner") - parser.add_argument("bot_file", nargs="?", help="Path to the bot file", default=None) - parser.add_argument( - "--host", default="localhost", help="Host for HTTP server (default: localhost)" - ) - parser.add_argument( - "--port", type=int, default=7860, help="Port for HTTP server (default: 7860)" - ) - parser.add_argument("--verbose", "-v", action="count", default=0) - args = parser.parse_args() - - logger.remove(0) - if args.verbose: - logger.add(sys.stderr, level="TRACE") - else: - logger.add(sys.stderr, level="DEBUG") - - # Infer the bot file from the caller if not provided explicitly - bot_file = args.bot_file - if bot_file is None: - # Get the __file__ of the script that called main() - import inspect - - caller_frame = inspect.stack()[1] - caller_globals = caller_frame.frame.f_globals - bot_file = caller_globals.get("__file__") - - if not bot_file: - print("❌ Could not determine the bot file. Pass it explicitly to main().") - sys.exit(1) - - # Import the bot file - try: - global run_bot_func, bot_module, is_webrtc_bot - bot_module, run_bot_func, is_webrtc_bot = import_bot_file(bot_file) - logger.info(f"Successfully loaded bot from {bot_file}") - - if is_webrtc_bot: - logger.info("Detected WebRTC-compatible bot, starting web server...") - uvicorn.run(app, host=args.host, port=args.port) - else: - logger.info("Detected standalone bot, running directly...") - asyncio.run(run_standalone_bot()) - except Exception as e: - logger.error(f"Error loading bot file: {e}") - sys.exit(1) - - -if __name__ == "__main__": - main() diff --git a/examples/open-telemetry/README.md b/examples/open-telemetry/README.md new file mode 100644 index 000000000..1d3871e94 --- /dev/null +++ b/examples/open-telemetry/README.md @@ -0,0 +1,69 @@ +# OpenTelemetry Tracing with Pipecat + +This repository demonstrates OpenTelemetry tracing integration for Pipecat services, with examples for different backends. + +## Tracing Features in Pipecat + +- **Hierarchical Tracing**: Track entire conversations, turns, and service calls +- **Service Tracing**: Detailed spans for TTS, STT, and LLM services with rich context +- **TTFB Metrics**: Capture Time To First Byte metrics for latency analysis +- **Usage Statistics**: Track character counts for TTS and token usage for LLMs + +## Trace Structure + +Traces are organized hierarchically: + +``` +Conversation (conversation) +├── turn +│ ├── stt_deepgramsttservice +│ ├── llm_openaillmservice +│ └── tts_cartesiattsservice +└── turn + ├── stt_deepgramsttservice + ├── llm_openaillmservice + └── tts_cartesiattsservice + turn + └── ... +``` + +This organization helps you track conversation-to-conversation and turn-to-turn interactions. + +## Available Demos + +| Demo | Description | +| ------------------------------- | ------------------------------------------------------------------------- | +| [Jaeger Tracing](./jaeger/) | Tracing with Jaeger, an open-source end-to-end distributed tracing system | +| [Langfuse Tracing](./langfuse/) | Tracing with Langfuse, a specialized platform for LLM observability | + +## Common Requirements + +- Python 3.10+ +- Pipecat and its dependencies +- API keys for the services used (Deepgram, Cartesia, OpenAI) +- The appropriate OpenTelemetry exporters + +## How Tracing Works + +The tracing system consists of: + +1. **TurnTrackingObserver**: Detects conversation turns +2. **TurnTraceObserver**: Creates spans for turns and conversations +3. **Service Decorators**: `@traced_tts`, `@traced_stt`, `@traced_llm` for service-specific tracing +4. **Context Providers**: Share context between different parts of the pipeline + +## Getting Started + +1. Choose one of the demos from the table above +2. Follow the README instructions in the respective directory + +## Common Troubleshooting + +- **Debugging Traces**: Set `OTEL_CONSOLE_EXPORT=true` to print traces to the console for debugging +- **Missing Metrics**: Check that `enable_metrics=True` in PipelineParams +- **API Key Issues**: Verify your API keys are set correctly in the .env file + +## References + +- [OpenTelemetry Python Documentation](https://opentelemetry-python.readthedocs.io/) +- [Pipecat Documentation](https://docs.pipecat.ai/server/utilities/opentelemetry) diff --git a/examples/open-telemetry/jaeger/README.md b/examples/open-telemetry/jaeger/README.md new file mode 100644 index 000000000..a19d3ee9d --- /dev/null +++ b/examples/open-telemetry/jaeger/README.md @@ -0,0 +1,80 @@ +# Jaeger Tracing for Pipecat + +This demo showcases OpenTelemetry tracing integration for Pipecat services using Jaeger, allowing you to visualize service calls, performance metrics, and dependencies. + +## Setup Instructions + +### 1. Start the Jaeger Container + +Run Jaeger in Docker to collect and visualize traces: + +```bash +docker run -d --name jaeger \ + -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \ + -p 16686:16686 \ + -p 4317:4317 \ + -p 4318:4318 \ + jaegertracing/all-in-one:latest +``` + +### 2. Environment Configuration + +Create a `.env` file with your API keys and enable tracing: + +``` +ENABLE_TRACING=true +OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 # Point to your Jaeger backend +# OTEL_CONSOLE_EXPORT=true # Set to any value for debug output to console + +# Service API keys +DEEPGRAM_API_KEY=your_key_here +CARTESIA_API_KEY=your_key_here +OPENAI_API_KEY=your_key_here +``` + +### 3. Install Dependencies + +```bash +pip install -r requirements.txt +``` + +### 4. Run the Demo + +```bash +python bot.py +``` + +### 5. View Traces in Jaeger + +Open your browser to [http://localhost:16686](http://localhost:16686) and select the "pipecat-demo" service to view traces. + +## Jaeger-Specific Configuration + +In the `bot.py` file, note the GRPC exporter configuration: + +```python +from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter + +# Create the exporter +otlp_exporter = OTLPSpanExporter( + endpoint=os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4317"), + insecure=True, +) + +# Set up tracing with the exporter +setup_tracing( + service_name="pipecat-demo", + exporter=otlp_exporter, + console_export=bool(os.getenv("OTEL_CONSOLE_EXPORT")), +) +``` + +## Troubleshooting + +- **No Traces in Jaeger**: Ensure the Docker container is running and the OTLP endpoint is correct +- **Connection Errors**: Verify network connectivity to the Jaeger container +- **Exporter Issues**: Try the Console exporter (`OTEL_CONSOLE_EXPORT=true`) to verify tracing works + +## References + +- [Jaeger Documentation](https://www.jaegertracing.io/docs/latest/) diff --git a/examples/open-telemetry-tracing/bot.py b/examples/open-telemetry/jaeger/bot.py similarity index 98% rename from examples/open-telemetry-tracing/bot.py rename to examples/open-telemetry/jaeger/bot.py index 0b44c3865..18fe34ef4 100644 --- a/examples/open-telemetry-tracing/bot.py +++ b/examples/open-telemetry/jaeger/bot.py @@ -6,6 +6,7 @@ import argparse import os +import sys from dotenv import load_dotenv from loguru import logger @@ -154,6 +155,7 @@ async def run_bot(webrtc_connection: SmallWebRTCConnection, _: argparse.Namespac if __name__ == "__main__": + sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) from run import main main() diff --git a/examples/open-telemetry-tracing/env.example b/examples/open-telemetry/jaeger/env.example similarity index 100% rename from examples/open-telemetry-tracing/env.example rename to examples/open-telemetry/jaeger/env.example diff --git a/examples/open-telemetry-tracing/requirements.txt b/examples/open-telemetry/jaeger/requirements.txt similarity index 100% rename from examples/open-telemetry-tracing/requirements.txt rename to examples/open-telemetry/jaeger/requirements.txt diff --git a/examples/open-telemetry/langfuse/README.md b/examples/open-telemetry/langfuse/README.md new file mode 100644 index 000000000..002a3f64a --- /dev/null +++ b/examples/open-telemetry/langfuse/README.md @@ -0,0 +1,82 @@ +# Langfuse Tracing for Pipecat + +This demo showcases [Langfuse](https://langfuse.com) tracing integration for Pipecat services via OpenTelemetry, allowing you to visualize service calls, performance metrics, and dependencies with a focus on LLM observability. + +Pipecat trace in Langfuse: + +https://github.com/user-attachments/assets/13dd7431-bf5e-42e3-8d6d-2ed84c51195d + +## Setup Instructions + +### 1. Create a Langfuse Project and get API keys + +[Self-host](https://langfuse.com/self-hosting) Langfuse or create a free [Langfuse Cloud](https://cloud.langfuse.com) account. +Create a new project and get the API keys. + +### 2. Environment Configuration + +Base64 encode your Langfuse public and secret key: + +```bash +echo -n "pk-lf-1234567890:sk-lf-1234567890" | base64 +``` + +Create a `.env` file with your API keys to enable tracing: + +``` +ENABLE_TRACING=true +# OTLP endpoint for Langfuse +OTEL_EXPORTER_OTLP_ENDPOINT=http://cloud.langfuse.com/api/public/otel +OTEL_EXPORTER_OTLP_HEADERS=Authorization=Basic%20 +# Set to any value to enable console output for debugging +# OTEL_CONSOLE_EXPORT=true + +# Service API keys +DEEPGRAM_API_KEY=your_key_here +CARTESIA_API_KEY=your_key_here +OPENAI_API_KEY=your_key_here +``` + +### 3. Install Dependencies + +```bash +pip install -r requirements.txt +``` + +### 4. Run the Demo + +```bash +python bot.py +``` + +### 5. View Traces in Langfuse + +Open your browser to [https://cloud.langfuse.com](https://cloud.langfuse.com) to view traces. + +## Langfuse-Specific Configuration + +In the `bot.py` file, note the HTTP exporter configuration: + +```python +from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter + +# Create the exporter - configured from environment variables +otlp_exporter = OTLPSpanExporter() + +# Set up tracing with the exporter +setup_tracing( + service_name="pipecat-demo", + exporter=otlp_exporter, + console_export=bool(os.getenv("OTEL_CONSOLE_EXPORT")), +) +``` + +## Troubleshooting + +- **No Traces in Langfuse**: Ensure that your credentials are correct and follow this [troubleshooting guide](https://langfuse.com/faq/all/missing-traces) +- **Connection Errors**: Verify network connectivity to Langfuse +- **Authorization Issues**: Check that your base64 encoding is correct and the API keys are valid + +## References + +- [Langfuse OpenTelemetry Documentation](https://langfuse.com/docs/opentelemetry/get-started) diff --git a/examples/open-telemetry-tracing-langfuse/bot.py b/examples/open-telemetry/langfuse/bot.py similarity index 98% rename from examples/open-telemetry-tracing-langfuse/bot.py rename to examples/open-telemetry/langfuse/bot.py index f4d6d76ac..9f311970e 100644 --- a/examples/open-telemetry-tracing-langfuse/bot.py +++ b/examples/open-telemetry/langfuse/bot.py @@ -6,6 +6,7 @@ import argparse import os +import sys from dotenv import load_dotenv from loguru import logger @@ -151,6 +152,7 @@ async def run_bot(webrtc_connection: SmallWebRTCConnection, _: argparse.Namespac if __name__ == "__main__": + sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) from run import main main() diff --git a/examples/open-telemetry-tracing-langfuse/env.example b/examples/open-telemetry/langfuse/env.example similarity index 100% rename from examples/open-telemetry-tracing-langfuse/env.example rename to examples/open-telemetry/langfuse/env.example diff --git a/examples/open-telemetry-tracing-langfuse/requirements.txt b/examples/open-telemetry/langfuse/requirements.txt similarity index 100% rename from examples/open-telemetry-tracing-langfuse/requirements.txt rename to examples/open-telemetry/langfuse/requirements.txt diff --git a/examples/open-telemetry-tracing-langfuse/run.py b/examples/open-telemetry/run.py similarity index 100% rename from examples/open-telemetry-tracing-langfuse/run.py rename to examples/open-telemetry/run.py