Gemini Live API جریانهای پیوسته صدا یا نوشتار را که جلسه نامیده میشود پردازش میکند. میتوانید چرخه حیات جلسه را از دستدهی اولیه تا پایان موفقیتآمیز مدیریت کنید.
محدودیتهای جلسات
برای Live API، جلسه به اتصال پایداری اشاره دارد که در آن ورودی و خروجی بهطور مداوم ازطریق اتصال جاری میشوند.
اگر جلسه از هرکدام از محدودیتهای زیر فراتر برود، اتصال قطع میشود. بااینحال، توجه داشته باشید که Live API گزینههایی (در زیر ببینید) برای مدیریت این محدودیتهای مربوط به جلسه ارائه میدهد.
پنجره بافت جلسه به ۱۲۸ هزار دادهواحد محدود است.
بهدلیل این محدودیت پنجره بافت، حداکثر طول تقریبی جلسه براساس روشهای ورودی در اینجا آمده است:
- جلسههای ورودی فقط صوتی به
۱۵ دقیقه محدود است. - ورودی ویدیو + صدا به
۲ دقیقه محدود است.
- جلسههای ورودی فقط صوتی به
طول اتصال به حدود
۱۰ دقیقه محدود است.حدود
۶۰ ثانیه قبلاز پایان اتصال، اعلان قطع شدن دریافت خواهید کرد.
در اینجا چند گزینه برای مدیریت محدودیتهای مربوط به جلسه ارائه شده است:
پنجره بافت جلسه را فشرده کنید تا سرور بهطور خودکار اندازه بافت را در حد مجاز نگه دارد.
ازسر گرفتن جلسه برای جلوگیری از دست رفتن بافت مکالمه درطول قطع شدنهای کوتاه شبکه یا پساز دریافت اعلان رفتن.
شروع کردن جلسه
برای مشاهده قطعه کد کامل نحوه شروع جلسه، به راهنمای شروع به کار برای Live API مراجعه کنید.
بهروزرسانی در اواسط جلسه
مدلهای Live API از قابلیتهای پیشرفته زیر برای بهروزرسانیهای میانجلسهای پشتیبانی میکنند:
بهروزرسانی دستورالعملهای سیستم (فقط برای Agent Platform Gemini API (formerly Vertex AI))
افزودن بهروزرسانیهای محتوای افزایشی
میتوانید درطول جلسه فعال، بهروزرسانیهای افزایشی اضافه کنید. از این برای ارسال ورودی نوشتاری، ایجاد بافت جلسه، یا بازیابی بافت جلسه استفاده کنید.
برای بافتهای طولانیتر، توصیه میکنیم خلاصه یک پیام را ارائه دهید تا پنجره بافت برای تعاملات بعدی آزاد شود.
برای زمینههای کوتاه، میتوانید تعاملات گامبهگام را ارسال کنید تا توالی دقیق رویدادها را نشان دهید، مانند قطعه کد زیر.
Swift
// Define initial turns (history/context).
let turns: [ModelContent] = [
ModelContent(role: "user", parts: [TextPart("What is the capital of France?")]),
ModelContent(role: "model", parts: [TextPart("Paris")]),
]
// Send history, keeping the conversational turn OPEN (false).
await session.sendContent(turns, turnComplete: false)
// Define the new user query.
let newTurn: [ModelContent] = [
ModelContent(role: "user", parts: [TextPart("What is the capital of Germany?")]),
]
// Send the final query, CLOSING the turn (true) to trigger the model response.
await session.sendContent(newTurn, turnComplete: true)
Kotlin
// Define initial turns (history/context).
val turns = listOf(
content("user") {
text("What is the capital of France?")
},
content("model") {
text("Paris")
}
)
// Send history, keeping the conversational turn OPEN (false).
turns.forEach {
session.send(
content = it,
turnComplete = false
)
}
// Define the new user query.
val newTurn = content("user") {
text("What is the capital of Germany?")
}
// Send the final query, CLOSING the turn (true) to trigger the model response.
session.send(
content = newTurn,
turnComplete = true
)
Java
// Define initial turns (history/context).
List turns =
Arrays.asList(
new Content.Builder().setRole("user").addText("What is the capital of France?").build(),
new Content.Builder().setRole("model").addText("Paris").build());
for (Content turn : turns) {
session.send(
turn,
false // turnComplete: false
);
}
// Define the new user query.
Content newTurn = new Content.Builder().addText("What is the capital of Germany?").build();
// Send the final query, CLOSING the turn (true) to trigger the model response.
session.send(
newTurn,
true // isTurnComplete: true
);
Web
const turns = [{ type: "text", text: "Hello from the user!" }];
await session.send(
turns,
false // turnComplete: false
);
console.log("Sent history. Waiting for next input...");
// Define the new user query.
const newTurn = [{ type: "text", text: "And what is the capital of Germany?" }];
// Send the final query, CLOSING the turn (true) to trigger the model response.
await session.send(
newTurn,
true // turnComplete: true
);
console.log("Sent final query. Model response expected now.");
Dart
// Define initial turns (history/context).
final List turns = [
Content(
"user",
[TextPart("What is the capital of France?")],
),
Content(
"model",
[TextPart("Paris")],
),
];
// Send history, keeping the conversational turn OPEN (false).
await session.send(
input: turns,
turnComplete: false,
);
// Define the new user query.
final List newTurn = [
Content(
"user",
[TextPart("What is the capital of Germany?")],
),
];
// Send the final query, CLOSING the turn (true) to trigger the model response.
await session.send(
input: newTurn,
turnComplete: true,
);
Unity
// Define initial turns (history/context).
List turns = new List {
new ModelContent("user", new ModelContent.TextPart("What is the capital of France?") ),
new ModelContent("model", new ModelContent.TextPart("Paris") ),
};
// Send history, keeping the conversational turn OPEN (false).
foreach (ModelContent turn in turns)
{
await session.SendAsync(
content: turn,
turnComplete: false
);
}
// Define the new user query.
ModelContent newTurn = ModelContent.Text("What is the capital of Germany?");
// Send the final query, CLOSING the turn (true) to trigger the model response.
await session.SendAsync(
content: newTurn,
turnComplete: true
);
بهروزرسانی دستورالعملهای سیستم در اواسط جلسه
| فقط هنگام استفاده از Agent Platform Gemini API (formerly Vertex AI) بهعنوان ارائهدهنده API دردسترس است. |
میتوانید دستورالعملهای سیستم را درطول جلسه فعال بهروز کنید. از این مورد برای تطبیق پاسخهای مدل استفاده کنید، برای مثال برای تغییر زبان پاسخ یا اصلاح لحن.
برای بهروزرسانی دستورالعملهای سیستم در اواسط جلسه، میتوانید محتوای نوشتاری را با
نقش system ارسال کنید. دستورالعملهای بهروزشده سیستم برای باقیمانده جلسه فعال خواهد ماند.
Swift
await session.sendContent(
[ModelContent(
role: "system",
parts: [TextPart("new system instruction")]
)],
turnComplete: false
)
Kotlin
// In a coroutine scope
session.send(
content = content("system") {
text("new system instruction")
},
turnComplete = false
)
Java
session.send(
new Content.Builder()
.setRole("system")
.addText("new system instruction")
.build(),
/* turnComplete: */ false
);
Web
Not yet supported for Web apps - check back soon!
Dart
try {
await _session.send(
input: Content(
'system',
[TextPart('new system instruction')],
),
turnComplete: false,
);
} catch (e) {
print('Failed to update system instructions: $e');
}
Unity
try
{
await session.SendAsync(
content: new ModelContent(
"system",
new ModelContent.TextPart("new system instruction")
),
turnComplete: false
);
}
catch (Exception e)
{
Debug.LogError($"Failed to update system instructions: {e.Message}");
}
سیگنالدهی دستی فعالیت کاربر
بهطور پیشفرض، Live API بااستفاده از تشخیص فعالیت گفتاری (VAD) بهطور خودکار شروع و پایان گفتار کاربر را تشخیص میدهد، که به شما امکان میدهد در هر زمان در مدل وقفه ایجاد کنید (با نحوه مدیریت وقفهها آشنا شوید).
بااینحال، میتوانید با غیرفعال کردن تشخیص خودکار فعالیت گفتاری (VAD)، کنترل کامل نوبتهای مکالمه را بهصورت دستی (مثلاً برای رابط فشار دادن برای صحبت) در دست بگیرید.
اگر VAD را غیرفعال کنید، سرور بهطور خودکار گفتار کاربر را شناسایی نمیکند یا پاسخها را براساس سکوت صوتی راهاندازی نمیکند. در این سناریو، باید بهطور دستی مرزهای هر نوبت فعالیت کاربر را مشخص کنید.
با نحوه غیرفعال کردن تشخیص خودکار فعالیت گفتاری (VAD) و علامتدهی دستی فعالیت کاربر آشنا شوید.
فشردهسازی پنجره بافت
|
روی ارائهدهنده Gemini API کلیک کنید تا محتوا و کد مختص ارائهدهنده را در این صفحه ببینید. |
Live API پنجره بافت جلسه دادههای جاریسازیشده همزمان (۲۵ دادهواحد در ثانیه (TPS) برای صدا و ۲۵۸ دادهواحد در ثانیه برای ویدیو) و همچنین محتوای دیگر، ازجمله ورودیهای نوشتاری و بروندادهای مدل را ذخیره میکند. همه مدلهای Live API حد مجاز پنجره بافت جلسه ۱۲۸ هزار دادهواحد دارند.
بهطور پیشفرض، بهدلیل این محدودیت پنجره بافت، حداکثر طول تقریبی جلسه براساس روشهای ورودی در اینجا آمده است:
- جلسههای ورودی فقط صوتی به
۱۵ دقیقه محدود است. - ورودی ویدیو + صدا به
۲ دقیقه محدود است.
در جلسههای طولانی، با پیشرفت مکالمه، سابقه نشانهای صوتی و/یا ویدیویی انباشته میشود. اگر این سابقه از حد مدل فراتر رود، ممکن است مدل دچار کژپنداری شود، سرعتش کاهش یابد، یا جلسه بهاجبار پایان یابد.
برای فعال کردن جلسههای طولانیتر، میتوانید فشردهسازی پنجره بافت را با تنظیم فیلد contextWindowCompression بهعنوان بخشی از LiveGenerationConfig فعال کنید. وقتی فعال باشد، سرور از سازوکار پنجره لغزان استفاده میکند تا بهطور خودکار قدیمیترین نوبتها را دور بیندازد یا آنها را خلاصه کند تا اندازه بافت را در محدوده پیشفرض یا مشخصشده حفظ کند. دستورالعملهای سیستم دور انداخته نمیشوند و همیشه در ابتدای پنجره زمینه باقی میمانند.
از دیدگاه کاربر، این کار ازنظر تئوری امکان مدت زمان جلسه نامحدود را فراهم میکند زیرا «حافظه» بهطور مداوم مدیریت میشود.
میتوانید سازوکار پنجره لغزان و همچنین بهصورت اختیاری تعداد نشانههایی را که باعث فشردهسازی میشوند پیکربندی کنید: (تنظیمات و مقادیر موجود را در زیر ببینید). در اینجا چند نکته مهم درباره استفاده از این تنظیمات آورده شده است:
تنظیم
targetTokensروی مقدار بسیار کم، فضای بافت بیشتری را برای جاریسازیهای مداوم آزاد میکند، اما مدل بهسرعت نوبتهای قدیمیتر مکالمه را «فراموش» خواهد کرد.تنظیم
targetTokensنزدیکتر بهtriggerTokensحافظه بیشتری را حفظ میکند اما روالهای فشردهسازی را بسیار بیشتر فعال میکند.
| تنظیم | پیشفرض برای پنجره لغزنده اگر در پیکربندی تنظیم نشده باشد | حداقل مقدار | بیشترین مقدار |
|---|---|---|---|
triggerTokensطول بافت قبلاز راهاندازی فشردهسازی |
٪۸۰ از حد مجاز پنجره بافت مدل | ۵٬۰۰۰ | ۱۲۸٬۰۰۰ |
targetTokensتعداد هدف از کدهای حفظشده |
٪۵۰ از مقدار triggerTokens
|
0 | ۱۲۸٬۰۰۰ |
Swift
// ...
let liveModel = FirebaseAI.firebaseAI(backend: .googleAI()).liveModel(
modelName: "GEMINI_LIVE_API_MODEL_NAME",
// Enable context window compression.
// (Optional) Configure the number of tokens in the context window that triggers the compression.
generationConfig: LiveGenerationConfig(
responseModalities: [.audio],
contextWindowCompression: ContextWindowCompressionConfig(
triggerTokens: 10000,
slidingWindow: SlidingWindow(
targetTokens: 2000,
)
)
)
)
Kotlin
// ...
val liveModel = Firebase.ai(backend = GenerativeBackend.googleAI()).liveModel(
modelName = "GEMINI_LIVE_API_MODEL_NAME",
// Enable context window compression.
// (Optional) Configure the number of tokens in the context window that triggers the compression.
generationConfig = liveGenerationConfig {
responseModality = ResponseModality.AUDIO,
contextWindowCompression = ContextWindowCompressionConfig(
triggerTokens = 10000,
slidingWindow = SlidingWindow(targetTokens = 2000)
)
}
)
Java
// ...
LiveGenerativeModel lm = FirebaseAI.getInstance(GenerativeBackend.googleAI()).liveModel(
"GEMINI_LIVE_API_MODEL_NAME",
// Enable context window compression.
// (Optional) Configure the number of tokens in the context window that triggers the compression.
new LiveGenerationConfig.Builder()
.setResponseModality(ResponseModality.AUDIO)
.setContextWindowCompression(
new ContextWindowCompressionConfig(10000, new SlidingWindow(2000))
)
.build()
);
Web
// ...
const ai = getAI(firebaseApp, { backend: new GoogleAIBackend() });
const liveModel = getLiveGenerativeModel(ai, {
model: "GEMINI_LIVE_API_MODEL_NAME",
// Enable context window compression.
// (Optional) Configure the number of tokens in the context window that triggers the compression.
generationConfig: {
responseModalities: [ResponseModality.AUDIO],
contextWindowCompression: {
triggerTokens: 10000,
slidingWindow: {
targetTokens: 2000,
},
},
},
});
Dart
// ...
final _liveModel = FirebaseAI.googleAI().liveGenerativeModel(
model: 'GEMINI_LIVE_API_MODEL_NAME',
// Enable context window compression.
// (Optional) Configure the number of tokens in the context window that triggers the compression.
liveGenerationConfig: LiveGenerationConfig(
responseModalities: [ResponseModalities.audio],
contextWindowCompression: ContextWindowCompressionConfig(
triggerTokens: 10000,
slidingWindow: SlidingWindow(targetTokens: 2000),
),
),
);
Unity
// ...
var liveModel = FirebaseAI.GetInstance(FirebaseAI.Backend.GoogleAI()).GetLiveModel(
modelName: "GEMINI_LIVE_API_MODEL_NAME",
// Enable context window compression.
// (Optional) Configure the number of tokens in the context window that triggers the compression.
liveGenerationConfig: new LiveGenerationConfig(
responseModalities: new[] { ResponseModality.Audio },
contextWindowCompression: new ContextWindowCompressionConfig(
triggerTokens: 10000,
slidingWindow: new SlidingWindow(targetTokens: 2000)
)
)
);
تشخیص زمان پایان جلسه
حداکثر مدت یک اتصال WebSocket تکی و پیوسته حدود
مثال زیر نشان میدهد که چگونه میتوان با گوش دادن به اعلان going away، قطع اتصال قریبالوقوع را تشخیص داد:
Swift
for try await response in session.responses {
switch response.payload {
case .goingAwayNotice(let goingAwayNotice):
// Prepare for the session to close soon
if let timeLeft = goingAwayNotice.timeLeft {
print("Server going away in \(timeLeft) seconds")
}
}
}
Kotlin
for (response in session.responses) {
when (val message = response.payload) {
is LiveServerGoAway -> {
// Prepare for the session to close soon
val remaining = message.timeLeft
logger.info("Server going away in $remaining")
}
}
}
Java
session.getResponses().forEach(response -> {
if (response.getPayload() instanceof LiveServerResponse.GoingAwayNotice) {
LiveServerResponse.GoingAwayNotice notice = (LiveServerResponse.GoingAwayNotice) response.getPayload();
// Prepare for the session to close soon
Duration timeLeft = notice.getTimeLeft();
}
});
Web
for await (const message of session.receive()) {
switch (message.type) {
...
case "goingAwayNotice":
console.log("Server going away. Time left:", message.timeLeft);
break;
}
}
Dart
Future _handleLiveServerMessage(LiveServerResponse response) async {
final message = response.message;
if (message is GoingAwayNotice) {
// Prepare for the session to close soon
developer.log('Server going away. Time left: ${message.timeLeft}');
}
}
Unity
foreach (var response in session.Responses) {
if (response.Payload is LiveSessionGoingAway notice) {
// Prepare for the session to close soon
TimeSpan timeLeft = notice.TimeLeft;
Debug.Log($"Server going away notice received. Remaining: {timeLeft}");
}
}
ازسر گرفتن جلسه
Live API از ازسرگیری جلسه پشتیبانی میکند تا از دست رفتن بافت مکالمه جلوگیری شود. هر جلسه یک دسته دارد و میتوان از آن به روشهای زیر استفاده کرد:
حفظ جلسه قبلاز رسیدن به محدودیت زمانی اتصال
حداکثر مدت یک اتصال WebSocket تکی و پیوسته حدود
۱۰ دقیقه است. میتوانید با گوش دادن به اعلان درحال رفتن، تشخیص دهید که اتصال چه زمانی درحال پایان یافتن است و سپس با ایجاد اتصال جدید بااستفاده از شناسه جلسه، جلسه را تمدید کنید.ازسر گرفتن جلسه بلافاصله پساز قطع اتصال
اگر اتصالی قبلاز حداکثر محدودیت زمانی اتصال قطع شود یا ازبین برود (برای مثال، جابهجایی از Wi-Fi به 5G)، سرور وضعیت جلسه را برای حدود
۱۰ دقیقه حفظ میکند. درطول این پنجره، میتوانید با ایجاد اتصال جدید بااستفاده از شناسه جلسه، جلسه را ازسر بگیرید.ازسر گرفتن جلسه پساز یک دوره زمانی طولانی
پساز پایان اتصال، سرور وضعیت جلسه را برای چند ساعت نگه میدارد. درطول این پنجره، میتوانید با ایجاد اتصال جدید بااستفاده از شناسه جلسه، جلسه را ازسر بگیرید. توجه داشته باشید که این پنجره برای دو ارائهدهنده Gemini API متفاوت است: Gemini Developer API
۲ ساعت است | Agent Platform Gemini API (formerly Vertex AI)۲۴ ساعت است.
بهطور پیشفرض، ازسرگیری جلسه غیرفعال است. برای فعال کردن ازسرگیری جلسه، هنگام برقراری اتصال جدید، پیکربندی ازسرگیری خالی را ارسال کنید. وقتی فعال باشد، سرور بهطور دورهای بهروزرسانیهایی حاوی دسته ازسرگیری جلسه ارسال میکند. اگر اتصال جلسه قطع شود، میتوانید دوباره متصل شوید و این دسته را ارسال کنید تا جلسه با بافت دستنخوردهاش ازسر گرفته شود.
مثالهای زیر دو گزینه برای ازسر گرفتن جلسه نشان میدهد:
Swift
// Local variable to save the active session handle
var activeSessionHandle: String?
// Initialize the session. Passing an empty config requests the server to send SessionResumptionUpdate
var session = try await liveModel.connect(
sessionResumption: SessionResumptionConfig()
)
// Start receiving responses
for try await message in session.responses {
// Check for new session handles inside your message handling loop
switch message.payload {
case let .sessionResumptionUpdate(updateMessage):
guard let newHandle = updateMessage.newHandle, updateMessage.resumable else {
continue
}
activeSessionHandle = newHandle
print("SessionResumptionUpdate: handle \(newHandle)")
// ... handle other LiveServerMessage types ...
default:
break
}
}
// The following are alternative options to resume a session. Choose only one.
// Option 1: Create and connect a session to resume with the saved handle
if let handle = activeSessionHandle {
session = try await liveModel.connect(
sessionResumption: SessionResumptionConfig(handle: handle)
)
}
// Option 2: Resume the session directly on an existing session object
if let handle = activeSessionHandle {
try await session.resumeSession(
sessionResumption: SessionResumptionConfig(handle: handle)
)
}
Kotlin
// Local variable to save the active session handle
var activeSessionHandle: String? = null
// Initialize the session. Passing an empty config requests the server to send SessionResumptionUpdate
var session = liveModel.connect(
sessionResumption = SessionResumptionConfig()
)
// Start receiving responses
session.receive().collect { message ->
// Process other received response types...
// Check for new session handles inside your message handling loop
if (message is LiveSessionResumptionUpdate) {
if (message.resumable == true && message.newHandle != null) {
activeSessionHandle = message.newHandle
Log.d("TAG", "SessionResumptionUpdate: handle ${message.newHandle}")
}
}
}
// The following are alternative options to resume a session. Choose only one.
// Option 1: Create and connect a session to resume with the saved handle
activeSessionHandle?.let { handle ->
session = liveModel.connect(
sessionResumption = SessionResumptionConfig(handle = handle)
)
}
// Option 2: Resume the session directly on an existing session object
activeSessionHandle?.let { handle ->
session.resumeSession(
sessionResumption = SessionResumptionConfig(handle = handle)
)
}
Java
For Java, session resumption is not yet supported. Check back soon!
Web
// Local variable to save the active session handle
let activeSessionHandle = null;
// Initialize the session. Passing an empty object requests the server to send SessionResumptionUpdate
let session = await liveModel.connect({});
// Start receiving responses
for await (const message of session.receive()) {
// Process other received response types...
// Check for new session handles inside your message handling loop
if (message.type === 'sessionResumptionUpdate') {
if (message.resumable && message.newHandle) {
activeSessionHandle = message.newHandle;
console.log(`SessionResumptionUpdate: handle ${activeSessionHandle}`);
}
}
}
// The following are alternative options to resume a session. Choose only one.
// Option 1: Create and connect a session to resume with the saved handle
if (activeSessionHandle) {
session = await liveModel.connect({
handle: activeSessionHandle
});
}
// Option 2: Resume the session directly on an existing session object
if (activeSessionHandle) {
await session.resumeSession({
handle: activeSessionHandle
});
}
Dart
// Local variable to save the active session handle
String? _activeSessionHandle;
// Initialize the session. Passing an empty config requests the server to send SessionResumptionUpdate
var _session = await _liveModel.connect(
sessionResumption: SessionResumptionConfig(),
);
// Start receiving responses
await for (final response in _session.receive()) {
// Process other received response types...
// Check for new session handles inside your message handling loop
final message = response.message;
if (message is SessionResumptionUpdate &&
message.resumable != null &&
message.resumable!) {
_activeSessionHandle = message.newHandle;
log('SessionResumptionUpdate: handle ${message.newHandle}');
}
}
// The following are alternative options to resume a session. Choose only one.
// Option 1: Create and connect a session to resume with the saved handle
if (_activeSessionHandle != null) {
_session = await _liveModel.connect(
sessionResumption: SessionResumptionConfig.resume(_activeSessionHandle!),
);
}
// Option 2: Alternatively, resume the session directly on an existing session object
if (_activeSessionHandle != null) {
await _session.resumeSession(
sessionResumption: SessionResumptionConfig.resume(_activeSessionHandle!),
);
}
Unity
// Local variable to save the active session handle
string activeSessionHandle = null;
// Initialize the session. Passing an empty config requests the server to send SessionResumptionUpdate
var session = await liveModel.ConnectAsync(
sessionResumption: new SessionResumptionConfig()
);
// Start receiving responses
await foreach (var response in session.ReceiveAsync())
{
// Process other received response types...
// Check for new session handles inside your message handling loop
if (response.Message is LiveSessionResumptionUpdate updateMessage)
{
if (updateMessage.Resumable == true && !string.IsNullOrEmpty(updateMessage.NewHandle))
{
activeSessionHandle = updateMessage.NewHandle;
Debug.Log($"SessionResumptionUpdate: handle {activeSessionHandle}");
}
}
}
// The following are alternative options to resume a session. Choose only one.
// Option 1: Create and connect a session to resume with the saved handle
if (!string.IsNullOrEmpty(activeSessionHandle)) {
session = await liveModel.ConnectAsync(
sessionResumption: new SessionResumptionConfig(activeSessionHandle)
);
}
// Option 2: Resume the session directly on an existing session object
if (!string.IsNullOrEmpty(activeSessionHandle)) {
await session.ResumeSessionAsync(
sessionResumption: new SessionResumptionConfig(activeSessionHandle)
);
}