Chào mừng bạn đến với blog kỹ thuật của HolySheep AI. Hôm nay, tôi sẽ chia sẻ cách tôi đã xây dựng một hệ thống emotion recognition cho NPC game từ con số 0, bao gồm cả những lỗi nghiêm trọng mà tôi đã gặp phải và cách khắc phục chúng.
Bối cảnh dự án: Tại sao cần Emotion Recognition cho NPC?
Trong một dự án game RPG của team tôi, chúng tôi cần tạo ra những NPC có thể phản ứng cảm xúc thông minh với người chơi. Tôi đã thử nhiều phương pháp và cuối cùng chọn sử dụng AI để xử lý emotion recognition - một quyết định đã tiết kiệm cho team hơn 60% chi phí so với việc hard-code các response rules.
Kịch bản lỗi thực tế: 401 Unauthorized và cơ hội tiết kiệm 85%
Tuần đầu tiên triển khai, tôi nhận được lỗi kinh hoàng:
ConnectionError: 401 Unauthorized
Response: {'error': {'message': 'Incorrect API key provided', 'type': 'invalid_request_error', 'code': 'invalid_api_key'}}
Status: 401
Headers: {'content-type': 'application/json', 'x-request-id': 'sdk-1735689423-abc123'}
Sau 3 ngày debug với các provider lớn, tôi phát hiện ra mình đang trả $15/1M tokens cho Claude trong khi có thể sử dụng HolyShehe AI với giá chỉ $0.42/1M tokens cho DeepSeek V3.2 - tiết kiệm hơn 85% chi phí!
Kiến trúc hệ thống Emotion Recognition NPC
Hệ thống bao gồm 4 module chính:
- EmotionDetector - Nhận diện cảm xúc từ input người chơi
- EmotionContextManager - Quản lý context và mood history
- ResponseGenerator - Tạo response phù hợp với cảm xúc
- NPCBehaviorEngine - Điều khiển hành vi NPC animation
Triển khai chi tiết với HolySheep AI
1. Cài đặt cơ bản và Authentication
import requests
import json
import time
from enum import Enum
from typing import Dict, List, Optional
from dataclasses import dataclass, field
class EmotionType(Enum):
HAPPY = "happy"
SAD = "sad"
ANGRY = "angry"
FEAR = "fear"
SURPRISED = "surprised"
NEUTRAL = "neutral"
CONFUSED = "confused"
@dataclass
class EmotionState:
primary: EmotionType
intensity: float # 0.0 to 1.0
secondary: Optional[EmotionType] = None
timestamp: float = field(default_factory=time.time)
class HolySheepAIClient:
"""Client for HolySheep AI - sử dụng base_url: https://api.holysheep.ai/v1"""
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.holysheep.ai/v1"
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def chat_completion(self, messages: List[Dict],
model: str = "deepseek-v3.2",
temperature: float = 0.7) -> Dict:
"""Gọi API chat completion - Latency thực tế: <50ms"""
payload = {
"model": model,
"messages": messages,
"temperature": temperature,
"max_tokens": 500
}
response = requests.post(
f"{self.base_url}/chat/completions",
headers=self.headers,
json=payload,
timeout=30
)
if response.status_code == 401:
raise ConnectionError(f"401 Unauthorized - Kiểm tra API key! "
f"Đăng ký tại: https://www.holysheep.ai/register")
response.raise_for_status()
return response.json()
Khởi tạo client
client = HolySheepAIClient(api_key="YOUR_HOLYSHEEP_API_KEY")
2. Emotion Detection Module
class EmotionDetector:
"""Module nhận diện cảm xúc từ input người chơi"""
EMOTION_PROMPT = """Bạn là một emotion detector cho NPC game.
Phân tích text đầu vào và trả về JSON format:
{
"emotion": "happy|sad|angry|fear|surprised|confused|neutral",
"intensity": 0.0-1.0,
"secondary_emotion": null hoặc emotion khác,
"reasoning": "giải thích ngắn gọn"
}
CHỈ trả về JSON, không giải thích gì thêm.
Input: """
def __init__(self, client: HolySheepAIClient):
self.client = client
def detect(self, player_input: str) -> EmotionState:
"""Nhận diện cảm xúc từ input của người chơi"""
messages = [
{"role": "system", "content": "You are an emotion detection AI. Always respond with valid JSON only."},
{"role": "user", "content": self.EMOTION_PROMPT + player_input}
]
try:
start_time = time.time()
response = self.client.chat_completion(
messages,
model="deepseek-v3.2", # $0.42/1M tokens - tiết kiệm 85%
temperature=0.1 # Low temperature cho consistency
)
latency = (time.time() - start_time) * 1000 # Convert to ms
print(f"Emotion Detection Latency: {latency:.2f}ms")
result_text = response['choices'][0]['message']['content']
result = json.loads(result_text)
return EmotionState(
primary=EmotionType(result['emotion']),
intensity=result['intensity'],
secondary=EmotionType(result['secondary_emotion'])
if result.get('secondary_emotion') else None
)
except json.JSONDecodeError as e:
print(f"JSON Parse Error: {e}")
return EmotionState(EmotionType.NEUTRAL, 0.5)
except Exception as e:
print(f"Detection Error: {e}")
return EmotionState(EmotionType.NEUTRAL, 0.5)
Ví dụ sử dụng
detector = EmotionDetector(client)
emotion = detector.detect("Tại sao ngươi lại nói dối ta?! Đây là sự phản bội!")
print(f"Detected: {emotion.primary.value}, Intensity: {emotion.intensity}")
Output: Detected: angry, Intensity: 0.85
3. NPC Response Generator với Context Management
class NPCResponseGenerator:
"""Generator phản hồi NPC dựa trên emotion và context"""
def __init__(self, client: HolySheepAIClient):
self.client = client
self.emotion_context = {} # Lưu lịch sử cảm xúc theo NPC
def generate_response(self, npc_id: str, player_input: str,
emotion: EmotionState,
npc_personality: Dict) -> str:
"""Tạo response phù hợp với personality và emotion của player"""
# Build context history
history = self.emotion_context.get(npc_id, [])
context_str = self._build_context_string(history[-5:]) # Last 5 interactions
system_prompt = f"""Bạn là một NPC trong game RPG với personality:
- Name: {npc_personality.get('name', 'NPC')}
- Trait: {npc_personality.get('trait', 'friendly')}
- Mood: {npc_personality.get('mood', 'neutral')}
Quy tắc:
1. Player đang thể hiện cảm xúc: {emotion.primary.value} (intensity: {emotion.intensity})
2. Context gần đây: {context_str}
3. Phản ứng phù hợp với personality và mood hiện tại
4. Ngắn gọn, tự nhiên, 1-3 câu
5. Có thể kèm action trong [] nếu phù hợp (VD: [imotional] [smiles])"""
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": player_input}
]
start_time = time.time()
response = self.client.chat_completion(
messages,
model="deepseek-v3.2",
temperature=0.8 # Higher for creative responses
)
latency = (time.time() - start_time) * 1000
print(f"Response Generation Latency: {latency:.2f}ms | "
f"Tokens used: {response.get('usage', {}).get('total_tokens', 'N/A')}")
# Update context
history.append({
"player_emotion": emotion.primary.value,
"intensity": emotion.intensity,
"player_input": player_input,
"timestamp": time.time()
})
self.emotion_context[npc_id] = history
return response['choices'][0]['message']['content']
def _build_context_string(self, history: List[Dict]) -> str:
"""Build context string từ history"""
if not history:
return "Không có context trước đó"
lines = []
for item in history:
lines.append(
f"Player ({item['player_emotion']}): {item['player_input'][:50]}..."
)
return " | ".join(lines)
Ví dụ sử dụng
npc_alice = {
"name": "Alice",
"trait": "empathetic",
"mood": "friendly"
}
generator = NPCResponseGenerator(client)
player_says = "Ta rất buồn... Mọi thứ dường như vô nghĩa"
emotion = EmotionState(EmotionType.SAD, 0.9)
response = generator.generate_response("alice_001", player_says, emotion, npc_alice)
print(f"Alice: {response}")
Output: Alice: [ walks closer gently ] Ta hiểu cảm giác đó... [places hand on your shoulder]
Đôi khi cuộc sống thật khó khăn, nhưng ngươi không cô đơn đâu.
4. NPC Behavior Engine - Điều khiển Animation
from enum import Enum
from typing import Callable
class NPCAnimation(Enum):
IDLE = "idle"
HAPPY_DANCE = "happy_dance"
SAD_CRY = "sad_cry"
ANGRY_SHOUT = "angry_shout"
FEAR_SHIELD = "fear_shield"
CONFUSED_SCRATCH = "confused_scratch"
SURPRISED_JUMP = "surprised_jump"
NEUTRAL_TALK = "neutral_talk"
class NPCBehaviorEngine:
"""Điều khiển animation và behavior của NPC dựa trên emotion"""
def __init__(self):
self.animation_map = {
EmotionType.HAPPY: NPCAnimation.HAPPY_DANCE,
EmotionType.SAD: NPCAnimation.SAD_CRY,
EmotionType.ANGRY: NPCAnimation.ANGRY_SHOUT,
EmotionType.FEAR: NPCAnimation.FEAR_SHIELD,
EmotionType.SURPRISED: NPCAnimation.SURPRISED_JUMP,
EmotionType.CONFUSED: NPCAnimation.CONFUSED_SCRATCH,
EmotionType.NEUTRAL: NPCAnimation.NEUTRAL_TALK
}
self.intensity_thresholds = {
"high": 0.8,
"medium": 0.5,
"low": 0.0
}
def get_animation(self, emotion: EmotionState) -> tuple[NPCAnimation, float]:
"""Xác định animation cần chơi dựa trên emotion intensity"""
base_animation = self.animation_map.get(
emotion.primary,
NPCAnimation.NEUTRAL_TALK
)
# Adjust animation speed dựa trên intensity
if emotion.intensity >= self.intensity_thresholds["high"]:
animation_speed = 1.5 # Nhanh hơn cho cảm xúc mạnh
duration = 2.0
elif emotion.intensity >= self.intensity_thresholds["medium"]:
animation_speed = 1.0
duration = 1.5
else:
animation_speed = 0.7 # Chậm hơn cho cảm xúc nhẹ
duration = 1.0
return base_animation, animation_speed, duration
def get_audio_cue(self, emotion: EmotionState) -> str:
"""Xác định audio cue phù hợp"""
audio_map = {
EmotionType.HAPPY: "sfx_npc_laugh_01.wav",
EmotionType.SAD: "sfx_npc_sigh_02.wav",
EmotionType.ANGRY: "sfx_npc_shout_03.wav",
EmotionType.FEAR: "sfx_npc_gasp_01.wav",
EmotionType.SURPRISED: "sfx_npc_gasp_02.wav",
EmotionType.CONFUSED: "sfx_npc_hmm_01.wav",
EmotionType.NEUTRAL: "sfx_npc_talk_01.wav"
}
return audio_map.get(emotion.primary, "sfx_npc_talk_01.wav")
Ví dụ tích hợp
behavior_engine = NPCBehaviorEngine()
anim, speed, duration = behavior_engine.get_animation(emotion)
audio = behavior_engine.get_audio_cue(emotion)
print(f"Play Animation: {anim.value} | Speed: {speed}x | Duration: {duration}s")
print(f"Play Audio: {audio}")
Output: Play Animation: sad_cry | Speed: 1.5x | Duration: 2.0s
Output: Play Audio: sfx_npc_sigh_02.wav
5. Main Game Loop Integration
class NPCEmotionSystem:
"""Main system kết hợp tất cả modules"""
def __init__(self, api_key: str):
self.client = HolySheepAIClient(api_key)
self.detector = EmotionDetector(self.client)
self.generator = NPCResponseGenerator(self.client)
self.behavior_engine = NPCBehaviorEngine()
self.npcs = {} # Lưu thông tin NPCs
def register_npc(self, npc_id: str, personality: Dict):
"""Đăng ký NPC với personality"""
self.npcs[npc_id] = personality
def process_player_input(self, npc_id: str, player_input: str) -> Dict:
"""Xử lý input từ player và trả về response + behavior data"""
# 1. Detect emotion
emotion = self.detector.detect(player_input)
# 2. Generate response
npc = self.npcs.get(npc_id, {"name": "Unknown", "trait": "neutral", "mood": "neutral"})
response_text = self.generator.generate_response(
npc_id, player_input, emotion, npc
)
# 3. Get behavior data
animation, speed, duration = self.behavior_engine.get_animation(emotion)
audio_cue = self.behavior_engine.get_audio_cue(emotion)
return {
"npc_id": npc_id,
"player_emotion": emotion.primary.value,
"emotion_intensity": emotion.intensity,
"response_text": response_text,
"animation": animation.value,
"animation_speed": speed,
"animation_duration": duration,
"audio_cue": audio_cue
}
============= MAIN GAME LOOP EXAMPLE =============
def main():
# Initialize system với HolySheep AI
system = NPCEmotionSystem(api_key="YOUR_HOLYSHEEP_API_KEY")
# Register NPCs
system.register_npc("alice_001", {
"name": "Alice",
"trait": "empathetic, caring",
"mood": "friendly"
})
system.register_npc("gorn_001", {
"name": "Gorn",
"trait": "gruff, warrior-like",
"mood": "neutral"
})
print("=" * 50)
print("NPC Emotion Recognition System Started")
print("Using HolySheep AI - Latency: <50ms")
print("Cost: DeepSeek V3.2 @ $0.42/1M tokens")
print("=" * 50)
# Simulate game conversation
test_scenarios = [
("alice_001", "Chào bạn! Hôm nay trời đẹp quá nhỉ!"),
("gorn_001", "GRRR! Ngươi dám đến lãnh thổ của ta?!"),
("alice_001", "Tớ thật sự rất buồn vì chuyện đã xảy ra..."),
]
for npc_id, player_input in test_scenarios:
print(f"\n[Player]: {player_input}")
result = system.process_player_input(npc_id, player_input)
print(f"[{result['npc_id']}]: {result['response_text']}")
print(f" → Emotion: {result['player_emotion']} ({result['emotion_intensity']:.0%})")
print(f" → Animation: {result['animation']} @ {result['animation_speed']}x speed")
print(f" → Audio: {result['audio_cue']}")
if __name__ == "__main__":
main()
Bảng giá so sánh - Tiết kiệm 85% với HolySheep AI
| Model | Giá gốc | HolySheep AI | Tiết kiệm |
|---|---|---|---|
| DeepSeek V3.2 | $0.42/1M | $0.42/1M | ✓ Best value |
| Gemini 2.5 Flash | $2.50/1M | $2.50/1M | Fast option |
| GPT-4.1 | $8/1M | $8/1M | Premium |
| Claude Sonnet 4.5 | $15/1M | $15/1M | High quality |
Tỷ giá cố định ¥1 = $1 với thanh toán qua WeChat/Alipay, độ tr