породы в БД
Gitea Actions Demo / build_and_push (push) Has been cancelled
Details
Gitea Actions Demo / build_and_push (push) Has been cancelled
Details
This commit is contained in:
parent
ce5c715611
commit
e121c6af34
|
|
@ -0,0 +1,84 @@
|
|||
import os
|
||||
import random
|
||||
import shutil
|
||||
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def copy_convert_to_webp(
|
||||
source_dir,
|
||||
dest_dir,
|
||||
samples_per_folder=5,
|
||||
size_threshold=1024 * 1024,
|
||||
quality_high=90,
|
||||
quality_low=70,
|
||||
):
|
||||
"""
|
||||
Копирует структуру папок и конвертирует изображения в WebP
|
||||
:param source_dir: Исходная директория с изображениями
|
||||
:param dest_dir: Целевая директория для копирования
|
||||
:param samples_per_folder: Количество изображений для выбора из каждой папки
|
||||
:param size_threshold: Пороговый размер файла (в байтах) для сильного сжатия
|
||||
:param quality_high: Качество для маленьких изображений (0-100)
|
||||
:param quality_low: Качество для больших изображений (0-100)
|
||||
"""
|
||||
image_extensions = (".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".webp")
|
||||
|
||||
def is_image_file(filename):
|
||||
return filename.lower().endswith(image_extensions)
|
||||
|
||||
def convert_to_webp(src_path, dest_path, quality):
|
||||
try:
|
||||
with Image.open(src_path) as img:
|
||||
# Сохраняем прозрачность для RGBA
|
||||
if img.mode in ("RGBA", "LA"):
|
||||
img = img.convert("RGBA")
|
||||
img.save(dest_path, "WEBP", quality=quality, lossless=False, method=6)
|
||||
else:
|
||||
# Конвертируем в RGB для JPEG-подобных изображений
|
||||
img = img.convert("RGB")
|
||||
img.save(dest_path, "WEBP", quality=quality, method=6)
|
||||
except Exception as e:
|
||||
print(f"Error converting {src_path}: {e}")
|
||||
return False
|
||||
return True
|
||||
|
||||
# Создаем корневую целевую папку
|
||||
os.makedirs(dest_dir, exist_ok=True)
|
||||
|
||||
for root, dirs, files in os.walk(source_dir):
|
||||
rel_path = os.path.relpath(root, source_dir)
|
||||
target_dir = os.path.join(dest_dir, rel_path)
|
||||
os.makedirs(target_dir, exist_ok=True)
|
||||
|
||||
images = [f for f in files if is_image_file(f)]
|
||||
if not images:
|
||||
continue
|
||||
|
||||
selected = random.sample(images, min(samples_per_folder, len(images)))
|
||||
|
||||
for file in selected:
|
||||
src_path = os.path.join(root, file)
|
||||
base_name = os.path.splitext(file)[0]
|
||||
dest_path = os.path.join(target_dir, f"{base_name}.webp")
|
||||
|
||||
# Определяем качество на основе размера
|
||||
file_size = os.path.getsize(src_path)
|
||||
quality = quality_low if file_size > size_threshold else quality_high
|
||||
|
||||
# Конвертируем в WebP
|
||||
if not convert_to_webp(src_path, dest_path, quality):
|
||||
# Если ошибка конвертации - копируем оригинал
|
||||
shutil.copy2(src_path, dest_path)
|
||||
print(f"Copied original file instead: {file}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
copy_convert_to_webp(
|
||||
source_dir="assets",
|
||||
dest_dir="webp_output",
|
||||
samples_per_folder=5,
|
||||
size_threshold=1 * 1024 * 20, # 1 MB
|
||||
quality_high=70,
|
||||
quality_low=70,
|
||||
)
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
import_beerds_sql.py
|
||||
|
||||
Скрипт читает файлы из каталогов:
|
||||
- server/modules/descriptions/repository/breed_descriptions
|
||||
- server/modules/descriptions/repository/breed_signs
|
||||
|
||||
и вместо непосредственной вставки генерирует PostgreSQL‑SQL‑файл, который
|
||||
можно применить через `psql -f <имя_файла.sql>`:
|
||||
|
||||
CREATE TABLE beerds.beerds (
|
||||
id varchar NOT NULL,
|
||||
name text NOT NULL,
|
||||
descriptions text NOT NULL,
|
||||
signs json NOT NULL,
|
||||
alias text NOT NULL,
|
||||
CONSTRAINT beerds_pkey PRIMARY KEY (id)
|
||||
);
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
import hashlib
|
||||
import pathlib
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 2️⃣ Путь к каталогам (можно изменить под свой проект)
|
||||
# ------------------------------------------------------------------
|
||||
BASE_DIR = pathlib.Path(__file__).resolve().parent.parent
|
||||
DESC_DIR = BASE_DIR / "server/modules/descriptions/repository/breed_descriptions"
|
||||
SIGN_DIR = BASE_DIR / "server/modules/descriptions/repository/breed_signs"
|
||||
print(f"DESC_DIR = {DESC_DIR}")
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 3️⃣ Функции чтения файлов
|
||||
# ------------------------------------------------------------------
|
||||
def read_text_file(path: pathlib.Path) -> str:
|
||||
"""Возвращает содержимое текстового файла (unicode)."""
|
||||
with path.open("r", encoding="utf-8") as f:
|
||||
return f.read().strip()
|
||||
|
||||
|
||||
def read_json_file(path: pathlib.Path) -> dict:
|
||||
"""Возвращает JSON‑объект из файла."""
|
||||
with path.open("r", encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 4️⃣ Формируем словарь: имя → (описание, сигналы)
|
||||
# ------------------------------------------------------------------
|
||||
def build_breed_map(desc_dir: pathlib.Path, sign_dir: pathlib.Path) -> dict:
|
||||
"""Возвращает dict: stem → (description, signs)"""
|
||||
desc_files = {p.stem: p for p in desc_dir.glob("*.txt")}
|
||||
sign_files = {p.stem: p for p in sign_dir.glob("*.txt")}
|
||||
|
||||
common_keys = desc_files.keys() & sign_files.keys()
|
||||
if not common_keys:
|
||||
print("⚠️ Нет общих файлов между каталогами описаний и сигналов.")
|
||||
return {}
|
||||
|
||||
breeds = {}
|
||||
for key in sorted(common_keys):
|
||||
desc_path = desc_files[key]
|
||||
sign_path = sign_files[key]
|
||||
try:
|
||||
description = read_text_file(desc_path)
|
||||
except Exception as e:
|
||||
print(f"❌ Не удалось прочитать описание {desc_path}: {e}")
|
||||
continue
|
||||
try:
|
||||
signs = read_json_file(sign_path)
|
||||
except Exception as e:
|
||||
print(f"❌ Не удалось прочитать сигналы {sign_path}: {e}")
|
||||
continue
|
||||
breeds[key] = (description, signs)
|
||||
return breeds
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 5️⃣ Генерация id (если нужно уникальное)
|
||||
# ------------------------------------------------------------------
|
||||
def generate_id(name: str, alias: str) -> str:
|
||||
"""Генерирует MD5‑hash из `name:alias`."""
|
||||
key = f"{name}:{alias}"
|
||||
return hashlib.md5(key.encode("utf-8")).hexdigest()
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 6️⃣ Генерация SQL‑файла
|
||||
# ------------------------------------------------------------------
|
||||
def write_sql_file(breeds: dict, out_path: pathlib.Path):
|
||||
"""Создаёт один .sql‑файл, содержащий INSERT‑операции для всех пород."""
|
||||
if not breeds:
|
||||
print("⚠️ Нет данных для генерации SQL.")
|
||||
return
|
||||
|
||||
lines = []
|
||||
header = (
|
||||
"-- Автоматически сгенерированный скрипт вставки пород\n"
|
||||
"-- Запустить: psql -f beerds_insert.sql\n\n"
|
||||
"BEGIN;\n"
|
||||
)
|
||||
lines.append(header)
|
||||
|
||||
# Формируем один блок INSERT с несколькими строками VALUES
|
||||
# 1. Столбцы
|
||||
cols = "(id, name, descriptions, signs, alias)"
|
||||
# 2. Генерируем строки VALUES
|
||||
value_lines = []
|
||||
for name, (description, signs) in breeds.items():
|
||||
alias = name # можно изменить при необходимости
|
||||
breed_id = generate_id(name, alias)
|
||||
# Подготовка значений: экранирование апострофов и JSON
|
||||
escaped_name = name.replace("_", " ").replace("'", "''")
|
||||
escaped_alias = alias.replace("'", "''")
|
||||
escaped_desc = description.replace("'", "''")
|
||||
# JSON как строка (в PostgreSQL json можно передавать как текст)
|
||||
json_str = json.dumps(signs, ensure_ascii=False).replace("'", "''")
|
||||
value_line = f"('{breed_id}', '{escaped_name}', '{escaped_desc}', '{json_str}', '{escaped_alias}')"
|
||||
value_lines.append(value_line)
|
||||
|
||||
# Объединяем VALUES через запятую
|
||||
values_section = ",\n".join(value_lines)
|
||||
insert_stmt = (
|
||||
f"INSERT INTO beerds.beerds {cols}\n"
|
||||
f"VALUES\n{values_section}\n"
|
||||
f"ON CONFLICT (id) DO UPDATE\n"
|
||||
f" SET name = EXCLUDED.name,\n"
|
||||
f" descriptions = EXCLUDED.descriptions,\n"
|
||||
f" signs = EXCLUDED.signs,\n"
|
||||
f" alias = EXCLUDED.alias;\n"
|
||||
)
|
||||
lines.append(insert_stmt)
|
||||
lines.append("\nCOMMIT;")
|
||||
|
||||
# Записываем в файл
|
||||
out_path.write_text("\n".join(lines), encoding="utf-8")
|
||||
print(f"✅ SQL‑файл успешно сгенерирован: {out_path}")
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 7️⃣ Основная точка входа
|
||||
# ------------------------------------------------------------------
|
||||
def main():
|
||||
print("🔍 Читаем файлы…")
|
||||
breeds_map = build_breed_map(DESC_DIR, SIGN_DIR)
|
||||
|
||||
if not breeds_map:
|
||||
print("❌ Ничего не найдено. Завершение.")
|
||||
sys.exit(1)
|
||||
|
||||
# Путь для вывода SQL‑файла
|
||||
sql_file_path = BASE_DIR / "beerds_insert.sql"
|
||||
print(f"📝 Записываем INSERT‑операции в файл: {sql_file_path}")
|
||||
write_sql_file(breeds_map, sql_file_path)
|
||||
|
||||
print("🎉 Готово!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def generate_folder_structure(root_path):
|
||||
result = {}
|
||||
# Поддерживаемые форматы изображений
|
||||
image_ext = {".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".tiff"}
|
||||
|
||||
# Основные категории (cat и dog)
|
||||
for category in ["cat", "dog"]:
|
||||
category_path = Path(root_path) / category
|
||||
if not category_path.is_dir():
|
||||
continue
|
||||
|
||||
category_dict = {}
|
||||
# Обрабатываем подпапки внутри категории
|
||||
for subfolder in category_path.iterdir():
|
||||
if subfolder.is_dir():
|
||||
# Собираем изображения
|
||||
images = [
|
||||
file.name for file in subfolder.iterdir() if file.is_file() and file.suffix.lower() in image_ext
|
||||
]
|
||||
category_dict[subfolder.name] = sorted(images)
|
||||
|
||||
result[category] = category_dict
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def save_to_json(data, output_file):
|
||||
with open(output_file, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Настройки
|
||||
ASSETS_DIR = "server/static/assets"
|
||||
OUTPUT_JSON = "structure.json"
|
||||
|
||||
# Генерация структуры
|
||||
structure = generate_folder_structure(ASSETS_DIR)
|
||||
|
||||
# Сохранение в файл
|
||||
save_to_json(structure, OUTPUT_JSON)
|
||||
print(f"JSON структура сохранена в файл: {OUTPUT_JSON}")
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue