Multimodal Live API ช่วยให้สามารถโต้ตอบด้วยเสียงและวิดีโอแบบ 2 ทิศทางที่มีเวลาในการตอบสนองต่ำกับ Gemini การใช้ Multimodal Live API ช่วยให้คุณมอบประสบการณ์การสนทนาด้วยเสียงที่เหมือนมนุษย์และเป็นธรรมชาติให้แก่ผู้ใช้ปลายทาง รวมถึงสามารถขัดจังหวะคำตอบของโมเดลได้โดยใช้คำสั่งเสียง โมเดลนี้สามารถประมวลผลอินพุตข้อความ เสียง และวิดีโอ รวมถึงให้เอาต์พุตข้อความและเสียง
คุณลองใช้ Multimodal Live API ได้ใน Google AI Studio
ใช้ Multimodal Live API
ส่วนนี้จะอธิบายวิธีใช้ Multimodal Live API กับ SDK ของเรา ดูข้อมูลเพิ่มเติมเกี่ยวกับ WebSockets API พื้นฐานได้ที่ข้อมูลอ้างอิง WebSockets API ด้านล่าง
ส่งและรับข้อความ
import asyncio
from google import genai
client = genai.Client(api_key="GEMINI_API_KEY", http_options={'api_version': 'v1alpha'})
model = "gemini-2.0-flash-exp"
config = {"response_modalities": ["TEXT"]}
async def main():
async with client.aio.live.connect(model=model, config=config) as session:
while True:
message = input("User> ")
if message.lower() == "exit":
break
await session.send(input=message, end_of_turn=True)
async for response in session.receive():
if response.text is not None:
print(response.text, end="")
if __name__ == "__main__":
asyncio.run(main())
รับเสียง
ตัวอย่างต่อไปนี้แสดงวิธีรับข้อมูลเสียงและเขียนลงในไฟล์ .wav
import asyncio
import wave
from google import genai
client = genai.Client(api_key="GEMINI_API_KEY", http_options={'api_version': 'v1alpha'})
model = "gemini-2.0-flash-exp"
config = {"response_modalities": ["AUDIO"]}
async def main():
async with client.aio.live.connect(model=model, config=config) as session:
wf = wave.open("audio.wav", "wb")
wf.setnchannels(1)
wf.setsampwidth(2)
wf.setframerate(24000)
message = "Hello? Gemini are you there?"
await session.send(input=message, end_of_turn=True)
async for idx,response in async_enumerate(session.receive()):
if response.data is not None:
wf.writeframes(response.data)
# Comment this out to print audio data info
# if response.server_content.model_turn is not None:
# print(response.server_content.model_turn.parts[0].inline_data.mime_type)
wf.close()
if __name__ == "__main__":
asyncio.run(main())
รูปแบบเสียง
Multimodal Live API รองรับรูปแบบเสียงต่อไปนี้
- รูปแบบเสียงอินพุต: เสียง PCM 16 บิตดิบที่ 16kHz แบบ Little-endian
- รูปแบบเสียงเอาต์พุต: เสียง PCM 16 บิตดิบที่ 24 kHz แบบ Little-endian
สตรีมเสียงและวิดีโอ
วิธีการของระบบ
คำสั่งของระบบช่วยให้คุณควบคุมลักษณะการทํางานของโมเดลตามความต้องการและกรณีการใช้งานที่เฉพาะเจาะจง คุณสามารถตั้งค่าวิธีการของระบบในการกําหนดค่าการตั้งค่าได้ และจะมีผลตลอดทั้งเซสชัน
from google.genai import types
config = {
"system_instruction": types.Content(
parts=[
types.Part(
text="You are a helpful assistant and answer in a friendly tone."
)
]
),
"response_modalities": ["TEXT"],
}
การอัปเดตเนื้อหาเพิ่มเติม
ใช้การอัปเดตแบบเพิ่มเพื่อส่งอินพุตข้อความ สร้างบริบทของเซสชัน หรือกู้คืนบริบทของเซสชัน สำหรับบริบทสั้นๆ คุณสามารถส่งการโต้ตอบแบบทีละขั้นเพื่อแสดงลำดับเหตุการณ์ที่แน่นอนได้ ดังนี้
from google.genai import types
turns = [
types.Content(parts=[types.Part(text="What is the capital of France?")], role="user"),
types.Content(parts=[types.Part(text="Paris")], role="model")
]
await session.send(input=types.LiveClientContent(turns=turns))
turns = [types.Content(parts=[types.Part(text="What is the capital of Germany?")], role="user")]
await session.send(input=types.LiveClientContent(turns=turns, turn_complete=True))
{
"clientContent": {
"turns": [
{
"parts":[
{
"text": ""
}
],
"role":"user"
},
{
"parts":[
{
"text": ""
}
],
"role":"model"
}
],
"turnComplete": true
}
}
สำหรับบริบทที่ยาวขึ้น เราขอแนะนำให้ระบุสรุปข้อความเดียวเพื่อเพิ่มพื้นที่ว่างในหน้าต่างบริบทสำหรับการโต้ตอบครั้งต่อๆ ไป
เปลี่ยนเสียง
Multimodal Live API รองรับเสียงต่อไปนี้ Aoede, Charon, Fenrir, Kore และ Puck
หากต้องการระบุเสียง ให้ตั้งค่าชื่อเสียงภายในออบเจ็กต์ speechConfig
โดยเป็นส่วนหนึ่งของการกำหนดค่าเซสชัน
from google.genai import types
config = types.LiveConnectConfig(
response_modalities=["AUDIO"],
speech_config=types.SpeechConfig(
voice_config=types.VoiceConfig(
prebuilt_voice_config=types.PrebuiltVoiceConfig(voice_name="Kore")
)
)
)
{
"voiceConfig": {
"prebuiltVoiceConfig": {
"voiceName": "Kore"
}
}
}
ใช้การเรียกใช้ฟังก์ชัน
คุณสามารถกําหนดเครื่องมือด้วย Multimodal Live API ดูบทแนะนำเกี่ยวกับการเรียกใช้ฟังก์ชันเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับการเรียกใช้ฟังก์ชัน
เครื่องมือต้องได้รับการกําหนดเป็นส่วนหนึ่งของการกําหนดค่าเซสชัน
config = types.LiveConnectConfig(
response_modalities=["TEXT"],
tools=[set_light_values]
)
async with client.aio.live.connect(model=model, config=config) as session:
await session.send(input="Turn the lights down to a romantic level", end_of_turn=True)
async for response in session.receive():
print(response.tool_call)
จากพรอมต์เดียว โมเดลสามารถสร้างการเรียกใช้ฟังก์ชันหลายรายการและโค้ดที่จําเป็นต่อเชื่อมเอาต์พุต โค้ดนี้จะทํางานในสภาพแวดล้อมแซนด์บ็อกซ์ ซึ่งจะสร้างข้อความ BidiGenerateContentToolCall ตามมา การดำเนินการจะหยุดชั่วคราวจนกว่าผลลัพธ์ของการเรียกฟังก์ชันแต่ละรายการจะพร้อมใช้งาน ซึ่งช่วยให้การประมวลผลเป็นไปตามลำดับ
โดยลูกค้าควรตอบกลับด้วย BidiGenerateContentToolResponse
อินพุตและเอาต์พุตเสียงส่งผลเสียต่อความสามารถของโมเดลในการใช้การเรียกใช้ฟังก์ชัน
จัดการสิ่งรบกวน
ผู้ใช้สามารถขัดจังหวะเอาต์พุตของโมเดลได้ทุกเมื่อ เมื่อการตรวจจับกิจกรรมเสียงพูด (VAD) ตรวจพบการหยุดชะงัก ระบบจะยกเลิกและทิ้งการสร้างที่กำลังดำเนินอยู่ เฉพาะข้อมูลที่ส่งไปยังไคลเอ็นต์แล้วเท่านั้นที่จะยังคงอยู่ในประวัติเซสชัน จากนั้นเซิร์ฟเวอร์จะส่งข้อความ BidiGenerateContentServerContent เพื่อรายงานการหยุดชะงัก
นอกจากนี้ เซิร์ฟเวอร์ Gemini จะทิ้งการเรียกฟังก์ชันที่รอดำเนินการและส่งข้อความ BidiGenerateContentServerContent
พร้อมรหัสของการเรียกที่ถูกยกเลิก
async for response in session.receive():
if response.server_content.interrupted is not None:
# The generation was interrupted
ข้อจำกัด
โปรดคำนึงถึงข้อจำกัดต่อไปนี้ของ Multimodal Live API และ Gemini 2.0 เมื่อวางแผนโปรเจ็กต์
การตรวจสอบสิทธิ์ไคลเอ็นต์
Multimodal Live API มีการตรวจสอบสิทธิ์แบบเซิร์ฟเวอร์ต่อเซิร์ฟเวอร์เท่านั้น และเราไม่แนะนำให้ใช้กับไคลเอ็นต์โดยตรง อินพุตของไคลเอ็นต์ควรกำหนดเส้นทางผ่านเซิร์ฟเวอร์แอปพลิเคชันระดับกลางเพื่อการตรวจสอบสิทธิ์ที่ปลอดภัยด้วย Multimodal Live API
ประวัติการสนทนา
แม้ว่าโมเดลจะติดตามการโต้ตอบในเซสชัน แต่ระบบจะไม่จัดเก็บประวัติการสนทนา เมื่อเซสชันสิ้นสุดลง ระบบจะลบบริบทที่เกี่ยวข้อง
หากต้องการกู้คืนเซสชันก่อนหน้าหรือให้บริบทที่ผ่านมาของการโต้ตอบของผู้ใช้แก่โมเดล แอปพลิเคชันควรเก็บรักษาบันทึกการสนทนาของตนเองและใช้ข้อความ BidiGenerateContentClientContent เพื่อส่งข้อมูลนี้เมื่อเริ่มต้นเซสชันใหม่
ระยะเวลาเซสชันสูงสุด
ระยะเวลาของเซสชันจะจำกัดไว้ที่ไม่เกิน 15 นาทีสำหรับเสียง หรือไม่เกิน 2 นาทีสำหรับเสียงและวิดีโอ เมื่อระยะเวลาของเซสชันเกินขีดจํากัด ระบบจะตัดการเชื่อมต่อ
โมเดลยังถูกจํากัดด้วยขนาดบริบทด้วย การส่งเนื้อหาขนาดใหญ่ไปพร้อมกับสตรีมวิดีโอและเสียงอาจส่งผลให้เซสชันสิ้นสุดเร็วขึ้น
การตรวจจับกิจกรรมเสียงพูด (VAD)
โมเดลจะดำเนินการตรวจจับกิจกรรมเสียง (VAD) โดยอัตโนมัติในสตรีมอินพุตเสียงแบบต่อเนื่อง VAD จะเปิดใช้อยู่เสมอ และไม่สามารถกําหนดค่าพารามิเตอร์ได้
จํานวนโทเค็น
ไม่รองรับจํานวนโทเค็น
ขีดจำกัดอัตรา
โดยจะมีการจำกัดจำนวนพรอมต์ดังต่อไปนี้
- เซสชันพร้อมกัน 3 รายการต่อคีย์ API
- โทเค็น 4 ล้านรายการต่อนาที
เอกสารอ้างอิง WebSockets API
Multimodal Live API เป็น API ที่มีสถานะซึ่งใช้ WebSockets ในส่วนนี้ คุณจะเห็นรายละเอียดเพิ่มเติมเกี่ยวกับ WebSockets API
เซสชัน
การเชื่อมต่อ WebSocket จะสร้างเซสชันระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์ Gemini หลังจากไคลเอ็นต์เริ่มการเชื่อมต่อใหม่ เซสชันจะแลกเปลี่ยนข้อความกับเซิร์ฟเวอร์เพื่อทำสิ่งต่อไปนี้ได้
- ส่งข้อความ เสียง หรือวิดีโอไปยังเซิร์ฟเวอร์ Gemini
- รับคําขอเสียง ข้อความ หรือการเรียกใช้ฟังก์ชันจากเซิร์ฟเวอร์ Gemini
ข้อความเริ่มต้นหลังจากการเชื่อมต่อจะตั้งค่าการกําหนดค่าเซสชัน ซึ่งรวมถึงรูปแบบ พารามิเตอร์การสร้าง วิธีการของระบบ และเครื่องมือ
ดูการกำหนดค่าตัวอย่างต่อไปนี้ โปรดทราบว่ารูปแบบตัวพิมพ์ของชื่อใน SDK อาจแตกต่างกันไป คุณดูตัวเลือกการกำหนดค่า Python SDK ได้ที่นี่
{
"model": string,
"generationConfig": {
"candidateCount": integer,
"maxOutputTokens": integer,
"temperature": number,
"topP": number,
"topK": integer,
"presencePenalty": number,
"frequencyPenalty": number,
"responseModalities": [string],
"speechConfig": object
},
"systemInstruction": string,
"tools": [object]
}
ส่งข้อความ
หากต้องการแลกเปลี่ยนข้อความผ่านการเชื่อมต่อ WebSocket ไคลเอ็นต์ต้องส่งออบเจ็กต์ JSON ผ่านการเชื่อมต่อ WebSocket ที่เปิดอยู่ ออบเจ็กต์ JSON ต้องมีฟิลด์จากชุดออบเจ็กต์ต่อไปนี้เพียง 1 ฟิลด์
{
"setup": BidiGenerateContentSetup,
"clientContent": BidiGenerateContentClientContent,
"realtimeInput": BidiGenerateContentRealtimeInput,
"toolResponse": BidiGenerateContentToolResponse
}
ข้อความไคลเอ็นต์ที่รองรับ
ดูข้อความไคลเอ็นต์ที่รองรับในตารางต่อไปนี้
ข้อความ | คำอธิบาย |
---|---|
BidiGenerateContentSetup |
การกําหนดค่าเซสชันที่จะส่งในข้อความแรก |
BidiGenerateContentClientContent |
การอัปเดตเนื้อหาเพิ่มเติมของบทสนทนาปัจจุบันที่ส่งมาจากไคลเอ็นต์ |
BidiGenerateContentRealtimeInput |
อินพุตเสียงหรือวิดีโอแบบเรียลไทม์ |
BidiGenerateContentToolResponse |
การตอบกลับ ToolCallMessage ที่ได้รับจากเซิร์ฟเวอร์ |
รับข้อความ
หากต้องการรับข้อความจาก Gemini ให้รอเหตุการณ์ "message" ของ WebSocket แล้วแยกวิเคราะห์ผลลัพธ์ตามคําจํากัดความของข้อความเซิร์ฟเวอร์ที่รองรับ
โปรดดูข้อมูลต่อไปนี้
async with client.aio.live.connect(model='...', config=config) as session:
await session.send(input='Hello world!', end_of_turn=True)
async for message in session.receive():
print(message)
ข้อความเซิร์ฟเวอร์จะมีช่องจากชุดออบเจ็กต์ต่อไปนี้เพียงช่องเดียว
{
"setupComplete": BidiGenerateContentSetupComplete,
"serverContent": BidiGenerateContentServerContent,
"toolCall": BidiGenerateContentToolCall,
"toolCallCancellation": BidiGenerateContentToolCallCancellation
}
ข้อความเซิร์ฟเวอร์ที่รองรับ
ดูข้อความเซิร์ฟเวอร์ที่รองรับในตารางต่อไปนี้
ข้อความ | คำอธิบาย |
---|---|
BidiGenerateContentSetupComplete |
ข้อความ BidiGenerateContentSetup จากลูกค้าซึ่งส่งเมื่อการตั้งค่าเสร็จสมบูรณ์ |
BidiGenerateContentServerContent |
เนื้อหาที่โมเดลสร้างขึ้นเพื่อตอบกลับข้อความของลูกค้า |
BidiGenerateContentToolCall |
ขอให้ไคลเอ็นต์เรียกใช้ฟังก์ชันและแสดงผลลัพธ์ที่มีรหัสที่ตรงกัน |
BidiGenerateContentToolCallCancellation |
ส่งเมื่อการเรียกฟังก์ชันถูกยกเลิกเนื่องจากผู้ใช้ขัดจังหวะเอาต์พุตของโมเดล |
ข้อความและกิจกรรม
BidiGenerateContentClientContent
การอัปเดตการสนทนาปัจจุบันที่เพิ่มขึ้นจากไคลเอ็นต์ เนื้อหาทั้งหมดที่นี่จะต่อท้ายประวัติการสนทนาโดยไม่มีเงื่อนไข และใช้เป็นพรอมต์ส่วนหนึ่งสำหรับโมเดลในการสร้างเนื้อหา
ข้อความที่นี่จะขัดจังหวะการสร้างโมเดลปัจจุบัน
ช่อง | |
---|---|
turns[] |
ไม่บังคับ เนื้อหาต่อท้ายการสนทนาปัจจุบันกับโมเดล สําหรับการค้นหาแบบเทิร์นเดียว อินสแตนซ์นี้จะเป็นแบบเดี่ยว สําหรับคําค้นหาแบบหลายรอบ ฟิลด์นี้จะซ้ำกันซึ่งมีประวัติการสนทนาและคําขอล่าสุด |
turn_ |
ไม่บังคับ หากเป็น "จริง" แสดงว่าการสร้างเนื้อหาของเซิร์ฟเวอร์ควรเริ่มต้นด้วยพรอมต์ที่สะสมไว้ในปัจจุบัน ไม่เช่นนั้น เซิร์ฟเวอร์จะรอข้อความเพิ่มเติมก่อนที่จะเริ่มสร้าง |
BidiGenerateContentRealtimeInput
อินพุตของผู้ใช้ที่ส่งแบบเรียลไทม์
ซึ่งแตกต่างจาก BidiGenerateContentClientContent
ตรงจุดต่อไปนี้
- ส่งได้อย่างต่อเนื่องโดยไม่หยุดชะงักการสร้างโมเดล
- หากจำเป็นต้องผสมข้อมูลที่สอดแทรกระหว่าง
BidiGenerateContentClientContent
กับBidiGenerateContentRealtimeInput
เซิร์ฟเวอร์จะพยายามเพิ่มประสิทธิภาพเพื่อให้การตอบกลับดีที่สุด แต่ไม่มีการรับประกัน - ไม่มีการระบุจุดสิ้นสุดของเทิร์นอย่างชัดเจน แต่ระบบจะดึงข้อมูลมาจากกิจกรรมของผู้ใช้ (เช่น สิ้นสุดการพูด)
- ระบบจะประมวลผลข้อมูลเพิ่มเติมเพื่อเพิ่มประสิทธิภาพให้เริ่มการตอบกลับจากโมเดลได้อย่างรวดเร็ว แม้กระทั่งก่อนที่เทิร์นจะสิ้นสุดลง
- ระบบจะถือว่าข้อมูลนี้เป็นอินพุตของผู้ใช้เสมอ (ใช้สร้างประวัติการสนทนาไม่ได้) ส่งได้อย่างต่อเนื่องโดยไม่หยุดชะงัก โมเดลจะตรวจหาจุดเริ่มต้นและจุดสิ้นสุดของคำพูดของผู้ใช้โดยอัตโนมัติ และเริ่มหรือหยุดสตรีมคำตอบตามความเหมาะสม ระบบจะประมวลผลข้อมูลทีละรายการเมื่อเข้ามา ซึ่งจะช่วยลดเวลาในการตอบสนอง
ช่อง | |
---|---|
media_ |
ไม่บังคับ ข้อมูลไบต์ที่ฝังอยู่สําหรับอินพุตสื่อ |
BidiGenerateContentServerContent
การอัปเดตเซิร์ฟเวอร์แบบเพิ่มที่โมเดลสร้างขึ้นเพื่อตอบสนองต่อข้อความของไคลเอ็นต์
ระบบจะสร้างเนื้อหาให้เร็วที่สุดเท่าที่จะทำได้ แต่ไม่ใช่แบบเรียลไทม์ ลูกค้าอาจเลือกที่จะบัฟเฟอร์และเล่นแบบเรียลไทม์
ช่อง | |
---|---|
turn_ |
เอาต์พุตเท่านั้น หากเป็นจริง แสดงว่าโมเดลสร้างเสร็จแล้ว การสร้างจะเริ่มต้นเมื่อมีการตอบกลับข้อความเพิ่มเติมของลูกค้าเท่านั้น ตั้งค่าควบคู่ไปกับ |
interrupted |
เอาต์พุตเท่านั้น หากเป็นจริง แสดงว่าข้อความไคลเอ็นต์ขัดจังหวะการสร้างโมเดลปัจจุบัน หากไคลเอ็นต์เล่นเนื้อหาแบบเรียลไทม์ นี่เป็นสัญญาณที่ดีในการหยุดและล้างคิวการเล่นปัจจุบัน |
grounding_ |
เอาต์พุตเท่านั้น ข้อมูลเมตาพื้นฐานสําหรับเนื้อหาที่สร้างขึ้น |
model_ |
เอาต์พุตเท่านั้น เนื้อหาที่โมเดลสร้างขึ้นซึ่งเป็นส่วนหนึ่งของการสนทนาปัจจุบันกับผู้ใช้ |
BidiGenerateContentSetup
ข้อความที่จะส่งในข้อความไคลเอ็นต์แรกและข้อความแรกเท่านั้น มีการกำหนดค่าที่จะมีผลตลอดระยะเวลาของเซสชันสตรีมมิง
ไคลเอ็นต์ควรรอข้อความ BidiGenerateContentSetupComplete
ก่อนส่งข้อความเพิ่มเติม
ช่อง | |
---|---|
model |
ต้องระบุ ชื่อทรัพยากรของโมเดล ซึ่งจะเป็นรหัสสําหรับโมเดลที่จะใช้ รูปแบบ: |
generation_ |
ไม่บังคับ การกำหนดค่าการสร้าง ระบบไม่รองรับช่องต่อไปนี้
|
system_ |
ไม่บังคับ วิธีการของระบบที่ผู้ใช้ระบุสำหรับโมเดล หมายเหตุ: ควรใช้เฉพาะข้อความในส่วนต่างๆ เนื้อหาในแต่ละส่วนจะอยู่ในรูปแบบย่อหน้าแยกกัน |
tools[] |
ไม่บังคับ รายการ
|
BidiGenerateContentSetupComplete
ประเภทนี้ไม่มีช่อง
ส่งเพื่อตอบกลับข้อความ BidiGenerateContentSetup
จากลูกค้า
BidiGenerateContentToolCall
ขอให้ไคลเอ็นต์เรียกใช้ฟังก์ชันและแสดงผลลัพธ์ที่มี id
ที่ตรงกัน
ช่อง | |
---|---|
function_ |
เอาต์พุตเท่านั้น การเรียกใช้ฟังก์ชันที่จะดำเนินการ |
BidiGenerateContentToolCallCancellation
การแจ้งเตือนลูกค้าว่าToolCallMessage
ที่ออกก่อนหน้านี้ซึ่งมีid
ที่ระบุไว้ไม่ควรได้รับการดําเนินการและควรถูกยกเลิก หากการเรียกใช้เครื่องมือเหล่านั้นมีผลข้างเคียง ไคลเอ็นต์อาจพยายามเลิกทำการใช้เครื่องมือ ข้อความนี้จะปรากฏขึ้นเฉพาะในกรณีที่ไคลเอ็นต์ขัดจังหวะการเปลี่ยนเซิร์ฟเวอร์เท่านั้น
ช่อง | |
---|---|
ids[] |
เอาต์พุตเท่านั้น รหัสของเครื่องมือที่เรียกให้ยกเลิก |
BidiGenerateContentToolResponse
การตอบกลับที่ไคลเอ็นต์สร้างขึ้นสําหรับ ToolCall
ที่ได้รับจากเซิร์ฟเวอร์ ระบบจะจับคู่ออบเจ็กต์ FunctionResponse
แต่ละรายการกับออบเจ็กต์ FunctionCall
ที่เกี่ยวข้องตามช่อง id
โปรดทราบว่าการเรียกใช้ฟังก์ชัน GenerateContent API แบบ unary และแบบสตรีมมิงจากเซิร์ฟเวอร์จะเกิดขึ้นโดยการแลกเปลี่ยนส่วน Content
ส่วนการเรียกใช้ฟังก์ชัน GenerateContent API แบบ bidi จะเกิดขึ้นผ่านชุดข้อความเฉพาะเหล่านี้
ช่อง | |
---|---|
function_ |
ไม่บังคับ การตอบสนองต่อการเรียกใช้ฟังก์ชัน |
ข้อมูลเพิ่มเติมเกี่ยวกับประเภทที่พบได้ทั่วไป
ดูข้อมูลเพิ่มเติมเกี่ยวกับประเภททรัพยากร API ที่ใช้กันโดยทั่วไป Blob
,
Content
, FunctionCall
, FunctionResponse
, GenerationConfig
,
GroundingMetadata
และ Tool
ได้ที่หัวข้อการสร้างเนื้อหา
การผสานรวมกับบุคคลที่สาม
สําหรับการติดตั้งใช้งานเว็บและแอปบนอุปกรณ์เคลื่อนที่ คุณสามารถดูตัวเลือกต่อไปนี้