wanderlust-chatbot / scripts /fix_ner_samples.py
Kiriten892's picture
Wave 3: expand NER fixture 85->102, time_preference F1 0.40->0.98, people/duration fixes
a832dee
Raw
History Blame Contribute Delete
9.66 kB
"""Fix the 17 new NER fixture samples added in Wave 3:
- Add proper Vietnamese diacritics to time_preference samples
- Fix gold annotations to be consistent with model keyword dictionaries
- Replace Bali Mount Batur with simpler text (avoid 'batu' FP)
- Fix 'Family of 4' sample to not conflict with travel_style suppression logic
"""
import json
import os
DATA_PATH = os.path.join(os.path.dirname(__file__), '..', 'app', 'data', 'datasets', 'ner_eval.json')
CORRECTED = [
# --- time_preference samples (12) with proper diacritics ---
# NOTE: each destination city annotated as BOTH 'location' AND 'destination'
# (matching convention in original 85 samples; model returns both)
{
'text': 'Muốn đi tham quan Hạ Long buổi sáng sớm trước khi tàu đông khách',
'language': 'vi',
'entities': [
{'type': 'location', 'value': 'ha-long'},
{'type': 'destination', 'value': 'ha-long'},
{'type': 'time_preference', 'value': 'early_morning'},
]
},
{
'text': 'Hội An 3 ngày, đi phố cổ buổi chiều và xem đèn lồng buổi tối',
'language': 'vi',
'entities': [
{'type': 'location', 'value': 'hoi-an'},
{'type': 'destination', 'value': 'hoi-an'},
{'type': 'duration', 'value': {'days': 3, 'nights': 2}},
{'type': 'time_preference', 'value': 'afternoon'},
{'type': 'time_preference', 'value': 'evening'},
]
},
{
'text': 'Chụp ảnh hoàng hôn ở Mũi Né, thích đi vào buổi chiều',
'language': 'vi',
'entities': [
{'type': 'location', 'value': 'mui-ne'},
{'type': 'destination', 'value': 'mui-ne'},
{'type': 'activity_preference', 'value': 'photography'},
{'type': 'time_preference', 'value': 'evening'},
]
},
{
'text': 'Sapa trekking buổi sáng, nghỉ trưa rồi tiếp tục leo núi',
'language': 'vi',
'entities': [
{'type': 'location', 'value': 'sapa'},
{'type': 'destination', 'value': 'sapa'},
{'type': 'activity_preference', 'value': 'trekking'},
{'type': 'time_preference', 'value': 'morning'},
{'type': 'time_preference', 'value': 'noon'},
]
},
{
'text': 'Hà Nội 2 ngày 1 đêm, tham quan buổi sáng, mua sắm buổi chiều',
'language': 'vi',
'entities': [
{'type': 'location', 'value': 'hanoi'},
{'type': 'destination', 'value': 'hanoi'},
{'type': 'duration', 'value': {'days': 2, 'nights': 1}},
{'type': 'activity_preference', 'value': 'sightseeing'},
{'type': 'activity_preference', 'value': 'shopping'},
{'type': 'time_preference', 'value': 'morning'},
{'type': 'time_preference', 'value': 'afternoon'},
]
},
{
'text': 'Nha Trang 4 ngày, lặn biển buổi sáng sớm và đi chợ đêm buổi tối',
'language': 'vi',
'entities': [
{'type': 'location', 'value': 'nha-trang'},
{'type': 'destination', 'value': 'nha-trang'},
{'type': 'duration', 'value': {'days': 4, 'nights': 3}},
{'type': 'activity_preference', 'value': 'diving'},
{'type': 'time_preference', 'value': 'early_morning'},
{'type': 'time_preference', 'value': 'evening'},
]
},
{
'text': 'Đi Phú Quốc ăn hải sản buổi trưa, ngắm hoàng hôn buổi chiều',
'language': 'vi',
'entities': [
{'type': 'location', 'value': 'phu-quoc'},
{'type': 'destination', 'value': 'phu-quoc'},
{'type': 'cuisine', 'value': 'seafood'},
{'type': 'time_preference', 'value': 'noon'},
{'type': 'time_preference', 'value': 'evening'},
]
},
{
# Bangkok: 'night markets in the evening' -> evening only (night compound suppressed)
'text': 'I want to explore Bangkok temples in the morning and night markets in the evening',
'language': 'en',
'entities': [
{'type': 'location', 'value': 'bangkok'},
{'type': 'destination', 'value': 'bangkok'},
{'type': 'activity_preference', 'value': 'sightseeing'},
{'type': 'time_preference', 'value': 'morning'},
{'type': 'time_preference', 'value': 'evening'},
]
},
{
'text': 'Kyoto 5 days, visit shrines early morning before crowds arrive',
'language': 'en',
'entities': [
{'type': 'location', 'value': 'kyoto'},
{'type': 'destination', 'value': 'kyoto'},
{'type': 'duration', 'value': {'days': 5, 'nights': 4}},
{'type': 'activity_preference', 'value': 'sightseeing'},
{'type': 'time_preference', 'value': 'early_morning'},
]
},
{
'text': 'Singapore 3 nights, food tour at noon and rooftop bar in the evening',
'language': 'en',
'entities': [
{'type': 'location', 'value': 'singapore'},
{'type': 'destination', 'value': 'singapore'},
{'type': 'duration', 'value': {'days': 3, 'nights': 3}},
{'type': 'cuisine', 'value': 'local_specialty'},
{'type': 'time_preference', 'value': 'noon'},
{'type': 'time_preference', 'value': 'evening'},
]
},
{
# Removed 'Mount Batur' to avoid 'batu' location FP; simplified to Bali morning hike
'text': 'Bali morning hike, afternoon spa and massage session',
'language': 'en',
'entities': [
{'type': 'location', 'value': 'bali'},
{'type': 'destination', 'value': 'bali'},
{'type': 'activity_preference', 'value': 'trekking'},
{'type': 'activity_preference', 'value': 'spa'},
{'type': 'time_preference', 'value': 'morning'},
{'type': 'time_preference', 'value': 'afternoon'},
]
},
{
'text': 'Paris night tour: Eiffel Tower at night, brunch in the morning',
'language': 'en',
'entities': [
{'type': 'location', 'value': 'paris'},
{'type': 'destination', 'value': 'paris'},
{'type': 'activity_preference', 'value': 'sightseeing'},
{'type': 'time_preference', 'value': 'night'},
{'type': 'time_preference', 'value': 'morning'},
]
},
# --- people edge cases (5 samples) ---
{
# 'Solo backpacker 7 days' - explicit '7 days' duration
# gold: backpacker+adventure (both fired by model keywords)
'text': 'Solo backpacker trip to Sapa 7 days, hiking and photography',
'language': 'en',
'entities': [
{'type': 'location', 'value': 'sapa'},
{'type': 'destination', 'value': 'sapa'},
{'type': 'duration', 'value': {'days': 7, 'nights': 6}},
{'type': 'people', 'value': {'adults': 1, 'children': 0, 'infants': 0}},
{'type': 'travel_style', 'value': 'backpacker'},
{'type': 'travel_style', 'value': 'adventure'},
{'type': 'activity_preference', 'value': 'trekking'},
{'type': 'activity_preference', 'value': 'photography'},
]
},
{
'text': 'Couple trip to Bali 7 days, honeymoon package',
'language': 'en',
'entities': [
{'type': 'location', 'value': 'bali'},
{'type': 'destination', 'value': 'bali'},
{'type': 'duration', 'value': {'days': 7, 'nights': 6}},
{'type': 'people', 'value': {'adults': 2, 'children': 0, 'infants': 0}},
{'type': 'travel_style', 'value': 'honeymoon'},
]
},
{
'text': 'Group of 8 friends to Da Nang beach, budget hostel',
'language': 'en',
'entities': [
{'type': 'location', 'value': 'da-nang'},
{'type': 'destination', 'value': 'da-nang'},
{'type': 'people', 'value': {'adults': 8, 'children': 0, 'infants': 0}},
{'type': 'hotel_type', 'value': 'hostel'},
]
},
{
'text': 'Đi Phú Quốc 2 vợ chồng 5 ngày nghỉ dưỡng',
'language': 'vi',
'entities': [
{'type': 'location', 'value': 'phu-quoc'},
{'type': 'destination', 'value': 'phu-quoc'},
{'type': 'duration', 'value': {'days': 5, 'nights': 4}},
{'type': 'people', 'value': {'adults': 2, 'children': 0, 'infants': 0}},
{'type': 'travel_style', 'value': 'relaxation'},
]
},
{
'text': 'Gia đình 5 người đi Đà Lạt 4 ngày, có 2 trẻ em',
'language': 'vi',
'entities': [
{'type': 'location', 'value': 'da-lat'},
{'type': 'destination', 'value': 'da-lat'},
{'type': 'duration', 'value': {'days': 4, 'nights': 3}},
{'type': 'people', 'value': {'adults': 3, 'children': 2, 'infants': 0}},
{'type': 'travel_style', 'value': 'family'},
]
},
]
assert len(CORRECTED) == 17, f'Expected 17, got {len(CORRECTED)}'
data = json.load(open(DATA_PATH, encoding='utf-8'))
print(f'Before: {len(data)} samples')
data[85:] = CORRECTED
print(f'After: {len(data)} samples')
tp = sum(1 for s in data if any(e['type'] == 'time_preference' for e in s.get('entities', [])))
print(f'time_preference samples: {tp}')
json.dump(data, open(DATA_PATH, 'w', encoding='utf-8'), ensure_ascii=False, indent=2)
print('Saved.')