File size: 6,745 Bytes
10d681d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import os
import json
import time
import random
import google.generativeai as genai
from google.api_core import exceptions

# ตัวแปรสำหรับเก็บโมเดล Gemini
model = None

# ตั้งค่า API Key และโมเดล
try:
    # อ่าน API Key จาก Environment Secret
    GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY')
    if not GEMINI_API_KEY:
        # ข้อความภาษาไทยที่แก้ไขแล้ว
        raise ValueError("ไม่พบ GEMINI_API_KEY ใน Environment Secret")
    
    genai.configure(api_key=GEMINI_API_KEY)
    # ใช้ gemini-1.5-flash เพื่อความรวดเร็วในการประมวลผล NLU
    model = genai.GenerativeModel('gemini-1.5-flash') 
except Exception as e:
    # ข้อความภาษาไทยที่แก้ไขแล้ว
    print(f"เกิดข้อผิดพลาดร้ายแรงตอนตั้งค่า Gemini: {e}")
    model = None

def generate_with_retry(model, prompt, max_retries=5):
    """เรียกใช้ Gemini API พร้อมกลไกการลองซ้ำ (retry) และ Exponential Backoff"""
    if not model:
        # ข้อความภาษาไทยที่แก้ไขแล้ว
        return {"intent": "error", "message": "Gemini model ไม่ได้ถูกตั้งค่าอย่างถูกต้อง"}

    attempt = 0
    wait_time = 1
    
    # กำหนดโครงสร้าง JSON และ System Instruction สำหรับ NLU
    config = {
        "generation_config": {
            "response_mime_type": "application/json",
        },
        "safety_settings": [
            {"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE"},
            {"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE"},
            {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_NONE"},
            {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE"},
        ]
    }
    
    system_instruction = """คุณคือ Natural Language Understanding (NLU) Processor ที่เก่งภาษาไทย
    หน้าที่ของคุณคือแปลงข้อความของผู้ใช้ให้เป็น JSON ที่มี intent และ entities เท่านั้น
    - intent: คือเจตนาหลักของผู้ใช้
    - entities: คือข้อมูลสำคัญที่สกัดได้จากข้อความ
    ห้ามเพิ่มข้อความอธิบายอื่นใดนอกเหนือจาก JSON object ที่ร้องขอ
    ตัวอย่าง:
    - ข้อความ: \"อยากจองห้องพักสำหรับ 2 คน วันที่ 25 ธันวา\"
    - ผลลัพธ์ JSON: {\"intent\": \"create_booking\", \"entities\": {\"guests\": 2, \"date\": \"25-12\"}}
    - ข้อความ: \"ขอดูข้อมูลผู้เช่าห้อง A101\"
    - ผลลัพธ์ JSON: {\"intent\": \"get_renter\", \"entities\": {\"room_number\": \"A101\"}}
    """
    
    while attempt < max_retries:
        try:
            response = model.generate_content(
                [system_instruction, prompt],
                generation_config=config["generation_config"],
                safety_settings=config["safety_settings"]
            )
            return response
            
        except exceptions.ResourceExhausted as e:
            # ข้อความภาษาไทยที่แก้ไขแล้ว
            print(f"Too Many Requests, กำลังลองใหม่ใน {wait_time} วินาที...")
            time.sleep(wait_time + random.uniform(0, 1))
            wait_time *= 2
            attempt += 1
        except Exception as e:
            # ข้อความภาษาไทยที่แก้ไขแล้ว
            print(f"เกิดข้อผิดพลาดที่ไม่คาดคิดขณะเรียก Gemini: {e}")
            return None
    
    print("ไม่สามารถรับการตอบกลับได้หลังจากการพยายามหลายครั้ง")
    return None

def process_user_message(user_message):
    """ประมวลผลข้อความของผู้ใช้เพื่อแยก Intent และ Entities"""
    
    # ใช้ Prompt ที่เรียบง่ายเนื่องจาก System Instruction กำหนดรูปแบบเอาไว้แล้ว
    prompt = f"ข้อความของผู้ใช้: '{user_message}'"

    response = generate_with_retry(model, prompt)

    if response and response.text:
        try:
            # โมเดลถูกบังคับให้ตอบกลับเป็น JSON ด้วย response_mime_type
            return json.loads(response.text)
        except json.JSONDecodeError:
            # ข้อความภาษาไทยที่แก้ไขแล้ว
            return {"intent": "error", "message": f"ผลลัพธ์ไม่ใช่ JSON ที่ถูกต้อง: {response.text}"}
    else:
        # ข้อความภาษาไทยที่แก้ไขแล้ว
        return {"intent": "error", "message": "ไม่ได้รับการตอบกลับจาก Gemini หรือข้อความว่างเปล่า"}

# ตัวอย่างการใช้งาน (สำหรับทดสอบ)
if __name__ == '__main__':
    # รันโค้ดนี้เมื่อไฟล์ถูกเรียกใช้โดยตรง
    print("--- ทดสอบ NLU Processor ---")
    
    test_message_1 = "ฉันอยากจองตั๋วรถไฟไปหัวหินวันที่ 25 ธันวาคม"
    print(f"\nข้อความที่ 1: {test_message_1}")
    result_1 = process_user_message(test_message_1)
    # ใช้ ensure_ascii=False เพื่อแสดงผลภาษาไทยใน JSON
    print(json.dumps(result_1, indent=4, ensure_ascii=False))

    test_message_2 = "สวัสดีครับ"
    print(f"\nข้อความที่ 2: {test_message_2}")
    result_2 = process_user_message(test_message_2)
    print(json.dumps(result_2, indent=4, ensure_ascii=False))