Files
Input_to_route/ouput_chat.py

278 lines
13 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Модуль для генерации описаний маршрутов и ответов на вопросы пользователей.
Использует Gemini-2.5-flash API через requests библиотеку.
"""
import json
import requests
from typing import List, Dict, Optional
class RouteDescriber:
"""
Класс для работы с описанием маршрутов и ответами на вопросы пользователей.
"""
def __init__(self):
"""
Инициализация с API ключом Gemini.
Args:
api_key: API ключ для доступа к Gemini API
"""
self.api_key = 'AIzaSyBXGBGH5NDY8L_jVmq2zb4i8xYEV2qN-48'
self.base_url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent"
self.conversation_history = []
self.route_points = []
self.route_description = ""
self.parser_chat_context = ""
def _call_gemini(self, prompt: str, system_instruction: Optional[str] = None) -> str:
"""
Выполняет запрос к Gemini API.
Args:
prompt: Текст промпта
system_instruction: Системная инструкция для модели
Returns:
Ответ модели
"""
url = f"{self.base_url}?key={self.api_key}"
headers = {
"Content-Type": "application/json"
}
# Формируем тело запроса
contents = []
# Добавляем историю разговора
for msg in self.conversation_history:
contents.append(msg)
# Добавляем текущий промпт
contents.append({
"role": "user",
"parts": [{"text": prompt}]
})
payload = {
"contents": contents
}
# Добавляем системную инструкцию если есть
if system_instruction:
payload["system_instruction"] = {
"parts": [{"text": system_instruction}]
}
try:
response = requests.post(url, headers=headers, json=payload, timeout=30)
response.raise_for_status()
result = response.json()
# Извлекаем текст ответа
if "candidates" in result and len(result["candidates"]) > 0:
candidate = result["candidates"][0]
if "content" in candidate and "parts" in candidate["content"]:
answer = candidate["content"]["parts"][0]["text"]
# Сохраняем в историю
self.conversation_history.append({
"role": "user",
"parts": [{"text": prompt}]
})
self.conversation_history.append({
"role": "model",
"parts": [{"text": answer}]
})
return answer
return "Ошибка при получении ответа"
except requests.exceptions.RequestException as e:
return f"Ошибка запроса: {str(e)}"
def generate_route_description(self, route_points: List[Dict],
parser_chat_history: Optional[List[Dict]] = None) -> str:
"""
Генерирует описание маршрута на основе точек.
Args:
route_points: Список точек маршрута с полями 'name' и 'description'
parser_chat_history: История чата с парсером в формате [{"role": "user"/"model", "text": "..."}]
Returns:
Описание маршрута (1-2 предложения на точку)
"""
self.route_points = route_points
self.conversation_history = [] # Очищаем историю для нового маршрута
# Обрабатываем историю чата с парсером
if parser_chat_history:
parser_messages = []
for msg in parser_chat_history:
role = msg.get('role', 'user')
text = msg.get('text', '')
parser_messages.append(f"{role.upper()}: {text}")
self.parser_chat_context = "\n".join(parser_messages)
else:
self.parser_chat_context = ""
# Формируем промпт
points_info = []
for i, point in enumerate(route_points, 1):
name = point.get('name', f'Точка {i}')
description = point.get('description', '')
points_info.append(f"{i}. {name}\nОписание: {description}")
prompt = f"""Создай краткое описание маршрута из {len(route_points)} точек.
Для каждой точки напиши 1-2 предложения, которые заинтересуют посетителя.
Используй только информацию из описаний точек.
Точки маршрута:
{chr(10).join(points_info)}
Формат ответа:
1. [Название точки]: [1-2 предложения описания]
2. [Название точки]: [1-2 предложения описания]
..."""
# Добавляем контекст парсера если есть
if self.parser_chat_context:
prompt = f"""История запроса пользователя:
{self.parser_chat_context}
{prompt}"""
system_instruction = """Ты — помощник для описания туристических маршрутов.
Твоя задача — создавать краткие, привлекательные описания точек маршрута (1-2 предложения на точку).
Используй только информацию, представленную в описаниях точек.
Пиши на русском языке."""
description = self._call_gemini(prompt, system_instruction)
self.route_description = description
return description
def answer_question(self, question: str) -> str:
"""
Отвечает на вопрос пользователя о точках маршрута.
Видит всю историю вопросов и ответов, а также описание маршрута.
Args:
question: Вопрос пользователя
Returns:
Ответ на основе информации из описаний точек
"""
# Формируем контекст с информацией о точках
points_context = []
for i, point in enumerate(self.route_points, 1):
name = point.get('name', f'Точка {i}')
description = point.get('description', 'Нет описания')
points_context.append(f"{i}. {name}: {description}")
context = "\n\n".join(points_context)
# Добавляем информацию о парсере если есть
parser_info = ""
if self.parser_chat_context:
parser_info = f"""
ИСТОРИЯ ЗАПРОСА ПОЛЬЗОВАТЕЛЯ (для контекста):
{self.parser_chat_context}
"""
# Добавляем описание маршрута если оно было сгенерировано
route_desc_info = ""
if self.route_description:
route_desc_info = f"""
ОПИСАНИЕ МАРШРУТА, КОТОРОЕ БЫЛО ПОКАЗАНО ПОЛЬЗОВАТЕЛЮ:
{self.route_description}
"""
system_instruction = f"""Ты — помощник по туристическому маршруту.
{parser_info}{route_desc_info}
ДОСТУПНАЯ ИНФОРМАЦИЯ О ТОЧКАХ МАРШРУТА:
{context}
СТРОГИЕ ПРАВИЛА:
1. Отвечай ТОЛЬКО на вопросы о точках маршрута
2. Используй ТОЛЬКО информацию из описаний точек выше
3. Если в описаниях нет информации для ответа на вопрос, вежливо уходи от ответа фразами вида "Вы узнаете ответ, когда посетите это место", адаптируй под контекст.
4. НЕ давай рекомендаций и советов
5. НЕ отвечай на вопросы, не связанные с маршрутом. В таких случаях отвечай: "Я могу ответить только на вопросы о точках вашего маршрута"
6. НЕ придумывай информацию, которой нет в описаниях
7. Отвечай кратко и по существу на русском языке
8. Ты видишь всю историю разговора, поэтому можешь отвечать на уточняющие вопросы"""
answer = self._call_gemini(question, system_instruction)
return answer
def reset_conversation(self):
"""Очищает историю разговора."""
self.conversation_history = []
self.route_points = []
self.route_description = ""
self.parser_chat_context = ""
# Пример использования
if __name__ == "__main__":
# Инициализация (замените на ваш API ключ)
API_KEY = "YOUR_GEMINI_API_KEY"
describer = RouteDescriber(API_KEY)
# Пример истории чата с парсером
parser_chat = [
{"role": "user", "text": "Хочу погулять по центру Москвы, интересует история и искусство"},
{"role": "model", "text": "Понял, вы хотите прогулку по историческому центру с посещением музеев. Сколько времени у вас есть?"},
{"role": "user", "text": "Часа 3-4"},
{"role": "model", "text": "Отлично, я составил маршрут из 3 точек по центру Москвы с историческими местами и музеем искусства."}
]
# Пример данных маршрута
route_points = [
{
"name": "Красная площадь",
"description": "Главная площадь Москвы, окружённая историческими зданиями. Здесь находятся Кремль, собор Василия Блаженного и Мавзолей Ленина. Площадь была основана в конце XV века."
},
{
"name": "Парк Горького",
"description": "Один из самых известных парков Москвы, расположенный на берегу Москвы-реки. Здесь есть зоны для отдыха, спортивные площадки, прокат велосипедов. Парк был открыт в 1928 году."
},
{
"name": "Третьяковская галерея",
"description": "Художественный музей с крупнейшей коллекцией русского искусства. В экспозиции представлены работы от древнерусских икон до картин XX века. Основана купцом Павлом Третьяковым."
}
]
# Генерация описания маршрута с историей парсера
print("=== ОПИСАНИЕ МАРШРУТА ===")
description = describer.generate_route_description(route_points, parser_chat)
print(description)
print()
# Примеры вопросов (теперь с контекстом истории)
print("=== ДИАЛОГ С ПОЛЬЗОВАТЕЛЕМ ===")
questions = [
"Когда был основан Парк Горького?",
"А что там можно делать?", # Уточняющий вопрос о предыдущей теме
"Какие картины есть в Третьяковской галерее?",
"Сколько стоит билет?", # Без контекста, но система поймет что это про музей
"Расскажи про Кремль",
"Что посоветуешь взять с собой?", # Попытка получить рекомендацию
"Как погода сегодня?" # Нерелевантный вопрос
]
for q in questions:
print(f"\n👤 Пользователь: {q}")
answer = describer.answer_question(q)
print(f"🤖 Бот: {answer}")