Multimodal Live API

Multimodal Live API ช่วยให้สามารถโต้ตอบด้วยเสียงและวิดีโอแบบ 2 ทิศทางที่มีเวลาในการตอบสนองต่ำกับ Gemini การใช้ Multimodal Live API ช่วยให้คุณมอบประสบการณ์การสนทนาด้วยเสียงที่เป็นธรรมชาติและเหมือนมนุษย์ให้แก่ผู้ใช้ปลายทาง รวมถึงสามารถขัดจังหวะคำตอบของโมเดลได้โดยใช้คำสั่งเสียง โมเดลสามารถประมวลผลอินพุตข้อความ เสียง และวิดีโอ รวมถึงให้เอาต์พุตข้อความและเสียง

ความสามารถ

Multimodal Live API มีความสามารถหลักๆ ดังต่อไปนี้

  • มัลติโมดัล: โมเดลสามารถมองเห็น ได้ยิน และพูดได้
  • การโต้ตอบแบบเรียลไทม์ที่มีเวลาในการตอบสนองต่ำ: ให้การตอบกลับที่รวดเร็ว
  • ความทรงจำของเซสชัน: โมเดลจะเก็บความทรงจำของการโต้ตอบทั้งหมดภายในเซสชันเดียว โดยจะจำข้อมูลที่ได้ยินหรือเห็นก่อนหน้านี้
  • การรองรับการเรียกใช้ฟังก์ชัน การดำเนินการโค้ด และ Search เป็นเครื่องมือ: ช่วยให้ผสานรวมกับบริการและแหล่งข้อมูลภายนอกได้
  • การตรวจจับกิจกรรมเสียงอัตโนมัติ (VAD): โมเดลจะจดจําได้อย่างแม่นยําเมื่อผู้ใช้เริ่มและหยุดพูด ซึ่งช่วยให้การโต้ตอบเป็นธรรมชาติและเป็นการสนทนา และช่วยให้ผู้ใช้ขัดจังหวะโมเดลได้ทุกเมื่อ

คุณลองใช้ Multimodal Live API ได้ใน Google AI Studio

เริ่มต้นใช้งาน

Multimodal Live API เป็น API ที่มีสถานะซึ่งใช้ WebSockets

ส่วนนี้จะแสดงตัวอย่างวิธีใช้ Multimodal Live API เพื่อสร้างข้อความจากข้อความโดยใช้ Python 3.9 ขึ้นไป

ติดตั้งไลบรารี Gemini API

หากต้องการติดตั้งแพ็กเกจ google-genai ให้ใช้คำสั่ง pip ต่อไปนี้

!pip3 install google-genai

นําเข้าทรัพยากร Dependency

วิธีนําเข้าทรัพยากร Dependency

from google import genai

ส่งและรับ SMS

import asyncio
from google import genai

client = genai.Client(api_key="GEMINI_API_KEY", http_options={'api_version': 'v1alpha'})
model_id = "gemini-2.0-flash-exp"
config = {"response_modalities": ["TEXT"]}

async def main():
    async with client.aio.live.connect(model=model_id, config=config) as session:
        while True:
            message = input("User> ")
            if message.lower() == "exit":
                break
            await session.send(message, end_of_turn=True)

            async for response in session.receive():
                if response.text is None:
                    continue
                print(response.text, end="")

if __name__ == "__main__":
    asyncio.run(main())

คู่มือการผสานรวม

ส่วนนี้จะอธิบายวิธีการทำงานของการผสานรวมกับ Multimodal Live API

เซสชัน

เซสชันแสดงการเชื่อมต่อ WebSocket รายการเดียวระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์ Gemini

หลังจากไคลเอ็นต์เริ่มการเชื่อมต่อใหม่ เซสชันจะแลกเปลี่ยนข้อความกับเซิร์ฟเวอร์เพื่อทำสิ่งต่อไปนี้ได้

  • ส่งข้อความ เสียง หรือวิดีโอไปยังเซิร์ฟเวอร์ Gemini
  • รับเสียง ข้อความ หรือการตอบกลับการเรียกฟังก์ชันจากเซิร์ฟเวอร์ Gemini

ระบบจะส่งการกําหนดค่าเซสชันในข้อความแรกหลังจากการเชื่อมต่อ การกำหนดค่าเซสชันประกอบด้วยรูปแบบ พารามิเตอร์การสร้าง วิธีการของระบบ และเครื่องมือ

ดูตัวอย่างการกำหนดค่าต่อไปนี้

{​​
  "model": string,
  "generation_config": {
    "candidate_count": integer,
    "max_output_tokens": integer,
    "temperature": number,
    "top_p": number,
    "top_k": integer,
    "presence_penalty": number,
    "frequency_penalty": number,
    "response_modalities": string,
    "speech_config":object
  },

  "system_instruction": "",
  "tools":[]
}

ดูข้อมูลเพิ่มเติมได้ที่ BidiGenerateContentSetup

ส่งข้อความ

ข้อความคือสตริงรูปแบบ JSON ที่แลกเปลี่ยนกันผ่านการเชื่อมต่อ WebSocket

หากต้องการส่งข้อความ ไคลเอ็นต์ต้องส่งข้อความไคลเอ็นต์ที่รองรับในรูปแบบสตริง JSON ผ่านการเชื่อมต่อ WebSocket ที่เปิดอยู่

ข้อความไคลเอ็นต์ที่รองรับ

ดูข้อความไคลเอ็นต์ที่รองรับในตารางต่อไปนี้

ข้อความ คำอธิบาย
BidiGenerateContentSetup การกําหนดค่าเซสชันที่จะส่งในข้อความแรก
BidiGenerateContentClientContent การอัปเดตเนื้อหาเพิ่มเติมของบทสนทนาปัจจุบันที่ส่งมาจากไคลเอ็นต์
BidiGenerateContentRealtimeInput อินพุตเสียงหรือวิดีโอแบบเรียลไทม์
BidiGenerateContentToolResponse การตอบกลับ ToolCallMessage ที่ได้รับจากเซิร์ฟเวอร์

รับข้อความ

หากต้องการรับข้อความจาก Gemini ให้รอเหตุการณ์ "message" ของ WebSocket แล้วแยกวิเคราะห์ผลลัพธ์ตามคําจํากัดความของข้อความเซิร์ฟเวอร์ที่รองรับ

โปรดดูข้อมูลต่อไปนี้

ws.addEventListener("message", async (evt) => {
  if (evt.data instanceof Blob) {
    // Process the received data (audio, video, etc.)
  } else {
    // Process JSON response
  }
});

ข้อความเซิร์ฟเวอร์ที่รองรับ

ดูข้อความเซิร์ฟเวอร์ที่รองรับในตารางต่อไปนี้

ข้อความ คำอธิบาย
BidiGenerateContentSetupComplete ข้อความ BidiGenerateContentSetup จากลูกค้าซึ่งส่งเมื่อการตั้งค่าเสร็จสมบูรณ์
BidiGenerateContentServerContent เนื้อหาที่โมเดลสร้างขึ้นเพื่อตอบกลับข้อความของลูกค้า
BidiGenerateContentToolCall ขอให้ไคลเอ็นต์เรียกใช้ฟังก์ชันและแสดงผลลัพธ์ที่มีรหัสที่ตรงกัน
BidiGenerateContentToolCallCancellation ส่งเมื่อการเรียกฟังก์ชันถูกยกเลิกเนื่องจากผู้ใช้ขัดจังหวะเอาต์พุตของโมเดล

การอัปเดตเนื้อหาเพิ่มเติม

ใช้การอัปเดตแบบเพิ่มเพื่อส่งอินพุตข้อความ สร้าง หรือกู้คืนบริบทเซสชัน สําหรับบริบทสั้นๆ คุณสามารถส่งการโต้ตอบแบบเลี้ยวต่อเลี้ยวเพื่อแสดงลําดับเหตุการณ์ที่แน่นอน สำหรับบริบทที่ยาวขึ้น เราขอแนะนำให้ระบุสรุปข้อความเดียวเพื่อเพิ่มพื้นที่ว่างในหน้าต่างบริบทสำหรับการโต้ตอบติดตามผล

ดูตัวอย่างข้อความตามบริบทต่อไปนี้

{
  "client_content": {
    "turns": [
      {
          "parts":[
          {
            "text": ""
          }
        ],
        "role":"user"
      },
      {
          "parts":[
          {
            "text": ""
          }
        ],
        "role":"model"
      }
    ],
    "turn_complete": true
  }
}

โปรดทราบว่าแม้ว่าเนื้อหาบางส่วนจะเป็นประเภท functionResponse ได้ แต่ไม่ควรใช้ BidiGenerateContentClientContent เพื่อตอบสนองต่อการเรียกใช้ฟังก์ชันที่โมเดลออก BidiGenerateContentToolResponse แทน BidiGenerateContentClientContent ควรใช้เพื่อกำหนดบริบทก่อนหน้าหรือป้อนข้อความในการสนทนาเท่านั้น

การสตรีมเสียงและวิดีโอ

การเรียกใช้ฟังก์ชัน

ต้องประกาศฟังก์ชันทั้งหมดเมื่อเริ่มเซสชันโดยการส่งคําจํากัดความของเครื่องมือเป็นส่วนหนึ่งของข้อความ BidiGenerateContentSetup

ดูบทแนะนำการเรียกใช้ฟังก์ชันเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับการเรียกใช้ฟังก์ชัน

จากพรอมต์เดียว โมเดลสามารถสร้างการเรียกฟังก์ชันหลายรายการและโค้ดที่จําเป็นต่อเชื่อมเอาต์พุต โค้ดนี้จะทํางานในสภาพแวดล้อมเสมือนจริง ซึ่งจะสร้างBidiGenerateContentToolCallข้อความต่อๆ ไป การดำเนินการจะหยุดชั่วคราวจนกว่าผลลัพธ์ของการเรียกฟังก์ชันแต่ละรายการจะพร้อมใช้งาน ซึ่งช่วยให้การประมวลผลเป็นไปตามลำดับ

ลูกค้าควรตอบกลับด้วย BidiGenerateContentToolResponse

อินพุตและเอาต์พุตเสียงส่งผลเสียต่อความสามารถของโมเดลในการใช้การเรียกฟังก์ชัน

รูปแบบเสียง

Multimodal Live API รองรับรูปแบบเสียงต่อไปนี้

  • รูปแบบเสียงอินพุต: เสียง PCM 16 บิตดิบที่ 16kHz แบบ Little-endian
  • รูปแบบเสียงเอาต์พุต: เสียง PCM 16 บิตดิบที่ 24 kHz แบบ Little-endian

วิธีการของระบบ

คุณสามารถระบุวิธีการของระบบเพื่อควบคุมเอาต์พุตของโมเดลได้ดียิ่งขึ้น รวมถึงระบุน้ำเสียงและความรู้สึกของคำตอบที่เป็นเสียง

ระบบจะเพิ่มวิธีการไปยังพรอมต์ก่อนที่การโต้ตอบจะเริ่มขึ้น และจะมีผลตลอดเซสชัน

คุณจะตั้งค่าคำสั่งของระบบได้ในตอนต้นของเซสชันเท่านั้น นั่นคือทันทีหลังจากการเชื่อมต่อครั้งแรก หากต้องการป้อนข้อมูลเพิ่มเติมให้กับโมเดลระหว่างเซสชัน ให้ใช้การอัปเดตเนื้อหาเพิ่มเติม

เสียงแทรก

ผู้ใช้สามารถขัดจังหวะเอาต์พุตของโมเดลได้ทุกเมื่อ เมื่อการตรวจจับกิจกรรมเสียง (VAD) ตรวจพบการหยุดชะงัก ระบบจะยกเลิกและทิ้งการแปลงที่กำลังดำเนินอยู่ เฉพาะข้อมูลที่ส่งไปยังไคลเอ็นต์แล้วเท่านั้นที่จะยังคงอยู่ในประวัติเซสชัน จากนั้นเซิร์ฟเวอร์จะส่งข้อความ BidiGenerateContentServerContent เพื่อรายงานการหยุดชะงัก

นอกจากนี้ เซิร์ฟเวอร์ Gemini จะทิ้งการเรียกฟังก์ชันที่รอดำเนินการและส่งข้อความ BidiGenerateContentServerContent พร้อมรหัสของการเรียกที่ถูกยกเลิก

เสียง

Multimodal Live API รองรับเสียงต่อไปนี้ Aoede, Charon, Fenrir, Kore และ Puck

หากต้องการระบุเสียง ให้ตั้งค่า voice_name ภายในออบเจ็กต์ speech_config ซึ่งเป็นส่วนหนึ่งของการกำหนดค่าเซสชัน

ดูการแสดง JSON ของออบเจ็กต์ speech_config ต่อไปนี้

{
  "voice_config": {
    "prebuilt_voice_config ": {
      "voice_name": <var>VOICE_NAME</var>
    }
  }
}

ข้อจำกัด

โปรดคำนึงถึงข้อจำกัดต่อไปนี้ของ Multimodal Live API และ Gemini 2.0 เมื่อวางแผนโปรเจ็กต์

การตรวจสอบสิทธิ์ไคลเอ็นต์

Multimodal Live API มีการตรวจสอบสิทธิ์แบบเซิร์ฟเวอร์ต่อเซิร์ฟเวอร์เท่านั้น และเราไม่แนะนำให้ใช้กับไคลเอ็นต์โดยตรง อินพุตของไคลเอ็นต์ควรกำหนดเส้นทางผ่านเซิร์ฟเวอร์แอปพลิเคชันระดับกลางเพื่อการตรวจสอบสิทธิ์ที่ปลอดภัยด้วย Multimodal Live API

สําหรับเว็บและแอปบนอุปกรณ์เคลื่อนที่ เราขอแนะนําให้ใช้การผสานรวมจากพาร์ทเนอร์ของเราที่ Daily

ประวัติการสนทนา

แม้ว่าโมเดลจะติดตามการโต้ตอบในเซสชัน แต่ระบบจะไม่จัดเก็บประวัติการสนทนา เมื่อเซสชันสิ้นสุดลง ระบบจะลบบริบทที่เกี่ยวข้อง

หากต้องการกู้คืนเซสชันก่อนหน้าหรือระบุบริบทที่ผ่านมาของการโต้ตอบของผู้ใช้ให้กับโมเดล แอปพลิเคชันควรเก็บบันทึกการสนทนาของตนเองและใช้ข้อความ BidiGenerateContentClientContent เพื่อส่งข้อมูลนี้เมื่อเริ่มต้นเซสชันใหม่

ระยะเวลาเซสชันสูงสุด

ระยะเวลาของเซสชันจะจำกัดไว้ที่ไม่เกิน 15 นาทีสำหรับเสียง หรือไม่เกิน 2 นาทีสำหรับเสียงและวิดีโอ เมื่อระยะเวลาของเซสชันเกินขีดจํากัด ระบบจะตัดการเชื่อมต่อ

โมเดลยังถูกจํากัดด้วยขนาดบริบทด้วย การส่งเนื้อหาขนาดใหญ่ไปพร้อมกับสตรีมวิดีโอและเสียงอาจส่งผลให้เซสชันสิ้นสุดเร็วขึ้น

การตรวจจับกิจกรรมเสียงพูด (VAD)

โมเดลจะดำเนินการตรวจจับกิจกรรมเสียง (VAD) โดยอัตโนมัติในสตรีมอินพุตเสียงแบบต่อเนื่อง VAD จะเปิดใช้อยู่เสมอ และไม่สามารถกําหนดค่าพารามิเตอร์ได้

จํานวนโทเค็น

ไม่รองรับจํานวนโทเค็น

ขีดจำกัดอัตรา

โดยจะมีการจำกัดจำนวนพรอมต์ดังต่อไปนี้

  • เซสชันพร้อมกัน 3 รายการต่อคีย์ API
  • โทเค็น 4 ล้านรายการต่อนาที

ข้อความและกิจกรรม

BidiGenerateContentClientContent

การอัปเดตการสนทนาปัจจุบันที่ส่งจากไคลเอ็นต์ เนื้อหาทั้งหมดที่นี่จะต่อท้ายประวัติการสนทนาโดยไม่มีเงื่อนไข และใช้เป็นพรอมต์สำหรับโมเดลในการสร้างเนื้อหา

ข้อความที่นี่จะขัดจังหวะการสร้างโมเดลปัจจุบัน

ช่อง
turns[]

Content

ไม่บังคับ เนื้อหาต่อท้ายการสนทนาปัจจุบันกับโมเดล

สําหรับการค้นหาแบบเทิร์นเดียว อินสแตนซ์นี้จะเป็นแบบเดี่ยว สําหรับคําค้นหาแบบหลายรอบ ฟิลด์นี้จะซ้ำกันซึ่งมีประวัติการสนทนาและคําขอล่าสุด

turn_complete

bool

ไม่บังคับ หากเป็น "จริง" แสดงว่าการสร้างเนื้อหาของเซิร์ฟเวอร์ควรเริ่มต้นด้วยพรอมต์ที่สะสมไว้ในปัจจุบัน ไม่เช่นนั้น เซิร์ฟเวอร์จะรอข้อความเพิ่มเติมก่อนที่จะเริ่มสร้าง

BidiGenerateContentRealtimeInput

อินพุตของผู้ใช้ที่ส่งแบบเรียลไทม์

ซึ่งแตกต่างจาก BidiGenerateContentClientContent ตรงจุดต่อไปนี้

  • ส่งได้อย่างต่อเนื่องโดยไม่หยุดชะงักการสร้างโมเดล
  • หากจำเป็นต้องผสมข้อมูลที่สอดแทรกระหว่าง BidiGenerateContentClientContent กับ BidiGenerateContentRealtimeInput เซิร์ฟเวอร์จะพยายามเพิ่มประสิทธิภาพเพื่อให้ได้การตอบกลับที่ดีที่สุด แต่ไม่มีการรับประกัน
  • ไม่มีการระบุการสิ้นสุดการพูดอย่างชัดเจน แต่ระบบจะดึงข้อมูลมาจากกิจกรรมของผู้ใช้ (เช่น การสิ้นสุดการพูด)
  • ระบบจะประมวลผลข้อมูลทีละน้อยเพื่อเพิ่มประสิทธิภาพให้เริ่มการตอบกลับจากโมเดลได้อย่างรวดเร็ว แม้กระทั่งก่อนที่เทิร์นจะสิ้นสุดลง
  • เป็นอินพุตโดยตรงจากผู้ใช้ที่ส่งแบบเรียลไทม์เสมอ ส่งได้อย่างต่อเนื่องโดยไม่หยุดชะงัก โมเดลจะตรวจหาจุดเริ่มต้นและจุดสิ้นสุดของคำพูดของผู้ใช้โดยอัตโนมัติ และเริ่มหรือหยุดสตรีมคำตอบตามความเหมาะสม ระบบจะประมวลผลข้อมูลทีละรายการเมื่อเข้ามา ซึ่งจะช่วยลดเวลาในการตอบสนอง
ช่อง
media_chunks[]

Blob

ไม่บังคับ ข้อมูลไบต์ที่ฝังอยู่สําหรับอินพุตสื่อ

BidiGenerateContentServerContent

การอัปเดตเซิร์ฟเวอร์แบบเพิ่มที่โมเดลสร้างขึ้นเพื่อตอบสนองต่อข้อความของไคลเอ็นต์

ระบบจะสร้างเนื้อหาให้เร็วที่สุดเท่าที่จะทำได้ แต่ไม่ใช่แบบเรียลไทม์ ลูกค้าอาจเลือกที่จะบัฟเฟอร์และเล่นแบบเรียลไทม์

ช่อง
turn_complete

bool

เอาต์พุตเท่านั้น หากเป็นจริง แสดงว่าโมเดลสร้างเสร็จแล้ว การสร้างจะเริ่มต้นเมื่อมีการตอบกลับข้อความเพิ่มเติมของลูกค้าเท่านั้น สามารถใช้ร่วมกับ content เพื่อระบุว่า content เป็นคำสุดท้ายในรอบ

interrupted

bool

เอาต์พุตเท่านั้น หากเป็นจริง แสดงว่าข้อความไคลเอ็นต์ขัดจังหวะการสร้างโมเดลปัจจุบัน หากไคลเอ็นต์เล่นเนื้อหาแบบเรียลไทม์ นี่เป็นสัญญาณที่ดีในการหยุดและล้างคิวการเล่นปัจจุบัน

grounding_metadata

GroundingMetadata

เอาต์พุตเท่านั้น ข้อมูลเมตาพื้นฐานสําหรับเนื้อหาที่สร้างขึ้น

model_turn

Content

เอาต์พุตเท่านั้น เนื้อหาที่โมเดลสร้างขึ้นซึ่งเป็นส่วนหนึ่งของการสนทนาปัจจุบันกับผู้ใช้

BidiGenerateContentSetup

ข้อความที่จะส่งในข้อความไคลเอ็นต์แรกและข้อความแรกเท่านั้น มีการกำหนดค่าที่จะมีผลตลอดระยะเวลาของเซสชันสตรีมมิง

ไคลเอ็นต์ควรรอข้อความ BidiGenerateContentSetupComplete ก่อนส่งข้อความเพิ่มเติม

ช่อง
model

string

ต้องระบุ ชื่อทรัพยากรของโมเดล ซึ่งจะเป็นรหัสสําหรับโมเดลที่จะใช้

รูปแบบ: models/{model}

generation_config

GenerationConfig

ไม่บังคับ การกำหนดค่าการสร้าง

ระบบไม่รองรับช่องต่อไปนี้

  • response_logprobs
  • response_mime_type
  • logprobs
  • response_schema
  • stop_sequence
  • routing_config
  • audio_timestamp
system_instruction

Content

ไม่บังคับ วิธีการของระบบที่ผู้ใช้ระบุสำหรับโมเดล

หมายเหตุ: ควรใช้เฉพาะข้อความในส่วนต่างๆ และเนื้อหาในแต่ละส่วนจะอยู่ในรูปแบบย่อหน้าแยกกัน

tools[]

Tool

ไม่บังคับ รายการ Tools ที่โมเดลอาจใช้เพื่อสร้างคำตอบถัดไป

Tool คือโค้ดที่ช่วยให้ระบบโต้ตอบกับระบบภายนอกเพื่อดําเนินการหรือชุดการดําเนินการนอกความรู้และขอบเขตของโมเดล

BidiGenerateContentSetupComplete

ประเภทนี้ไม่มีช่อง

ส่งเพื่อตอบกลับข้อความ BidiGenerateContentSetup จากลูกค้า

BidiGenerateContentToolCall

ขอให้ไคลเอ็นต์เรียกใช้ function_calls และแสดงผลลัพธ์ที่มี id ที่ตรงกัน

ช่อง
function_calls[]

FunctionCall

เอาต์พุตเท่านั้น การเรียกใช้ฟังก์ชันที่จะดำเนินการ

BidiGenerateContentToolCallCancellation

การแจ้งเตือนลูกค้าว่าToolCallMessageที่ออกก่อนหน้านี้ซึ่งมีidที่ระบุไว้ไม่ควรดำเนินการและควรยกเลิก หากการเรียกใช้เครื่องมือเหล่านั้นมีผลข้างเคียง ไคลเอ็นต์อาจพยายามเลิกทำการใช้เครื่องมือ ข้อความนี้จะปรากฏขึ้นเฉพาะในกรณีที่ไคลเอ็นต์ขัดจังหวะการเปลี่ยนเซิร์ฟเวอร์เท่านั้น

ช่อง
ids[]

string

เอาต์พุตเท่านั้น รหัสของเครื่องมือที่จะยกเลิก

BidiGenerateContentToolResponse

การตอบกลับที่ไคลเอ็นต์สร้างขึ้นสําหรับ ToolCall ที่ได้รับจากเซิร์ฟเวอร์ ระบบจะจับคู่ออบเจ็กต์ FunctionResponse แต่ละรายการกับออบเจ็กต์ FunctionCall ที่เกี่ยวข้องตามช่อง id

โปรดทราบว่าการเรียกใช้ฟังก์ชัน GenerateContent API แบบ unary และแบบสตรีมมิงจากเซิร์ฟเวอร์จะเกิดขึ้นโดยการแลกเปลี่ยนส่วน Content ส่วนการเรียกใช้ฟังก์ชัน GenerateContent API แบบ bidi จะเกิดขึ้นผ่านชุดข้อความเฉพาะเหล่านี้

ช่อง
function_responses[]

FunctionResponse

ไม่บังคับ การตอบสนองต่อการเรียกใช้ฟังก์ชัน

ข้อมูลเพิ่มเติมเกี่ยวกับประเภทที่พบได้ทั่วไป

ดูข้อมูลเพิ่มเติมเกี่ยวกับประเภททรัพยากร API ที่ใช้กันโดยทั่วไป Blob, Content, FunctionCall, FunctionResponse, GenerationConfig, GroundingMetadata และ Tool ได้ที่หัวข้อการสร้างเนื้อหา