my-gradio-app / agents /core /unified_tone.py
Nguyen Trong Lap
Recreate history without binary blobs
eeb0f9c
"""
Unified Tone System - Ensures consistent personality across all agents
Makes the AI feel like ONE knowledgeable assistant, not multiple people
"""
class UnifiedTone:
"""
Provides consistent tone and personality across all agents
The AI is ONE medical professional with multiple specialties
"""
# Base personality - applies to ALL agents
BASE_PERSONALITY = """
Bạn là một trợ lý sức khỏe AI thông minh và đa năng.
QUAN TRỌNG - Tính nhất quán:
- Bạn là MỘT NGƯỜI duy nhất với nhiều chuyên môn
- KHÔNG tự giới thiệu là "chuyên gia dinh dưỡng" hay "huấn luyện viên"
- Chỉ nói "Tôi sẽ tư vấn về [lĩnh vực]" khi cần
- Giữ giọng điệu nhất quán xuyên suốt
SMART GREETING - Câu đầu tiên:
- Nếu user CHỈ chào (vd: "chào", "hello") → Chào đầy đủ + giới thiệu
- Nếu user VÀO THẲNG VẤN ĐỀ (vd: "đau lưng", "tôi muốn giảm cân") → Chào ngắn gọn + trả lời luôn
* Ví dụ: "Chào bạn! Để giúp bạn về vấn đề đau lưng..."
* KHÔNG greeting dài dòng khi user đã có vấn đề cụ thể
Phong cách chung:
- Thân thiện nhưng chuyên nghiệp
- Rõ ràng, súc tích, dễ hiểu
- Quan tâm nhưng không quá emotional
- Thực tế, có căn cứ khoa học
- Tránh emoji quá nhiều (chỉ dùng khi cần thiết)
"""
# Smooth transitions between specialties
TRANSITION_PHRASES = {
'to_nutrition': "Về mặt dinh dưỡng, ",
'to_exercise': "Về vận động và tập luyện, ",
'to_symptom': "Về triệu chứng bạn đang gặp, ",
'to_mental': "Về mặt tinh thần và cảm xúc, ",
'general': "Dựa trên thông tin bạn cung cấp, "
}
@staticmethod
def apply_unified_tone(response: str, agent_type: str) -> str:
"""
Apply unified tone to agent response
Ensures consistency across all agents
"""
# Remove agent-specific introductions
replacements = [
("Tôi là chuyên gia dinh dưỡng", "Về dinh dưỡng"),
("Tôi là huấn luyện viên", "Về tập luyện"),
("Với tư cách bác sĩ", "Theo y học"),
("Là chuyên gia tâm lý", "Về mặt tâm lý"),
]
for old, new in replacements:
response = response.replace(old, new)
# Moderate emoji usage
if agent_type == 'symptom':
# Remove excessive medical emojis
response = response.replace('🏥', '').replace('💊', '')
elif agent_type == 'exercise':
# Keep motivational but not excessive
response = response.replace('💪💪💪', '💪')
response = response.replace('🔥🔥🔥', '🔥')
return response
@staticmethod
def create_smooth_handoff(from_agent: str, to_agent: str, context: str) -> str:
"""
Create smooth transition between agent specialties
Makes it feel like one person switching topics, not different people
"""
transition = UnifiedTone.TRANSITION_PHRASES.get(f'to_{to_agent}', '')
# Don't say "I'm handing you over to..."
# Instead, smoothly transition topics
handoff_message = f"{context}\n\n{transition}"
return handoff_message
@staticmethod
def check_information_before_asking(chat_history: list, field: str) -> bool:
"""
Check if information already exists in chat history
Prevents duplicate questions across agents
"""
import re
# Patterns to check for each field
patterns = {
'age': r'\d+\s*tuổi',
'gender': r'(nam|nữ|male|female)',
'weight': r'\d+\s*kg',
'height': r'\d+\s*cm',
'goal': r'(giảm cân|tăng cân|tăng cơ|khỏe mạnh)',
'condition': r'(tiểu đường|huyết áp|tim mạch|dị ứng)'
}
if field not in patterns:
return False
# Check all messages in history
for user_msg, bot_msg in chat_history:
if user_msg and re.search(patterns[field], user_msg.lower()):
return True # Information already provided
if bot_msg and "không biết" in bot_msg.lower():
return True # User already declined to provide
return False
@staticmethod
def generate_smart_question(needed_info: list, chat_history: list) -> str:
"""
Generate intelligent questions that don't repeat
Groups multiple needs into one natural question
"""
# Filter out already known information
actually_needed = []
for info in needed_info:
if not UnifiedTone.check_information_before_asking(chat_history, info):
actually_needed.append(info)
if not actually_needed:
return "" # Don't ask anything
# Group related questions
if len(actually_needed) > 2:
# Ask for multiple things naturally
return "Để tư vấn chính xác, bạn có thể cho tôi biết tuổi, giới tính, cân nặng và mục tiêu của bạn được không?"
elif len(actually_needed) == 2:
field_names = {
'age': 'tuổi',
'gender': 'giới tính',
'weight': 'cân nặng',
'height': 'chiều cao',
'goal': 'mục tiêu'
}
fields = ' và '.join([field_names.get(f, f) for f in actually_needed])
return f"Bạn có thể cho tôi biết {fields} của bạn không?"
else:
# Single question
questions = {
'age': "Bạn bao nhiêu tuổi?",
'gender': "Giới tính của bạn là gì?",
'weight': "Cân nặng hiện tại của bạn là bao nhiêu?",
'height': "Chiều cao của bạn là bao nhiêu?",
'goal': "Mục tiêu sức khỏe của bạn là gì?"
}
return questions.get(actually_needed[0], "")