This commit is contained in:
2025-12-04 16:45:03 +03:00
parent cf8f71e24a
commit d48e3ff952

View File

@@ -1,28 +1,60 @@
import logging
import httpx
from openai import AsyncOpenAI
from config.settings import settings
from typing import Dict, List
logger = logging.getLogger(__name__)
class AIService:
"""Сервис для работы с OpenAI API через Cloudflare Gateway"""
def __init__(self):
self.api_key = settings.openai_api_key
# Проверяем, настроен ли Cloudflare AI Gateway
if settings.cloudflare_account_id:
# Используем Cloudflare AI Gateway
base_url = (
# Используем Cloudflare AI Gateway с прямыми HTTP запросами
self.base_url = (
f"https://gateway.ai.cloudflare.com/v1/"
f"{settings.cloudflare_account_id}/"
f"{settings.cloudflare_gateway_id}/"
f"compat"
)
self.client = AsyncOpenAI(
api_key=settings.openai_api_key,
base_url=base_url
f"openai"
)
self.use_cloudflare = True
logger.info(f"AI Service initialized with Cloudflare Gateway: {self.base_url}")
else:
# Прямое подключение к OpenAI
self.client = AsyncOpenAI(api_key=settings.openai_api_key)
self.base_url = "https://api.openai.com/v1"
self.use_cloudflare = False
logger.info("AI Service initialized with direct OpenAI connection")
# HTTP клиент для всех запросов
self.http_client = httpx.AsyncClient(
timeout=httpx.Timeout(60.0, connect=10.0),
limits=httpx.Limits(max_keepalive_connections=5, max_connections=10)
)
async def _make_openai_request(self, messages: list, temperature: float = 0.3, model: str = "gpt-4o-mini") -> dict:
"""Выполнить запрос к OpenAI API (через Cloudflare или напрямую)"""
url = f"{self.base_url}/chat/completions"
headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
}
payload = {
"model": model,
"messages": messages,
"temperature": temperature,
"response_format": {"type": "json_object"}
}
response = await self.http_client.post(url, headers=headers, json=payload)
response.raise_for_status()
return response.json()
async def translate_word(self, word: str, target_lang: str = "ru") -> Dict:
"""
@@ -53,21 +85,22 @@ class AIService:
Важно: верни только JSON, без дополнительного текста."""
try:
response = await self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Ты - помощник для изучения английского языка. Отвечай только в формате JSON."},
{"role": "user", "content": prompt}
],
temperature=0.3,
response_format={"type": "json_object"}
)
logger.info(f"[GPT Request] translate_word: word='{word}', target_lang='{target_lang}'")
messages = [
{"role": "system", "content": "Ты - помощник для изучения английского языка. Отвечай только в формате JSON."},
{"role": "user", "content": prompt}
]
response_data = await self._make_openai_request(messages, temperature=0.3)
import json
result = json.loads(response.choices[0].message.content)
result = json.loads(response_data['choices'][0]['message']['content'])
logger.info(f"[GPT Response] translate_word: success, translation='{result.get('translation', 'N/A')}'")
return result
except Exception as e:
logger.error(f"[GPT Error] translate_word: {type(e).__name__}: {str(e)}")
# Fallback в случае ошибки
return {
"word": word,
@@ -106,21 +139,22 @@ class AIService:
Учитывай возможные вариации ответа. Если смысл передан правильно, даже с небольшими грамматическими неточностями, засчитывай ответ."""
try:
response = await self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Ты - преподаватель английского языка. Проверяй ответы справедливо, учитывая контекст."},
{"role": "user", "content": prompt}
],
temperature=0.3,
response_format={"type": "json_object"}
)
logger.info(f"[GPT Request] check_answer: user_answer='{user_answer[:30]}...'")
messages = [
{"role": "system", "content": "Ты - преподаватель английского языка. Проверяй ответы справедливо, учитывая контекст."},
{"role": "user", "content": prompt}
]
response_data = await self._make_openai_request(messages, temperature=0.3)
import json
result = json.loads(response.choices[0].message.content)
result = json.loads(response_data['choices'][0]['message']['content'])
logger.info(f"[GPT Response] check_answer: is_correct={result.get('is_correct', False)}, score={result.get('score', 0)}")
return result
except Exception as e:
logger.error(f"[GPT Error] check_answer: {type(e).__name__}: {str(e)}")
return {
"is_correct": False,
"feedback": "Ошибка проверки ответа",
@@ -150,21 +184,22 @@ class AIService:
Предложение должно быть простым и естественным. Контекст должен четко подсказывать правильное слово."""
try:
response = await self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Ты - преподаватель английского языка. Создавай простые и понятные упражнения."},
{"role": "user", "content": prompt}
],
temperature=0.7,
response_format={"type": "json_object"}
)
logger.info(f"[GPT Request] generate_fill_in_sentence: word='{word}'")
messages = [
{"role": "system", "content": "Ты - преподаватель английского языка. Создавай простые и понятные упражнения."},
{"role": "user", "content": prompt}
]
response_data = await self._make_openai_request(messages, temperature=0.7)
import json
result = json.loads(response.choices[0].message.content)
result = json.loads(response_data['choices'][0]['message']['content'])
logger.info(f"[GPT Response] generate_fill_in_sentence: success")
return result
except Exception as e:
logger.error(f"[GPT Error] generate_fill_in_sentence: {type(e).__name__}: {str(e)}")
return {
"sentence": f"I like to ___ every day.",
"answer": word,
@@ -205,21 +240,23 @@ class AIService:
- Разнообразными (существительные, глаголы, прилагательные)"""
try:
response = await self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Ты - преподаватель английского языка. Подбирай полезные и актуальные слова."},
{"role": "user", "content": prompt}
],
temperature=0.7,
response_format={"type": "json_object"}
)
logger.info(f"[GPT Request] generate_thematic_words: theme='{theme}', level='{level}', count={count}")
messages = [
{"role": "system", "content": "Ты - преподаватель английского языка. Подбирай полезные и актуальные слова."},
{"role": "user", "content": prompt}
]
response_data = await self._make_openai_request(messages, temperature=0.7)
import json
result = json.loads(response.choices[0].message.content)
result = json.loads(response_data['choices'][0]['message']['content'])
words_count = len(result.get('words', []))
logger.info(f"[GPT Response] generate_thematic_words: success, generated {words_count} words")
return result.get('words', [])
except Exception as e:
logger.error(f"[GPT Error] generate_thematic_words: {type(e).__name__}: {str(e)}")
return []
async def extract_words_from_text(self, text: str, level: str = "B1", max_words: int = 15) -> List[Dict]:
@@ -259,21 +296,24 @@ class AIService:
- Разнообразие: существительные, глаголы, прилагательные, устойчивые выражения"""
try:
response = await self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Ты - преподаватель английского языка. Помогаешь извлекать полезные слова для изучения из текстов."},
{"role": "user", "content": prompt}
],
temperature=0.5,
response_format={"type": "json_object"}
)
text_preview = text[:100] + "..." if len(text) > 100 else text
logger.info(f"[GPT Request] extract_words_from_text: text_length={len(text)}, level='{level}', max_words={max_words}")
messages = [
{"role": "system", "content": "Ты - преподаватель английского языка. Помогаешь извлекать полезные слова для изучения из текстов."},
{"role": "user", "content": prompt}
]
response_data = await self._make_openai_request(messages, temperature=0.5)
import json
result = json.loads(response.choices[0].message.content)
result = json.loads(response_data['choices'][0]['message']['content'])
words_count = len(result.get('words', []))
logger.info(f"[GPT Response] extract_words_from_text: success, extracted {words_count} words")
return result.get('words', [])
except Exception as e:
logger.error(f"[GPT Error] extract_words_from_text: {type(e).__name__}: {str(e)}")
return []
async def start_conversation(self, scenario: str, level: str = "B1") -> Dict:
@@ -316,21 +356,22 @@ class AIService:
- Подсказки должны помочь пользователю ответить"""
try:
response = await self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Ты - дружелюбный собеседник для практики английского. Веди естественный диалог."},
{"role": "user", "content": prompt}
],
temperature=0.8,
response_format={"type": "json_object"}
)
logger.info(f"[GPT Request] start_conversation: scenario='{scenario}', level='{level}'")
messages = [
{"role": "system", "content": "Ты - дружелюбный собеседник для практики английского. Веди естественный диалог."},
{"role": "user", "content": prompt}
]
response_data = await self._make_openai_request(messages, temperature=0.8)
import json
result = json.loads(response.choices[0].message.content)
result = json.loads(response_data['choices'][0]['message']['content'])
logger.info(f"[GPT Response] start_conversation: success, scenario='{scenario}'")
return result
except Exception as e:
logger.error(f"[GPT Error] start_conversation: {type(e).__name__}: {str(e)}")
return {
"message": "Hello! How are you today?",
"translation": "Привет! Как дела сегодня?",
@@ -388,6 +429,8 @@ User: {user_message}
- Используй лексику уровня {level}"""
try:
logger.info(f"[GPT Request] continue_conversation: scenario='{scenario}', level='{level}', history_length={len(conversation_history)}")
# Формируем сообщения для API
messages = [
{"role": "system", "content": f"Ты - дружелюбный собеседник для практики английского языка уровня {level}. Веди естественный диалог и помогай исправлять ошибки."}
@@ -403,18 +446,16 @@ User: {user_message}
# Добавляем инструкцию для форматирования ответа
messages.append({"role": "user", "content": prompt})
response = await self.client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
temperature=0.8,
response_format={"type": "json_object"}
)
response_data = await self._make_openai_request(messages, temperature=0.8)
import json
result = json.loads(response.choices[0].message.content)
result = json.loads(response_data['choices'][0]['message']['content'])
has_errors = result.get('feedback', {}).get('has_errors', False)
logger.info(f"[GPT Response] continue_conversation: success, has_errors={has_errors}")
return result
except Exception as e:
logger.error(f"[GPT Error] continue_conversation: {type(e).__name__}: {str(e)}")
return {
"response": "I see. Tell me more about that.",
"translation": "Понятно. Расскажи мне больше об этом.",
@@ -458,21 +499,23 @@ User: {user_message}
- Вопросы на грамматику, лексику и понимание"""
try:
response = await self.client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": "Ты - эксперт по тестированию уровня английского языка. Создавай объективные тесты."},
{"role": "user", "content": prompt}
],
temperature=0.7,
response_format={"type": "json_object"}
)
logger.info(f"[GPT Request] generate_level_test: generating 7 questions")
messages = [
{"role": "system", "content": "Ты - эксперт по тестированию уровня английского языка. Создавай объективные тесты."},
{"role": "user", "content": prompt}
]
response_data = await self._make_openai_request(messages, temperature=0.7)
import json
result = json.loads(response.choices[0].message.content)
result = json.loads(response_data['choices'][0]['message']['content'])
questions_count = len(result.get('questions', []))
logger.info(f"[GPT Response] generate_level_test: success, generated {questions_count} questions")
return result.get('questions', [])
except Exception as e:
logger.error(f"[GPT Error] generate_level_test: {type(e).__name__}: {str(e)}, using fallback questions")
# Fallback с базовыми вопросами
return [
{