123
This commit is contained in:
@@ -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 [
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user