Python CLI คุย Gemini API ให้โปรด้วย Context Manager และ Resilience
สวัสดีครับ เพื่อนๆ โปรแกรมเมอร์ทุกคน วันนี้ผมจะมาคุยกันเรื่องการสร้าง Python CLI ที่คุยกับ Gemini API แบบโปรๆ กันนะครับ เราจะเน้นไปที่เรื่อง resilience หรือความทนทานของโค้ด และการจัดการโค้ดให้ optimization ด้วย Context Manager นะครับ
เวลาเราเขียนโค้ดที่ต้องเชื่อมต่อกับอะไรบางอย่างบ่อยๆ ไม่ว่าจะเป็น API หรือ Database เรามักจะต้องมานั่งคิดว่าจะเปิด Connection ยังไง แล้วก็ต้องไม่ลืมปิด Connection ให้ถูกจังหวะด้วยใช่ไหมครับ บางทีก็มีเรื่องต้องจัดการเยอะ เช่น การตั้งค่า Key, การจัดการ Connection, หรือแม้กระทั่งการ Retry เมื่อเกิดข้อผิดพลาด แบบนี้นะครับ ถ้าเราจัดการไม่ดี โค้ดของเราก็จะหลุด หรือพังง่ายๆ เลยนะ
ทำไมต้อง Context Manager กับ API?
Context Manager เนี่ยเป็นเครื่องมือใน Python ที่เจ๋งมากๆ เลยครับ มันช่วยให้เราจัดการทรัพยากรพวกนี้ได้แบบอัตโนมัติ ทำให้โค้ดเราสะอาดขึ้น อ่านง่ายขึ้น และมั่นใจได้ว่าทรัพยากรจะถูกจัดสรรและคืนอย่างถูกต้องเสมอครับ ไม่ว่าโค้ดเราจะทำงานได้สำเร็จ หรือจะเกิด Error ขึ้นมา Context Manager ก็จะจัดการให้ทุกอย่างเรียบร้อยครับ ทำให้แอปพลิเคชัน CLI ของเราที่คุยกับ Gemini API มีความ resilience สูงขึ้นอย่างเห็นได้ชัดเลย
แบบธรรมดาๆ ก่อน (ยังไม่โปรเท่าไหร่)
มาดูตัวอย่างแรกกันนะครับ แบบที่ยังไม่ได้ใช้ Context Manager นะครับ เวลาเราคุยกับ Gemini API แบบตรงไปตรงมา เราก็ต้อง Configure API Key แล้วก็สร้าง Model กับ Chat Object ขึ้นมาใช้งานแบบนี้นะครับ ถ้ามีหลายฟังก์ชัน ก็อาจจะต้องเขียนซ้ำๆ หรือจัดการเองเยอะหน่อยนะ
# gemini_cli_basic.py
# ก่อนรันโค้ด อย่าลืมติดตั้ง library ด้วย pip install google-generativeai
# และตั้งค่า Environment Variable GEMINI_API_KEY ด้วย API Key ของคุณนะครับ
# เช่น export GEMINI_API_KEY="your_api_key_here" (สำหรับ Linux/macOS)
# หรือ set GEMINI_API_KEY="your_api_key_here" (สำหรับ Windows Command Prompt)
# หรือ $env:GEMINI_API_KEY="your_api_key_here" (สำหรับ Windows PowerShell)
import google.generativeai as genai
import os
import time
def simple_gemini_chat(prompt: str):
api_key = os.environ.get("GEMINI_API_KEY")
if not api_key:
print("กรุณาตั้งค่า GEMINI_API_KEY ใน Environment Variables ด้วยนะครับ")
return
genai.configure(api_key=api_key)
model = genai.GenerativeModel('gemini-pro')
try:
# เราต้องมาสร้าง chat object ใหม่ทุกครั้ง หรือจัดการ state เอง
chat = model.start_chat(history=[])
response = chat.send_message(prompt)
print(f"Gemini บอกว่า: {response.text}")
except Exception as e:
print(f"เกิดข้อผิดพลาดตอนคุยกับ Gemini: {e}")
finally:
# ถ้ามีอะไรต้อง Clean Up ก็ต้องมาเขียนตรงนี้เองครับ ซึ่งบางทีอาจจะลืมได้นะ
print("จบการสนทนา (แบบธรรมดา) ครับ")
if __name__ == "__main__":"
print("--- คุยกับ Gemini แบบธรรมดา ---")
simple_gemini_chat("แนะนำสถานที่ท่องเที่ยวในประเทศไทยหน่อยครับ")
time.sleep(2) # รอหน่อยนะครับ
simple_gemini_chat("เล่าเรื่องสั้นๆ เกี่ยวกับหมาป่าหน่อยครับ")
จากตัวอย่างนี้ จะเห็นว่าเราต้องคอยจัดการ genai.configure และ model.start_chat เองทุกครั้งใช่ไหมครับ ถ้ามีขั้นตอนที่ซับซ้อนกว่านี้ หรือมีทรัพยากรอื่นๆ ที่ต้อง open/close โค้ดเราก็จะเริ่มรกแล้วก็มีโอกาสพลาดได้ง่ายๆ เลยครับ
มาโปรขึ้นด้วย Context Manager กันครับ!
คราวนี้เราจะสร้างคลาสเล็กๆ ที่ทำงานเป็น Context Manager เพื่อห่อหุ้มการจัดการ Gemini API นะครับ แบบนี้โค้ดเราจะ optimization ขึ้นเยอะเลย และ resilience ด้วยครับ ลองดูโค้ดตัวอย่างกันนะ
# gemini_cli_pro.py
# ก่อนรันโค้ด อย่าลืมติดตั้ง library ด้วย pip install google-generativeai
# และตั้งค่า Environment Variable GEMINI_API_KEY ด้วย API Key ของคุณนะครับ
import google.generativeai as genai
import os
import time
class GeminiChatSession:
def __init__(self, api_key: str):
self.api_key = api_key
self.model = None
self.chat = None
def __enter__(self):
# นี่คือส่วนที่ Context Manager จะรันตอนเริ่ม 'with' Block นะครับ
genai.configure(api_key=self.api_key)
self.model = genai.GenerativeModel('gemini-pro')
self.chat = self.model.start_chat(history=[])
print("--- เริ่ม Gemini Chat Session ครับ ---")
return self.chat # คืน chat object ให้เอาไปใช้งานใน 'with' Block
def __exit__(self, exc_type, exc_val, exc_tb):
# ตรงนี้แหละครับที่เราสามารถจัดการ Clean Up, Log Error หรือ Retry ได้
# ไม่ว่าใน 'with' Block จะเกิด Error หรือไม่ก็ตาม ส่วนนี้จะถูกรันเสมอครับ
if exc_type:
print(f"เกิดข้อผิดพลาดใน Session: {exc_val}")
# อาจจะส่ง Error ไปที่ระบบ Log ของเราเพื่อตรวจสอบได้นะครับ ทำให้ App เรา Resilient ขึ้นนะ
print("--- จบ Gemini Chat Session ครับ (ไม่ว่าจะเกิดอะไรขึ้น) ---")
# ไม่มีเมธอด Disconnect ชัดเจนสำหรับ genai library แต่ถ้ามีทรัพยากรอื่น เราก็จัดการได้ตรงนี้เลย
def pro_gemini_chat(prompt: str):
api_key = os.environ.get("GEMINI_API_KEY")
if not api_key:
print("กรุณาตั้งค่า GEMINI_API_KEY ใน Environment Variables ด้วยนะครับ")
return
with GeminiChatSession(api_key) as chat_session:
try:
response = chat_session.send_message(prompt)
print(f"Gemini ตอบว่า: {response.text}")
except Exception as e:
print(f"ข้อผิดพลาดระหว่างส่งข้อความ: {e}")
if __name__ == "__main__":"
print("\
--- คุยกับ Gemini แบบโปรด้วย Context Manager ---")
pro_gemini_chat("เล่าเรื่องสั้นเกี่ยวกับอวกาศให้ฟังหน่อยครับ")
time.sleep(2)
pro_gemini_chat("เพลงที่ฮิตที่สุดในปี 2000 มีเพลงอะไรบ้างครับ")
# ลองดูเวลาเกิด Error ครับ จะเห็นว่า __exit__ ก็ยังทำงานอยู่ดีนะ
print("\
--- ลองทดสอบเมื่อเกิดข้อผิดพลาด (เช่น API Key ผิด) ---")
# สมมติว่าตั้งใจทำให้ Key ผิด เพื่อดูว่า Context Manager ทำงานยังไงตอนมี Error
os.environ["GEMINI_API_KEY"] = "BAD_KEY"
pro_gemini_chat("สวัสดีครับ") # ควรจะเห็น Error
# คืนค่า Key เดิม (สมมติว่า Key ถูกต้องแล้ว) เพื่อการทดสอบต่อไปนะ
os.environ["GEMINI_API_KEY"] = "YOUR_REAL_API_KEY" # ต้องเปลี่ยนเป็น API Key จริงๆ ของคุณนะ
print("ถึงแม้มี Error แต่ Context Manager ก็จัดการจบ Session ให้ครับ")
จะเห็นว่าโค้ด pro_gemini_chat ดูสะอาดตาขึ้นเยอะเลยใช่ไหมครับ เพราะว่าการจัดการ genai.configure และ model.start_chat รวมถึงการจัดการตอนจบ Session ย้ายไปอยู่ใน GeminiChatSession หมดแล้วครับ ทำให้เราไม่ต้องมานั่งกังวลเรื่องการ Clean Up ทรัพยากรเองเลยนะ ถ้าเกิด Error ขึ้นมาใน with block เมธอด __exit__ ก็ยังถูกเรียกใช้เสมอครับ แบบนี้แหละครับที่ทำให้แอปพลิเคชันของเรามีความ resilience มากขึ้นอย่างเห็นได้ชัดเลย
สรุปนะครับ
การใช้ Context Manager ไม่ได้แค่ทำให้โค้ดเราดูดีขึ้นนะครับ แต่มันช่วยให้แอปพลิเคชัน CLI ของเราที่คุยกับ Gemini API มีความ resilience สูงขึ้นอย่างเห็นได้ชัด เพราะมันช่วยจัดการ Lifecycle ของทรัพยากรต่างๆ ให้เราอย่างอัตโนมัติ ทำให้เราไม่ต้องกังวลว่าจะลืมปิด หรือทำความสะอาดอะไรครับ โค้ดก็จะ optimization ในแง่ของความอ่านง่ายและบำรุงรักษาง่ายด้วยนะ ลองเอาไปปรับใช้กับโปรเจกต์ของเพื่อนๆ ดูนะครับ!