This commit is contained in:
20
services/__init__.py
Normal file
20
services/__init__.py
Normal file
@@ -0,0 +1,20 @@
|
||||
"""
|
||||
Сервисы приложения
|
||||
"""
|
||||
from .proxy_manager import (
|
||||
download_proxies,
|
||||
get_shuffled_proxies,
|
||||
fetch_with_proxy,
|
||||
fetch_with_proxy_retry
|
||||
)
|
||||
from .gpt_client import gpt_response_message
|
||||
from .document_builder import update_bd_and_create_document
|
||||
|
||||
__all__ = [
|
||||
'download_proxies',
|
||||
'get_shuffled_proxies',
|
||||
'fetch_with_proxy',
|
||||
'fetch_with_proxy_retry',
|
||||
'gpt_response_message',
|
||||
'update_bd_and_create_document'
|
||||
]
|
||||
78
services/document_builder.py
Normal file
78
services/document_builder.py
Normal file
@@ -0,0 +1,78 @@
|
||||
"""
|
||||
Document Builder - создание JSON и DOCX файлов
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
from docx import Document
|
||||
from config import DOCUMENTS_DIR
|
||||
from utils import logger
|
||||
import parser_bd as pbd
|
||||
|
||||
|
||||
def update_bd_and_create_document(
|
||||
response_text: str,
|
||||
article_date: str,
|
||||
url: str,
|
||||
parsed_at: str,
|
||||
original_text: str,
|
||||
other: str
|
||||
) -> None:
|
||||
"""
|
||||
Обрабатывает ответ от GPT, сохраняет в БД и создаёт DOCX документ
|
||||
"""
|
||||
clean_response = ''
|
||||
|
||||
if not response_text:
|
||||
print(f"Пустой ответ от GPT для URL: {url}")
|
||||
logger.info(f"Пустой ответ от GPT для URL: {url}")
|
||||
return
|
||||
|
||||
try:
|
||||
clean_response = response_text.strip().replace('```json', '').replace('```', '').strip()
|
||||
data = json.loads(clean_response)
|
||||
|
||||
if data['category']:
|
||||
data['article_date'] = article_date
|
||||
data['url'] = url
|
||||
data['parsed_at'] = parsed_at
|
||||
data['original_text'] = original_text
|
||||
data['status'] = False
|
||||
data['viewed'] = False
|
||||
data['other'] = other
|
||||
|
||||
# Сохранение в БД через pbd
|
||||
parsed_data = pbd.ParsedData(**data)
|
||||
pbd.save_parsed_data_to_db(parsed_data)
|
||||
print("Данные успешно сохранены в БД")
|
||||
|
||||
# Создание DOCX документа
|
||||
path_day = article_date.split()[0]
|
||||
documents_path = os.path.join(DOCUMENTS_DIR, path_day)
|
||||
if not os.path.exists(documents_path):
|
||||
os.makedirs(documents_path)
|
||||
print(f"Создана папка: {documents_path}")
|
||||
|
||||
doc = Document()
|
||||
doc.add_heading('Ссылка на статью', level=1)
|
||||
doc.add_paragraph(other)
|
||||
doc.add_heading('Дата и время', level=1)
|
||||
doc.add_paragraph(article_date)
|
||||
doc.add_heading('Обнаруженные тематики текста', level=1)
|
||||
doc.add_paragraph(data["category"])
|
||||
doc.add_heading('Заголовок', level=1)
|
||||
doc.add_paragraph(data["title"])
|
||||
doc.add_heading('Краткий пересказ', level=1)
|
||||
doc.add_paragraph(data["short_text"])
|
||||
doc.add_heading('Переведенный текст статьи в газете', level=1)
|
||||
doc.add_paragraph(data["translation_text"])
|
||||
doc.add_heading('Оригинальный текст', level=1)
|
||||
doc.add_paragraph(original_text)
|
||||
|
||||
doc_name = f"{data['title']}.docx"
|
||||
doc_path = os.path.join(documents_path, doc_name)
|
||||
doc.save(doc_path)
|
||||
print(f"Сохранен документ: {doc_path}")
|
||||
|
||||
except Exception as ex:
|
||||
print(f"Ошибка при обработке ответа GPT: {ex}")
|
||||
logger.info(f"Ошибка при обработке ответа GPT: {ex}")
|
||||
48
services/gpt_client.py
Normal file
48
services/gpt_client.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""
|
||||
GPT клиент - отправка запросов к нейросети
|
||||
"""
|
||||
import time
|
||||
import requests
|
||||
from config import GPT_SERVER_URL, GPT_MAX_RETRIES, GPT_TIMEOUT
|
||||
from utils import logger
|
||||
import work_parser as wp
|
||||
|
||||
|
||||
def gpt_response_message(content: str, name_promt: str) -> str:
|
||||
"""
|
||||
Отправляет текст на обработку GPT серверу
|
||||
Возвращает ответ или пустую строку при ошибке
|
||||
"""
|
||||
contentGPT = wp.get_promt(name_promt).replace('{content}', content)
|
||||
|
||||
url = GPT_SERVER_URL
|
||||
params = {'text': contentGPT}
|
||||
|
||||
max_retries = GPT_MAX_RETRIES
|
||||
retries = 0
|
||||
|
||||
while retries < max_retries:
|
||||
try:
|
||||
response = requests.get(url, params=params, timeout=GPT_TIMEOUT)
|
||||
return response.text
|
||||
except requests.exceptions.ConnectTimeout as e:
|
||||
print(f"Ошибка подключения (timeout): {e}")
|
||||
logger.warning(f"gpt_response_message timeout:")
|
||||
retries += 1
|
||||
if retries < max_retries:
|
||||
time.sleep(2 ** (retries - 1))
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
print(f"Ошибка соединения: {e}")
|
||||
logger.warning(f"gpt_response_message connection error: ")
|
||||
retries += 1
|
||||
if retries < max_retries:
|
||||
time.sleep(2 ** (retries - 1))
|
||||
except Exception as ex:
|
||||
print(f"Ошибка при запросе к GPT: {ex}")
|
||||
logger.error(f"gpt_response_message: ")
|
||||
retries += 1
|
||||
if retries < max_retries:
|
||||
time.sleep(2 ** (retries - 1))
|
||||
|
||||
logger.info(f"Превышен лимит запросов {max_retries}")
|
||||
return ""
|
||||
75
services/proxy_manager.py
Normal file
75
services/proxy_manager.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""
|
||||
Менеджер прокси - управление загрузкой и использованием прокси
|
||||
"""
|
||||
import random
|
||||
import requests
|
||||
from config import PROXIES_URL
|
||||
|
||||
|
||||
def download_proxies(url: str = PROXIES_URL) -> list[str]:
|
||||
"""
|
||||
Загружает список прокси из удаленного источника
|
||||
"""
|
||||
response = requests.get(url)
|
||||
if response.status_code == 200:
|
||||
proxies = response.text.splitlines()
|
||||
return proxies
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def get_shuffled_proxies(proxies_list: list[str]) -> list[str]:
|
||||
"""
|
||||
Перемешивает список прокси для случайного начала
|
||||
"""
|
||||
shuffled = proxies_list.copy()
|
||||
random.shuffle(shuffled)
|
||||
return shuffled
|
||||
|
||||
|
||||
def fetch_with_proxy(url: str, proxy: str, verify: bool = True, timeout: int = 10) -> str | None:
|
||||
"""
|
||||
Выполняет запрос к URL через прокси
|
||||
Возвращает текст ответа или None при ошибке
|
||||
"""
|
||||
proxies = {
|
||||
'http': f'http://{proxy}',
|
||||
'https': f'http://{proxy}',
|
||||
}
|
||||
try:
|
||||
response = requests.get(url, proxies=proxies, timeout=timeout, verify=verify)
|
||||
response.encoding = 'utf-8'
|
||||
if response.status_code == 200:
|
||||
# Проверяем содержимое - если это ошибка от прокси
|
||||
if '"message":"Request failed' in response.text or '403' in response.text[:500]:
|
||||
print(f"Proxy {proxy} - Site returned 403 (inside response)")
|
||||
return None
|
||||
print(f"Proxy {proxy} - SUCCESS")
|
||||
return response.text
|
||||
elif response.status_code == 403:
|
||||
print(f"Proxy {proxy} - 403 Forbidden")
|
||||
return None # Прокси работает, но сайт блокирует
|
||||
else:
|
||||
print(f"Proxy {proxy} - Status {response.status_code}")
|
||||
return None
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def fetch_with_proxy_retry(url: str, timeout: int = 10, verify: bool = True) -> str:
|
||||
"""
|
||||
Выполняет запрос с перебором прокси до успешного
|
||||
Возвращает пустую строку если все прокси не сработали
|
||||
"""
|
||||
proxies_list = download_proxies(PROXIES_URL)
|
||||
proxies_list = get_shuffled_proxies(proxies_list)
|
||||
|
||||
response = ""
|
||||
for proxy in proxies_list:
|
||||
response = fetch_with_proxy(url, proxy=proxy, timeout=timeout, verify=verify)
|
||||
if response:
|
||||
break
|
||||
else:
|
||||
response = ""
|
||||
|
||||
return response
|
||||
Reference in New Issue
Block a user