Skip to content

Commit

Permalink
use conditional imports and show help errors if modules not found
Browse files Browse the repository at this point in the history
  • Loading branch information
aconchillo committed Apr 3, 2024
1 parent 34f0f95 commit 8fad3cc
Show file tree
Hide file tree
Showing 19 changed files with 137 additions and 67 deletions.
2 changes: 1 addition & 1 deletion examples/starter-apps/patient-intake.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
# from dailyai.services.deepgram_ai_services import DeepgramTTSService
from dailyai.services.elevenlabs_ai_service import ElevenLabsTTSService
from dailyai.pipeline.frames import (
OpenAILLMContextFrame,
Frame,
LLMFunctionCallFrame,
LLMFunctionStartFrame,
AudioFrame,
)
from dailyai.pipeline.openai_frames import OpenAILLMContextFrame
from dailyai.services.ai_services import FrameLogger, AIService
from openai._types import NotGiven, NOT_GIVEN

Expand Down
11 changes: 0 additions & 11 deletions src/dailyai/pipeline/frames.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from dataclasses import dataclass
from typing import Any, List

from dailyai.services.openai_llm_context import OpenAILLMContext
import dailyai.pipeline.protobufs.frames_pb2 as frame_protos


class Frame:
def __str__(self):
Expand Down Expand Up @@ -135,14 +132,6 @@ class LLMMessagesFrame(Frame):
messages: List[dict]


@dataclass()
class OpenAILLMContextFrame(Frame):
"""Like an LLMMessagesFrame, but with extra context specific to the
OpenAI API. The context in this message is also mutable, and will be
changed by the OpenAIContextAggregator frame processor."""
context: OpenAILLMContext


@dataclass()
class ReceivedAppMessageFrame(Frame):
message: Any
Expand Down
10 changes: 8 additions & 2 deletions src/dailyai/pipeline/opeanai_llm_aggregator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@
Frame,
LLMResponseEndFrame,
LLMResponseStartFrame,
OpenAILLMContextFrame,
TextFrame,
TranscriptionFrame,
UserStartedSpeakingFrame,
UserStoppedSpeakingFrame,
)
from dailyai.pipeline.openai_frames import OpenAILLMContextFrame
from dailyai.services.openai_llm_context import OpenAILLMContext

from openai.types.chat import ChatCompletionRole
try:
from openai.types.chat import ChatCompletionRole
except ModuleNotFoundError as e:
print(f"Exception: {e}")
print(
"In order to use OpenAI, you need to `pip install dailyai[openai]`. Also, set `OPENAI_API_KEY` environment variable.")
raise Exception(f"Missing module: {e}")


class OpenAIContextAggregator(FrameProcessor):
Expand Down
12 changes: 12 additions & 0 deletions src/dailyai/pipeline/openai_frames.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from dataclasses import dataclass

from dailyai.pipeline.frames import Frame
from dailyai.services.openai_llm_context import OpenAILLMContext


@dataclass()
class OpenAILLMContextFrame(Frame):
"""Like an LLMMessagesFrame, but with extra context specific to the
OpenAI API. The context in this message is also mutable, and will be
changed by the OpenAIContextAggregator frame processor."""
context: OpenAILLMContext
9 changes: 8 additions & 1 deletion src/dailyai/services/anthropic_llm_service.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
from typing import AsyncGenerator
from anthropic import AsyncAnthropic
from dailyai.pipeline.frames import Frame, LLMMessagesFrame, TextFrame

from dailyai.services.ai_services import LLMService

try:
from anthropic import AsyncAnthropic
except ModuleNotFoundError as e:
print(f"Exception: {e}")
print(
"In order to use Anthropic, you need to `pip install dailyai[anthropic]`. Also, set `ANTHROPIC_API_KEY` environment variable.")
raise Exception(f"Missing module: {e}")


class AnthropicLLMService(LLMService):

Expand Down
18 changes: 12 additions & 6 deletions src/dailyai/services/azure_ai_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@
from PIL import Image

# See .env.example for Azure configuration needed
from azure.cognitiveservices.speech import (
SpeechSynthesizer,
SpeechConfig,
ResultReason,
CancellationReason,
)
try:
from azure.cognitiveservices.speech import (
SpeechSynthesizer,
SpeechConfig,
ResultReason,
CancellationReason,
)
except ModuleNotFoundError as e:
print(f"Exception: {e}")
print(
"In order to use Azure TTS, you need to `pip install dailyai[azure]`. Also, set `SPEECH_KEY` and `SPEECH_REGION` environment variables.")
raise Exception(f"Missing module: {e}")

from dailyai.services.openai_api_llm_service import BaseOpenAILLMService

Expand Down
9 changes: 7 additions & 2 deletions src/dailyai/services/fal_ai_services.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import fal
import aiohttp
import asyncio
import io
Expand All @@ -10,7 +9,13 @@

from dailyai.services.ai_services import ImageGenService

# Fal expects FAL_KEY_ID and FAL_KEY_SECRET to be set in the env
try:
import fal
except ModuleNotFoundError as e:
print(f"Exception: {e}")
print(
"In order to use Fal, you need to `pip install dailyai[fal]`. Also, set `FAL_KEY_ID` and `FAL_KEY_SECRET` environment variables.")
raise Exception(f"Missing module: {e}")


class FalImageGenService(ImageGenService):
Expand Down
10 changes: 9 additions & 1 deletion src/dailyai/services/open_ai_services.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import aiohttp
from PIL import Image
import io
from openai import AsyncOpenAI

from dailyai.services.ai_services import ImageGenService
from dailyai.services.openai_api_llm_service import BaseOpenAILLMService


try:
from openai import AsyncOpenAI
except ModuleNotFoundError as e:
print(f"Exception: {e}")
print(
"In order to use OpenAI, you need to `pip install dailyai[openai]`. Also, set `OPENAI_API_KEY` environment variable.")
raise Exception(f"Missing module: {e}")


class OpenAILLMService(BaseOpenAILLMService):

def __init__(self, model="gpt-4", * args, **kwargs):
Expand Down
21 changes: 14 additions & 7 deletions src/dailyai/services/openai_api_llm_service.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
import json
import time
from typing import AsyncGenerator, List
from openai import AsyncOpenAI, AsyncStream
from dailyai.pipeline.frames import (
Frame,
LLMFunctionCallFrame,
LLMFunctionStartFrame,
LLMMessagesFrame,
LLMResponseEndFrame,
LLMResponseStartFrame,
OpenAILLMContextFrame,
TextFrame,
)
from dailyai.services.ai_services import LLMService
from dailyai.pipeline.openai_frames import OpenAILLMContextFrame
from dailyai.services.openai_llm_context import OpenAILLMContext

from openai.types.chat import (
ChatCompletion,
ChatCompletionChunk,
ChatCompletionMessageParam,
)
try:
from openai import AsyncOpenAI, AsyncStream

from openai.types.chat import (
ChatCompletion,
ChatCompletionChunk,
ChatCompletionMessageParam,
)
except ModuleNotFoundError as e:
print(f"Exception: {e}")
print(
"In order to use OpenAI, you need to `pip install dailyai[openai]`. Also, set `OPENAI_API_KEY` environment variable.")
raise Exception(f"Missing module: {e}")


class BaseOpenAILLMService(LLMService):
Expand Down
19 changes: 13 additions & 6 deletions src/dailyai/services/openai_llm_context.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
from typing import List
from openai._types import NOT_GIVEN, NotGiven

from openai.types.chat import (
ChatCompletionToolParam,
ChatCompletionToolChoiceOptionParam,
ChatCompletionMessageParam,
)
try:
from openai._types import NOT_GIVEN, NotGiven

from openai.types.chat import (
ChatCompletionToolParam,
ChatCompletionToolChoiceOptionParam,
ChatCompletionMessageParam,
)
except ModuleNotFoundError as e:
print(f"Exception: {e}")
print(
"In order to use OpenAI, you need to `pip install dailyai[openai]`. Also, set `OPENAI_API_KEY` environment variable.")
raise Exception(f"Missing module: {e}")


class OpenAILLMContext:
Expand Down
13 changes: 10 additions & 3 deletions src/dailyai/services/playht_ai_service.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import io
import struct
from pyht import Client
from pyht.client import TTSOptions
from pyht.protos.api_pb2 import Format

from dailyai.services.ai_services import TTSService

try:
from pyht import Client
from pyht.client import TTSOptions
from pyht.protos.api_pb2 import Format
except ModuleNotFoundError as e:
print(f"Exception: {e}")
print(
"In order to use PlayHT, you need to `pip install dailyai[playht]`. Also, set `PLAY_HT_USER_ID` and `PLAY_HT_API_KEY` environment variables.")
raise Exception(f"Missing module: {e}")


class PlayHTAIService(TTSService):

Expand Down
10 changes: 9 additions & 1 deletion src/dailyai/services/whisper_ai_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,18 @@
from enum import Enum
import logging
from typing import BinaryIO
from faster_whisper import WhisperModel
from dailyai.services.local_stt_service import LocalSTTService


try:
from faster_whisper import WhisperModel
except ModuleNotFoundError as e:
print(f"Exception: {e}")
print(
"In order to use Whisper, you need to `pip install dailyai[whisper]`.")
raise Exception(f"Missing module: {e}")


class Model(Enum):
"""Class of basic Whisper model selection options"""
TINY = "tiny"
Expand Down
23 changes: 15 additions & 8 deletions src/dailyai/transports/daily_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,21 @@

from threading import Event

from daily import (
EventHandler,
CallClient,
Daily,
VirtualCameraDevice,
VirtualMicrophoneDevice,
VirtualSpeakerDevice,
)
try:
from daily import (
EventHandler,
CallClient,
Daily,
VirtualCameraDevice,
VirtualMicrophoneDevice,
VirtualSpeakerDevice,
)
except ModuleNotFoundError as e:
print(f"Exception: {e}")
print(
"In order to use the Daily transport, you need to `pip install dailyai[daily]`.")
raise Exception(f"Missing module: {e}")


from dailyai.transports.threaded_transport import ThreadedTransport

Expand Down
15 changes: 8 additions & 7 deletions src/dailyai/transports/local_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@

from dailyai.transports.threaded_transport import ThreadedTransport

try:
import pyaudio
except ModuleNotFoundError as e:
print(f"Exception: {e}")
print(
"In order to use the local transport, you need to `pip install dailyai[local]`. On MacOS, you also need to `brew install portaudio`.")
raise Exception(f"Missing module: {e}")


class LocalTransport(ThreadedTransport):
def __init__(self, **kwargs):
super().__init__(**kwargs)
try:
global pyaudio
import pyaudio
except ModuleNotFoundError as e:
print(f"Exception: {e}")
print("In order to use the local transport, you'll need to `pip install pyaudio`. On MacOS, you'll also need to `brew install portaudio`.")
raise Exception(f"Missing module: {e}")
self._sample_width = kwargs.get("sample_width") or 2
self._n_channels = kwargs.get("n_channels") or 1
self._tk_root = kwargs.get("tk_root") or None
Expand Down
1 change: 0 additions & 1 deletion src/dailyai/transports/threaded_transport.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from abc import abstractmethod
import asyncio
import itertools
import logging
import numpy as np

import queue
Expand Down
9 changes: 8 additions & 1 deletion src/dailyai/transports/websocket_transport.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import asyncio
import time
from typing import AsyncGenerator, List
import websockets

from dailyai.pipeline.frame_processor import FrameProcessor
from dailyai.pipeline.frames import AudioFrame, ControlFrame, EndFrame, Frame, TTSEndFrame, TTSStartFrame, TextFrame
Expand All @@ -10,6 +9,14 @@
from dailyai.transports.abstract_transport import AbstractTransport
from dailyai.transports.threaded_transport import ThreadedTransport

try:
import websockets
except ModuleNotFoundError as e:
print(f"Exception: {e}")
print(
"In order to use the websocket transport, you need to `pip install dailyai[websocket]`.")
raise Exception(f"Missing module: {e}")


class WebSocketFrameProcessor(FrameProcessor):
"""This FrameProcessor filters and mutates frames before they're sent over the websocket.
Expand Down
4 changes: 1 addition & 3 deletions tests/integration/integration_azure_llm.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import asyncio
import os
from dailyai.pipeline.frames import (
OpenAILLMContextFrame,
)
from dailyai.pipeline.openai_frames import OpenAILLMContextFrame
from dailyai.services.azure_ai_services import AzureLLMService
from dailyai.services.openai_llm_context import OpenAILLMContext

Expand Down
4 changes: 1 addition & 3 deletions tests/integration/integration_ollama_llm.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import asyncio
from dailyai.pipeline.frames import (
OpenAILLMContextFrame,
)
from dailyai.pipeline.openai_frames import OpenAILLMContextFrame
from dailyai.services.openai_llm_context import OpenAILLMContext

from openai.types.chat import (
Expand Down
4 changes: 1 addition & 3 deletions tests/integration/integration_openai_llm.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import asyncio
import os
from dailyai.pipeline.frames import (
OpenAILLMContextFrame,
)
from dailyai.pipeline.openai_frames import OpenAILLMContextFrame
from dailyai.services.openai_llm_context import OpenAILLMContext

from openai.types.chat import (
Expand Down

0 comments on commit 8fad3cc

Please sign in to comment.