Files
hotels/test_semantic_search_chukotka.py

250 lines
9.5 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""
Тест семантического поиска по Чукотскому автономному округу
на основе готовой базы с эмбеддингами
"""
import psycopg2
from urllib.parse import unquote
import requests
import json
import time
# API настройки
BGE_API_URL = "http://147.45.146.17:8002/embed"
BGE_API_KEY = "22564b177aa73b6ac0b8642d7773350ff4c01d4983f028beff15ea247f09fa89"
class ChukotkaAnalyzer:
def __init__(self):
self.conn = None
self.cur = None
self.connect_db()
def connect_db(self):
"""Подключение к базе данных"""
try:
self.conn = psycopg2.connect(
host='147.45.189.234',
port=5432,
database='default_db',
user='gen_user',
password=unquote('2~~9_%5EkVsU%3F2%5CS')
)
self.conn.autocommit = True
self.cur = self.conn.cursor()
print("✅ Подключение к БД установлено")
except Exception as e:
print(f"❌ Ошибка подключения к БД: {e}")
raise
def get_chukotka_stats(self):
"""Получение статистики по Чукотке"""
self.cur.execute("""
SELECT
COUNT(DISTINCT metadata->>'hotel_id') as hotels_count,
COUNT(*) as total_chunks,
AVG(LENGTH(text)) as avg_chunk_length
FROM hotel_website_chunks
WHERE metadata->>'region_name' = 'Чукотский автономный округ';
""")
result = self.cur.fetchone()
return {
'hotels_count': result[0],
'total_chunks': result[1],
'avg_chunk_length': result[2]
}
def get_chukotka_hotels(self):
"""Получение списка отелей Чукотки"""
self.cur.execute("""
SELECT DISTINCT
metadata->>'hotel_id' as hotel_id,
metadata->>'hotel_name' as hotel_name,
COUNT(*) as chunks_count
FROM hotel_website_chunks
WHERE metadata->>'region_name' = 'Чукотский автономный округ'
GROUP BY metadata->>'hotel_id', metadata->>'hotel_name'
ORDER BY chunks_count DESC;
""")
return self.cur.fetchall()
def generate_query_embedding(self, query: str):
"""Генерация эмбеддинга для поискового запроса"""
try:
headers = {
"X-API-Key": BGE_API_KEY,
"Content-Type": "application/json"
}
payload = {"text": query}
response = requests.post(BGE_API_URL, json=payload, headers=headers, timeout=30)
if response.status_code == 200:
result = response.json()
return result.get('embeddings', [[]])[0]
else:
print(f"❌ Ошибка API: {response.status_code}")
return None
except Exception as e:
print(f"❌ Ошибка генерации эмбеддинга: {e}")
return None
def search_chukotka(self, query: str, limit: int = 5):
"""Семантический поиск по Чукотке"""
query_embedding = self.generate_query_embedding(query)
if not query_embedding:
return []
embedding_str = json.dumps(query_embedding)
self.cur.execute("""
SELECT
metadata->>'hotel_name' as hotel_name,
metadata->>'url' as url,
LEFT(text, 150) as sample_text,
LENGTH(text) as text_length,
embedding <-> %s::vector as distance
FROM hotel_website_chunks
WHERE metadata->>'region_name' = 'Чукотский автономный округ'
AND embedding IS NOT NULL
ORDER BY embedding <-> %s::vector
LIMIT %s;
""", (embedding_str, embedding_str, limit))
return self.cur.fetchall()
def analyze_hotel_criteria(self, hotel_id: str):
"""Анализ отеля по критериям аудита"""
criteria_queries = {
'Юридическая идентификация': 'инн огрн егрюл организация',
'Контактная информация': 'телефон адрес email контакты',
'Политика конфиденциальности': 'политика конфиденциальности персональные данные',
'Условия бронирования': 'бронирование условия отмена возврат',
'Услуги отеля': 'услуги сервис завтрак wi-fi парковка',
'Доступность': 'доступность инвалиды коляска лифт'
}
results = {}
for criteria, query in criteria_queries.items():
self.cur.execute("""
SELECT
embedding <-> %s::vector as distance,
LEFT(text, 200) as sample_text
FROM hotel_website_chunks
WHERE metadata->>'hotel_id' = %s
AND embedding IS NOT NULL
ORDER BY embedding <-> %s::vector
LIMIT 1;
""", (json.dumps(self.generate_query_embedding(query)), hotel_id, json.dumps(self.generate_query_embedding(query))))
result = self.cur.fetchone()
if result:
distance, sample_text = result
relevance = "🟢 Высокая" if distance < 0.9 else "🟡 Средняя" if distance < 1.0 else "🔴 Низкая"
results[criteria] = {
'distance': distance,
'relevance': relevance,
'sample_text': sample_text
}
return results
def close(self):
"""Закрытие соединения с БД"""
if self.cur:
self.cur.close()
if self.conn:
self.conn.close()
def main():
print("="*70)
print("🏔️ АНАЛИЗ ЧУКОТСКОГО АВТОНОМНОГО ОКРУГА")
print("="*70)
analyzer = ChukotkaAnalyzer()
try:
# Статистика по региону
stats = analyzer.get_chukotka_stats()
print(f"\n📊 СТАТИСТИКА ПО ЧУКОТКЕ:")
print(f" Отелей: {stats['hotels_count']}")
print(f" Chunks: {stats['total_chunks']}")
print(f" Средняя длина chunk: {stats['avg_chunk_length']:.0f} символов")
# Список отелей
hotels = analyzer.get_chukotka_hotels()
print(f"\n🏨 ОТЕЛИ ЧУКОТКИ:")
print("-" * 70)
for hotel_id, hotel_name, chunks_count in hotels:
print(f" 🏨 {hotel_name}")
print(f" ID: {hotel_id}")
print(f" Chunks: {chunks_count}")
print()
# Тестовые поисковые запросы
test_queries = [
"телефон отеля",
"услуги и сервисы",
"бронирование номеров",
"адрес и контакты",
"политика конфиденциальности",
"завтрак и питание"
]
print("🔍 ТЕСТИРОВАНИЕ СЕМАНТИЧЕСКОГО ПОИСКА:")
print("-" * 70)
for query in test_queries:
print(f"\n🔍 Запрос: '{query}'")
results = analyzer.search_chukotka(query, 3)
for i, (hotel_name, url, sample_text, text_length, distance) in enumerate(results, 1):
if distance < 0.9:
relevance = "🟢 Отлично"
elif distance < 1.0:
relevance = "🟡 Хорошо"
else:
relevance = "🔴 Слабо"
print(f" {i}. Distance: {distance:.4f} {relevance}")
print(f" Отель: {hotel_name[:50]}...")
print(f" Текст: {sample_text}...")
print()
# Анализ одного отеля по критериям
if hotels:
test_hotel_id, test_hotel_name, _ = hotels[0]
print(f"\n📋 АНАЛИЗ ОТЕЛЯ ПО КРИТЕРИЯМ:")
print(f"🏨 {test_hotel_name}")
print("-" * 70)
criteria_results = analyzer.analyze_hotel_criteria(test_hotel_id)
for criteria, data in criteria_results.items():
print(f"{data['relevance']} {criteria}")
print(f" Distance: {data['distance']:.4f}")
print(f" Найденный текст: {data['sample_text'][:100]}...")
print()
print("="*70)
print("✅ АНАЛИЗ ЗАВЕРШЁН!")
print("="*70)
except Exception as e:
print(f"❌ Ошибка анализа: {e}")
finally:
analyzer.close()
if __name__ == "__main__":
main()