Merge branch 'main' into mcp-http-gemini-support
This commit is contained in:
@@ -2,4 +2,4 @@ aiofiles
|
|||||||
python-dotenv
|
python-dotenv
|
||||||
fastapi[all]
|
fastapi[all]
|
||||||
uvicorn
|
uvicorn
|
||||||
pipecat-ai[daily,deepgram,openai,silero,cartesia]
|
pipecat-ai[daily,deepgram,openai,silero,cartesia,soundfile]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
fastapi
|
fastapi
|
||||||
uvicorn
|
uvicorn
|
||||||
python-dotenv
|
python-dotenv
|
||||||
pipecat-ai[webrtc,silero,cartesia,deepgram,openai,tracing]
|
pipecat-ai[daily,webrtc,silero,cartesia,deepgram,openai,tracing]
|
||||||
pipecat-ai-small-webrtc-prebuilt
|
pipecat-ai-small-webrtc-prebuilt
|
||||||
opentelemetry-exporter-otlp-proto-grpc
|
opentelemetry-exporter-otlp-proto-grpc
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
fastapi
|
fastapi
|
||||||
uvicorn
|
uvicorn
|
||||||
python-dotenv
|
python-dotenv
|
||||||
pipecat-ai[webrtc,silero,cartesia,deepgram,openai,tracing]
|
pipecat-ai[daily,webrtc,silero,cartesia,deepgram,openai,tracing]
|
||||||
pipecat-ai-small-webrtc-prebuilt
|
pipecat-ai-small-webrtc-prebuilt
|
||||||
opentelemetry-exporter-otlp-proto-http
|
opentelemetry-exporter-otlp-proto-http
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
pipecat-ai[daily,elevenlabs,openai,silero]
|
pipecat-ai[daily,cartesia,openai,silero]
|
||||||
fastapi==0.115.6
|
fastapi==0.115.6
|
||||||
uvicorn
|
uvicorn
|
||||||
python-dotenv
|
python-dotenv
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
90031FC22C616EE900408370 /* SimpleChatbotUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90031FC12C616EE900408370 /* SimpleChatbotUITests.swift */; };
|
90031FC22C616EE900408370 /* SimpleChatbotUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90031FC12C616EE900408370 /* SimpleChatbotUITests.swift */; };
|
||||||
90031FC42C616EE900408370 /* SimpleChatbotUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90031FC32C616EE900408370 /* SimpleChatbotUITestsLaunchTests.swift */; };
|
90031FC42C616EE900408370 /* SimpleChatbotUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90031FC32C616EE900408370 /* SimpleChatbotUITestsLaunchTests.swift */; };
|
||||||
90031FDC2C6D5DD700408370 /* ToastModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90031FDB2C6D5DD700408370 /* ToastModifier.swift */; };
|
90031FDC2C6D5DD700408370 /* ToastModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90031FDB2C6D5DD700408370 /* ToastModifier.swift */; };
|
||||||
907C98842D37E6AF0079441F /* PipecatClientIOSDaily in Frameworks */ = {isa = PBXBuildFile; productRef = 907C98832D37E6AF0079441F /* PipecatClientIOSDaily */; };
|
|
||||||
90ABB98E2C735ED6000D9CC7 /* MeetingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90ABB98D2C735ED6000D9CC7 /* MeetingView.swift */; };
|
90ABB98E2C735ED6000D9CC7 /* MeetingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90ABB98D2C735ED6000D9CC7 /* MeetingView.swift */; };
|
||||||
90ABB9902C736A8B000D9CC7 /* WaveformView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90ABB98F2C736A8B000D9CC7 /* WaveformView.swift */; };
|
90ABB9902C736A8B000D9CC7 /* WaveformView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90ABB98F2C736A8B000D9CC7 /* WaveformView.swift */; };
|
||||||
90ABB9932C73820D000D9CC7 /* MicrophoneView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90ABB9922C73820D000D9CC7 /* MicrophoneView.swift */; };
|
90ABB9932C73820D000D9CC7 /* MicrophoneView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90ABB9922C73820D000D9CC7 /* MicrophoneView.swift */; };
|
||||||
@@ -25,6 +24,8 @@
|
|||||||
90ABB9A32C74E1CE000D9CC7 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90ABB9A22C74E1CE000D9CC7 /* SettingsView.swift */; };
|
90ABB9A32C74E1CE000D9CC7 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90ABB9A22C74E1CE000D9CC7 /* SettingsView.swift */; };
|
||||||
90ABB9A62C74EA8A000D9CC7 /* SettingsPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90ABB9A52C74EA8A000D9CC7 /* SettingsPreference.swift */; };
|
90ABB9A62C74EA8A000D9CC7 /* SettingsPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90ABB9A52C74EA8A000D9CC7 /* SettingsPreference.swift */; };
|
||||||
90ABB9A82C74EAB1000D9CC7 /* SettingsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90ABB9A72C74EAB1000D9CC7 /* SettingsManager.swift */; };
|
90ABB9A82C74EAB1000D9CC7 /* SettingsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90ABB9A72C74EAB1000D9CC7 /* SettingsManager.swift */; };
|
||||||
|
90CC98B02E158093003C2706 /* PipecatClientIOSDaily in Frameworks */ = {isa = PBXBuildFile; productRef = 90CC98AF2E158093003C2706 /* PipecatClientIOSDaily */; };
|
||||||
|
90CC98B62E15820B003C2706 /* PipecatClientIOSDaily in Frameworks */ = {isa = PBXBuildFile; productRef = 90CC98B52E15820B003C2706 /* PipecatClientIOSDaily */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -73,7 +74,8 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
907C98842D37E6AF0079441F /* PipecatClientIOSDaily in Frameworks */,
|
90CC98B62E15820B003C2706 /* PipecatClientIOSDaily in Frameworks */,
|
||||||
|
90CC98B02E158093003C2706 /* PipecatClientIOSDaily in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -218,7 +220,8 @@
|
|||||||
);
|
);
|
||||||
name = SimpleChatbot;
|
name = SimpleChatbot;
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
907C98832D37E6AF0079441F /* PipecatClientIOSDaily */,
|
90CC98AF2E158093003C2706 /* PipecatClientIOSDaily */,
|
||||||
|
90CC98B52E15820B003C2706 /* PipecatClientIOSDaily */,
|
||||||
);
|
);
|
||||||
productName = SimpleChatbot;
|
productName = SimpleChatbot;
|
||||||
productReference = 90031FA32C616EE700408370 /* SimpleChatbot.app */;
|
productReference = 90031FA32C616EE700408370 /* SimpleChatbot.app */;
|
||||||
@@ -293,7 +296,7 @@
|
|||||||
);
|
);
|
||||||
mainGroup = 90031F9A2C616EE700408370;
|
mainGroup = 90031F9A2C616EE700408370;
|
||||||
packageReferences = (
|
packageReferences = (
|
||||||
907C98822D37E6AF0079441F /* XCRemoteSwiftPackageReference "pipecat-client-ios-daily" */,
|
90CC98B42E15820B003C2706 /* XCRemoteSwiftPackageReference "pipecat-client-ios-daily" */,
|
||||||
);
|
);
|
||||||
productRefGroup = 90031FA42C616EE700408370 /* Products */;
|
productRefGroup = 90031FA42C616EE700408370 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
@@ -682,20 +685,24 @@
|
|||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
/* Begin XCRemoteSwiftPackageReference section */
|
/* Begin XCRemoteSwiftPackageReference section */
|
||||||
907C98822D37E6AF0079441F /* XCRemoteSwiftPackageReference "pipecat-client-ios-daily" */ = {
|
90CC98B42E15820B003C2706 /* XCRemoteSwiftPackageReference "pipecat-client-ios-daily" */ = {
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/pipecat-ai/pipecat-client-ios-daily/";
|
repositoryURL = "https://github.com/pipecat-ai/pipecat-client-ios-daily/";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = upToNextMajorVersion;
|
kind = upToNextMajorVersion;
|
||||||
minimumVersion = 0.3.2;
|
minimumVersion = 0.3.6;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/* End XCRemoteSwiftPackageReference section */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
||||||
/* Begin XCSwiftPackageProductDependency section */
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
907C98832D37E6AF0079441F /* PipecatClientIOSDaily */ = {
|
90CC98AF2E158093003C2706 /* PipecatClientIOSDaily */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = 907C98822D37E6AF0079441F /* XCRemoteSwiftPackageReference "pipecat-client-ios-daily" */;
|
productName = PipecatClientIOSDaily;
|
||||||
|
};
|
||||||
|
90CC98B52E15820B003C2706 /* PipecatClientIOSDaily */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 90CC98B42E15820B003C2706 /* XCRemoteSwiftPackageReference "pipecat-client-ios-daily" */;
|
||||||
productName = PipecatClientIOSDaily;
|
productName = PipecatClientIOSDaily;
|
||||||
};
|
};
|
||||||
/* End XCSwiftPackageProductDependency section */
|
/* End XCSwiftPackageProductDependency section */
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
{
|
{
|
||||||
|
"originHash" : "cc17f08b06def9570d775e9c6f7a8dc10d1588b98127e977c47d052abac659b7",
|
||||||
"pins" : [
|
"pins" : [
|
||||||
{
|
{
|
||||||
"identity" : "daily-client-ios",
|
"identity" : "daily-client-ios",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/daily-co/daily-client-ios.git",
|
"location" : "https://github.com/daily-co/daily-client-ios.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "15804ce495780da3ec2d05ab99736315f7bfbd24",
|
"revision" : "431938db25e5807120e89e2dc5bab1c076729f59",
|
||||||
"version" : "0.28.0"
|
"version" : "0.31.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -14,8 +15,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/pipecat-ai/pipecat-client-ios.git",
|
"location" : "https://github.com/pipecat-ai/pipecat-client-ios.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "c679512e367002a1a67da85d503fec72d9b17191",
|
"revision" : "f92b5e68e56a8311f7d8ead68a7a5674843cbc40",
|
||||||
"version" : "0.3.2"
|
"version" : "0.3.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -23,10 +24,10 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/pipecat-ai/pipecat-client-ios-daily/",
|
"location" : "https://github.com/pipecat-ai/pipecat-client-ios-daily/",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "a337fe6642c52376d2f90eafcb965f5be772ce72",
|
"revision" : "8f494da903192c22c367ecf9e51248c9b651fbc6",
|
||||||
"version" : "0.3.2"
|
"version" : "0.3.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"version" : 2
|
"version" : 3
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,10 +78,11 @@ class CallContainerModel: ObservableObject {
|
|||||||
self.saveCredentials(backendURL: baseUrl)
|
self.saveCredentials(backendURL: baseUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
|
||||||
func disconnect() {
|
func disconnect() {
|
||||||
self.rtviClientIOS?.disconnect(completion: nil)
|
Task { @MainActor in
|
||||||
self.rtviClientIOS?.release()
|
try await self.rtviClientIOS?.disconnect()
|
||||||
|
self.rtviClientIOS?.release()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func showError(message: String) {
|
func showError(message: String) {
|
||||||
|
|||||||
@@ -46,10 +46,6 @@ class SileroOnnxModel:
|
|||||||
path: Path to the ONNX model file.
|
path: Path to the ONNX model file.
|
||||||
force_onnx_cpu: Whether to force CPU execution provider.
|
force_onnx_cpu: Whether to force CPU execution provider.
|
||||||
"""
|
"""
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
global np
|
|
||||||
|
|
||||||
opts = onnxruntime.SessionOptions()
|
opts = onnxruntime.SessionOptions()
|
||||||
opts.inter_op_num_threads = 1
|
opts.inter_op_num_threads = 1
|
||||||
opts.intra_op_num_threads = 1
|
opts.intra_op_num_threads = 1
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class DebugLogObserver(BaseObserver):
|
|||||||
|
|
||||||
Log specific frame types from any source/destination::
|
Log specific frame types from any source/destination::
|
||||||
|
|
||||||
from pipecat.frames.frames import TranscriptionFrame, InterimTranscriptionFrame
|
from pipecat.frames.frames import LLMTextFrame, TranscriptionFrame
|
||||||
observers=[
|
observers=[
|
||||||
DebugLogObserver(frame_types=(LLMTextFrame,TranscriptionFrame,)),
|
DebugLogObserver(frame_types=(LLMTextFrame,TranscriptionFrame,)),
|
||||||
]
|
]
|
||||||
@@ -55,7 +55,8 @@ class DebugLogObserver(BaseObserver):
|
|||||||
Log frames with specific source/destination filters::
|
Log frames with specific source/destination filters::
|
||||||
|
|
||||||
from pipecat.frames.frames import StartInterruptionFrame, UserStartedSpeakingFrame, LLMTextFrame
|
from pipecat.frames.frames import StartInterruptionFrame, UserStartedSpeakingFrame, LLMTextFrame
|
||||||
from pipecat.transports.base_output_transport import BaseOutputTransport
|
from pipecat.observers.loggers.debug_log_observer import DebugLogObserver, FrameEndpoint
|
||||||
|
from pipecat.transports.base_output import BaseOutputTransport
|
||||||
from pipecat.services.stt_service import STTService
|
from pipecat.services.stt_service import STTService
|
||||||
|
|
||||||
observers=[
|
observers=[
|
||||||
|
|||||||
@@ -26,29 +26,6 @@ class GatedAggregator(FrameProcessor):
|
|||||||
until and not including the gate-closed frame. The aggregator maintains an
|
until and not including the gate-closed frame. The aggregator maintains an
|
||||||
internal gate state that controls whether frames are passed through immediately
|
internal gate state that controls whether frames are passed through immediately
|
||||||
or accumulated for later release.
|
or accumulated for later release.
|
||||||
|
|
||||||
Doctest: FIXME to work with asyncio
|
|
||||||
>>> from pipecat.frames.frames import ImageRawFrame
|
|
||||||
|
|
||||||
>>> async def print_frames(aggregator, frame):
|
|
||||||
... async for frame in aggregator.process_frame(frame):
|
|
||||||
... if isinstance(frame, TextFrame):
|
|
||||||
... print(frame.text)
|
|
||||||
... else:
|
|
||||||
... print(frame.__class__.__name__)
|
|
||||||
|
|
||||||
>>> aggregator = GatedAggregator(
|
|
||||||
... gate_close_fn=lambda x: isinstance(x, LLMResponseStartFrame),
|
|
||||||
... gate_open_fn=lambda x: isinstance(x, ImageRawFrame),
|
|
||||||
... start_open=False)
|
|
||||||
>>> asyncio.run(print_frames(aggregator, TextFrame("Hello")))
|
|
||||||
>>> asyncio.run(print_frames(aggregator, TextFrame("Hello again.")))
|
|
||||||
>>> asyncio.run(print_frames(aggregator, ImageRawFrame(image=bytes([]), size=(0, 0))))
|
|
||||||
ImageRawFrame
|
|
||||||
Hello
|
|
||||||
Hello again.
|
|
||||||
>>> asyncio.run(print_frames(aggregator, TextFrame("Goodbye.")))
|
|
||||||
Goodbye.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|||||||
@@ -23,20 +23,10 @@ class SentenceAggregator(FrameProcessor):
|
|||||||
Useful for ensuring downstream processors receive coherent, complete sentences
|
Useful for ensuring downstream processors receive coherent, complete sentences
|
||||||
rather than fragmented text.
|
rather than fragmented text.
|
||||||
|
|
||||||
Frame input/output:
|
Frame input/output::
|
||||||
|
|
||||||
TextFrame("Hello,") -> None
|
TextFrame("Hello,") -> None
|
||||||
TextFrame(" world.") -> TextFrame("Hello, world.")
|
TextFrame(" world.") -> TextFrame("Hello, world.")
|
||||||
|
|
||||||
Doctest: FIXME to work with asyncio
|
|
||||||
>>> import asyncio
|
|
||||||
>>> async def print_frames(aggregator, frame):
|
|
||||||
... async for frame in aggregator.process_frame(frame):
|
|
||||||
... print(frame.text)
|
|
||||||
|
|
||||||
>>> aggregator = SentenceAggregator()
|
|
||||||
>>> asyncio.run(print_frames(aggregator, TextFrame("Hello,")))
|
|
||||||
>>> asyncio.run(print_frames(aggregator, TextFrame(" world.")))
|
|
||||||
Hello, world.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|||||||
@@ -20,17 +20,6 @@ class VisionImageFrameAggregator(FrameProcessor):
|
|||||||
This aggregator waits for a consecutive TextFrame and an InputImageRawFrame.
|
This aggregator waits for a consecutive TextFrame and an InputImageRawFrame.
|
||||||
After the InputImageRawFrame arrives it will output a VisionImageRawFrame
|
After the InputImageRawFrame arrives it will output a VisionImageRawFrame
|
||||||
combining both the text and image data for multimodal processing.
|
combining both the text and image data for multimodal processing.
|
||||||
|
|
||||||
>>> from pipecat.frames.frames import ImageFrame
|
|
||||||
|
|
||||||
>>> async def print_frames(aggregator, frame):
|
|
||||||
... async for frame in aggregator.process_frame(frame):
|
|
||||||
... print(frame)
|
|
||||||
|
|
||||||
>>> aggregator = VisionImageFrameAggregator()
|
|
||||||
>>> asyncio.run(print_frames(aggregator, TextFrame("What do you see?")))
|
|
||||||
>>> asyncio.run(print_frames(aggregator, ImageFrame(image=bytes([]), size=(0, 0))))
|
|
||||||
VisionImageFrame, text: What do you see?, image size: 0x0, buffer size: 0 B
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|||||||
@@ -18,14 +18,6 @@ class StatelessTextTransformer(FrameProcessor):
|
|||||||
This processor intercepts TextFrame objects and applies a user-provided
|
This processor intercepts TextFrame objects and applies a user-provided
|
||||||
transformation function to the text content. The function can be either
|
transformation function to the text content. The function can be either
|
||||||
synchronous or asynchronous (coroutine).
|
synchronous or asynchronous (coroutine).
|
||||||
|
|
||||||
>>> async def print_frames(aggregator, frame):
|
|
||||||
... async for frame in aggregator.process_frame(frame):
|
|
||||||
... print(frame.text)
|
|
||||||
|
|
||||||
>>> aggregator = StatelessTextTransformer(lambda x: x.upper())
|
|
||||||
>>> asyncio.run(print_frames(aggregator, TextFrame("Hello")))
|
|
||||||
HELLO
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
|
|
||||||
"""Gemini File API client for uploading and managing files.
|
"""Gemini File API client for uploading and managing files.
|
||||||
|
|
||||||
This module provides the GeminiFileAPI class for interacting with Google's Gemini File API,
|
This module provides a client for Google's Gemini File API, enabling file
|
||||||
including uploading, fetching, listing, and deleting files that can be used with Gemini
|
uploads, metadata retrieval, listing, and deletion. Files uploaded through
|
||||||
generative models.
|
this API can be referenced in Gemini generative model calls.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import mimetypes
|
import mimetypes
|
||||||
|
|||||||
@@ -382,7 +382,14 @@ class GeminiMultimodalModalities(Enum):
|
|||||||
|
|
||||||
|
|
||||||
class GeminiMediaResolution(str, Enum):
|
class GeminiMediaResolution(str, Enum):
|
||||||
"""Media resolution options for Gemini Multimodal Live."""
|
"""Media resolution options for Gemini Multimodal Live.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
UNSPECIFIED: Use default resolution setting.
|
||||||
|
LOW: Low resolution with 64 tokens.
|
||||||
|
MEDIUM: Medium resolution with 256 tokens.
|
||||||
|
HIGH: High resolution with zoomed reframing and 256 tokens.
|
||||||
|
"""
|
||||||
|
|
||||||
UNSPECIFIED = "MEDIA_RESOLUTION_UNSPECIFIED" # Use default
|
UNSPECIFIED = "MEDIA_RESOLUTION_UNSPECIFIED" # Use default
|
||||||
LOW = "MEDIA_RESOLUTION_LOW" # 64 tokens
|
LOW = "MEDIA_RESOLUTION_LOW" # 64 tokens
|
||||||
@@ -499,7 +506,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
params: Configuration parameters for the model. Defaults to InputParams().
|
params: Configuration parameters for the model. Defaults to InputParams().
|
||||||
inference_on_context_initialization: Whether to generate a response when context
|
inference_on_context_initialization: Whether to generate a response when context
|
||||||
is first set. Defaults to True.
|
is first set. Defaults to True.
|
||||||
file_api_base_url: Base URL for the file API. Defaults to the official Gemini Live endpoint.
|
file_api_base_url: Base URL for the Gemini File API. Defaults to the official endpoint.
|
||||||
**kwargs: Additional arguments passed to parent LLMService.
|
**kwargs: Additional arguments passed to parent LLMService.
|
||||||
"""
|
"""
|
||||||
super().__init__(base_url=base_url, **kwargs)
|
super().__init__(base_url=base_url, **kwargs)
|
||||||
@@ -772,6 +779,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
await self._ws_send(event.model_dump(exclude_none=True))
|
await self._ws_send(event.model_dump(exclude_none=True))
|
||||||
|
|
||||||
async def _connect(self):
|
async def _connect(self):
|
||||||
|
"""Establish WebSocket connection to Gemini Live API."""
|
||||||
if self._websocket:
|
if self._websocket:
|
||||||
# Here we assume that if we have a websocket, we are connected. We
|
# Here we assume that if we have a websocket, we are connected. We
|
||||||
# handle disconnections in the send/recv code paths.
|
# handle disconnections in the send/recv code paths.
|
||||||
@@ -876,6 +884,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
self._websocket = None
|
self._websocket = None
|
||||||
|
|
||||||
async def _disconnect(self):
|
async def _disconnect(self):
|
||||||
|
"""Disconnect from Gemini Live API and clean up resources."""
|
||||||
logger.info("Disconnecting from Gemini service")
|
logger.info("Disconnecting from Gemini service")
|
||||||
try:
|
try:
|
||||||
self._disconnecting = True
|
self._disconnecting = True
|
||||||
@@ -892,6 +901,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
logger.error(f"{self} error disconnecting: {e}")
|
logger.error(f"{self} error disconnecting: {e}")
|
||||||
|
|
||||||
async def _ws_send(self, message):
|
async def _ws_send(self, message):
|
||||||
|
"""Send a message to the WebSocket connection."""
|
||||||
# logger.debug(f"Sending message to websocket: {message}")
|
# logger.debug(f"Sending message to websocket: {message}")
|
||||||
try:
|
try:
|
||||||
if self._websocket:
|
if self._websocket:
|
||||||
@@ -912,6 +922,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
#
|
#
|
||||||
|
|
||||||
async def _receive_task_handler(self):
|
async def _receive_task_handler(self):
|
||||||
|
"""Handle incoming messages from the WebSocket connection."""
|
||||||
async for message in WatchdogAsyncIterator(self._websocket, manager=self.task_manager):
|
async for message in WatchdogAsyncIterator(self._websocket, manager=self.task_manager):
|
||||||
evt = events.parse_server_event(message)
|
evt = events.parse_server_event(message)
|
||||||
# logger.debug(f"Received event: {message[:500]}")
|
# logger.debug(f"Received event: {message[:500]}")
|
||||||
@@ -940,6 +951,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
#
|
#
|
||||||
|
|
||||||
async def _send_user_audio(self, frame):
|
async def _send_user_audio(self, frame):
|
||||||
|
"""Send user audio frame to Gemini Live API."""
|
||||||
if self._audio_input_paused:
|
if self._audio_input_paused:
|
||||||
return
|
return
|
||||||
# Send all audio to Gemini
|
# Send all audio to Gemini
|
||||||
@@ -956,6 +968,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
self._user_audio_buffer = self._user_audio_buffer[-length:]
|
self._user_audio_buffer = self._user_audio_buffer[-length:]
|
||||||
|
|
||||||
async def _send_user_video(self, frame):
|
async def _send_user_video(self, frame):
|
||||||
|
"""Send user video frame to Gemini Live API."""
|
||||||
if self._video_input_paused:
|
if self._video_input_paused:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -969,6 +982,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
await self.send_client_event(evt)
|
await self.send_client_event(evt)
|
||||||
|
|
||||||
async def _create_initial_response(self):
|
async def _create_initial_response(self):
|
||||||
|
"""Create initial response based on context history."""
|
||||||
if not self._api_session_ready:
|
if not self._api_session_ready:
|
||||||
self._run_llm_when_api_session_ready = True
|
self._run_llm_when_api_session_ready = True
|
||||||
return
|
return
|
||||||
@@ -994,6 +1008,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
self._needs_turn_complete_message = True
|
self._needs_turn_complete_message = True
|
||||||
|
|
||||||
async def _create_single_response(self, messages_list):
|
async def _create_single_response(self, messages_list):
|
||||||
|
"""Create a single response from a list of messages."""
|
||||||
# Refactor to combine this logic with same logic in GeminiMultimodalLiveContext
|
# Refactor to combine this logic with same logic in GeminiMultimodalLiveContext
|
||||||
messages = []
|
messages = []
|
||||||
for item in messages_list:
|
for item in messages_list:
|
||||||
@@ -1046,6 +1061,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
|
|
||||||
@traced_gemini_live(operation="llm_tool_result")
|
@traced_gemini_live(operation="llm_tool_result")
|
||||||
async def _tool_result(self, tool_result_message):
|
async def _tool_result(self, tool_result_message):
|
||||||
|
"""Send tool result back to the API."""
|
||||||
# For now we're shoving the name into the tool_call_id field, so this
|
# For now we're shoving the name into the tool_call_id field, so this
|
||||||
# will work until we revisit that.
|
# will work until we revisit that.
|
||||||
id = tool_result_message.get("tool_call_id")
|
id = tool_result_message.get("tool_call_id")
|
||||||
@@ -1071,6 +1087,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
|
|
||||||
@traced_gemini_live(operation="llm_setup")
|
@traced_gemini_live(operation="llm_setup")
|
||||||
async def _handle_evt_setup_complete(self, evt):
|
async def _handle_evt_setup_complete(self, evt):
|
||||||
|
"""Handle the setup complete event."""
|
||||||
# If this is our first context frame, run the LLM
|
# If this is our first context frame, run the LLM
|
||||||
self._api_session_ready = True
|
self._api_session_ready = True
|
||||||
# Now that we've configured the session, we can run the LLM if we need to.
|
# Now that we've configured the session, we can run the LLM if we need to.
|
||||||
@@ -1079,6 +1096,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
await self._create_initial_response()
|
await self._create_initial_response()
|
||||||
|
|
||||||
async def _handle_evt_model_turn(self, evt):
|
async def _handle_evt_model_turn(self, evt):
|
||||||
|
"""Handle the model turn event."""
|
||||||
part = evt.serverContent.modelTurn.parts[0]
|
part = evt.serverContent.modelTurn.parts[0]
|
||||||
if not part:
|
if not part:
|
||||||
return
|
return
|
||||||
@@ -1120,6 +1138,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
|
|
||||||
@traced_gemini_live(operation="llm_tool_call")
|
@traced_gemini_live(operation="llm_tool_call")
|
||||||
async def _handle_evt_tool_call(self, evt):
|
async def _handle_evt_tool_call(self, evt):
|
||||||
|
"""Handle tool call events."""
|
||||||
function_calls = evt.toolCall.functionCalls
|
function_calls = evt.toolCall.functionCalls
|
||||||
if not function_calls:
|
if not function_calls:
|
||||||
return
|
return
|
||||||
@@ -1140,6 +1159,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
|
|
||||||
@traced_gemini_live(operation="llm_response")
|
@traced_gemini_live(operation="llm_response")
|
||||||
async def _handle_evt_turn_complete(self, evt):
|
async def _handle_evt_turn_complete(self, evt):
|
||||||
|
"""Handle the turn complete event."""
|
||||||
self._bot_is_speaking = False
|
self._bot_is_speaking = False
|
||||||
text = self._bot_text_buffer
|
text = self._bot_text_buffer
|
||||||
|
|
||||||
@@ -1223,6 +1243,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def _handle_evt_output_transcription(self, evt):
|
async def _handle_evt_output_transcription(self, evt):
|
||||||
|
"""Handle the output transcription event."""
|
||||||
if not evt.serverContent.outputTranscription:
|
if not evt.serverContent.outputTranscription:
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -1241,6 +1262,7 @@ class GeminiMultimodalLiveLLMService(LLMService):
|
|||||||
await self.push_frame(TTSTextFrame(text=text))
|
await self.push_frame(TTSTextFrame(text=text))
|
||||||
|
|
||||||
async def _handle_evt_usage_metadata(self, evt):
|
async def _handle_evt_usage_metadata(self, evt):
|
||||||
|
"""Handle the usage metadata event."""
|
||||||
if not evt.usageMetadata:
|
if not evt.usageMetadata:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -25,15 +25,6 @@ def obj_id() -> int:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A unique integer identifier that increments globally across all objects.
|
A unique integer identifier that increments globally across all objects.
|
||||||
|
|
||||||
Examples::
|
|
||||||
|
|
||||||
>>> obj_id()
|
|
||||||
0
|
|
||||||
>>> obj_id()
|
|
||||||
1
|
|
||||||
>>> obj_id()
|
|
||||||
2
|
|
||||||
"""
|
"""
|
||||||
with _ID_LOCK:
|
with _ID_LOCK:
|
||||||
return next(_ID)
|
return next(_ID)
|
||||||
@@ -47,16 +38,6 @@ def obj_count(obj) -> int:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A unique integer count that increments per class type.
|
A unique integer count that increments per class type.
|
||||||
|
|
||||||
Examples::
|
|
||||||
|
|
||||||
>>> obj_count(object())
|
|
||||||
0
|
|
||||||
>>> obj_count(object())
|
|
||||||
1
|
|
||||||
>>> new_type = type('NewType', (object,), {})
|
|
||||||
>>> obj_count(new_type())
|
|
||||||
0
|
|
||||||
"""
|
"""
|
||||||
with _COUNTS_LOCK:
|
with _COUNTS_LOCK:
|
||||||
return next(_COUNTS[obj.__class__.__name__])
|
return next(_COUNTS[obj.__class__.__name__])
|
||||||
|
|||||||
Reference in New Issue
Block a user