Gateway

การเติมข้อความแชตของ OpenAI

Gateway สามารถให้บริการพื้นผิว Chat Completions ขนาดเล็กที่เข้ากันได้กับ OpenAI โดยค่าเริ่มต้นจะ ปิดใช้งาน

เมื่อเปิดใช้งานแล้ว บริการทั้งหมดต่อไปนี้จะทำงานบนพอร์ตเดียวกับ Gateway (มัลติเพล็กซ์ WS + HTTP):

เมธอด พาธ
POST /v1/chat/completions
GET /v1/models
GET /v1/models/{id}
POST /v1/embeddings
POST /v1/responses

คำขอจะทำงานเหมือนการเรียกใช้เอเจนต์ Gateway ตามปกติ (ใช้เส้นทางโค้ดเดียวกับ openclaw agent) ดังนั้นการกำหนดเส้นทาง สิทธิ์ และการกำหนดค่าจะตรงกับ Gateway ของคุณ

การเปิดใช้งานปลายทาง

json5
{  gateway: {    http: {      endpoints: {        chatCompletions: { enabled: true },      },    },  },}

ตั้งค่า enabled: false (หรือละเว้นไว้) เพื่อปิดใช้งาน

ขอบเขตความปลอดภัย (สำคัญ)

ให้ถือว่าปลายทางนี้มอบ สิทธิ์การเข้าถึงอินสแตนซ์ Gateway อย่างเต็มรูปแบบในระดับผู้ปฏิบัติงาน:

  • โทเค็น/รหัสผ่าน Gateway ที่ถูกต้องสำหรับปลายทางนี้เทียบเท่ากับข้อมูลรับรองของเจ้าของ/ผู้ปฏิบัติงาน ไม่ใช่ขอบเขตที่จำกัดเฉพาะผู้ใช้แต่ละราย
  • คำขอจะผ่านเส้นทางเอเจนต์ของระนาบควบคุมเดียวกับการดำเนินการของผู้ปฏิบัติงานที่เชื่อถือได้ ดังนั้นหากนโยบายของเอเจนต์เป้าหมายอนุญาตเครื่องมือที่มีความละเอียดอ่อน ปลายทางนี้ก็สามารถใช้เครื่องมือเหล่านั้นได้
  • ให้ใช้งานเฉพาะบน loopback/tailnet/ทางเข้าระบบส่วนตัวเท่านั้น อย่าเปิดเผยต่ออินเทอร์เน็ตสาธารณะ

เมทริกซ์การยืนยันตัวตน:

เส้นทางการยืนยันตัวตน ลักษณะการทำงาน
gateway.auth.mode="token" หรือ "password" + Authorization: Bearer ... พิสูจน์ว่าผู้เรียกครอบครองข้อมูลลับที่ใช้ร่วมกันของ Gateway โดยไม่สนใจส่วนหัว x-openclaw-scopes ใดๆ และคืนค่าชุดขอบเขตเริ่มต้นทั้งหมดของผู้ปฏิบัติงาน ได้แก่ operator.admin, operator.approvals, operator.pairing, operator.read, operator.talk.secrets, operator.write และถือว่าเทิร์นการแชตเป็นเทิร์นที่ส่งโดยเจ้าของ
HTTP ที่เชื่อถือได้และมีข้อมูลระบุตัวตน (การยืนยันตัวตนผ่านพร็อกซีที่เชื่อถือได้ หรือ gateway.auth.mode="none" บนทางเข้าระบบส่วนตัว) เคารพ x-openclaw-scopes เมื่อมีการระบุไว้ และย้อนกลับไปใช้ชุดขอบเขตเริ่มต้นของผู้ปฏิบัติงานเมื่อไม่ได้ระบุไว้ จะสูญเสียความหมายเชิงเจ้าของเฉพาะเมื่อผู้เรียกจำกัดขอบเขตอย่างชัดเจนและละเว้น operator.admin เท่านั้น ต้องมี operator.admin สำหรับการควบคุมระดับเจ้าของ เช่น x-openclaw-model

ดูขอบเขตของผู้ปฏิบัติงาน, ความปลอดภัย และการเข้าถึงจากระยะไกล

การยืนยันตัวตน

ใช้การกำหนดค่าการยืนยันตัวตนของ Gateway (ดูรายละเอียดของโหมดดังกล่าวที่การยืนยันตัวตนผ่านพร็อกซีที่เชื่อถือได้):

โหมด วิธียืนยันตัวตน
gateway.auth.mode="token" Authorization: Bearer <token> ตั้งค่าผ่าน gateway.auth.token หรือ OPENCLAW_GATEWAY_TOKEN
gateway.auth.mode="password" Authorization: Bearer <password> ตั้งค่าผ่าน gateway.auth.password หรือ OPENCLAW_GATEWAY_PASSWORD
gateway.auth.mode="trusted-proxy" กำหนดเส้นทางผ่านพร็อกซีที่รับรู้ข้อมูลระบุตัวตนซึ่งกำหนดค่าไว้ โดยพร็อกซีจะแทรกส่วนหัวข้อมูลระบุตัวตนที่จำเป็น พร็อกซี loopback บนโฮสต์เดียวกันต้องกำหนด gateway.auth.trustedProxy.allowLoopback = true อย่างชัดเจน
gateway.auth.mode="none" ไม่ต้องใช้ส่วนหัวการยืนยันตัวตน (เฉพาะทางเข้าระบบส่วนตัว)

หมายเหตุ:

  • ผู้เรียกบนโฮสต์เดียวกันที่ข้ามพร็อกซีบน Gateway แบบ trusted-proxy สามารถย้อนกลับไปใช้ gateway.auth.password / OPENCLAW_GATEWAY_PASSWORD โดยตรงได้ หลักฐานในส่วนหัว Forwarded, X-Forwarded-* หรือ X-Real-IP ใดๆ จะทำให้คำขอยังคงอยู่บนเส้นทางพร็อกซีที่เชื่อถือได้แทน
  • หากกำหนดค่า gateway.auth.rateLimit และมีความพยายามยืนยันตัวตนล้มเหลวมากเกินไป ปลายทางจะส่งคืน 429 พร้อมส่วนหัว Retry-After

กรณีที่ควรใช้ปลายทางนี้

  • ควรใช้ปลายทางนี้แทนการเพิ่มช่องทางในตัวใหม่ เมื่อการผสานรวมเป็นเพียงพื้นผิวผู้ปฏิบัติงาน/ไคลเอนต์อีกรูปแบบหนึ่งสำหรับ Gateway เดียวกัน
  • สำหรับไคลเอนต์มือถือแบบเนทีฟที่เชื่อมต่อโดยตรงกับ Gateway ระยะไกล ควรใช้ WebChat หรือโปรโตคอล Gateway พร้อมขั้นตอนบูตสแตรปอุปกรณ์ที่จับคู่/โทเค็นอุปกรณ์ เพื่อให้อุปกรณ์ไม่จำเป็นต้องใช้โทเค็น/รหัสผ่าน HTTP ที่ใช้ร่วมกัน
  • ให้สร้าง Plugin ช่องทางแทนเมื่อผสานรวมเครือข่ายรับส่งข้อความภายนอกที่มีผู้ใช้ ห้อง การส่งผ่าน Webhook หรือการขนส่งขาออกเป็นของตนเอง ดูการสร้าง Plugin

สัญญาโมเดลที่ให้เอเจนต์เป็นหลัก

OpenClaw ถือว่าฟิลด์ model ของ OpenAI เป็น เป้าหมายเอเจนต์ ไม่ใช่รหัสโมเดลของผู้ให้บริการโดยตรง

ค่า model กำหนดเส้นทางไปยัง
openclaw เอเจนต์เริ่มต้นที่กำหนดค่าไว้
openclaw/default เอเจนต์เริ่มต้นที่กำหนดค่าไว้ (นามแฝงที่เสถียร สามารถฮาร์ดโค้ดได้อย่างปลอดภัย แม้ว่ารหัสเอเจนต์เริ่มต้นจริงจะแตกต่างกันระหว่างสภาพแวดล้อม)
openclaw/<agentId> หรือ openclaw:<agentId> เอเจนต์ที่ระบุ
agent:<agentId> เอเจนต์ที่ระบุ (นามแฝงเพื่อความเข้ากันได้)

ส่วนหัวคำขอที่ไม่บังคับ:

ส่วนหัว ผล
x-openclaw-model: <provider/model-or-bare-id> แทนที่โมเดลแบ็กเอนด์สำหรับเอเจนต์ที่เลือก ผู้เรียกแบบ bearer ที่ใช้ข้อมูลลับร่วมกันสามารถใช้รายการนี้ได้โดยตรง ส่วนผู้เรียกที่มีข้อมูลระบุตัวตน (พร็อกซีที่เชื่อถือได้ หรือทางเข้าระบบส่วนตัวที่ไม่ต้องยืนยันตัวตนแต่มี x-openclaw-scopes) ต้องมี operator.admin มิฉะนั้นจะได้รับ 403 missing scope: operator.admin
x-openclaw-agent-id: <agentId> การแทนที่เพื่อความเข้ากันได้สำหรับการเลือกเอเจนต์
x-openclaw-session-key: <sessionKey> การกำหนดเส้นทางเซสชันอย่างชัดเจน จะถูกปฏิเสธด้วย 400 invalid_request_error หากใช้เนมสเปซภายในที่สงวนไว้ (subagent:, cron:, acp:)
x-openclaw-message-channel: <channel> ตั้งค่าบริบทช่องทางขาเข้าสังเคราะห์สำหรับพรอมต์/นโยบายที่รับรู้ช่องทาง

/v1/models แสดงรายการเป้าหมายเอเจนต์ระดับบนสุด (openclaw, openclaw/default, openclaw/<agentId>) ไม่ใช่โมเดลผู้ให้บริการแบ็กเอนด์และไม่ใช่เอเจนต์ย่อย โดยเอเจนต์ย่อยยังคงเป็นโทโพโลยีการดำเนินการภายใน หากละเว้น x-openclaw-model เอเจนต์ที่เลือกจะทำงานด้วยโมเดลที่กำหนดค่าไว้ตามปกติ

/v1/embeddings ใช้รหัส model ของเป้าหมายเอเจนต์ชุดเดียวกัน ส่ง x-openclaw-model (จากผู้เรียกที่ใช้ข้อมูลลับร่วมกัน หรือผู้เรียกที่มีข้อมูลระบุตัวตนและมี operator.admin) เพื่อเลือกโมเดล embedding ที่ระบุ มิฉะนั้นคำขอจะใช้การตั้งค่า embedding ตามปกติของเอเจนต์ที่เลือก

ลักษณะการทำงานของเซสชัน

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

หากคำขอมีสตริง user ของ OpenAI Gateway จะสร้างคีย์เซสชันที่เสถียรจากค่านั้น เพื่อให้การเรียกซ้ำสามารถใช้เซสชันเอเจนต์ร่วมกันได้ สำหรับแอปที่กำหนดเอง ให้ใช้ค่า user เดียวกันซ้ำสำหรับแต่ละเธรดการสนทนา หลีกเลี่ยงตัวระบุระดับบัญชี เว้นแต่ต้องการให้หลายการสนทนา/อุปกรณ์ใช้เซสชัน OpenClaw เดียวกัน ใช้ x-openclaw-session-key เฉพาะเมื่อต้องควบคุมการกำหนดเส้นทางระหว่างหลายไคลเอนต์/เธรดอย่างชัดเจน โดยใช้คีย์ที่แอปพลิเคชันเป็นเจ้าของและหลีกเลี่ยงเนมสเปซที่สงวนไว้ข้างต้น

ขีดจำกัดคำขอ

ปลายทางใช้ขีดจำกัดในตัวที่ 20 MB ต่อเนื้อหาคำขอ, 8 ส่วน image_url จากข้อความล่าสุดของผู้ใช้ และข้อมูลรูปภาพที่ถอดรหัสแล้วสะสมรวม 20 MB นโยบายแหล่งที่มาของรูปภาพยังคงกำหนดค่าได้ภายใต้ gateway.http.endpoints.chatCompletions.images:

json5
{  gateway: {    http: {      endpoints: {        chatCompletions: {          enabled: true,          images: {            allowUrl: false,            urlAllowlist: ["cdn.example.com", "*.assets.example.com"],            allowedMimes: [              "image/jpeg",              "image/png",              "image/gif",              "image/webp",              "image/heic",              "image/heif",            ],            maxBytes: 10485760,            maxRedirects: 3,            timeoutMs: 10000,          },        },      },    },  },}

ค่าเริ่มต้นของการตั้งค่ารูปภาพมีดังนี้:

คีย์ ค่าเริ่มต้น
images.allowUrl false (ส่วน image_url ที่มีแหล่งที่มาจาก URL จะถูกปฏิเสธ เว้นแต่จะเปิดใช้งาน)
images.maxBytes 10MB ต่อรูปภาพ
images.maxRedirects 3
images.timeoutMs 10s

แหล่งที่มา image_url แบบ HEIC/HEIF ได้รับการยอมรับและปรับเป็น JPEG ก่อนส่งให้ผู้ให้บริการผ่านตัวประมวลผลรูปภาพ OpenClaw ที่ใช้ร่วมกัน (Rastermill) ซึ่งจะย้อนกลับไปใช้ตัวแปลงของระบบ (sips, ImageMagick, GraphicsMagick หรือ ffmpeg) สำหรับรูปแบบที่ต้องใช้การรองรับโคเดกภายนอก

หมายเหตุด้านความปลอดภัย: การเพิ่มชื่อโฮสต์ในรายการอนุญาตไม่ได้ข้ามการบล็อก IP ส่วนตัว/ภายใน สำหรับ Gateway ที่เปิดเผยต่ออินเทอร์เน็ต ให้ใช้การควบคุมทราฟฟิกขาออกของเครือข่ายเพิ่มเติมจากกลไกป้องกันระดับแอป ดูความปลอดภัย

สัญญาเครื่องมือแชต

/v1/chat/completions รองรับชุดย่อยของเครื่องมือฟังก์ชันที่เข้ากันได้กับไคลเอนต์ OpenAI Chat ทั่วไป

ฟิลด์คำขอที่รองรับ

ฟิลด์ หมายเหตุ
tools อาร์เรย์ของ { "type": "function", "function": { ... } }
tool_choice "auto", "none", "required" หรือ { "type": "function", "function": { "name": "..." } }
messages[*].role: "tool" รอบสนทนาต่อเนื่อง
messages[*].tool_call_id เชื่อมโยงผลลัพธ์ของเครื่องมือกลับไปยังการเรียกเครื่องมือก่อนหน้า
max_completion_tokens ตัวเลข; ขีดจำกัดต่อการเรียกสำหรับโทเค็นการตอบให้เสร็จสมบูรณ์ทั้งหมด (รวมโทเค็นการให้เหตุผล) ชื่อฟิลด์ปัจจุบัน; ใช้เมื่อส่งทั้งฟิลด์นี้และ max_tokens
max_tokens ตัวเลข; นามแฝงแบบเดิม ซึ่งจะถูกละเว้นเมื่อมี max_completion_tokens อยู่ด้วย
temperature ตัวเลข 0-2; ดำเนินการอย่างดีที่สุดเท่าที่ทำได้ และส่งต่อไปยังผู้ให้บริการต้นทาง ใช้ 400 invalid_request_error หากอยู่นอกช่วง
top_p ตัวเลข 0-1; ดำเนินการอย่างดีที่สุดเท่าที่ทำได้ ใช้ 400 invalid_request_error หากอยู่นอกช่วง
frequency_penalty ตัวเลข -2.0 ถึง 2.0; ดำเนินการอย่างดีที่สุดเท่าที่ทำได้ ใช้ 400 invalid_request_error หากอยู่นอกช่วง
presence_penalty ตัวเลข -2.0 ถึง 2.0; ดำเนินการอย่างดีที่สุดเท่าที่ทำได้ ใช้ 400 invalid_request_error หากอยู่นอกช่วง
seed จำนวนเต็ม; ดำเนินการอย่างดีที่สุดเท่าที่ทำได้ ใช้ 400 invalid_request_error สำหรับค่าที่ไม่ใช่จำนวนเต็ม
stop สตริงหรืออาร์เรย์ที่มีสตริงได้สูงสุด 4 รายการ; ดำเนินการอย่างดีที่สุดเท่าที่ทำได้ ใช้ 400 invalid_request_error เมื่อมีลำดับมากกว่า 4 ลำดับ หรือมีรายการที่ไม่ใช่สตริง/ว่างเปล่า

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

  • ขีดจำกัดโทเค็น: ชื่อฟิลด์บนสายสื่อสารถูกเลือกโดยทรานสปอร์ตของผู้ให้บริการ: max_completion_tokens สำหรับเอนด์พอยต์ตระกูล OpenAI และ max_tokens สำหรับผู้ให้บริการที่ยอมรับเฉพาะชื่อแบบเดิม (Mistral, Chutes)
  • stop จะแมปไปยังฟิลด์หยุดของทรานสปอร์ต: stop สำหรับแบ็กเอนด์ Chat Completions และ stop_sequences สำหรับ Anthropic โดย OpenAI Responses API ไม่มีพารามิเตอร์หยุด ดังนั้นจึงไม่ใช้ stop กับโมเดลที่ทำงานผ่าน Responses
  • แบ็กเอนด์ Codex Responses ที่ใช้ ChatGPT ใช้การสุ่มตัวอย่างคงที่ฝั่งเซิร์ฟเวอร์ และนำ temperature/top_p (รวมถึง max_output_tokens, metadata, prompt_cache_retention, service_tier) ออกก่อนที่คำขอจะไปถึงแบ็กเอนด์ดังกล่าว

รูปแบบที่ไม่รองรับ

ส่งคืน 400 invalid_request_error สำหรับ:

  • tools ที่ไม่ใช่อาร์เรย์ รายการเครื่องมือที่ไม่ใช่ฟังก์ชัน หรือไม่มี tool.function.name
  • รูปแบบ tool_choice เช่น allowed_tools และ custom
  • ค่า tool_choice.function.name ที่ไม่ตรงกับเครื่องมือที่ระบุ

สำหรับ tool_choice: "required" และ tool_choice ที่ตรึงไว้กับฟังก์ชัน เอนด์พอยต์จะจำกัดชุดเครื่องมือฟังก์ชันฝั่งไคลเอนต์ที่เปิดเผย สั่งให้รันไทม์เรียกเครื่องมือไคลเอนต์ก่อนตอบกลับ และแจ้งข้อผิดพลาดหากการตอบกลับของเอเจนต์ไม่มีการเรียกเครื่องมือไคลเอนต์แบบมีโครงสร้างที่ตรงกัน ข้อนี้ใช้กับรายการ HTTP tools ที่ผู้เรียกส่งมา ไม่ใช่เครื่องมือภายในทั้งหมดของเอเจนต์ OpenClaw

รูปแบบการตอบกลับของเครื่องมือแบบไม่สตรีม

เมื่อเอเจนต์เรียกเครื่องมือ การตอบกลับจะใช้:

  • choices[0].finish_reason = "tool_calls"
  • รายการ choices[0].message.tool_calls[] ที่มี id, type: "function", function.name, function.arguments (สตริง JSON)
  • คำอธิบายประกอบจากผู้ช่วยก่อนการเรียกเครื่องมือใน choices[0].message.content (อาจว่างเปล่า)

รูปแบบการตอบกลับของเครื่องมือแบบสตรีม

เมื่อ stream: true การเรียกเครื่องมือจะมาถึงเป็นส่วนย่อย SSE แบบเพิ่มทีละส่วน ได้แก่ เดลตาบทบาทผู้ช่วยเริ่มต้น เดลตาคำอธิบายประกอบจากผู้ช่วยที่อาจมีหรือไม่มีก็ได้ ส่วนย่อย delta.tool_calls อย่างน้อยหนึ่งส่วนที่มีข้อมูลประจำตัวของเครื่องมือและส่วนย่อยของอาร์กิวเมนต์ จากนั้นตามด้วยส่วนย่อยสุดท้ายที่มี finish_reason: "tool_calls" และ data: [DONE]

หาก stream_options.include_usage=true จะมีการส่งส่วนย่อยข้อมูลการใช้งานปิดท้ายก่อน [DONE]

ลูปการดำเนินการต่อหลังใช้เครื่องมือ

หลังจากได้รับ tool_calls ให้เรียกใช้ฟังก์ชันที่ร้องขอ แล้วส่งคำขอต่อเนื่องที่รวมข้อความการเรียกเครื่องมือของผู้ช่วยก่อนหน้า พร้อมข้อความ role: "tool" อย่างน้อยหนึ่งข้อความที่มี tool_call_id ตรงกัน การดำเนินการนี้จะดำเนินลูปการให้เหตุผลของเอเจนต์เดิมต่อไปเพื่อสร้างคำตอบสุดท้าย

การสตรีม (SSE)

ตั้งค่า stream: true เพื่อรับ Server-Sent Events:

  • Content-Type: text/event-stream
  • แต่ละบรรทัดของเหตุการณ์คือ data: <json>
  • สตรีมสิ้นสุดด้วย data: [DONE]

การตั้งค่า Open WebUI อย่างรวดเร็ว

  • URL ฐาน: http://127.0.0.1:18789/v1
  • URL ฐานของ Docker บน macOS: http://host.docker.internal:18789/v1
  • คีย์ API: โทเค็น Bearer ของ Gateway
  • โมเดล: openclaw/default

ลักษณะการทำงานที่คาดหวัง: GET /v1/models แสดงรายการ openclaw/default และ Open WebUI ใช้ค่านี้เป็นรหัสโมเดลแชต สำหรับผู้ให้บริการ/โมเดลแบ็กเอนด์เฉพาะ ให้ตั้งค่าโมเดลเริ่มต้นตามปกติของเอเจนต์ หรือส่ง x-openclaw-model (ผู้เรียกที่ใช้ข้อมูลลับร่วมกัน หรือผู้เรียกที่มีข้อมูลประจำตัวพร้อม operator.admin)

การทดสอบเบื้องต้นอย่างรวดเร็ว:

bash
curl -sS http://127.0.0.1:18789/v1/models \  -H 'Authorization: Bearer YOUR_TOKEN'

หากส่งคืน openclaw/default การตั้งค่า Open WebUI ส่วนใหญ่จะเชื่อมต่อได้โดยใช้ URL ฐานและโทเค็นเดียวกัน

ตัวอย่าง

เซสชันคงที่สำหรับการสนทนาหนึ่งรายการในแอป:

bash
curl -sS http://127.0.0.1:18789/v1/chat/completions \  -H 'Authorization: Bearer YOUR_TOKEN' \  -H 'Content-Type: application/json' \  -d '{    "model": "openclaw/default",    "user": "conv:YOUR_CONVERSATION_ID",    "messages": [{"role":"user","content":"สรุปงานของฉันสำหรับวันนี้"}]  }'

ใช้ค่า user เดิมซ้ำในการเรียกครั้งถัดไปสำหรับการสนทนานั้น เพื่อดำเนินเซสชันเอเจนต์เดิมต่อ

แบบไม่สตรีม:

bash
curl -sS http://127.0.0.1:18789/v1/chat/completions \  -H 'Authorization: Bearer YOUR_TOKEN' \  -H 'Content-Type: application/json' \  -d '{    "model": "openclaw/default",    "messages": [{"role":"user","content":"สวัสดี"}]  }'

แบบสตรีม:

bash
curl -N http://127.0.0.1:18789/v1/chat/completions \  -H 'Authorization: Bearer YOUR_TOKEN' \  -H 'Content-Type: application/json' \  -H 'x-openclaw-model: openai/gpt-5.4' \  -d '{    "model": "openclaw/research",    "stream": true,    "messages": [{"role":"user","content":"สวัสดี"}]  }'

แสดงรายการโมเดล:

bash
curl -sS http://127.0.0.1:18789/v1/models \  -H 'Authorization: Bearer YOUR_TOKEN'

ดึงข้อมูลโมเดลหนึ่งรายการ:

bash
curl -sS http://127.0.0.1:18789/v1/models/openclaw%2Fdefault \  -H 'Authorization: Bearer YOUR_TOKEN'

สร้าง embeddings:

bash
curl -sS http://127.0.0.1:18789/v1/embeddings \  -H 'Authorization: Bearer YOUR_TOKEN' \  -H 'Content-Type: application/json' \  -H 'x-openclaw-model: openai/text-embedding-3-small' \  -d '{    "model": "openclaw/default",    "input": ["alpha", "beta"]  }'

/v1/embeddings รองรับ input ในรูปแบบสตริงหรืออาร์เรย์ของสตริง

ที่เกี่ยวข้อง

Was this useful?
On this page

On this page