Skip to content

Neko #266

Description

@xoxoxo-af
import json
import time
import os
from datetime import datetime
from typing import Dict, Optional, List
import urllib.request
import urllib.error

# === ตรวจสอบและโหลดไลบรารีสำหรับระบบเสียง ===
try:
    import speech_recognition as sr
    from gtts import gTTS
    import playsound
    VOICE_AVAILABLE = True
except ImportError:
    VOICE_AVAILABLE = False
    print("⚠️  คำเตือน: ไม่พบไลบรารีเสียง - ระบบจะทำงานในโหมดข้อความ (Text-only Mode)")
    print("💡 ติดตั้งด้วยคำสั่ง: pip install SpeechRecognition gTTS playsound pyaudio")


class MandateSyntaxAPI:
    """
    ระบบประมวลผลคำสั่งระดับสูง (Mandate Architecture) ที่ได้รับการตรวจสอบและแก้ไขจุดบั๊กแล้ว
    เชื่อมต่อกับ Google Gemini API (gemini-2.5-flash-preview-09-2025) 
    เพื่อแปลภาษาไทยธรรมชาติเป็นโครงสร้างสั่งงานทีม AI ทำเพลง (Songwriter, Singer, Producer)
    """
    def __init__(self):
        self.system_active = True
        self.security_protocols = {
            "omega": {"clearance": 9, "risk_limit": "medium"},
            "alpha": {"clearance": 7, "risk_limit": "low"},
            "critical": {"encryption": "AES-512", "integrity": "SHA-512"}
        }
        self.log_archive: List[str] = []
        self.active_agents: List[str] = []
        
        # ดึง API Key จาก Environment variable
        self.api_key = os.environ.get("GEMINI_API_KEY", "")
        
        # เริ่มต้นระบบรับคำสั่งเสียง
        if VOICE_AVAILABLE:
            try:
                self.recognizer = sr.Recognizer()
                # ปรับจูนเพื่อไม่ให้โปรแกรมค้างหากรอบข้างมีเสียงรบกวน
                self.recognizer.dynamic_energy_threshold = True
                self.recognizer.energy_threshold = 3000 
                self.recognizer.pause_threshold = 1.0 # เว้นจังหวะหยุดพูด 1 วินาทีถึงจะประมวลผล
            except Exception as e:
                print(f"⚠️  ไม่สามารถเชื่อมต่อไมโครโฟนได้: {e}")

    def _speak(self, text: str) -> None:
        """แปลงข้อความภาษาไทยเป็นเสียงพูด พร้อมระบบป้องกันไฟล์ถูกล็อก (File Lock Prevention)"""
        print(f"🔊 AI: {text}")
        if not VOICE_AVAILABLE:
            return
            
        filename = f"response_{int(time.time())}.mp3" # ใช้ Timestamp เพื่อป้องกันชื่อไฟล์ซ้ำซ้อน
        try:
            tts = gTTS(text=text, lang='th', slow=False)
            tts.save(filename)
            
            # เล่นเสียงแบบบล็อกการทำงาน
            playsound.playsound(filename, block=True)
            
            # หน่วงเวลาสั้นๆ ป้องกันไม่ให้ระบบล็อกไฟล์ OS พังขณะทำการลบ
            time.sleep(0.3)
            if os.path.exists(filename):
                os.remove(filename)
        except Exception as e:
            self._log("AUDIO OUTPUT", f"ไม่สามารถเล่นหรือลบไฟล์เสียงได้: {e}", "WARNING")
            # ทำความสะอาดไฟล์ที่ค้างในระบบหากมี
            try:
                if os.path.exists(filename):
                    os.remove(filename)
            except:
                pass

    def _listen(self) -> str:
        """รับเสียงพูดและแปลงเป็นข้อความภาษาไทย พร้อมป้องกันโปรแกรมค้าง"""
        if not VOICE_AVAILABLE:
            return input("\n⌨️  ป้อนคำสั่งของคุณ: ").strip()
        
        try:
            with sr.Microphone() as source:
                print("\n🎤 กำลังฟัง... พูดคำสั่งทำเพลงภาษาไทยของคุณได้เลยค่ะ")
                # ลด duration ลงเหลือ 0.5 วินาที เพื่อไม่ให้ผู้ใช้งานรอนานตอนเริ่มระบบ
                self.recognizer.adjust_for_ambient_noise(source, duration=0.5)
                # กำหนด timeout และ limit ให้กระชับขึ้นเพื่อป้องกันการค้างยาว
                audio = self.recognizer.listen(source, timeout=5, phrase_time_limit=8)
                print("🔍 กำลังถอดรหัสเสียงพูด...")
                text = self.recognizer.recognize_google(audio, language='th-TH')
                print(f"👂 ได้ยินว่า: \"{text}\"")
                return text.strip()
        except sr.WaitTimeoutError:
            # ไม่มีเสียงพูดเข้ามาในเวลาที่กำหนด
            return ""
        except sr.UnknownValueError:
            self._speak("ขออภัยค่ะ ฉันฟังคำนี้ไม่ชัดเจนเลย")
            return ""
        except Exception as e:
            self._log("AUDIO INPUT", f"สลับโหมดเป็นคีย์บอร์ดเนื่องจากเกิดข้อผิดพลาด: {e}", "WARNING")
            return input("\n⌨️  เกิดข้อผิดพลาดด้านระบบเสียง กรุณาพิมพ์คำสั่งแทน: ").strip()

    def _log(self, stage: str, message: str, level: str = "INFO") -> None:
        """ระบบบันทึก Log การทำงานร่วมกันของ AI Team"""
        timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
        entry = f"[{timestamp}] [{level}] {stage}: {message}"
        self.log_archive.append(entry)
        print(entry)

    def _call_gemini_llm(self, user_command: str) -> Optional[Dict]:
        """
        เชื่อมต่อกับ Google Gemini API โดยใช้โครงสร้างและข้อกำหนดที่ถูกต้อง 100%
        มีระบบป้องกันความหน่วงแบบ Exponential Backoff สูงสุด 5 ครั้ง
        """
        if not self.api_key:
            self._log("LLM ENGINE", "ไม่พบ API Key ในระบบ", "ERROR")
            return None

        url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-09-2025:generateContent?key={self.api_key}"
        
        # จัดชุดคำสั่ง (System Instruction) เพื่อบีบให้ AI ตอบกลับมาเป็น JSON ตามมาตรฐานที่คุณต้องการ
        system_instruction = (
            "คุณคือผู้จัดการกลางของทีม AI ทำเพลง (AI Music Orchestrator)\n"
            "มีหน้าที่รับคำสั่งภาษาไทยแล้วแปลงเป็น JSON Mandate เพื่อส่งต่อให้ทีมงาน AI ดังนี้:\n"
            "1. SONGWRITER-AI: แต่งเนื้อเพลง, คิด Hook ติดหู, วางโครงสร้างเพลง (Intro, Verse, Hook, Bridge)\n"
            "2. SINGER-AI: ตีความน้ำเสียง กำหนดอารมณ์ร้อง (Tone Voice, Emotion, Flow, Vocal Style)\n"
            "3. BEAT-DESIGNER: ดีไซน์บีท จังหวะ แนวเพลง (Sad Rap, Lo-Fi, Pop)\n"
            "4. VIRAL-HOOK: ปรับแต่งคำร้องจุดไคลแม็กซ์ให้เป็นไวรัลในโซเชียล\n"
            "5. MUSIC-ANALYST: วิเคราะห์โครงสร้างอารมณ์องค์รวมของเพลง\n\n"
            "คุณต้องตอบกลับเป็นข้อความ JSON เสมอ โดยห้ามมี Markdown หรือตัวอักษรอื่นนอกวงเล็บปีกกาเด็ดขาด และต้องประกอบไปด้วยคีย์เหล่านี้:\n"
            "{\n"
            "  \"intent\": \"[write_song | analyze_vocal | design_beat | system_status | shutdown | unknown]\",\n"
            "  \"mandate\": \"[ระบุวัตถุประสงค์งานภาษาอังกฤษสั้นๆ เช่น Compose Sad Rap Song]\",\n"
            "  \"priority\": \"[omega | alpha | critical]\",\n"
            "  \"target_agent\": \"[ระบุชื่อ Agent หลัก เช่น SONGWRITER-AI หรือ SINGER-AI]\",\n"
            "  \"constraints\": {\n"
            "     \"mood\": \"[ระบุอารมณ์เพลง เช่น เศร้า, เจ็บปวด, ดาร์ค, สดใส]\",\n"
            "     \"vocal_style\": \"[ระบุสไตล์เสียงร้อง เช่น เหนื่อยล้า, สดใส, แร็ปดุดัน]\",\n"
            "     \"genre\": \"[แนวเพลง เช่น Sad Rap, Lo-Fi, Hip Hop, R&B]\"\n"
            "  },\n"
            "  \"raw_text_extracted\": \"[ทวนข้อความต้นฉบับของผู้ใช้]\",\n"
            "  \"spoken_feedback\": \"[คำพูดภาษาไทยสั้นๆ 1 ประโยค เพื่อให้ระบบพูดตอบรับผู้ใช้]\"\n"
            "}"
        )

        # โครงสร้าง Payload ที่ถูกต้องตามหลักการพัฒนา Gemini API
        payload = {
            "contents": [{
                "parts": [{"text": f"คำสั่งผู้ใช้: {user_command}"}]
            }],
            "systemInstruction": {
                "parts": [{"text": system_instruction}]
            },
            "generationConfig": {
                "responseMimeType": "application/json"
            }
        }

        # การประมวลผลด้วย Exponential Backoff (1s, 2s, 4s, 8s, 16s)
        delays = [1, 2, 4, 8, 16]
        for attempt, delay in enumerate(delays):
            try:
                req = urllib.request.Request(
                    url,
                    data=json.dumps(payload).encode("utf-8"),
                    headers={"Content-Type": "application/json"},
                    method="POST"
                )
                with urllib.request.urlopen(req, timeout=12) as response:
                    res_body = response.read().decode("utf-8")
                    res_json = json.loads(res_body)
                    
                    # คัดแยกข้อมูลออกมาตรวจสอบความถูกต้อง
                    text_content = res_json['candidates'][0]['content']['parts'][0]['text']
                    return json.loads(text_content.strip())
                    
            except urllib.error.HTTPError as e:
                if e.code == 400 or e.code == 403:
                    self._log("LLM ENGINE", f"การยืนยันตัวตนผิดพลาด (กรุณาเช็ค API Key) Code: {e.code}", "ERROR")
                    break
                time.sleep(delay)
            except Exception as e:
                # เกิดปัญหาด้านการเชื่อมต่อหรือการพาร์ส JSON
                time.sleep(delay)
                
        return None

    def get_system_status(self) -> Dict:
        """ตรวจสอบสถานะระบบ"""
        return {
            "status": "ออนไลน์",
            "version": "Mandate AI Music Orchestrator v3.1 (Stable Verified)",
            "active_agents": len(self.active_agents),
            "logs_count": len(self.log_archive),
            "voice_system": "ทำงานปกติ" if VOICE_AVAILABLE else "ไม่พบบุปกรณ์เสียง (สลับใช้โหมดคีย์บอร์ด)"
        }

    def process_semantic_mandate(self, parsed_mandate: Dict) -> Dict:
        """
        ประมวลผลและส่งต่อหน้าที่ให้กลุ่ม AI Agents ทำงานร่วมกันตามระบบ Workflow ที่กำหนดไว้
        """
        intent = parsed_mandate.get("intent", "unknown")
        feedback = parsed_mandate.get("spoken_feedback", "กำลังประมวลผลคำสั่งตามแมนเดตค่ะ")
        self._speak(feedback)

        if intent == "shutdown":
            self.system_active = False
            return {"status": "ปิดระบบสมบูรณ์"}

        if intent == "system_status":
            status = self.get_system_status()
            self._speak(f"สถานะระบบขณะนี้เป็นปกติ มีบันทึกเหตุการณ์ทั้งหมด {status['logs_count']} รายการค่ะ")
            return status

        self._log("MANDATE INPUT", f"เริ่มกระบวนการตามเจตนา: {parsed_mandate.get('mandate')}", "SUCCESS")
        
        # คัดกรองและดึงค่า Constraints
        constraints = parsed_mandate.get("constraints", {})
        mood = constraints.get("mood", "ทั่วไป")
        vocal_style = constraints.get("vocal_style", "ปกติ")
        genre = constraints.get("genre", "Lo-Fi")
        
        # จัดแจงจัดสรร Agents (Orchestrator) ตามความคุ้นเคยและแนวคิด 6 Agents
        agents = ["MUSIC-ANALYST"]
        target_agent = parsed_mandate.get("target_agent", "SONGWRITER-AI")
        
        if target_agent == "SONGWRITER-AI":
            agents.extend(["SONGWRITER-AI", "VIRAL-HOOK"])
        elif target_agent == "SINGER-AI":
            agents.extend(["SINGER-AI", "SONGWRITER-AI"])
        elif target_agent == "BEAT-DESIGNER":
            agents.extend(["BEAT-DESIGNER", "SINGER-AI", "PRODUCER-AI"])
        else:
            agents.extend(["SONGWRITER-AI", "SINGER-AI", "PRODUCER-AI"])

        self.active_agents = list(set(agents))
        self._log("AGENT ORCHESTRATOR", f"ระดมพลทีมทำเพลง: {', '.join(self.active_agents)}", "SUCCESS")

        # จำลองการสร้างเนื้อเพลงและแนวการร้องตามกฎ AI Team ที่ตั้งไว้
        print("\n" + "🎵 " + "="*50 + " 🎵")
        print(f"🎬 [เริ่มสายการทำงานของ AI ทำเพลงอัตโนมัติ]")
        print(f"• อารมณ์ธีมเพลง: {mood}")
        print(f"• สไตล์การร้อง: {vocal_style}")
        print(f"• แนวบีทดนตรี: {genre}")
        print("="*54 + "\n")
        
        time.sleep(1.0) # จำลองระยะเวลาแต่งเนื้อเพลงและวิเคราะห์น้ำเสียง

        # การจำลองผลลัพธ์ของ Songwriter AI และ Singer AI แบบครบโครงสร้างจริง
        creative_output = {}
        if "SONGWRITER-AI" in self.active_agents:
            creative_output["Songwriter_AI_Output"] = {
                "structure": "Intro -> Verse 1 -> Hook -> Verse 2 -> Hook -> Bridge -> Final Hook",
                "lyric_sample": f"({mood.upper()} Verse 1) ในคืนที่ฟ้าหม่น แสงดาวมืดมนไร้ทาง... (Viral Hook) เจ็บปวดจนชินชา น้ำตามันไหลผ่านไหล่ขวา...",
                "flow_rap": "Slow-tempo 16-bars melodic flow"
            }
        
        if "SINGER-AI" in self.active_agents:
            creative_output["Singer_AI_Output"] = {
                "tone_voice": "Husky, Deep breathy chest tone",
                "emotion": f"{mood} (อารมณ์สะเทือนอารมณ์)",
                "vocal_style": f"{vocal_style} (เน้นการเว้นช่องไฟเพื่อสร้างความลึกของเพลง)"
            }

        result = {
            "status": "สร้างสรรค์ผลงานเสร็จสมบูรณ์",
            "theme_profile": constraints,
            "creative_details": creative_output,
            "system_stability": "100.0%",
            "completed_at": datetime.utcnow().isoformat()
        }

        self._log("EXECUTION LAYER", "ความเสถียรของงานเต็มพิกัด ส่งข้อมูลเข้าคลังข้อมูลสำเร็จ", "SUCCESS")
        self._speak("วิเคราะห์และเขียนเนื้อเพลงเสร็จสมบูรณ์เรียบร้อยแล้วค่ะ")
        return result

    def start_voice_assistant(self) -> None:
        """ฟังก์ชันเริ่มต้นคำสั่งเสียงทำเพลงร่วมกับ Gemini LLM"""
        # แนะนำการตั้งค่า API Key หากผู้ใช้ลืมระบุลงใน OS Environment
        if not self.api_key:
            print("\n⚠️  ระบบไม่พบ API Key ของ Google Gemini")
            print("กรุณาเปิด Terminal แล้วพิมพ์: export GEMINI_API_KEY=\"คีย์จริงของคุณ\"")
            self.api_key = input("🔑 หรือนำรหัส API Key มาวางตรงนี้เพื่อรันชั่วคราวได้เลยค่ะ: ").strip()
            if not self.api_key:
                print("❌ ไม่พบ API Key สิ้นสุดกระบวนการทำงาน")
                return

        print("\n" + "🚀 " + "="*56)
        print("🎤  [ระบบทีมสร้างสรรค์เพลงอัจฉริยะ AI Music Assistant - Verified]")
        print("="*60)
        
        self._speak("ระบบทีมเอไอพร้อมสร้างสรรค์เสียงดนตรีแล้วค่ะ")
        
        while self.system_active:
            try:
                user_input = self._listen()
                if not user_input:
                    continue

                print("🧠 กำลังประมวลผลคำสั่งเชิงลึกด้วยสมองกล Gemini...")
                parsed_mandate = self._call_gemini_llm(user_input)
                
                if parsed_mandate:
                    print(f"\n📋 โครงสร้างแมนเดตที่วิเคราะห์ได้จาก LLM:\n{json.dumps(parsed_mandate, indent=2, ensure_ascii=False)}")
                    result = self.process_semantic_mandate(parsed_mandate)
                    print(f"⚡ สรุปผลการปฏิบัติการ: {json.dumps(result, indent=2, ensure_ascii=False)}\n")
                else:
                    self._speak("เครือข่ายมีปัญหานิดหน่อยค่ะ ลองสั่งงานใหม่อีกครั้งนะคะ")
                    
            except KeyboardInterrupt:
                # รองรับการกด Ctrl+C เพื่อออกจากโปรแกรมอย่างปลอดภัย
                print("\n🛑 ตรวจพบคำสั่งหยุดการรันโปรแกรมจากคีย์บอร์ด")
                self._speak("ปิดระบบเรียบร้อยค่ะ ขอบคุณที่ใช้งานนะคะ")
                break


# -----------------------------------------------------------------------------
# 🚀 เริ่มทดสอบโปรแกรมทำเพลงอัจฉริยะ
# -----------------------------------------------------------------------------
if __name__ == "__main__":
    system = MandateSyntaxAPI()
    system.start_voice_assistant()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions