import os
import time
import random # !!! Добавлен импорт модуля random !!!
import datetime # !!! Добавлен импорт модуля datetime !!!
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from selenium.webdriver.chrome.options import Options as ChromeOptions
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# from pyvirtualdisplay import Display # !!! Удален импорт Display !!!
import pandas as pd
import csv # !!! Добавлен импорт модуля csv !!!
# --- Инициализация перед циклом ---
# # Start virtual display # !!! Удалены строки, связанные с виртуальным дисплеем !!!
# print("Запуск виртуального дисплея...")
# display = Display(visible=0, size=(1920, 1080))
# display.start()
# print("Виртуальный дисплей запущен.
")
# Настройка и инициализация WebDriver
print("Инициализация WebDriver...")
chrome_options = ChromeOptions()
chrome_options.add_argument('--headless') # !!! Убеждаемся, что headless режим включен !!!
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--window-size=1920,1080')
chrome_options.binary_location = '/usr/bin/google-chrome'
service = ChromeService(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=chrome_options)
print("WebDriver инициализирован.
")
# !!! alice_interface.html используется ask_alice_via_interface для внутреннего отображения ответов Алисы.
# !!! Его удаление или изменение без существенной переработки функции ask_alice_via_interface
# !!! приведет к нарушению ее работы.
# Создание HTML-интерфейса (один раз)
html_content = """
Alice Interface
"""
file_name = 'alice_interface.html'
with open(file_name, 'w') as f:
f.write(html_content)
print(f"HTML interface '{file_name}' создана успешно.
")
html_file_path = os.path.abspath(file_name)
# Определение функции для взаимодействия с Алисой (один раз)
def ask_alice_via_interface(question_text):
global driver, html_file_path # Доступ к глобальным driver и html_file_path
print(f"Запрос Алисе: '{question_text}'")
time.sleep(random.uniform(2, 5)) # !!! Добавлена случайная задержка перед переходом на сайт Алисы !!!
# 1. Переходим на сайт Алисы
driver.get('https://alice.yandex.ru')
print("Переход на сайт Алисы.")
# 2. Находим поле ввода на сайте Алисы
try:
input_field = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'textarea'))
)
except Exception:
input_field = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'input[type="text"]'))
)
print("Поле ввода Алисы найдено.")
# 3. Перед отправкой сообщения получаем общее количество сообщений в чате
initial_total_messages_count = len(driver.find_elements(By.CSS_SELECTOR, 'div.Message'))
time.sleep(random.uniform(1, 3)) # !!! Добавлена случайная задержка перед отправкой вопроса !!!
# 4. Отправляем вопрос Алисе
input_field.send_keys(question_text)
input_field.send_keys(Keys.ENTER)
print("Вопрос отправлен Алисе. Ожидание ответа...")
# 5. Механизм ожидания и извлечения ответа Алисы
alice_response = ""
try:
# 5.1. Ждем, пока общее количество сообщений в чате увеличится (ваш вопрос + ответ Алисы)
WebDriverWait(driver, 60).until(
lambda d: len(d.find_elements(By.CSS_SELECTOR, 'div.Message')) > initial_total_messages_count + 1
)
# 5.2. После того как общее количество сообщений увеличилось, находим элемент с z-index: 2
# Это должен быть самый свежий ответ Алисы, как было указано пользователем.
alice_response_element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'div.Message[style*="z-index: 2"]'))
)
# 5.3. Ждем, пока текст в этом элементе станет достаточно длинным и стабильным
def message_has_stable_text(driver_instance, element):
current_text = element.text.strip()
word_count = len(current_text.split()) # Подсчет слов
if current_text and len(current_text) > 30: # Проверка на наличие существенного текста
if word_count <= 200: # !!! Добавлена проверка на количество слов !!!
time.sleep(random.uniform(0.5, 1.5)) # Случайная короткая задержка для проверки стабильности
stable_text = element.text.strip()
if stable_text == current_text: # Возвращаем текст, если он стабилен
return stable_text
else:
print(f"Предупреждение: Ответ Алисы слишком длинный ({word_count} слов). Максимум 200 слов.
")
return False
alice_response = WebDriverWait(driver, 30).until(
lambda d: message_has_stable_text(d, alice_response_element)
)
if not alice_response: # Если alice_response пустой после ожидания (из-за слишком длинного ответа)
alice_response = "Ошибка: Ответ Алисы превысил допустимую длину (более 200 слов)."
print(f"Сырой ответ Алисы: {alice_response}")
time.sleep(random.uniform(3, 7)) # !!! Добавлена случайная задержка после получения ответа Алисы !!!
except Exception as e:
print(f"Не удалось дождаться или извлечь ответ Алисы: {e}")
alice_response = "Ошибка: Не удалось получить ответ от Алисы."
# 6. Возвращаемся к локальному HTML-интерфейсу
driver.get(f'file://{html_file_path}')
print("Возврат к локальному HTML-интерфейсу.")
# 7. Обновляем область отображения ответа Алисы в HTML
# Очищаем ответ для вставки в JavaScript (экранируем кавычки)
sanitized_response = alice_response.replace("'", "'").replace('
', '
')
script = f"document.getElementById('alice_response').innerHTML = '{sanitized_response}';"
driver.execute_script(script)
print("Ответ Алисы отображен в HTML-интерфейсе.")
return alice_response
print("Функция 'ask_alice_via_interface' определена.
")
# --- Бесконечный цикл для повторной проверки каждые полчаса ---
while True:
print(f"
--- Начинаем проверку и обработку в {time.ctime()} ---")
bd_file_name = 'bd.csv'
# 5. Load news articles from bd.csv
df_bd = pd.DataFrame()
try:
# Check if bd.csv exists; if not, create a dummy one with proper columns
if not os.path.exists(bd_file_name):
print(f"'{bd_file_name}' not found. Creating a dummy file with 'published' and 'short_text' columns.")
today = datetime.date.today()
yesterday = today - datetime.timedelta(days=1)
dummy_data_bd = {
'link': ['http://example.com/dummy_news_1', 'http://example.com/dummy_news_2', 'http://example.com/old_news'],
'full_text': [
'Это первая фейковая новость о прорыве в технологиях. Она достаточно длинная для суммаризации.',
'Это вторая фейковая новость об экономических тенденциях и прогнозах.',
'Это старая новость о чем-то неактуальном, которая не должна быть суммаризирована.'
],
'published': [today.isoformat(), yesterday.isoformat(), (today - datetime.timedelta(days=7)).isoformat()],
'short_text': ['', '', ''] # Initially empty
}
dummy_df_bd = pd.DataFrame(dummy_data_bd)
dummy_df_bd.to_csv(bd_file_name, index=False, sep=';', encoding='utf-8-sig', quoting=csv.QUOTE_ALL)
print(f"Dummy '{bd_file_name}' created.")
# Try multiple encodings and the new delimiter for bd.csv
encodings_to_try = ['utf-8-sig', 'windows-1251', 'utf-8']
df_bd_loaded = False
for enc in encodings_to_try:
try:
df_bd = pd.read_csv(bd_file_name, encoding=enc, sep=';')
df_bd_loaded = True
print(f"'{bd_file_name}' успешно загружен с кодировкой '{enc}' (sep=';'). Всего статей: {len(df_bd)})")
break
except (UnicodeDecodeError, pd.errors.ParserError) as read_e:
print(f"Попытка загрузки '{bd_file_name}' с кодировкой '{enc}' (sep=';') не удалась: {read_e}.")
continue
if not df_bd_loaded:
raise Exception("Не удалось загрузить bd.csv ни с одной из предложенных кодировок (sep=';').")
# Ensure 'published' column is datetime and 'short_text' is string for filtering
df_bd['published'] = pd.to_datetime(df_bd['published'], errors='coerce').dt.date
df_bd['short_text'] = df_bd['short_text'].fillna('') # Fill NaN with empty string for consistent comparison
except Exception as e:
print(f"Ошибка загрузки или обработки '{bd_file_name}': {e}. Инициализация пустого DataFrame.")
df_bd = pd.DataFrame(columns=['link', 'full_text', 'published', 'short_text']) # Ensure all columns are present
# 6. Filtering for new articles to summarize
# Articles published today or yesterday AND with empty short_text
current_date = datetime.date.today()
yesterday_date = current_date - datetime.timedelta(days=1)
articles_to_summarize = df_bd[
((df_bd['published'] == current_date) | (df_bd['published'] == yesterday_date)) &
(df_bd['full_text'].notna()) &
(df_bd['short_text'] == '')
].copy()
if articles_to_summarize.empty:
print("В этом цикле нет новых статей для суммаризации (опубликованы сегодня/вчера и без резюме).")
else:
print(f"Найдено {len(articles_to_summarize)} новых статей для суммаризации.")
# 8. Summarize each new article with Alice and update df_bd
for index, row in articles_to_summarize.iterrows():
original_link = row['link']
full_news_text = row['full_text']
# Construct the question for Alice with specific phrasing
question_for_alice = f'Алиса, суммаризируй новость до 3 небольших предложений (раздельно) {full_news_text}'
alice_summary = ""
try:
print(f" Summarizing: {original_link}")
alice_summary = ask_alice_via_interface(question_for_alice)
print(f" Summary received for {os.path.basename(original_link)}: {alice_summary[:100]}...") # Print first 100 chars
# Add random delay after summarization before next article
time.sleep(random.uniform(5, 10))
except Exception as e:
print(f" Error processing {original_link}: {e}")
alice_summary = "Ошибка: Не удалось получить резюме от Алисы."
# Update the original df_bd DataFrame with the new summary
df_bd.loc[index, 'short_text'] = alice_summary
# 9. Save the updated df_bd to bd.csv after processing all new articles
df_bd.to_csv(bd_file_name, index=False, sep=';', encoding='utf-8-sig', quoting=csv.QUOTE_ALL)
print(f"Успешно суммаризированы и обновлены статьи в '{bd_file_name}'.")
# 10. Pause before the next iteration
print(f"
Пауза на 30 минут до следующего цикла... (Следующий запуск в {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time() + 1800))})")
time.sleep(random.uniform(1700, 1900)) # Random delay around 30 minutes
print("Цикл суммаризации остановлен.")
# --- Окончательная очистка (выполняется при прерывании цикла) ---
print("
## Инструкции по очистке: Закрытие WebDriver
") # !!! Убрана ссылка на виртуальный дисплей !!!
print('Для освобождения ресурсов и правильного завершения работы Selenium WebDriver, пожалуйста, запустите следующие команды в новой ячейке кода, когда закончите все взаимодействия:
') # !!! Убрана ссылка на виртуальный дисплей !!!
print('```python
driver.quit()
print("Selenium WebDriver закрыт.")
```
') # !!! Убрана ссылка на виртуальный дисплей и его остановка !!!
driver.quit()
print("Selenium WebDriver закрыт.")
# display.stop() # !!! Удалена остановка виртуального дисплея !!!