новый алгоритм диалога из групп фраз..

- вот  новый алгоритм - как связать фразу ввода с фразами ответа
фразы ответа объединяем в группы примерно по 10 и более штук
нужную группу фраз находим по статистике ключевых слов данной группы
то есть ищем группу в которой больше совпадений слов которые есть в фразе ввода
группы фраз ответа разделяем строкой с символом =
фразы ответа храним в файле фразы1.txt и фразы2.txt
фразы ввода сохраняем в другом файле - ввод фраз.txt

итак я ввожу фразу -
программа находит подходящую группу фраз ответа по её набору (совпадений) ключевых слов
далее она выводит случайную фразу из найденной группы фраз ответов
затем я ввожу новую фразу - и так далее по циклу диалога из наших фраз






import random
import re

def get_words(text):
    text = text.lower()
    text = re.sub(r'[^\w\s]', '', text)
    words = text.split()
    stop_words = {'и', 'в', 'на', 'с', 'по', 'как', 'что', 'к', 'из', 'за', 'от', 'для', 'о', 'а', 'но', 'то', 'же'}
    words = [w for w in words if w not in stop_words]
    return set(words)

def load_response_groups(filename):
    with open(filename, encoding='utf-8') as f:
        lines = [line.strip() for line in f.readlines()]
    groups = []
    current_group = []
    for line in lines:
        if line == '=':
            if current_group:
                groups.append(current_group)
                current_group = []
        elif line != '':
            current_group.append(line)
    if current_group:
        groups.append(current_group)
    return groups

def build_group_keywords(groups):
    group_keywords = []
    for group in groups:
        words = set()
        for phrase in group:
            words.update(get_words(phrase))
        group_keywords.append(words)
    return group_keywords

def find_best_group(input_words, group_keywords):
    max_matches = 0
    best_indices = []
    for i, keywords in enumerate(group_keywords):
        matches = len(input_words.intersection(keywords))
        if matches > max_matches:
            max_matches = matches
            best_indices = [i]
        elif matches == max_matches and matches > 0:
            best_indices.append(i)
    if not best_indices:
        return None
    return random.choice(best_indices)

def main():
    groups = load_response_groups('фразы1.txt')
    group_keywords = build_group_keywords(groups)

    print("Введите фразу (программа работает бесконечно):")
    while True:
        user_input = input('> ').strip()
        # Сохраняем ввод в файл
        with open('ввод фраз.txt', 'a', encoding='utf-8') as f_in:
            f_in.write(user_input + '\n')

        input_words = get_words(user_input)
        best_group_index = find_best_group(input_words, group_keywords)
        if best_group_index is None:
            print("Извините, я не понял. Попробуйте сформулировать иначе.")
        else:
            response = random.choice(groups[best_group_index])
            print(response)

if __name__ == '__main__':
    main()







Вы описали простой и достаточно эффективный алгоритм для выбора ответа на основе ключевых слов и группировки фраз. Вот несколько рекомендаций и вариантов реализации, которые могут помочь вам улучшить и структурировать этот процесс:

Как можно реализовать ваш алгоритм на Python:

Структура хранения данных:
Файл фразы1.txt, фразы2.txt и т.д. содержат группы ответов, разделённые строкой с символом =:

привет
здравствуй
что нового
добрый день
можно так думать
=
как дела?
что нового?
это уже есть
=

...


Файл ввод фраз.txt содержит фразы ввода (возможно, для анализа или обучения).
Алгоритм поиска нужной группы:
Для каждой группы ответов заранее собираете множество ключевых слов (например, разбиваете все фразы в группе на слова, убираете стоп-слова и приводите к нормальной форме).

На входе получаете фразу пользователя, разбиваете её на слова, приводите к нормальной форме.

Для каждой группы считаете количество совпадений ключевых слов с фразой ввода.

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

Случайным образом выбираете одну фразу из этой группы и выводите её.

Пример кода ( упрощённый алгоритм выбора фраз и слов ):




import random
import re

def normalize(text):
    # Приведение к нижнему регистру, удаление знаков препинания
    text = text.lower()
    text = re.sub(r'[^\w\s]', '', text)
    return text

def load_groups(filename):
    groups = []
    with open(filename, encoding='utf-8') as f:
        group = []
        for line in f:
            line = line.strip()
            if line == '=':
                if group:
                groups.append(group)
                group = []
            elif line:
                group.append(line)
        if group:
            groups.append(group)
    return groups

def extract_keywords(phrases):
    # Простое выделение слов без стоп-слов и нормализация
    stop_words = {'и', 'в', 'на', 'с', 'как', 'что', 'то', 'это', 'а', 'но', 'за', 'от', 'до'}
    keywords = set()
    for phrase in phrases:
        words = normalize(phrase).split()
        keywords.update(w for w in words if w not in stop_words)
    return keywords

def find_best_group(input_phrase, groups_keywords):
    input_words = set(normalize(input_phrase).split())
    best_group_index = None
    max_matches = 0
    for i, keywords in enumerate(groups_keywords):
        matches = len(input_words.intersection(keywords))
        if matches > max_matches:
            max_matches = matches
            best_group_index = i
    return best_group_index

if __name__ == '__main__':
    groups = load_groups('фразы1.txt') + load_groups('фразы2.txt')
    groups_keywords = [extract_keywords(group) for group in groups]

    while True:
        user_input = input('Введите фразу: ')
        if user_input.lower() in ('выход', 'exit', 'quit'):
            break
        group_index = find_best_group(user_input, groups_keywords)
        if group_index is not None:
            response = random.choice(groups[group_index])
            print('Ответ:', response)
        else:
            print('Извините, я не понял.')




Рекомендации по улучшению:
Лемматизация или стемминг: для русского языка можно использовать библиотеки pymorphy2 или natasha, чтобы приводить слова к нормальной форме
(например, "программы" и "программа" - считать одним словом )

Расширение стоп-слов: стоит добавить больше служебных слов, чтобы фильтровать их из ключевых слов.

Весовые коэффициенты: можно учитывать не только количество совпадений, но и важность слов (например, редкие слова имеют больший вес).

Кэширование: если групп много, можно заранее индексировать ключевые слова для быстрого поиска.

Обработка синонимов: для повышения качества можно использовать словари синонимов.

Если хотите, могу помочь с доработкой кода или с идеями по улучшению алгоритма!


- а что здесь значит упрощенный код ?

Под «упрощённым кодом» я имел в виду пример, который демонстрирует основную идею алгоритма без сложных оптимизаций, обработки ошибок, расширенной лингвистической обработки и дополнительных функций. Такой код:

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

добавь в алгоритм лемматизацию - то есть анализ набора ключевых слов в группе фразы ответа по их корням и леммам

Конечно -
Для лемматизации русского языка в Python удобно использовать библиотеку pymorphy2 — она позволяет приводить слова к нормальной (лемматизированной) форме. Я обновлю пример кода, добавив лемматизацию при извлечении ключевых слов и обработке пользовательского ввода.

Что нужно сделать:

Установить pymorphy2, если ещё не установлен:
pip install pymorphy2
В коде добавить лемматизацию слов — то есть преобразовать каждое слово к его базовой форме.
Обновлённый пример с лемматизацией:




import random
import re
import pymorphy2

morph = pymorphy2.MorphAnalyzer()

def normalize(text):
    # Приведение к нижнему регистру, удаление знаков препинания
    text = text.lower()
    text = re.sub(r'[^\w\s]', '', text)
    return text

def lemmatize_words(words):
    lemmas = []
    for w in words:
        p = morph.parse(w)
        if p:
            # Берём лемму самого вероятного разбора
            lemmas.append(p[0].normal_form)
        else:
            lemmas.append(w)
    return lemmas

def load_groups(filename):
    groups = []
    with open(filename, encoding='utf-8') as f:
        group = []
        for line in f:
            line = line.strip()
            if line == '=':
                if group:
                groups.append(group)
                group = []
            elif line:
                group.append(line)
        if group:
            groups.append(group)
    return groups

def extract_keywords(phrases):
    stop_words = {'и', 'в', 'на', 'с', 'как', 'что', 'то', 'это', 'а', 'но', 'за', 'от', 'до'}
    keywords = set()
    for phrase in phrases:
        words = normalize(phrase).split()
        lemmas = lemmatize_words(words)
        keywords.update(w for w in lemmas if w not in stop_words)
    return keywords

def find_best_group(input_phrase, groups_keywords):
    words = normalize(input_phrase).split()
    input_lemmas = set(w for w in lemmatize_words(words) if w not in {'и', 'в', 'на', 'с', 'как', 'что', 'то', 'это', 'а', 'но', 'за', 'от', 'до'})
    best_group_index = None
    max_matches = 0
    for i, keywords in enumerate(groups_keywords):
        matches = len(input_lemmas.intersection(keywords))
        if matches > max_matches:
            max_matches = matches
            best_group_index = i
    return best_group_index

if __name__ == '__main__':
    groups = load_groups('фразы1.txt') + load_groups('фразы2.txt')
    groups_keywords = [extract_keywords(group) for group in groups]

    while True:
        user_input = input('Введите фразу: ')
        if user_input.lower() in ('выход', 'exit', 'quit'):
            break
        group_index = find_best_group(user_input, groups_keywords)
        if group_index is not None:
            response = random.choice(groups[group_index])
            print('Ответ:', response)
        else:
            print('Извините, я не понял.')




Что изменилось в коде:
Добавлена функция lemmatize_words, которая преобразует слова в леммы с помощью pymorphy2.
При извлечении ключевых слов и при обработке пользовательского ввода слова лемматизируются.
Стоп-слова фильтруются уже по леммам.
Если хотите, могу помочь добавить также обработку синонимов или другие улучшения!

также надо придумать - как нам набор большого числа фраз в файле txt разделить на группы
в которых фразы были бы похожи по содержанию
число фраз в группе - 20

Хороший вопрос
Чтобы автоматически разбить большой набор фраз в txt файле на группы примерно по 20 фраз, где фразы внутри группы похожи по смыслу, можно использовать методы кластеризации на основе текстовых признаков.

Общий подход
Предобработка текста:

Очистка от знаков препинания, приведение к нижнему регистру.
Лемматизация (например, с pymorphy2).
Удаление стоп-слов.

Векторизация:
Преобразовать каждую фразу в числовой вектор.
Можно использовать TF-IDF векторизацию с sklearn.feature_extraction.text.TfidfVectorizer.
Или более продвинутые эмбеддинги (например, с помощью моделей sentence-transformers).
Кластеризация:

Применить алгоритм кластеризации, например:
KMeans (если известно число кластеров).
Agglomerative Clustering (иерархическая).
DBSCAN (плотностная).
Цель — получить кластеры, где внутри — похожие фразы.
Размер групп:

Если нужно ровно по 20 фраз, можно задать число кластеров = (общее число фраз) / 20.
Если число фраз не кратно 20, некоторые группы будут чуть больше или меньше.
Пример кода с KMeans и TF-IDF





import re
import pymorphy2
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans

morph = pymorphy2.MorphAnalyzer()

def normalize(text):
    text = text.lower()
    text = re.sub(r'[^\w\s]', '', text)
    return text

def lemmatize_text(text):
    words = text.split()
    lemmas = [morph.parse(w)[0].normal_form for w in words]
    return ' '.join(lemmas)

def preprocess(phrase):
    text = normalize(phrase)
    text = lemmatize_text(text)
    return text

def cluster_phrases(phrases, group_size=12):
    preprocessed = [preprocess(p) for p in phrases]

    # Кол-во кластеров
    n_clusters = max(1, len(phrases) // group_size)

    vectorizer = TfidfVectorizer(stop_words='russian')
    X = vectorizer.fit_transform(preprocessed)

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

    clusters = [[] for _ in range(n_clusters)]
    for phrase, label in zip(phrases, labels):
        clusters[label].append(phrase)
    return clusters

if __name__ == '__main__':
    with open('all_phrases.txt', encoding='utf-8') as f:
        phrases = [line.strip() for line in f if line.strip()]

    groups = cluster_phrases(phrases, group_size=12)

    # Сохраним группы в отдельные файлы
    for i, group in enumerate(groups, 1):
        with open(f'group_{i}.txt', 'w', encoding='utf-8') as f:
            for phrase in group:
                f.write(phrase + '\n')
        print(f'Группа {i}: {len(group)} фраз')



Несколько советов:
Если фразы очень короткие, TF-IDF может быть не очень информативен — тогда лучше использовать эмбеддинги предложений (sentence-transformers).

Если хотите более равномерные группы, можно после кластеризации дополнительно разбивать или сливать кластеры.

Можно экспериментировать с параметрами кластеризации.

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

да можно это попробовать

 Вот пример, как использовать библиотеку sentence-transformers для получения эмбеддингов предложений и кластеризации фраз по смыслу с помощью KMeans.

Шаги:
Установите необходимые библиотеки:
pip install sentence-transformers scikit-learn pymorphy2
Используйте следующий код:



import re
import pymorphy2
from sentence_transformers import SentenceTransformer
from sklearn.cluster import KMeans

morph = pymorphy2.MorphAnalyzer()

def normalize(text):
    text = text.lower()
    text = re.sub(r'[^\w\s]', '', text)
    return text

def lemmatize_text(text):
    words = text.split()
    lemmas = [morph.parse(w)[0].normal_form for w in words]
    return ' '.join(lemmas)

def preprocess(phrase):
    text = normalize(phrase)
    text = lemmatize_text(text)
    return text

def cluster_phrases(phrases, group_size=12):
    preprocessed = [preprocess(p) for p in phrases]

    # Загружаем модель для эмбеддингов
    model = SentenceTransformer('distiluse-base-multilingual-cased-v1')

    embeddings = model.encode(preprocessed, show_progress_bar=True)

    n_clusters = max(1, len(phrases) // group_size)
    kmeans = KMeans(n_clusters=n_clusters, random_state=42)
    labels = kmeans.fit_predict(embeddings)

    clusters = [[] for _ in range(n_clusters)]
    for phrase, label in zip(phrases, labels):
        clusters[label].append(phrase)
    return clusters

if __name__ == '__main__':
    with open('all_phrases.txt', encoding='utf-8') as f:
        phrases = [line.strip() for line in f if line.strip()]

    groups = cluster_phrases(phrases, group_size=12)

    for i, group in enumerate(groups, 1):
        with open(f'group_{i}.txt', 'w', encoding='utf-8') as f:
            for phrase in group:
                f.write(phrase + '\n')
        print(f'Группа {i}: {len(group)} фраз')




Пояснения к коду:

SentenceTransformer загружает предобученную модель для получения смысловых векторных представлений фраз.

Лемматизация помогает нормализовать текст перед эмбеддингом.

KMeans разбивает фразы на кластеры по смыслу.

Результат сохраняется в отдельные файлы group_1.txt, group_2.txt и т.д.





есть файл фразы.txt
в нём много фраз - примерно 36400
нужно поделить все эти фразы на группы по 10 штук
так чтобы фразы в каждой группе были похожи по содержанию
сохранить группы фраз в файл группы 10.txt
группы разделить строкой с символом =


Для решения задачи группировки фраз по содержанию с последующим сохранением групп по 10 штук в файл, можно использовать подход с векторизацией текста и кластеризацией.

Ниже пример на Python, который:

1. Считывает фразы из файла `фразы.txt`.
2. Преобразует фразы в векторы с помощью модели TF-IDF.
3. Кластеризует фразы с помощью алгоритма KMeans, где количество кластеров = количество фраз / 10.
4. Сохраняет группы по 10 фраз в файл `группы 10.txt`, разделяя группы строкой с символом `=`.



 Пример кода


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

# Читаем фразы из файла
with open('фразы.txt', 'r', encoding='utf-8') as f:
    phrases = [line.strip() for line in f if line.strip()]

num_phrases = len(phrases)
group_size = 10
num_clusters = math.ceil(num_phrases / group_size)

# Векторизация фраз
vectorizer = TfidfVectorizer(stop_words='russian')
X = vectorizer.fit_transform(phrases)

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

# Организуем фразы по кластерам
clusters = {}
for label, phrase in zip(labels, phrases):
    clusters.setdefault(label, []).append(phrase)

# Записываем группы по 10 фраз в файл
with open('группы 10.txt', 'w', encoding='utf-8') as f_out:
    for cluster_id in sorted(clusters.keys()):
        group = clusters[cluster_id]
        # Если в группе больше 10 фраз, разбиваем на подгруппы по 10
        for i in range(0, len(group), group_size):
            sub_group = group[i:i+group_size]
            f_out.write('\n'.join(sub_group) + '\n')
            f_out.write('=\n')
```




 Объяснение к коду:

 Используется `TfidfVectorizer` с русским стоп-листом для преобразования текста в числовой формат.
 Алгоритм `KMeans` разбивает фразы на кластеры, где каждая группа примерно содержит 10 фраз.
 Если в кластере больше 10 фраз (что может быть, если количество фраз не кратно 10), то он дополнительно разбивается на подгруппы по 10.
 Между группами добавляется строка `=`.



 Что нужно для запуска:

 Python 3
 Установленные библиотеки: `scikit-learn`
 
Установить можно так:

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




исправленный код программы сортировки фраз на группы:



import os
os.environ["LOKY_MAX_CPU_COUNT"] = "6"  # замените на число ядер вашего процессора

import math
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.cluster import KMeans

with open('фразы.txt', 'r', encoding='utf-8') as f:
    phrases = [line.strip() for line in f if line.strip()]

num_phrases = len(phrases)
group_size = 10
num_clusters = math.ceil(num_phrases / group_size)

vectorizer = TfidfVectorizer(stop_words=None)
X = vectorizer.fit_transform(phrases)

kmeans = KMeans(n_clusters=num_clusters, random_state=42, n_init=10)
labels = kmeans.fit_predict(X)

clusters = {}
for label, phrase in zip(labels, phrases):
    clusters.setdefault(label, []).append(phrase)

with open('группы 10.txt', 'w', encoding='utf-8') as f_out:
    for cluster_id in sorted(clusters.keys()):
        group = clusters[cluster_id]
        for i in range(0, len(group), group_size):
            sub_group = group[i:i+group_size]
            f_out.write('\n'.join(sub_group) + '\n')
            f_out.write('=\n')


Рецензии