Upload files to "/"
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
# Общие настройки
|
||||
SECRET_KEY=24af5f41dba9d8cc0dbc1841660da0b14d7df86ab5e0ed973cdd3bc2dbac23f6
|
||||
LOG_FILE = /var/log/zilantposter.log
|
||||
|
||||
# логин и пароль по умолчанию для первого запуска веб-контроллера
|
||||
DEFNM=admin
|
||||
DEFPW=Z1l@ntAdm1n23
|
||||
|
||||
# VK access
|
||||
VK_GROUP_ID = -3342146
|
||||
VK_ACCESS_TOKEN = 'e3732a7ee3732a7ee3732a7ea7e044a75fee373e3732a7e8bf4e48a52d012e946b952a8'
|
||||
VK_API_VERSION = '5.131'
|
||||
|
||||
# MySQL database
|
||||
MDBASE = 'zilant_posts'
|
||||
MDB_HOST = 'localhost'
|
||||
MDB_USER = 'zilantposter'
|
||||
MDB_PW = 'Z1l@ntp08t3r'
|
||||
|
||||
# Poster bot
|
||||
BOT_TOKEN = "8301828103:AAHDuBkw7EUkmMvv5TPpVJaLeeBLu-EB21U"
|
||||
|
||||
# Poster channel
|
||||
CHANNEL_ID = "@posto1638"
|
||||
# DB_NAME = "vk_posts.db"
|
||||
MAX_CAPTION_LENGTH = 1000
|
||||
MAX_TEXT_LENGTH = 4000
|
||||
|
||||
# Button scripts
|
||||
RESCAN_SCRIPT = "vk_load.py"
|
||||
PUBLISH_SCRIPT = "dummy.py"
|
||||
|
||||
# Event status
|
||||
IS_EVENT = false
|
||||
AUTO_PUBLISH = false
|
||||
@@ -0,0 +1,45 @@
|
||||
import os
|
||||
import mysql.connector
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Загрузка переменных окружения из .env файла
|
||||
load_dotenv()
|
||||
|
||||
# Конфигурация базы данных из переменных окружения
|
||||
DB_CONFIG = {
|
||||
'host': os.getenv('MDB_HOST'),
|
||||
'user': os.getenv('MDB_USER'),
|
||||
'password': os.getenv('MDB_PW'),
|
||||
'database': os.getenv('MDBASE')
|
||||
}
|
||||
|
||||
def alter_column_type():
|
||||
try:
|
||||
# Устанавливаем соединение с базой данных
|
||||
connection = mysql.connector.connect(**DB_CONFIG)
|
||||
cursor = connection.cursor()
|
||||
|
||||
# Выполняем ALTER TABLE запрос
|
||||
alter_query = """
|
||||
ALTER TABLE events
|
||||
MODIFY COLUMN about TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
|
||||
"""
|
||||
cursor.execute(alter_query)
|
||||
|
||||
# Подтверждаем изменения
|
||||
connection.commit()
|
||||
|
||||
print("Тип поля 'about' успешно изменен на TEXT")
|
||||
|
||||
except mysql.connector.Error as error:
|
||||
print(f"Ошибка при изменении типа поля: {error}")
|
||||
if connection:
|
||||
connection.rollback()
|
||||
finally:
|
||||
if cursor:
|
||||
cursor.close()
|
||||
if connection:
|
||||
connection.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
alter_column_type()
|
||||
@@ -0,0 +1 @@
|
||||
mysqldump -utestuser -pT38tU83r69 testposts > test_posts_backup.sql
|
||||
+1355
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,244 @@
|
||||
import os
|
||||
import pymysql
|
||||
from dotenv import load_dotenv
|
||||
import requests
|
||||
import json
|
||||
import re
|
||||
import time
|
||||
import sys
|
||||
import random
|
||||
from datetime import datetime
|
||||
|
||||
# Загрузка переменных окружения
|
||||
load_dotenv()
|
||||
|
||||
# Конфигурация из переменных окружения
|
||||
DB_CONFIG = {
|
||||
'host': os.getenv('MDB_HOST'),
|
||||
'user': os.getenv('MDB_USER'),
|
||||
'password': os.getenv('MDB_PW'),
|
||||
'database': os.getenv('MDBASE'),
|
||||
'charset': 'utf8mb4'
|
||||
}
|
||||
|
||||
OPENROUTER_CONFIG = {
|
||||
'api_key': os.getenv('OR_KEY'),
|
||||
'model': os.getenv('OR_MODEL_NAME')
|
||||
}
|
||||
|
||||
# Настройки журналирования
|
||||
LOG_FILE = os.getenv('LOG_FILE', 'ai_namer.log') # Путь к лог-файлу
|
||||
LOG_PREFIX = "AI_namer" # Уникальный префикс для идентификации скрипта
|
||||
|
||||
def log_message(message, max_retries=5, retry_delay=0.1):
|
||||
"""
|
||||
Записывает сообщение в лог-файл с обработкой блокировок
|
||||
и идентификатором скрипта
|
||||
"""
|
||||
if not LOG_FILE:
|
||||
return
|
||||
|
||||
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
# Добавляем идентификатор скрипта к сообщению
|
||||
log_line = f"[{timestamp}] [{LOG_PREFIX}] {message}\n"
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
with open(LOG_FILE, 'a', encoding='utf-8') as log:
|
||||
log.write(log_line)
|
||||
return True
|
||||
except (IOError, OSError) as e:
|
||||
if "locked" in str(e).lower() and attempt < max_retries - 1:
|
||||
# Случайная задержка для уменьшения коллизий
|
||||
sleep_time = retry_delay * (1 + random.random() * 0.5)
|
||||
time.sleep(sleep_time)
|
||||
else:
|
||||
# Если не удалось записать после всех попыток
|
||||
print(f"Ошибка записи в лог: {e}")
|
||||
print(f"Сообщение для лога: {log_line.strip()}")
|
||||
return False
|
||||
|
||||
def _generate_shortname_by_api(text):
|
||||
"""Внутренняя функция для генерации краткого названия через OpenRouter API"""
|
||||
url = "https://openrouter.ai/api/v1/chat/completions"
|
||||
headers = {
|
||||
"Authorization": f"Bearer {OPENROUTER_CONFIG['api_key']}",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
prompt = f"""
|
||||
Прочитай нижеприведенный анонс и сформируй краткое (до 80 знаков) название этого события для каталога.
|
||||
Место, дата и время проведения для каталога несущественны.
|
||||
Важно название и, в зависимости от того, что это за событие, выступающие на нем или проводящие его.
|
||||
Для данного каталога допустимо использование никнеймов вместо официальных имен и фамилий.
|
||||
|
||||
Ответ должен содержать только одно название без каких-либо объяснений, комментариев и вариантов.
|
||||
|
||||
АНОНС: {text}
|
||||
Название:"""
|
||||
|
||||
data = {
|
||||
"model": OPENROUTER_CONFIG['model'],
|
||||
"messages": [{"role": "user", "content": prompt}],
|
||||
"max_tokens": 5000,
|
||||
"temperature": 0.3
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, json=data, timeout=60)
|
||||
|
||||
# Обработка ошибки 429 (Too Many Requests)
|
||||
if response.status_code == 429:
|
||||
error_info = {
|
||||
"status_code": response.status_code,
|
||||
"headers": dict(response.headers),
|
||||
"body": response.text
|
||||
}
|
||||
|
||||
# Пытаемся распарсить JSON ответ
|
||||
try:
|
||||
error_info["body"] = response.json()
|
||||
except:
|
||||
pass
|
||||
|
||||
log_message(f"Ошибка 429: Превышен лимит запросов. Ответ API: {json.dumps(error_info, ensure_ascii=False)}")
|
||||
print("Ошибка 429: Превышен лимит запросов. Подробности в логе.")
|
||||
sys.exit(1)
|
||||
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
# Извлекаем только текст ответа
|
||||
shortname = result['choices'][0]['message']['content'].strip()
|
||||
|
||||
# Удаляем возможные кавычки и лишние символы
|
||||
shortname = re.sub(r'^["\']|["\']$', '', shortname)
|
||||
|
||||
# Обрезаем до 80 символов
|
||||
return shortname[:80]
|
||||
|
||||
except requests.exceptions.HTTPError as e:
|
||||
if e.response.status_code == 429:
|
||||
error_info = {
|
||||
"status_code": e.response.status_code,
|
||||
"headers": dict(e.response.headers),
|
||||
"body": e.response.text
|
||||
}
|
||||
|
||||
# Пытаемся распарсить JSON ответ
|
||||
try:
|
||||
error_info["body"] = e.response.json()
|
||||
except:
|
||||
pass
|
||||
|
||||
log_message(f"Ошибка 429: Превышен лимит запросов. Ответ API: {json.dumps(error_info, ensure_ascii=False)}")
|
||||
print("Ошибка 429: Превышен лимит запросов. Подробности в логе.")
|
||||
sys.exit(1)
|
||||
else:
|
||||
error_msg = f"HTTP ошибка при генерации названия: {e}"
|
||||
log_message(error_msg)
|
||||
print(error_msg)
|
||||
return None
|
||||
except Exception as e:
|
||||
error_msg = f"Ошибка при генерации названия: {e}"
|
||||
log_message(error_msg)
|
||||
print(error_msg)
|
||||
return None
|
||||
|
||||
def generate_ai_shortname(text):
|
||||
"""
|
||||
Генерирует краткое название для описанного в тексте мероприятия.
|
||||
|
||||
Args:
|
||||
text (str): Текст описания мероприятия
|
||||
|
||||
Returns:
|
||||
str: Краткое название (до 80 знаков) или None в случае ошибки
|
||||
"""
|
||||
log_message(f"Начало генерации названия для текста длиной {len(text)} символов")
|
||||
|
||||
if not text or not text.strip():
|
||||
log_message("Получен пустой текст для генерации названия")
|
||||
return None
|
||||
|
||||
shortname = _generate_shortname_by_api(text)
|
||||
|
||||
if shortname:
|
||||
log_message(f"Успешно сгенерировано название: {shortname}")
|
||||
else:
|
||||
log_message("Не удалось сгенерировать название")
|
||||
|
||||
return shortname
|
||||
|
||||
def ai_shortname_all():
|
||||
"""
|
||||
Обрабатывает все записи в базе данных с пустым полем shortname,
|
||||
генерируя для них краткие названия с помощью нейросети.
|
||||
"""
|
||||
log_message("Запуск обработки всех записей с пустым shortname")
|
||||
|
||||
# Подключение к БД
|
||||
try:
|
||||
connection = pymysql.connect(**DB_CONFIG)
|
||||
log_message("Успешное подключение к базе данных")
|
||||
except Exception as e:
|
||||
error_msg = f"Ошибка подключения к базе данных: {e}"
|
||||
log_message(error_msg)
|
||||
print(error_msg)
|
||||
return
|
||||
|
||||
try:
|
||||
with connection.cursor() as cursor:
|
||||
# Выбор записей с пустым shortname
|
||||
cursor.execute("SELECT id, text FROM posts WHERE shortname IS NULL OR shortname = ''")
|
||||
posts = cursor.fetchall()
|
||||
|
||||
log_message(f"Найдено {len(posts)} записей для обработки")
|
||||
print(f"Найдено {len(posts)} записей для обработки")
|
||||
|
||||
for i, (post_id, text) in enumerate(posts, 1):
|
||||
if not text:
|
||||
continue
|
||||
|
||||
log_message(f"Обрабатывается запись {i}/{len(posts)} (ID: {post_id})")
|
||||
print(f"Обрабатывается запись {i}/{len(posts)} (ID: {post_id})")
|
||||
|
||||
shortname = generate_ai_shortname(text)
|
||||
|
||||
if shortname:
|
||||
# Обновление записи
|
||||
try:
|
||||
cursor.execute(
|
||||
"UPDATE posts SET shortname = %s WHERE id = %s",
|
||||
(shortname, post_id)
|
||||
)
|
||||
connection.commit()
|
||||
log_message(f"Запись {post_id} успешно обновлена: {shortname}")
|
||||
print(f"Обновлено: {shortname}")
|
||||
except Exception as e:
|
||||
error_msg = f"Ошибка обновления записи {post_id}: {e}"
|
||||
log_message(error_msg)
|
||||
print(error_msg)
|
||||
else:
|
||||
log_message(f"Не удалось сгенерировать название для записи {post_id}")
|
||||
print("Не удалось сгенерировать название")
|
||||
|
||||
# Небольшая пауза между запросами
|
||||
time.sleep(1)
|
||||
|
||||
log_message("Обработка всех записей завершена")
|
||||
print("Обработка завершена")
|
||||
except SystemExit:
|
||||
# Перехватываем системный выход для корректного закрытия соединения
|
||||
log_message("Завершение работы из-за ошибки 429")
|
||||
print("Завершение работы из-за ошибки 429")
|
||||
except Exception as e:
|
||||
error_msg = f"Произошла ошибка при обработке записей: {e}"
|
||||
log_message(error_msg)
|
||||
print(error_msg)
|
||||
finally:
|
||||
connection.close()
|
||||
log_message("Соединение с базой данных закрыто")
|
||||
|
||||
if __name__ == "__main__":
|
||||
ai_shortname_all()
|
||||
Reference in New Issue
Block a user