Respan Dataset Explorer

Select one behavior. Every returned turn has one binary label: Present or Absent. Source: final dense boolean release.

5,167,182physical rows
86shards
0.00%qualified row coverage
0.00%qualified cell coverage
Random row JSON API

turns-00069.parquet:34901

76b48598a0e5eb46bbac3af2
turn 1/12gpt-4.1-mini-2025-04-14RussianRussia651 words
degenerate_repetitionAbsentFinal dense release
USER
Смотри мне для всего моего плана нужно текстовые файловая и нейросеть что будет анализировать всё что находится в папках сохранённых которые находятся в cleaning base и это не сеть будет переписывать если текст анализируй и обобщая но при этом оставляя общую структуру текста должна структурировать эти файлы создаваем название чтобы можно было легко искать нужные файлы вот к примеру у меня есть это не сесть будет создавать отдельную категорию которая будет называться done baza в этой базе нейросеть должна создавать папку с начальным сайтом с понятным названием что это за сайт и подписывать в папки файлы внутри этой папки также понятно чтобы легко было ориентироваться
ASSISTANT
Понял задачу. Попробую описать общий подход и предложить пример архитектуры нейросетевого решения для анализа, структурирования и переименования файлов в заданных папках.

---

## Задача:

1. Имеется папка с сохранёнными данными (текстовые файлы) — `cleaning base`.
2. Нужно создать нейросеть или систему, которая:
   - Анализирует все тексты в папках внутри `cleaning base`.
   - Обобщает и структурирует информацию, при этом сохраняя общую структуру текста.
   - Создаёт структуру папок и подкаталогов с осмысленными названиями по содержимому.
   - Создаёт отдельную категорию `done baza`, в которой:
     - будут папки, названные согласно с начальным сайтом или темой (например, название сайта),
     - внутри эти папки содержат файлы с понятными, однозначными названиями.
3. Названия папок и файлов должны быть понятными и удобными для поиска и навигации.

---

## Возможный подход

### 1. Сбор и чтение текстов
- Сканируем папку `cleaning base`, перебираем все вложенные папки и файлы, читаем тексты.
- Для каждого текстового файла извлекаем содержимое.

### 2. Анализ и обобщение текстов (нейросеть)
- Для анализа можно использовать модели типа GPT-4, BERT или специализированные модели для кластеризации и классификации текстов.
- Задачи нейросети:
  - Определить основную тематику или название (например, по содержимому, метаданным, URL, внутри текстов и пр.).
  - Обобщить или кратко описать содержание.
  - Разбить текст на смысловые блоки, чем поддержать структуру.
  
### 3. Формирование структуры папок и названий
- Исходя из классификации и тематики создаём папку с названием, которое отражает сайт или тематику (например, www.example.com).
- Внутри создаём подкаталоги с разбивкой на категории или по смысловым блокам.
- Переименовываем исходные файлы с осмысленными именами (например, "Главная_страница.txt", "Статья_о_теме_Х.txt" и т.д.).

### 4. Вывод и сохранение результата
- В папку `done baza` помещаем структуру с итоговыми папками и файлами.
- Тексты сохранены либо в исходном виде, либо с незначительным переписыванием для обобщения.
- Можно дополнительно сохранять JSON с метаданными для удобного поиска.

---

## Техническая реализация (пример):

```python
import os
from transformers import pipeline
from pathlib import Path

# Пример использования модели для классификации или суммаризации текста
summarizer = pipeline("summarization", model="facebook/bart-large-cnn")  # или GPT API

def read_text(filepath):
    with open(filepath, "r", encoding="utf-8") as f:
        return f.read()

def summarize_text(text):
    # Краткое резюме, если текст слишком большой, можно делить на части
    summary = summarizer(text, max_length=150, min_length=40, do_sample=False)
    return summary[0]['summary_text']

def classify_or_extract_site_name(text):
    # Тут можно использовать ключевые слова, регулярные выражения
    # или нейросеть для выделения названия сайта
    # пример-заглушка:
    return "example_site"

def process_cleaning_base(input_dir, output_dir):
    for root, _, files in os.walk(input_dir):
        for file in files:
            if file.endswith(".txt"):
                filepath = os.path.join(root, file)
                text = read_text(filepath)
                
                site_name = classify_or_extract_site_name(text)
                summary = summarize_text(text)
                
                # Создаём нужную папку если не существует
                site_folder = os.path.join(output_dir, site_name)
                os.makedirs(site_folder, exist_ok=True)

                # Генерируем понятное имя файла
                new_name = "summary_" + file
                output_path = os.path.join(site_folder, new_name)

                # Записываем суммарный текст
                with open(output_path, "w", encoding="utf-8") as fw:
                    fw.write(summary)

if __name__ == "__main__":
    input_path = "cleaning base"
    output_path = "done baza"
    process_cleaning_base(input_path, output_path)
```

---

## Дополнительные рекомендации

- Если файлов очень много и тексты большие — лучше делать обработку пакетами.
- Для классификации тематики можно дообучить специализированную модель на своих данных.
- Можно добавить к структуре индексный файл с описанием содержимого (например, index.json).
- Для именования используйте транслитерацию или англоязычные названия, чтобы избежать проблем с кодировками и поиском.
- Можно создать небольшое веб-приложение для просмотра и поиска по структуре `done baza`.

---

Если нужна помощь с более подробной реализацией или адаптацией под ваши конкретные данные — пишите, могу помочь!

turns-00069.parquet:34902

5d0c5796e65cf0faf2a9dc61
turn 2/12gpt-4.1-mini-2025-04-14RussianRussia1291 words
degenerate_repetitionAbsentFinal dense release
USER
Так подожди у меня уже есть код на питоне который скачивает текст с сайта указанный в текстовом файле файле специальном также у меня есть программа на питоне которая убирает лишний мусор в сохранённый в сохранённых текстовых файлах и сохраняется это специально директории мне нужно чтобы университете из этой директории зачищенным кодом анализировала и распределяла папки по темам для более удобного и быстрого доступа к файлам вот кот программы для скачивания текста и для первичной фильтрации: import os
import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse, urljoin
import re

visited = set()

def sanitize_filename(name):
    """Очищает имя файла/папки от запрещённых символов."""
    return re.sub(r'[<>:"/\\|?*]', '_', name)

def extract_visible_text(soup):
    """
    Извлекает видимый текст с HTML-страницы —  
    убирает скрипты, стили, навигацию, скрытые элементы и т.п.
    """
    # Убираем скрипты/стили
    for script in soup(['script', 'style', 'head', 'title', 'meta', '[document]', 'noscript']):
        script.extract()

    # Можно попытаться убрать навигационные блоки (если есть стандартные id/классы)
    nav_classes_ids = ['nav', 'navigation', 'footer', 'header', 'sidebar', 'menu', 'breadcrumbs']
    for cls_id in nav_classes_ids:
        for tag in soup.find_all(attrs={'class': lambda x: x and cls_id in x.lower()}):
            tag.extract()
        for tag in soup.find_all(id=lambda x: x and cls_id in x.lower()):
            tag.extract()

    # Теперь получаем текст и очищаем лишние пустоты
    texts = soup.stripped_strings
    visible_text = '\n'.join(texts)
    return visible_text

def save_text(folder, url, text):
    parsed = urlparse(url)
    path = parsed.path.strip('/')

    if not path or path.endswith('/'):
        filename = 'index.txt'
    else:
        filename = sanitize_filename(path) + '.txt'

    os.makedirs(folder, exist_ok=True)
    filepath = os.path.join(folder, filename)
    with open(filepath, 'w', encoding='utf-8') as f:
        f.write(text)
    print(f'[+] Сохранён текст: {filepath}')

def is_internal_link(link, base_domain):
    parsed_link = urlparse(link)
    return parsed_link.netloc == base_domain

def crawl(url, folder, base_domain, max_depth=2, depth=0):
    if depth > max_depth:
        return
    if url in visited:
        return
    visited.add(url)

    print(f'{"  "*depth}Скачиваем: {url}')
    try:
        resp = requests.get(url, timeout=10)
        resp.raise_for_status()
    except Exception as e:
        print(f'{"  "*depth}Ошибка при загрузке {url}: {e}')
        return

    soup = BeautifulSoup(resp.text, 'html.parser')
    text = extract_visible_text(soup)
    save_text(folder, url, text)

    # Ссылки на странице
    links = set()
    for tag in soup.find_all('a', href=True):
        href = tag['href']
        abs_link = urljoin(url, href)
        # проверяем, что ссылка http/https, и внутренняя
        if (abs_link.startswith('http://') or abs_link.startswith('https://')) and is_internal_link(abs_link, base_domain):
            links.add(abs_link)

    for link in links:
        parsed_link = urlparse(link)
        subfolder_name = sanitize_filename(parsed_link.netloc + parsed_link.path.replace('/', '_'))
        if not subfolder_name:
            subfolder_name = 'root'
        new_folder = os.path.join(folder, subfolder_name)
        crawl(link, new_folder, base_domain, max_depth, depth + 1)

def main():
    url_file = 'urls.txt'
    if not os.path.exists(url_file):
        print(f'Файл {url_file} не найден.')
        return

    with open(url_file, 'r', encoding='utf-8') as f:
        start_urls = [line.strip() for line in f if line.strip()]

    baza_folder = os.path.join(os.getcwd(), 'baza')
    os.makedirs(baza_folder, exist_ok=True)

    for url in start_urls:
        parsed = urlparse(url)
        domain_folder = sanitize_filename(parsed.netloc)
        start_folder = os.path.join(baza_folder, domain_folder)
        print(f'\n=== Обход сайта: {url} ===')
        crawl(url, start_folder, base_domain=parsed.netloc, max_depth=2, depth=0)

if __name__ == '__main__':
    main();import os
import re

SOURCE_ROOT = 'baza'            # Ваш базовый каталог с исходными текстами
OUTPUT_ROOT = 'cleaned_baza'   # Папка для сохранения "очищенных" файлов

def is_noise_line(line):
    line = line.strip()
    if not line:
        return True
    # Удаляем линии, состоящие из одних цифр (часто - номера страниц)
    if re.fullmatch(r'(\d+|\s)+', line):
        return True
    # Номера страниц на разных языках, например "page 1", "стр. 2"
    if re.fullmatch(r'(page|страница|стр|№)\s*\d+', line.lower()):
        return True

    # Если строка состоит из 1-2 символов и не содержит букв - считаем мусором
    if len(line) <= 2 and not re.search(r'[а-яА-Яa-zA-Z]', line):
        return True

    # Можно добавить другие паттерны для "мусора" (например, слишком короткие слова)
    return False

def clean_text(text):
    lines = text.split('\n')
    cleaned_lines = []
    for line in lines:
        if not is_noise_line(line):
            # Можно дополнительно чистить строку: например, удалять мусорные символы
            line = line.strip()
            # Уберите лишние пробелы внутри строки
            line = re.sub(r'\s+', ' ', line)
            if line:
                cleaned_lines.append(line)
    return '\n'.join(cleaned_lines)

def process_files(source_dir, output_dir):
    for root, dirs, files in os.walk(source_dir):
        # Создаем соответствующую структуру папок в output_dir
        relative_path = os.path.relpath(root, source_dir)
        target_folder = os.path.join(output_dir, relative_path)
        os.makedirs(target_folder, exist_ok=True)

        for filename in files:
            if filename.endswith('.txt'):
                source_path = os.path.join(root, filename)
                target_path = os.path.join(target_folder, filename)

                with open(source_path, 'r', encoding='utf-8') as f:
                    text = f.read()

                cleaned = clean_text(text)

                with open(target_path, 'w', encoding='utf-8') as f:
                    f.write(cleaned)

                print(f'Обработан файл: {source_path} -> {target_path}')

if __name__ == '__main__':
    process_files(SOURCE_ROOT, OUTPUT_ROOT)
ASSISTANT
Понял, спасибо за детали — у вас уже есть:

- Парсер/краулер, который скачивает сайты и сохраняет тексты в структуре папок (`baza`).
- Скрипт очистки — фильтрует мусорный текст, складывает очищенные файлы в `cleaned_baza`.

Теперь вам нужна универсальная **программа (или нейросеть/модель)**, которая:

- Анализирует содержимое файлов из `cleaned_baza`.
- Автоматически группирует и распределяет файлы/папки в **новую структуру** по темам.
- Создаёт итоговую папку, например `done_baza`, с понятными категориями (названия категорий — по теме, сайту, либо использованию).
- Переименовывает файлы так, чтобы было ясно, что где хранится и чтобы было проще искать.

---

## Конкретные рекомендации и идеи реализации

### 1. Подход к классификации/группировке

Чтобы тематика/категория подсказывались автоматически, можно:

- Использовать предобученную языковую модель (например, BERT, или GPT) для извлечения темы из текста.
- Варианты:
  - Классифицировать каждый файл по уже заданным темам (если они есть).
  - Или кластеризовать файлы, основываясь на семантическом сходстве текстов, чтобы потом каждой группе ручками дать название.
  - Или использовать моделирование тем (topic modeling) — LDA, NMF и т.п. — чтобы выделить основные темы.

### 2. Подход к структуре и именованию

- Для каждой темы (кластера) создаем папку с соответствующим названием.  
- В папке создаем файлы, переименовывая исходные в виде `<короткое_описание>.txt`.  
  Для описания можно использовать результат суммаризации, или первые N слов в тексте, или заголовок (если есть).

---

## Минимальный рабочий пример на Python

Я покажу упрощённый вариант, использующий библиотеку `sentence-transformers` для векторизации текста и `sklearn` для кластеризации.  
Дальше можно будет выводить список кластеров, вручную их подпишете, и на основе тем автоматизируете именование папок.

```python
import os
from sentence_transformers import SentenceTransformer
from sklearn.cluster import AgglomerativeClustering
from sklearn.metrics.pairwise import cosine_distances
import numpy as np

INPUT_DIR = 'cleaned_baza'
OUTPUT_DIR = 'done_baza'

model = SentenceTransformer('all-MiniLM-L6-v2')

def read_text(file_path):
    with open(file_path, 'r', encoding='utf-8') as f:
        return f.read()

def cluster_texts(texts, n_clusters=10):
    embeddings = model.encode(texts, batch_size=16, show_progress_bar=True)
    clustering_model = AgglomerativeClustering(n_clusters=n_clusters, affinity='cosine', linkage='complete')
    clustering_model.fit(embeddings)
    labels = clustering_model.labels_
    return labels

def sanitize_name(name):
    return ''.join(c if c.isalnum() or c == '_' else '_' for c in name)[:50]

def main():
    file_paths = []
    texts = []

    # Считаем все тексты в cleaned_baza
    for root, dirs, files in os.walk(INPUT_DIR):
        for file in files:
            if file.endswith('.txt'):
                path = os.path.join(root, file)
                text = read_text(path)
                texts.append(text)
                file_paths.append(path)

    if not texts:
        print('Нет текстовых файлов для обработки')
        return

    # Кластеризуем тексты (число кластеров можно подбирать динамически)
    n_clusters = 10
    labels = cluster_texts(texts, n_clusters=n_clusters)

    # Создаём папки по кластерам и сохраняем файлы
    os.makedirs(OUTPUT_DIR, exist_ok=True)

    cluster_texts_map = {i: [] for i in range(n_clusters)}
    for path, text, label in zip(file_paths, texts, labels):
        cluster_texts_map[label].append((path, text))

    for cluster_id, files in cluster_texts_map.items():
        folder_name = f'topic_{cluster_id}'
        folder_path = os.path.join(OUTPUT_DIR, folder_name)
        os.makedirs(folder_path, exist_ok=True)

        for i, (path, text) in enumerate(files):
            # Краткое имя файла - первые 5 слов исходного файла
            snippet = ' '.join(text.split()[:5])
            filename = sanitize_name(snippet) or f'doc_{i}'
            target_path = os.path.join(folder_path, f'{filename}.txt')

            # Читаем исходный файл заново или просто копируем очищенный текст
            with open(target_path, 'w', encoding='utf-8') as f:
                f.write(text)

    print(f'Кластеризация завершена, результаты в папке {OUTPUT_DIR}')

if __name__ == '__main__':
    main()
```

---

## Что дальше?

- После запуска получите папки `topic_0`, `topic_1`, ..., в которых сгруппированы похожие тексты.
- Можно вручную посмотреть несколько файлов в папках, и понять тематику, переименовать папки в осмысленные названия (например, «Новости», «Технологии» и т.п.).
- Для автоматизации именования папок можно попробовать запросить краткое описание содержания текстов папки через GPT.
- По желанию можно сделать более продвинутое индексирование для поиска (например, ElasticSearch или vector search).


---

## Если хотите именно нейросетевое «обобщение» и создание понятных имя файлов/папок

- Используйте API GPT (например, GPT-4) или open-source аналог.
- Запрашивайте краткое резюме первого файла из кластера/темы — название темы.
- Аналогично — генерируйте индивидуальные короткие названия файлов.
  
**Пример промпта к GPT:**
```
Вот текст веб-страницы:
<текст>
Дай короткое, емкое название (3-5 слов) для папки/темы.
```

---

Если интересно, могу помочь написать обвязку для запуска GPT API, или интегрировать с вашим кодом!

---

Если нужно:  
- объединить с вашими существующими скриптами  
- добавить уточнения по работе с файлами  
- или выполнить именно «на лету» автоматический разбор с генерацией ультимативной структуры — дайте знать!

turns-00069.parquet:34903

65ba130d88ecaa60777b6468
turn 3/12gpt-4.1-mini-2025-04-14RussianRussia692 words
degenerate_repetitionAbsentFinal dense release
USER
Нет мне нужно чтобы это нейросеть была как обычный скрипт питоновский то есть я с помощью первой программы скачиваю весь текст запускаю вторую программу она очищает от лишнего понятного мусора этот текст весь и я хочу чтобы я именно что нейросеть модель которая не будет со мной общаться но в консоль она будет просто выводить значит запуск выполняю группирование задачи она не будет со мной разговаривать её задача - это сгруппировать используя готовые базы данных для более тщательного анализа и обобщения групп тем
ASSISTANT
Понятно, что вам нужна автономная Python-программа, которая:

- получает на входём множество чистых текстов (с уже снятым мусором),
- без участии пользователя (через консоль) — выполняет глубокий анализ, группирует тексты по темам,
- возможно, обобщает (создаёт краткие описания),
- и на выходе даёт структуру папок в `done_baza` с именами категорий и понятными именами файлов.

---

## Какие возможности можете использовать (в оффлайн-режиме, без API)?

- Классические методы обработки текста: TF-IDF + кластеризация
- Topic modeling (LDA, NMF) — выделяет темы
- Векторизация текста нейросетями (`sentence-transformers`) + кластеризация
- Генерация заголовков/титулов через автосуммаризацию ("extractive summarization")
- Для обобщения тем и описания кластеров можно использовать ключевые слова/токены.

---

## Пример готового скрипта — автономное тематическое группирование с обобщением

Используем библиотеки:

- `sentence-transformers` — для векторизации предложений
- `sklearn` — для кластеризации
- `keybert` — для автоматического извлечения ключевых слов и тем (которые можно подставить в название папки)
- обычный Python для работы с файлами

---

### Установка необходимых библиотек:

```bash
pip install sentence-transformers scikit-learn keybert
```

---

### Пример итогового скрипта

```python
import os
from sentence_transformers import SentenceTransformer
from sklearn.cluster import AgglomerativeClustering
from keybert import KeyBERT

INPUT_DIR = 'cleaned_baza'
OUTPUT_DIR = 'done_baza'

# Инициализируем модели
embedder = SentenceTransformer('all-MiniLM-L6-v2')
kw_model = KeyBERT()

def read_text(filepath):
    with open(filepath, encoding='utf-8') as f:
        return f.read()

def sanitize_name(name):
    # Убираем непечатные символы для имени папок/файлов
    return ''.join(c if c.isalnum() or c in (' ', '_', '-') else '_' for c in name).strip()[:50]

def extract_keywords(text, keyphrase_ngram_range=(1,2), top_n=3):
    # возвращает список ключевых слов/фраз по тексту
    keywords = kw_model.extract_keywords(text, keyphrase_ngram_range=keyphrase_ngram_range, top_n=top_n)
    return [kw[0] for kw in keywords]

def create_folder(path):
    if not os.path.exists(path):
        os.makedirs(path)

def main():
    files = []
    texts = []

    print("Сканируем входную директорию...")
    for root, _, filenames in os.walk(INPUT_DIR):
        for fname in filenames:
            if fname.endswith('.txt'):
                fp = os.path.join(root, fname)
                text = read_text(fp)
                texts.append(text)
                files.append(fp)

    if not texts:
        print("Нет текстовых файлов для обработки!")
        return

    print(f"Найдено файлов: {len(files)}. Векторизуем...")

    embeddings = embedder.encode(texts, batch_size=16, show_progress_bar=True)

    # Кластеризация - попробуем от 5 до 20 кластеров (зависит от числа файлов)
    n_clusters = max(5, min(20, len(files)//10))
    print(f"Выполняем кластеризацию на {n_clusters} кластеров...")
    clustering = AgglomerativeClustering(n_clusters=n_clusters, affinity='cosine', linkage='average')
    labels = clustering.fit_predict(embeddings)

    cluster_texts = {}
    for label, path, text in zip(labels, files, texts):
        cluster_texts.setdefault(label, []).append((path, text))

    print("Формируем конечную структуру...")
    create_folder(OUTPUT_DIR)

    for cluster_id, file_text_list in cluster_texts.items():
        # Объединяем тексты кластера для извлечения ключевых слов тематики
        combined_text = ' '.join([t[1] for t in file_text_list])
        keywords = extract_keywords(combined_text)

        theme_name = sanitize_name(' '.join(keywords)) or f'topic_{cluster_id}'
        cluster_folder = os.path.join(OUTPUT_DIR, theme_name)
        create_folder(cluster_folder)

        for idx, (original_path, text) in enumerate(file_text_list):
            # Создаем компактное имя файла из начала текста
            snippet = ' '.join(text.split()[:7])
            filename = sanitize_name(snippet) or f'doc_{idx}'
            filepath = os.path.join(cluster_folder, filename + '.txt')
            with open(filepath, 'w', encoding='utf-8') as f:
                f.write(text)

    print(f"Группировка завершена, результаты находятся в {OUTPUT_DIR}")

if __name__ == '__main__':
    main()
```

---

## Как это работает под капотом:

- Сначала читаются все файлы из `cleaned_baza`.
- Все тексты векторизуются нейросетью SentenceTransformer, которая генерирует семантические embedding'и.
- Они кластеризуются (`AgglomerativeClustering` по косинусному расстоянию).
- Для каждого кластера объединяется весь текст, выделяются ключевые слова через KeyBERT.
- По ключевым словам формируется название папки (например, «автомобили технология»).
- Внутри папки лежат файлы с понятными именами по первому предложению/словам текста.

---

## Почему это автономно и без диалога?

- Скрипт НЕ вызывает API, не ждёт ввода пользователя.
- Запускается из консоли, выводит лишь ход работы.
- Генерирует структурированный материал для дальнейшего удобного поиска.

---

## Можно ли добавить полноценное обобщение?

Да, но тогда без GPT API придётся ограничиваться:

- Либо extractive summarization (подбор ключевых фраз, вывод первых предложений)
- Либо интеграция с open-source моделями типа BART для суммаризации (сложно сразу встроить).

---

Если хотите — могу помочь вам с более продвинутым обобщением на базе transformers (суммаризация), либо с интеграцией в уже существующий пайплайн.

---

Если что-то непонятно — спрашивайте!

turns-00069.parquet:34904

ff62a1d64e3c42d6f6755b29
turn 4/12gpt-4.1-mini-2025-04-14RussianRussia291 words
degenerate_repetitionAbsentFinal dense release
USER
Подожди тогда получается вот это вот программа сама проанализирует все мои папки с распределит их по темам и даст нормальные и понятный человеку заголовки к ним
ASSISTANT
Да, именно так!

---

Этот скрипт:

- **сам прочитает все тексты из папки `cleaned_baza` (ваш очищенный от мусора корпус),**
- **проанализирует их содержимое с помощью предобученной нейросети (SentenceTransformer),**
- **выполнит кластеризацию файлов по смысловым темам (близким по содержанию текстам присвоит один кластер),**
- **для каждого кластера соберёт ключевые слова (через KeyBERT) — это и будет название темы (папки),**
- **создаст итоговую папку `done_baza`, где для каждого кластера сделает подпапку с «человеко-понятным» названием, основанным на ключевых словах,**
- **и положит туда файлы из этого кластера, переименованные в удобочитаемые имена, основанные на первых словах текста.**

---

### Почему это удобно и понятно:

- Названия папок — автоматически сгенерированные ключевые фразы, отражающие основную тематику группы файлов.
- Файлы внутри групп — названы кратко и информативно, чтобы сразу понять, о чём текст.
- Нет необходимости вручную нумеровать или искать нужные документы — группировка по смыслу.
- Автоматический и полностью автономный процесс, запускаете и получаете организованную базу.

---

### Ограничения и нюансы

- Названия папок — это ключевые слова из текста, их качество зависит от содержимого.
- Если в базе очень разноплановые темы — полезно настроить число кластеров (в скрипте переменная `n_clusters`).
- Иногда «ключевые слова» могут быть достаточно абстрактными — для улучшения можно менять параметры KeyBERT или добавлять фильтрацию.
- Скрипт не генерирует «человеческие» заголовки в стиле GPT, но даёт очень близкие к теме автоматические названия.

---

### Резюмируя

Это удобный и мощный способ быстро организовать и систематизировать большой массив текстов с минимальной ручной работой.

Если хотите, могу помочь подстроить под ваши задачи, улучшить генерацию названий, добавить суммаризацию, или сделать наоборот — вывести из кластеров детальное описание. Просто скажите!

turns-00069.parquet:34905

76309b7877c663dfd474c402
turn 5/12gpt-4.1-mini-2025-04-14RussianRussia298 words
degenerate_repetitionAbsentFinal dense release
USER
И на телефоне этот код тоже будет работать да?
ASSISTANT
В общем случае — **нет, не сразу**. Вот почему:

---

### Причины, почему код не будет просто так работать на телефоне

1. **Зависимости и ресурсы**  
   Скрипт использует крупные ML-модели (`sentence-transformers`, `keybert`, `sklearn`), которые требуют:
   - Значительных ресурсов CPU и памяти.
   - Часто — GPU для ускорения (актуально, если данных много).
  
   На большинстве смартфонов (Android/iOS) таких ресурсов нет или очень ограничены.

2. **Окружение Python**  
   - На телефоне не всегда просто поднять полноценное окружение Python с нужными библиотеками.
   - Особенно сложно с библиотеками, имеющими нативные зависимости (например, `scikit-learn`, `faiss`, `transformers`).
  
3. **Размер моделей**  
   - SentenceTransformer и KeyBERT используют относительно большие TF/Transformer-модели (несколько сотен мегабайт).
   - Поддержка таких моделей на мобильных платформах редка и сложна.

---

### Что можно сделать, чтобы запустить на телефоне

- Использовать легковесные модели, специально оптимизированные для мобильных (например, TinyBERT, DistilBERT с quantization).
- Писать приложение с интеграцией ML-моделей через ONNX Runtime Mobile или TensorFlow Lite, но это уже сложная разработка (не просто Python-скрипт).
- Запускать модель/логику на сервере, а на телефоне — только интерфейс для управления и просмотра результата.
- Для Android есть проекты с Python (например, Pydroid, Termux), но:
  - Установка всех нужных библиотек будет непростой задачей.
  - Скорее всего, на больших данных и моделях телефон либо "задохнётся", либо будет очень медленно.

---

### Итог

- **Если вы собираетесь запускать этот скрипт в таком виде — лучше на компьютере/сервере.**
- **Для мобильного — нужно либо сильно оптимизировать и адаптировать модели, либо сделать серверную часть, а на телефоне только клиент.**

Если интересно — могу подсказать, как сделать лёгкое серверное API, чтобы на телефоне вы просто отправляли тексты и получали группировку обратно.

---

Если нужен простой способ — запускать анализ только на ПК, а на телефоне — доступ к уже отсортированным файлам (например, через файловый менеджер или веб-интерфейс).

turns-00069.parquet:34906

5c1381b3c5df55256294cd9e
turn 6/12gpt-4.1-mini-2025-04-14RussianRussia475 words
degenerate_repetitionAbsentFinal dense release
USER
Traceback (most recent call last):
  File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 31, in <module>
    start(fakepyfile,mainpyfile)
    ~~~~~^^^^^^^^^^^^^^^^^^^^^^^
  File "/data/user/0/ru.iiec.pydroid3/files/accomp_files/iiec_run/iiec_run.py", line 30, in start
    exec(open(mainpyfile).read(),  __main__.__dict__)
    ~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<string>", line 2, in <module>
ModuleNotFoundError: No module named 'sentence_transformers'
[Program finished]
ASSISTANT
Ошибка `ModuleNotFoundError: No module named 'sentence_transformers'` означает, что в вашей среде Python (в данном случае, в Pydroid 3 на телефоне) не установлен модуль `sentence-transformers`.

---

## Вот что можно сделать

### 1. Установка `sentence-transformers` в Pydroid 3

Попробуйте в терминале Pydroid 3 выполнить команду:

```bash
pip install sentence-transformers
```

**Однако!**

- `sentence-transformers` зависит от `transformers`, `torch` и других больших библиотек.
- В мобильной среде установка и работа этих библиотек очень проблематична.
- Pydroid 3 может не поддерживать или выдавать ошибки при сборке/установке.

### 2. Аналогичные ошибки для других зависимостей

Вы, скорее всего, встретите те же проблемы и с `keybert` и `sklearn`.

---

## Резюме для запуска на телефоне

- Запуск сложных Python ML-пакетов на мобильном крайне ограничен.
- `sentence-transformers` и `keybert` лучше использовать на PC или сервере.
- На телефоне можно использовать более простые решения (например, базовый TF-IDF+кластеризацию из `sklearn`, что обычно устанавливается проще, но качество будет значительно хуже).

---

## Что рекомендую сделать

- **Работать с этим кодом на ноутбуке или десктопе.**
- Сделать скрипт, который формирует результат в виде удобной структуры папок.
- Если надо доступ с телефона — поднять простой HTTP-сервер (на вашем ПК или в облаке) для просмотра/поиска.
- Либо попробовать облегчённые модели — но для этого нужно будет перестраивать код и искать/обучать мобильные версии моделей.

---

## Если очень хотите попробовать облегчённый вариант с TF-IDF

Можно написать пример, который только через `sklearn` (без `sentence-transformers`) сделает простую кластеризацию — он может работать в Pydroid 3, если там установлен `scikit-learn`.

Пример:

```python
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
import os

INPUT_DIR = 'cleaned_baza'
OUTPUT_DIR = 'done_baza'

def read_text(filepath):
    with open(filepath, encoding='utf-8') as f:
        return f.read()

def sanitize_name(name):
    return ''.join(c if c.isalnum() or c in (' ', '_', '-') else '_' for c in name).strip()[:50]

def main():
    files = []
    texts = []

    for root, _, filenames in os.walk(INPUT_DIR):
        for fname in filenames:
            if fname.endswith('.txt'):
                fp = os.path.join(root, fname)
                text = read_text(fp)
                texts.append(text)
                files.append(fp)

    if not texts:
        print("Файлов для обработки нет")
        return

    vectorizer = TfidfVectorizer(max_features=5000, stop_words='english')
    X = vectorizer.fit_transform(texts)

    n_clusters = max(2, min(10, len(files)//5))
    clustering = KMeans(n_clusters=n_clusters, random_state=42)
    labels = clustering.fit_predict(X)

    os.makedirs(OUTPUT_DIR, exist_ok=True)

    cluster_texts = {}
    for label, file_path, text in zip(labels, files, texts):
        cluster_texts.setdefault(label, []).append((file_path, text))

    for cluster_id, files_texts in cluster_texts.items():
        folder_name = f'topic_{cluster_id}'
        folder_path = os.path.join(OUTPUT_DIR, folder_name)
        os.makedirs(folder_path, exist_ok=True)

        for idx, (_, text) in enumerate(files_texts):
            snippet = ' '.join(text.split()[:7])
            filename = sanitize_name(snippet) or f'doc_{idx}'
            path = os.path.join(folder_path, filename + '.txt')
            with open(path, 'w', encoding='utf-8') as f:
                f.write(text)

    print(f'Группировка завершена, результаты в {OUTPUT_DIR}')

if __name__ == '__main__':
    main()
```

Этот скрипт не требует `sentence-transformers` и использует только `scikit-learn`.

---

Если у вас возникнут вопросы — пишите! Помогу адаптировать под возможности телефона или посоветую другую реализацию.

turns-00069.parquet:34907

e71a03ff8a0defd114aac003
turn 7/12gpt-4.1-mini-2025-04-14RussianRussia398 words
degenerate_repetitionAbsentFinal dense release
USER
ERROR: Resolutionlmpossible: for help visit https://pip.pypa.io/en/latest/topics/dependency -resolution/#dealing-with-dependency-conflicts
ASSISTANT
Ошибка `ERROR: ResolutionImpossible` при установке пакетов через pip обычно означает, что между требуемыми версиями пакетов существует конфликт зависимостей, которые pip не может автоматически разрешить.

---

### Что это значит конкретно в вашем случае?

- При попытке установить `sentence-transformers` (или другие большие ML-библиотеки) в Pydroid 3 или в ограниченной мобильной среде часто возникают зависимости, которые конфликтуют друг с другом.
- Некоторые пакеты требуют разные версии одних и тех же библиотек (например, `transformers`, `torch`, `numpy`).
- В мобильной среде Pydroid 3 не всегда можно гибко менять версии библиотек.
- А сборка или установка некоторых пакетов может завершаться ошибкой из-за отсутствия компиляторов или ограничений платформы.

---

### Практические варианты решения

1. **Попробуйте обновить pip** внутри Pydroid 3:
   ```bash
   pip install --upgrade pip setuptools wheel
   ```
2. **Попробуйте установить `sentence-transformers` с более простыми параметрами:**
   - Можно принудительно указать версии библиотек, которые совместимы (но это сложно без понимания конфликтов).
   - Например, сначала установить низкоуровневые зависимости вручную.

3. **Установите поочередно ключевые зависимости, чтобы понять где именно конфликт:**
   ```bash
   pip install torch
   pip install transformers
   pip install sentence-transformers
   ```
   Если на каком-то этапе возникнет ошибка — она даст понять, где конфликт.

4. **При невозможности решить конфликты — рекомендую:**
   - Перенести выполнение на ноутбук/компьютер с полноценным Python.
   - Запустить код там, без ограничений мобильной среды.
   - На телефон передавать уже готовую сгруппированную информацию (например, через облако, FTP, web-сервер).

---

### Мобильная среда — всегда сложность

- Pydroid 3 и подобные приложения для Python на Android не предназначены для сложных ML моделей.
- Поддержка `torch` и `transformers` ограничена или отсутствует.
- Возможен вариант с `Termux` (Linux-подобная среда на Android), но и там изначально нужна установка многих пакетов и настройка.

---

### Альтернатива: простая кластеризация с TF-IDF и KMeans

Как я писал ранее — если нужна работа в рамках телефона, попробуйте упрощённый скрипт, который работает только с `scikit-learn` (TF-IDF + KMeans). Этот скрипт менее точен, зато проще устанавливается:

```bash
pip install scikit-learn
```

И запускайте такой скрипт (пример выше). Это самое реально работающее решение для мобильного Python окружения.

---

### Если хотите — могу помочь с диагностикой конфликтов pip:

- Покажите пожалуйста полный лог ошибки (желательно с командой установки).
- Или расскажите, какую команду / последовательность вызовов вы выполняли.

---

**Короткий итог:**  
Для вашей задачи, если установка `sentence-transformers` не получается — делайте анализ на ПК или с помощью упрощённого кода с `scikit-learn`. На телефоне полноценная нейросеть — это пока очень сложно.

turns-00069.parquet:34908

b0d450ce928c038445f794ff
turn 8/12gpt-4.1-mini-2025-04-14RussianRussia469 words
degenerate_repetitionAbsentFinal dense release
USER
А если возможность как-нибудь переписать этот код без использования этой библиотеки?
ASSISTANT
Да, можно переписать код для тематической группировки *без* использования тяжелых нейросетевых моделей `sentence-transformers` и `keybert`, используя классические текстовые методы из `scikit-learn` — TF-IDF и кластеризацию KMeans или AgglomerativeClustering.

Такой скрипт будет гораздо легче запускать, в том числе (с вероятностью) на телефоне с Pydroid3 — при условии, что там установлен `scikit-learn`.

---

## Вот полностью рабочий пример скрипта без `sentence-transformers` и `keybert`:

```python
import os
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans

INPUT_DIR = 'cleaned_baza'
OUTPUT_DIR = 'done_baza'


def read_text(filepath):
    with open(filepath, encoding='utf-8') as f:
        return f.read()


def sanitize_name(name):
    # Удаляем неподходящие символы для имени файла/папки
    return ''.join(c if c.isalnum() or c in (' ', '_', '-') else '_' for c in name).strip()[:50]


def main():
    files = []
    texts = []

    # Считываем все тексты
    for root, _, filenames in os.walk(INPUT_DIR):
        for fname in filenames:
            if fname.endswith('.txt'):
                fp = os.path.join(root, fname)
                text = read_text(fp)
                texts.append(text)
                files.append(fp)

    if not texts:
        print("Нет текстовых файлов в директории для обработки.")
        return

    # Векторизуем тексты с помощью TF-IDF
    vectorizer = TfidfVectorizer(max_features=5000, stop_words='english')
    X = vectorizer.fit_transform(texts)

    # Задаём число кластеров (можно менять под размер корпуса)
    n_clusters = max(2, min(10, len(files)//5))

    print(f"Выполняем кластеризацию на {n_clusters} групп...")

    # Кластеризация KMeans
    clustering = KMeans(n_clusters=n_clusters, random_state=42)
    labels = clustering.fit_predict(X)

    # Создаём структуру папок для результатов
    os.makedirs(OUTPUT_DIR, exist_ok=True)

    cluster_texts = {}
    for label, file_path, text in zip(labels, files, texts):
        cluster_texts.setdefault(label, []).append((file_path, text))

    # Сохраняем файлы по кластерам
    for cluster_id, files_texts in cluster_texts.items():
        folder_name = f'topic_{cluster_id}'
        folder_path = os.path.join(OUTPUT_DIR, folder_name)
        os.makedirs(folder_path, exist_ok=True)

        for idx, (_, text) in enumerate(files_texts):
            snippet = ' '.join(text.split()[:7])  # первые 7 слов для имени
            filename = sanitize_name(snippet) or f'doc_{idx}'
            path = os.path.join(folder_path, filename + '.txt')
            with open(path, 'w', encoding='utf-8') as f:
                f.write(text)

    print(f"Группировка завершена. Результаты в папке {OUTPUT_DIR}")


if __name__ == '__main__':
    main()
```

---

## Что делает этот скрипт?

- Считывает все `.txt` файлы из `cleaned_baza`.
- Преобразует тексты в TF-IDF векторы.
- Кластеризует векторы на заданное число групп (по содержанию текстов).
- Создаёт по кластеру отдельную папку `topic_<номер>`.
- В каждую папку складывает исходные тексты, переименованные по первым 7 словам (короткий и понятный заголовок).
- Не использует нейросети — только классические NLP-инструменты `scikit-learn`.
- Существенно легче и быстрее, намного выше шанс, что запустится и на телефоне.

---

## Плюсы и минусы

| Плюсы                                       | Минусы                                        |
|----------------------------------------------|-----------------------------------------------|
| Легко запустится в мобильном Python (Pydroid3) | Названия папок — просто номера (topic_0, topic_1), мало «человеческой» читаемости |
| Быстро и эффективно                           | Без продвинутого выделения ключевых слов, название папок не подскажет тематику |
| Можно в дальнейшем улучшить за счёт добавления простых правил именования | Для улучшения темы папок — нужно ручное переименование или дополнительный анализ |

---

Если хотите — я могу помочь улучшить генерацию названий папок простыми эвристиками (например, по самым частым TF-IDF словам в кластере) — без тяжёлых библиотек.  

Сообщите, если интересно!

turns-00069.parquet:34909

634c49281076cfe15bc2d5bc
turn 9/12gpt-4.1-mini-2025-04-14RussianRussia517 words
degenerate_repetitionAbsentFinal dense release
USER
Мне всё же нужно чтобы этот код анализировал что находится в этих папках чтобы название этой папки отображало суть содержания
ASSISTANT
Понял вашу задачу: нужно, чтобы программа **автоматически анализировала содержимое каждого кластера и формировала для него понятное тематическое название**, отражающее суть текстов в этой группе.

При этом вы хотите, чтобы решение было без тяжелых нейросетевых библиотек (типа `sentence-transformers`), то есть с классическими инструментами и в рамках Python, который можно запустить и, возможно, на телефоне.

---

# Как этого добиться?

Самый простой и популярный способ — ориентироваться на **ключевые слова с самым высоким TF-IDF весом внутри кластера** и использовать их для названия темы-папки.

---

# Пример дополненного скрипта, который:

- Кластеризует тексты (через TF-IDF + KMeans)
- Для каждого кластера:
  - Объединяет тексты
  - Считает TF-IDF слова для объединенного корпуса внутри кластера
  - Берёт топ-N самых "важных" слов
- Использует эту подборку ключевых слов для названия папки

---

## Код:

```python
import os
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
import numpy as np

INPUT_DIR = 'cleaned_baza'
OUTPUT_DIR = 'done_baza'

def read_text(filepath):
    with open(filepath, encoding='utf-8') as f:
        return f.read()

def sanitize_name(name):
    # Делает имя безопасным для папок/файлов, максимум 50 символов
    return ''.join(c if c.isalnum() or c in (' ', '_', '-') else '_' for c in name).strip()[:50]

def extract_top_keywords(texts, top_n=3):
    # texts — список текстов, объединяем и вычисляем TF-IDF, выбираем топ ключевых слов
    joined_text = ' '.join(texts)
    vectorizer = TfidfVectorizer(stop_words='english', max_features=1000)
    tfidf_matrix = vectorizer.fit_transform([joined_text])
    feature_array = np.array(vectorizer.get_feature_names_out())
    tfidf_sorting = np.argsort(tfidf_matrix.toarray()).flatten()[::-1]
    top_keywords = feature_array[tfidf_sorting][:top_n]
    return top_keywords

def main():
    files = []
    texts = []

    for root, _, filenames in os.walk(INPUT_DIR):
        for fname in filenames:
            if fname.endswith('.txt'):
                fp = os.path.join(root, fname)
                text = read_text(fp)
                texts.append(text)
                files.append(fp)

    if not texts:
        print("Нет текстовых файлов для обработки.")
        return

    n_clusters = max(2, min(10, len(files)//5))

    print(f"Кластеризуем {len(files)} файлов на {n_clusters} кластеров...")

    vectorizer_all = TfidfVectorizer(max_features=5000, stop_words='english')
    X = vectorizer_all.fit_transform(texts)

    clustering = KMeans(n_clusters=n_clusters, random_state=42)
    labels = clustering.fit_predict(X)

    cluster_contents = {}
    for label, path, text in zip(labels, files, texts):
        cluster_contents.setdefault(label, []).append((path, text))

    os.makedirs(OUTPUT_DIR, exist_ok=True)

    for cluster_id, files_texts in cluster_contents.items():
        cluster_texts = [text for _, text in files_texts]
        keywords = extract_top_keywords(cluster_texts, top_n=3)
        folder_name = sanitize_name('_'.join(keywords)) or f'topic_{cluster_id}'
        cluster_folder = os.path.join(OUTPUT_DIR, folder_name)
        os.makedirs(cluster_folder, exist_ok=True)

        for idx, (_, text) in enumerate(files_texts):
            snippet = ' '.join(text.split()[:7])
            filename = sanitize_name(snippet) or f'doc_{idx}'
            filepath = os.path.join(cluster_folder, filename + '.txt')
            with open(filepath, 'w', encoding='utf-8') as f:
                f.write(text)

    print(f"Группировка завершена. Результаты в {OUTPUT_DIR}")

if __name__ == '__main__':
    main()
```

---

## Что тут происходит

- Для каждого кластера мы объединяем все тексты.
- Считаем TF-IDF по всему объединённому тексту кластера.
- Берём 3 самых "важных" слова с наибольшими TF-IDF весами, они и становятся названием папки.
- Потом создаём папку с понятным названием и складываем туда соответствующие документы.

---

## Как улучшить?

- Увеличить число ключевых слов для названий (например `top_n=5`).
- Добавить фильтрацию по длине ключевых слов, убрать слишком короткие.
- Сделать более сложный анализ — извлекать биграммы, триграммы с `ngram_range=(1,3)` в TF-IDF.
- Можно сохранять индекс ключевых слов для поиска.

---

### Итог

Этот код **даёт автоматическую генерацию папок по тематике на основе реального анализа текстов** и при этом не требует тяжелых ИИ-библиотек — работает классическими средствами `scikit-learn`.

Если есть вопросы по адаптации — помогу!

turns-00069.parquet:34910

9101491349de891df1930d8b
turn 10/12gpt-4.1-mini-2025-04-14RussianRussia575 words
degenerate_repetitionAbsentFinal dense release
USER
Так подожди я тебе скидывал две мои программы одна скачивай текст другая его исправляться с ошибок мне нужно чтобы программа которую ты меня сейчас сделал не просто просматривал содержимое папок создавая им название по смыслу папки но и для каждого сайта создавала свою директорию в которой будет находиться папки с текстом этого сайта которая будет находиться в территории done baza
ASSISTANT
Понял, давайте сведём всё в один понятный, универсальный скрипт, который:

- На вход берёт уже очищенные тексты из папки (например, `cleaned_baza`), в которой структура папок соответствует разным сайтам (как генерировалось вашим краулером).
- Для каждого сайта (корневой папки с сайтом внутри `cleaned_baza`) создаёт отдельную папку в `done_baza`.
- В папке сайта кластеризует ВСЕ тексты, скачанные с этого сайта, по тематическим кластерам.
- Для каждого тематического кластера создаёт подпапку с **автоматическим тематическим названием** (через ключевые слова TF-IDF из кластера).
- В каждую из папок кластеров складывает тексты этого сайта с понятными короткими именами.

---

## Пример рабочего кода, который реализует логику с учётом структуры по сайтам

```python
import os
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans
import numpy as np

# Путь с очищенными текстами, где структура: cleaned_baza/<site_domain>/<файлы>
CLEANED_BASE_DIR = 'cleaned_baza'
# Итоговая папка с результатами: done_baza/<site_domain>/<тематика>/*.txt
DONE_BASE_DIR = 'done_baza'

def read_text(filepath):
    with open(filepath, encoding='utf-8') as f:
        return f.read()

def sanitize_name(name):
    return ''.join(c if c.isalnum() or c in (' ', '_', '-') else '_' for c in name).strip()[:50]

def extract_top_keywords(texts, top_n=3):
    joined_text = ' '.join(texts)
    vectorizer = TfidfVectorizer(stop_words='english', max_features=1000, ngram_range=(1,2))
    tfidf_matrix = vectorizer.fit_transform([joined_text])
    feature_array = np.array(vectorizer.get_feature_names_out())
    tfidf_sorting = np.argsort(tfidf_matrix.toarray()).flatten()[::-1]
    top_keywords = feature_array[tfidf_sorting][:top_n]
    return top_keywords

def cluster_and_save(site_folder, output_site_folder):
    # Список файлов и текстов с этого сайта
    files = []
    texts = []

    for root, _, filenames in os.walk(site_folder):
        for fname in filenames:
            if fname.endswith('.txt'):
                fp = os.path.join(root, fname)
                txt = read_text(fp)
                if txt.strip():
                    files.append(fp)
                    texts.append(txt)

    if not texts:
        print(f"Нет текстовых файлов у сайта {site_folder}")
        return

    # Кластеризация
    n_clusters = max(2, min(10, len(files) // 5))
    vectorizer_all = TfidfVectorizer(max_features=5000, stop_words='english')
    X = vectorizer_all.fit_transform(texts)

    clustering = KMeans(n_clusters=n_clusters, random_state=42)
    labels = clustering.fit_predict(X)

    cluster_contents = {}
    for label, path, text in zip(labels, files, texts):
        cluster_contents.setdefault(label, []).append((path, text))

    # Создаём папки для кластеров по темам
    for cluster_id, files_texts in cluster_contents.items():
        cluster_texts = [t[1] for t in files_texts]
        keywords = extract_top_keywords(cluster_texts, top_n=3)
        folder_name = sanitize_name('_'.join(keywords)) or f'topic_{cluster_id}'
        cluster_folder = os.path.join(output_site_folder, folder_name)
        os.makedirs(cluster_folder, exist_ok=True)

        for idx, (_, text) in enumerate(files_texts):
            snippet = ' '.join(text.split()[:7])
            filename = sanitize_name(snippet) or f'doc_{idx}'
            filepath = os.path.join(cluster_folder, filename + '.txt')
            with open(filepath, 'w', encoding='utf-8') as f:
                f.write(text)

    print(f"Обработка сайта '{os.path.basename(site_folder)}' завершена. Результаты в {output_site_folder}")

def main():
    os.makedirs(DONE_BASE_DIR, exist_ok=True)

    # Для каждого сайта (папки в cleaned_baza) запускаем группировку и кластеризацию
    for site_name in os.listdir(CLEANED_BASE_DIR):
        site_path = os.path.join(CLEANED_BASE_DIR, site_name)
        if os.path.isdir(site_path):
            print(f"\nОбрабатываем сайт: {site_name}")
            output_site_path = os.path.join(DONE_BASE_DIR, site_name)
            os.makedirs(output_site_path, exist_ok=True)
            cluster_and_save(site_path, output_site_path)

if __name__ == '__main__':
    main()
```

---

### Как запускать?

- Предполагается, что:

```
cleaned_baza/
 ├── example.com/
 │     ├── page1.txt
 │     ├── article2.txt
 │     └── ...
 ├── another-site.ru/
 │     ├── index.txt
 │     └── ...
```

- Запускаете этот скрипт.
- В папке `done_baza` окажутся папки с названиями сайтов, а внутри них — папки с тематическими группами на основе анализа текстов.

---

### Чем этот адаптированный скрипт полезен?

- Сохраняет структуру по сайтам (то есть не смешивает тексты с разных доменов).
- Для каждого сайта свои тематические папки.
- Тема формируется автоматически (ключевые слова TF-IDF из кластера).
- Легко запускать в стандартном Python с установленным `scikit-learn`.

---

Если хотите, могу помочь интегрировать этот скрипт в ваш текущий пайплайн, помочь с настройкой или подойти под особенности ваших данных — просто скажите!