import gradio as gr import requests import os import json import pandas as pd import time from langchain.schema import SystemMessage from langchain_community.chat_models.gigachat import GigaChat from openpyxl import load_workbook from openpyxl.utils import get_column_letter from openpyxl.styles import Alignment import base64 from together import Together import pymorphy2 import re import string import io from datetime import datetime, timedelta import plotly.express as px from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity from sentence_transformers import SentenceTransformer, util import numpy as np morph = pymorphy2.MorphAnalyzer() # Установка ключа API для OpenAI, GigaChat и Mistral openai_api_key = os.getenv('GPT_KEY') gc_key = os.getenv('GC_KEY') token = os.getenv('GITHUB_TOKEN') TOGETHER_API_KEY = os.getenv('TOGETHER_API_KEY') # Инициализация клиента для Together client = Together(api_key=TOGETHER_API_KEY) # Авторизация в сервисе GigaChat chat_pro = GigaChat(credentials=gc_key, model='GigaChat-Pro', max_tokens=68, temperature=1.15, verify_ssl_certs=False) chat_lite = GigaChat(credentials=gc_key, model='GigaChat', max_tokens=68, temperature=1.15, verify_ssl_certs=False) chat_plus = GigaChat(credentials=gc_key, model='GigaChat-Plus', max_tokens=68, temperature=1.15, verify_ssl_certs=False) # Загрузка данных из Excel-файла try: data = pd.read_excel('Признаки.xlsx', sheet_name=None) except Exception as e: print(f"Ошибка при загрузке Excel-файла: {e}") data = {} # Создание списка признаков и их значений features = {} for sheet_name, df in data.items(): try: if sheet_name == "Пол Поколение Психотип": # Создаем словарь, где ключи — это кортежи (Пол, Поколение, Психотип), а значения — инструкции features[sheet_name] = df.set_index(['Пол', 'Поколение', 'Психотип'])['Инструкция'].to_dict() else: features[sheet_name] = df.set_index(df.columns[0]).to_dict()[df.columns[1]] except Exception as e: print(f"Ошибка при обработке данных листа {sheet_name}: {e}") features[sheet_name] = {} current_request_index = -1 # Изначально указывает на последний запрос def download_current_message_database(): # Mapping of GitHub repositories and authors repos = { 'Storage_1': 'Редакторы', 'Storage_Ira': 'Ира', 'Storage_Kate': 'Катя', 'Storage_Sveta': 'Света', 'Storage_Lera': 'Лера', 'Storage_Dasha': 'Даша', } # Base GitHub API URL base_url = 'https://api.github.com/repos/fruitpicker01/{repo}/contents' data_list = [] headers = { "Authorization": f"token {token}", "Content-Type": "application/json" } for repo_name, author in repos.items(): url = base_url.format(repo=repo_name) response = requests.get(url, headers=headers) if response.status_code == 200: files = response.json() # Filter files starting with 'file' and ending with '.json' json_files = [file for file in files if file['name'].startswith("file") and file['name'].endswith('.json')] for file_info in json_files: file_name = file_info['name'] file_url = file_info['download_url'] # Extract timestamp from filename try: timestamp = file_name.split('_')[1].split('.')[0] # Add 3 hours to the time save_date = datetime.utcfromtimestamp(int(timestamp)) + timedelta(hours=3) save_date = save_date.strftime('%Y-%m-%d %H:%M:%S') except: save_date = None # or set default value # Download and decode file content file_response = requests.get(file_url) if file_response.status_code == 200: data = json.loads(file_response.text) normalized_data = pd.json_normalize(data) normalized_data['Дата сохранения'] = save_date normalized_data['Автор'] = author data_list.append(normalized_data) else: print(f"Error downloading file {file_name} from repository {repo_name}: {file_response.status_code}") else: print(f"Error accessing repository {repo_name}: {response.status_code}") if data_list: df = pd.concat(data_list, ignore_index=True) # Преобразуем 'Дата сохранения' в datetime и корректируем на +3 часа df['Дата сохранения'] = pd.to_datetime(df['Дата сохранения'], format='%Y-%m-%d %H:%M:%S', errors='coerce') # Удаляем дубликаты, игнорируя 'Дата сохранения' columns_to_consider = df.columns.tolist() columns_to_consider.remove('Дата сохранения') df.drop_duplicates(subset=columns_to_consider, inplace=True) # Сортируем по 'Дата сохранения' по убыванию df.sort_values(by='Дата сохранения', ascending=False, inplace=True) # *** Добавляем этот блок кода для удаления пустых строк *** # Удаляем строки, где все три столбца одновременно пусты или содержат только пробелы df = df[~( df['Персонализированное сообщение'].fillna('').str.strip().eq('') & df['Комментарий'].fillna('').str.strip().eq('') & df['Откорректированное сообщение'].fillna('').str.strip().eq('') )] # Set column order desired_columns = [ "Модель", "Автор", "Дата сохранения", "Персонализированное сообщение", "Комментарий", "Откорректированное сообщение", "Описание предложения", "Преимущества", "Ключевое сообщение", "Подход", "Пол", "Поколение", "Психотип", "Стадия бизнеса", "Отрасль", "ОПФ", "Неперсонализированный промпт", "Неперсонализированное сообщение", "Персонализированный промпт" ] # Ensure all specified columns are in the DataFrame existing_columns = [col for col in desired_columns if col in df.columns] df = df[existing_columns] # Save Excel file in memory output = io.BytesIO() with pd.ExcelWriter(output, engine='openpyxl') as writer: df.to_excel(writer, index=False) # Get worksheet workbook = writer.book worksheet = writer.sheets['Sheet1'] # Adjust column widths and text wrapping from openpyxl.styles import Alignment # Columns to fit content width columns_fit_content = ["Модель", "Автор", "Дата сохранения", "Пол", "Поколение", "Психотип", "Стадия бизнеса", "ОПФ"] # Columns to set fixed width and wrap text columns_wrap_text = ["Персонализированное сообщение", "Комментарий", "Откорректированное сообщение"] for idx, col in enumerate(df.columns, 1): column_letter = get_column_letter(idx) if col in columns_fit_content: max_length = 0 column = df[col].astype(str) for cell_value in column: if cell_value: max_length = max(max_length, len(cell_value)) adjusted_width = (max_length + 2) worksheet.column_dimensions[column_letter].width = adjusted_width elif col in columns_wrap_text: worksheet.column_dimensions[column_letter].width = 50 # Set fixed width for cell in worksheet[column_letter]: cell.alignment = Alignment(wrap_text=True) else: worksheet.column_dimensions[column_letter].width = 20 # Default width output.seek(0) # Reset pointer # Encode file content in base64 for uploading to GitHub content = base64.b64encode(output.read()).decode('utf-8') # Parameters for uploading file to GitHub repo = "fruitpicker01/Storage_dev" # Get current time and adjust by +3 hours current_time = datetime.utcnow() + timedelta(hours=3) filename = f"db_{current_time.strftime('%d.%m.%Y_%H.%M')}.xlsx" path = filename # Use new filename url = f"https://api.github.com/repos/{repo}/contents/{path}" # Check if file already exists get_response = requests.get(url, headers=headers) if get_response.status_code == 200: sha = get_response.json()['sha'] else: sha = None data = { "message": f"Updated file {filename}", "content": content, } if sha: data["sha"] = sha # Needed for updating existing file # Upload (or update) file on GitHub put_response = requests.put(url, headers=headers, data=json.dumps(data)) if put_response.status_code in [200, 201]: # Get download link download_url = f"https://raw.githubusercontent.com/{repo}/main/{path}" return download_url, df # Return file URL and DataFrame else: print(f"Error uploading file to GitHub: {put_response.status_code}, {put_response.text}") return "Error uploading file to GitHub.", None else: return "No data to generate file.", None def update_download_link(): result = download_current_message_database() link, df = result if isinstance(result, tuple) else (result, None) if isinstance(link, str) and link.startswith("http") and df is not None: # Compute analytics total_messages = len(df) # Total messages without need for corrections clean_df = df[ df['Персонализированное сообщение'].notna() & df['Персонализированное сообщение'].str.strip().ne('') & ((df['Комментарий'].isna()) | (df['Комментарий'].str.strip() == '')) & ((df['Откорректированное сообщение'].isna()) | (df['Откорректированное сообщение'].str.strip() == '')) ] total_clean_messages = len(clean_df) # Number of messages by model model_counts = df['Модель'].value_counts() # Number of messages without corrections by model clean_model_counts = clean_df['Модель'].value_counts() # Most active contributors contributor_counts = df['Автор'].value_counts() # Number of messages by date df['Дата сохранения'] = pd.to_datetime(df['Дата сохранения'], errors='coerce') date_counts = df['Дата сохранения'].dt.date.value_counts().sort_index() # Вычисляем накопительное количество сообщений по моделям во времени df['Дата сохранения'] = pd.to_datetime(df['Дата сохранения'], errors='coerce') model_date_counts = df.groupby([df['Дата сохранения'].dt.date, 'Модель']).size().reset_index(name='counts') model_date_pivot = model_date_counts.pivot(index='Дата сохранения', columns='Модель', values='counts').fillna(0) model_date_pivot = model_date_pivot.sort_index() model_cumulative = model_date_pivot.cumsum() # После вычисления model_cumulative # 1. Получаем накопительные итоги на последнюю дату last_date_totals = model_cumulative.iloc[-1] # 2. Сортируем модели по накопительным итогам sorted_models = last_date_totals.sort_values(ascending=False).index.tolist() # 3. Переупорядочиваем столбцы в model_cumulative model_cumulative = model_cumulative[sorted_models] # 4. Сбрасываем индекс и преобразуем DataFrame для построения графика model_cumulative_reset = model_cumulative.reset_index() model_cumulative_melted = model_cumulative_reset.melt(id_vars='Дата сохранения', var_name='Модель', value_name='Количество сообщений') # Создаем график с указанием порядка категорий cumulative_model_fig = px.line( model_cumulative_melted, x='Дата сохранения', y='Количество сообщений', color='Модель', title='Накопительное количество сообщений по моделям', category_orders={'Модель': sorted_models} ) # Вычисляем накопительное количество сообщений без корректировок по моделям clean_df['Дата сохранения'] = pd.to_datetime(clean_df['Дата сохранения'], errors='coerce') # Группируем данные по дате и модели, считаем количество сообщений clean_model_date_counts = clean_df.groupby([clean_df['Дата сохранения'].dt.date, 'Модель']).size().reset_index(name='counts') # Поворачиваем таблицу так, чтобы модели были столбцами, а даты — строками clean_model_date_pivot = clean_model_date_counts.pivot(index='Дата сохранения', columns='Модель', values='counts').fillna(0) # Сортируем даты по возрастанию clean_model_date_pivot = clean_model_date_pivot.sort_index() # Вычисляем накопительную сумму по датам clean_model_cumulative = clean_model_date_pivot.cumsum() # После вычисления clean_model_cumulative # 1. Получаем накопительные итоги на последнюю дату last_date_clean_totals = clean_model_cumulative.iloc[-1] # 2. Сортируем модели по накопительным итогам sorted_clean_models = last_date_clean_totals.sort_values(ascending=False).index.tolist() # 3. Переупорядочиваем столбцы в clean_model_cumulative clean_model_cumulative = clean_model_cumulative[sorted_clean_models] # 4. Сбрасываем индекс и преобразуем DataFrame для построения графика clean_model_cumulative_reset = clean_model_cumulative.reset_index() clean_model_cumulative_melted = clean_model_cumulative_reset.melt(id_vars='Дата сохранения', var_name='Модель', value_name='Количество сообщений без корректировок') # Создаем график с указанием порядка категорий cumulative_clean_model_fig = px.line( clean_model_cumulative_melted, x='Дата сохранения', y='Количество сообщений без корректировок', color='Модель', title='Накопительное количество сообщений без корректировок по моделям', category_orders={'Модель': sorted_clean_models} ) # Вычисляем накопительное количество сообщений по авторам df['Дата сохранения'] = pd.to_datetime(df['Дата сохранения'], errors='coerce') # Группируем данные по дате и автору, считаем количество сообщений author_date_counts = df.groupby([df['Дата сохранения'].dt.date, 'Автор']).size().reset_index(name='counts') # Поворачиваем таблицу так, чтобы авторы были столбцами, а даты — строками author_date_pivot = author_date_counts.pivot(index='Дата сохранения', columns='Автор', values='counts').fillna(0) # Сортируем даты по возрастанию author_date_pivot = author_date_pivot.sort_index() # Вычисляем накопительную сумму по датам author_cumulative = author_date_pivot.cumsum() # После вычисления author_cumulative # 1. Получаем накопительные итоги на последнюю дату last_date_author_totals = author_cumulative.iloc[-1] # 2. Сортируем авторов по накопительным итогам sorted_authors = last_date_author_totals.sort_values(ascending=False).index.tolist() # 3. Переупорядочиваем столбцы в author_cumulative author_cumulative = author_cumulative[sorted_authors] # 4. Сбрасываем индекс и преобразуем DataFrame для построения графика author_cumulative_reset = author_cumulative.reset_index() author_cumulative_melted = author_cumulative_reset.melt(id_vars='Дата сохранения', var_name='Автор', value_name='Количество сообщений') # Создаем график с указанием порядка категорий cumulative_author_fig = px.line( author_cumulative_melted, x='Дата сохранения', y='Количество сообщений', color='Автор', title='Накопительное количество сообщений по авторам', category_orders={'Автор': sorted_authors} ) # Prepare display outputs total_messages_display_value = f"**Общее количество сообщений:** {total_messages}" total_clean_messages_display_value = f"**Общее количество сообщений без необходимости корректировок:** {total_clean_messages}" # Create charts using plotly model_pie_fig = px.pie(values=model_counts.values, names=model_counts.index, title='Все сообщения') clean_model_pie_fig = px.pie(values=clean_model_counts.values, names=clean_model_counts.index, title='Сообщения без корректировок') contributor_pie_fig = px.pie(values=contributor_counts.values, names=contributor_counts.index, title='Наиболее активные контрибьюторы') date_message_fig = px.bar(x=date_counts.index, y=date_counts.values, labels={'x': 'Дата', 'y': 'Количество сообщений'}, title='Количество добавленных сообщений по датам') # Сообщения без корректировок messages_without_corrections = df[ (df['Персонализированное сообщение'].notna()) & (df['Персонализированное сообщение'].str.strip() != '') & ((df['Комментарий'].isna()) | (df['Комментарий'].str.strip() == '')) & ((df['Откорректированное сообщение'].isna()) | (df['Откорректированное сообщение'].str.strip() == '')) ].copy() messages_without_corrections['Сообщение'] = messages_without_corrections['Персонализированное сообщение'] # Откорректированные сообщения corrected_messages = df[ (df['Откорректированное сообщение'].notna()) & (df['Откорректированное сообщение'].str.strip() != '') ].copy() corrected_messages['Сообщение'] = corrected_messages['Откорректированное сообщение'] # Объединяем сообщения messages_df = pd.concat([messages_without_corrections, corrected_messages], ignore_index=True) def remove_extra_text(message): if pd.isnull(message): return '' # Удаляем строки вида "------\nКоличество знаков: число" return re.sub(r'\n-{6,}\nКоличество знаков: \d+', '', message).strip() # Применяем функцию к персонализированным и откорректированным сообщениям messages_df['Сообщение'] = messages_df['Сообщение'].apply(remove_extra_text) # Подсчитываем количество символов messages_df['Количество символов'] = messages_df['Сообщение'].str.len() mean_characters = messages_df['Количество символов'].mean() median_characters = messages_df['Количество символов'].median() # Подсчитываем количество предложений messages_df['Количество предложений'] = messages_df['Сообщение'].apply(lambda x: len(re.findall(r'[.!?]+', x))) # График распределения по количеству символов character_counts = messages_df['Количество символов'].value_counts().sort_index() char_count_fig = px.bar( x=character_counts.index, y=character_counts.values, labels={'x': 'Количество символов', 'y': 'Количество сообщений'}, title='Распределение сообщений по количеству символов' ) char_count_fig.add_vline( x=mean_characters, line_width=3, line_dash="dash", line_color="green", annotation_text=f"Среднее: {mean_characters:.1f}" ) # График распределения по количеству предложений sentence_counts = messages_df['Количество предложений'].value_counts().sort_index() sentence_count_fig = px.bar( x=sentence_counts.index, y=sentence_counts.values, labels={'x': 'Количество предложений', 'y': 'Количество сообщений'}, title='Распределение сообщений по количеству предложений' ) return ( f"[Скачать базу сообщений]({link})", total_messages_display_value, total_clean_messages_display_value, model_pie_fig, clean_model_pie_fig, contributor_pie_fig, date_message_fig, cumulative_model_fig, cumulative_clean_model_fig, cumulative_author_fig, char_count_fig, sentence_count_fig ) else: return link, "", "", None, None, None, None def correct_dash_usage(text): morph = pymorphy2.MorphAnalyzer() # Step 1: Replace any dash with long dash if surrounded by spaces text = re.sub(r'\s[-–—]\s', ' — ', text) # Step 2: Replace any dash with short dash if surrounded by numbers without spaces text = re.sub(r'(?<=\d)[-–—](?=\d)', '–', text) # Step 3: Replace any dash with hyphen if surrounded by letters or a combination of letters and digits text = re.sub(r'(?<=[a-zA-Zа-яА-Я0-9])[-–—](?=[a-zA-Zа-яА-Я0-9])', '-', text) # Step 4: Replace quotation marks "..." with «...» text = re.sub(r'"([^\"]+)"', r'«\1»', text) # Step 5: Remove single quotes if text.count('"') == 1: text = text.replace('"', '') # Step 6: Remove outer quotes if the entire text is enclosed in quotes (straight or elided) if (text.startswith('"') and text.endswith('"')) or (text.startswith('«') and text.endswith('»')): text = text[1:-1].strip() # Step 7: Replace 100k with 100 000 text = re.sub(r'(\d+)[kкКK]', r'\1 000', text, flags=re.IGNORECASE) # Step 8: Remove first sentence if it contains greetings and is less than 5 words greeting_patterns = [ r"привет\b", r"здравствуй", r"добрый\s(день|вечер|утро)", r"дорогой\b", r"уважаемый\b", r"дорогая\b", r"уважаемая\b", r"господин\b", r"госпожа\b", r"друг\b", r"коллега\b", r"товарищ\b", r"приятель\b", r"подруга\b" ] def is_greeting_sentence(sentence): words = sentence.split() if len(words) < 5: # Check if sentence is less than 5 words for word in words: parsed = morph.parse(word.lower())[0] # Parse the word to get its base form for pattern in greeting_patterns: if re.search(pattern, parsed.normal_form): return True return False # Split text into sentences sentences = re.split(r'(?<=[.!?])\s+', text) # Check the first sentence for greetings and remove it if necessary if sentences and is_greeting_sentence(sentences[0]): sentences = sentences[1:] # Join the sentences back text = ' '.join(sentences) def restore_yo(text): morph = pymorphy2.MorphAnalyzer() words = text.split() restored_words = [] for word in words: parsed = morph.parse(word)[0] restored_word = parsed.word # Сохраняем оригинальный регистр первой буквы if word and word[0].isupper(): restored_word = restored_word.capitalize() restored_words.append(restored_word) return ' '.join(restored_words) text = restore_yo(text) return text def save_user_request_to_github(description, advantages, key_message, approach, personalization_params): global current_request_index # Используем глобальную переменную current_request_index = -1 # Сбрасываем позицию к последнему запросу # Собираем все данные в один словарь data_to_save = { "description": description, "advantages": advantages, "key_message": key_message, "approach": approach, "personalization_params": personalization_params, "timestamp": time.time() } # Преобразуем контент в JSON-строку и кодируем в base64 file_content_encoded = base64.b64encode(json.dumps(data_to_save).encode()).decode() # Параметры для GitHub API repo = "fruitpicker01/Storage_dev" path = f"user_request_{int(time.time())}.json" url = f"https://api.github.com/repos/{repo}/contents/{path}" headers = { "Authorization": f"token {token}", "Content-Type": "application/json" } data = { "message": f"Добавлен новый файл {path}", "content": file_content_encoded } # Отправка POST-запроса на GitHub API для создания файла в репозитории response = requests.put(url, headers=headers, data=json.dumps(data)) if response.status_code == 201: print("Данные успешно сохранены на GitHub") else: print(f"Ошибка при сохранении данных на GitHub: {response.status_code} {response.text}") def save_message_to_table(data): # data is a dictionary containing the message and personalization parameters repo = "fruitpicker01/Storage_dev" file_path = "messages.csv" # Use 'messages.xlsx' if you prefer Excel # Get the file from the repository url = f"https://api.github.com/repos/{repo}/contents/{file_path}" headers = { "Authorization": f"token {token}", "Content-Type": "application/json" } response = requests.get(url, headers=headers) if response.status_code == 200: # File exists, download and load it content = response.json() file_content = base64.b64decode(content['content']) if file_path.endswith('.xlsx'): df = pd.read_excel(io.BytesIO(file_content)) else: df = pd.read_csv(io.StringIO(file_content.decode('utf-8'))) sha = content['sha'] # For updating the file later elif response.status_code == 404: # File does not exist, create an empty DataFrame df = pd.DataFrame(columns=[ "Timestamp", "Персонализированное сообщение", "Откорректированное сообщение", "Пол", "Поколение", "Психотип", "Стадия бизнеса", "Отрасль", "ОПФ" ]) sha = None # No sha since the file doesn't exist yet else: print(f"Error accessing the file: {response.status_code}") return # Append the new data using pd.concat df = pd.concat([df, pd.DataFrame([data])], ignore_index=True) # Convert the DataFrame back to a file if file_path.endswith('.xlsx'): with io.BytesIO() as output: df.to_excel(output, index=False) file_content_encoded = base64.b64encode(output.getvalue()).decode('utf-8') else: csv_string = df.to_csv(index=False) file_content_encoded = base64.b64encode(csv_string.encode('utf-8')).decode('utf-8') # Prepare the data for the API request data = { "message": "Update messages file", "content": file_content_encoded, "sha": sha # Include the sha if the file exists } # Send the PUT request to update the file response = requests.put(url, headers=headers, data=json.dumps(data)) if response.status_code in [200, 201]: print("Messages file updated successfully.") else: print(f"Error updating messages file: {response.status_code}") def save_both(adapted_message, personalized_message, model_name, comment, corrected_message, description, advantages, non_personalized_prompt, non_personalized_message, personalization_prompt, gender, generation, psychotype, business_stage, industry, legal_form, key_message, approach): # Вызываем функцию для сохранения в JSON-файл save_to_github(adapted_message, personalized_message, model_name, comment, corrected_message, description, advantages, non_personalized_prompt, non_personalized_message, personalization_prompt, gender, generation, psychotype, business_stage, industry, legal_form, key_message, approach) # Подготавливаем данные для сохранения в CSV/XLSX data = { "Timestamp": time.time(), "Модель": model_name, "Адаптированное сообщение": adapted_message, "Персонализированное сообщение": personalized_message, "Комментарий": comment, "Откорректированное сообщение": corrected_message, "Описание предложения": description, "Преимущества": advantages, "Ключевое сообщение": key_message, "Подход": approach, "Пол": gender, "Поколение": generation, "Психотип": psychotype, "Стадия бизнеса": business_stage, "Отрасль": industry, "ОПФ": legal_form } # Вызываем функцию для сохранения в CSV/XLSX save_message_to_table(data) def load_previous_user_request_from_github(): global current_request_index # Используем глобальную переменную repo = "fruitpicker01/Storage_dev" url = f"https://api.github.com/repos/{repo}/contents" headers = { "Authorization": f"token {token}", "Content-Type": "application/json" } # Получаем список файлов в репозитории response = requests.get(url, headers=headers) if response.status_code == 200: files = response.json() json_files = [file for file in files if file['name'].startswith("user_request_")] if not json_files: print("Нет сохраненных запросов.") return "", "", "", "", "", "", "", "", "", "", None, None, None, None, None, None # Определяем новый индекс для загрузки предыдущего файла current_request_index -= 1 # Если достигли начала списка, остаёмся на первой записи if abs(current_request_index) > len(json_files): current_request_index = -len(json_files) # Находим файл с нужным индексом target_file = json_files[current_request_index] file_url = target_file['download_url'] # Загружаем и декодируем содержимое файла file_response = requests.get(file_url) if file_response.status_code == 200: data = json.loads(file_response.text) description = data.get('description', "") advantages = data.get('advantages', "") key_message = data.get('key_message', "") # Load key message approach = data.get('approach', "") # Load approach personalization_params = data.get('personalization_params', [None] * 6) # Убедитесь, что размер списка соответствует количеству полей # Возвращаем данные по отдельности для каждого компонента Gradio return description, advantages, key_message, approach, *personalization_params else: print(f"Ошибка при загрузке файла: {file_response.status_code}") return "", "", "", "", "", "", "", "", "", "", None, None, None, None, None, None else: print(f"Ошибка при обращении к GitHub: {response.status_code}") return "", "", "", "", "", "", "", "", "", "", None, None, None, None, None, None def get_reference_message(current_description, gender, generation, psychotype, business_stage, industry, legal_form): import io import numpy as np from sentence_transformers import SentenceTransformer repo = "fruitpicker01/Storage_dev" file_path = "messages.csv" url = f"https://api.github.com/repos/{repo}/contents/{file_path}" headers = { "Authorization": f"token {token}", "Content-Type": "application/json" } response = requests.get(url, headers=headers) if response.status_code == 200: content = response.json() file_content = base64.b64decode(content['content']) df = pd.read_csv(io.StringIO(file_content.decode('utf-8'))) else: print(f"Error accessing the file: {response.status_code}") return None for col in ["Пол", "Поколение", "Психотип", "Стадия бизнеса", "Отрасль", "ОПФ"]: df[col] = df[col].astype(str).str.strip().str.lower() params = { "Пол": str(gender).strip().lower() if gender else None, "Поколение": str(generation).strip().lower() if generation else None, "Психотип": str(psychotype).strip().lower() if psychotype else None, "Стадия бизнеса": str(business_stage).strip().lower() if business_stage else None, "Отрасль": str(industry).strip().lower() if industry else None, "ОПФ": str(legal_form).strip().lower() if legal_form else None } df = df[df["Комментарий"].isna() | (df["Комментарий"].str.strip() == '')] filter_conditions = [] for col, value in params.items(): if value and value.lower() != 'none': filter_conditions.append(df[col] == value) if not filter_conditions: print("Не заданы параметры персонализации.") return None filter_condition = filter_conditions[0] for condition in filter_conditions[1:]: filter_condition &= condition filtered_df = df[filter_condition] if filtered_df.empty: print("Сообщения с заданными параметрами не найдены.") return None if 'Описание предложения' not in filtered_df.columns: print("Описание предложения отсутствует в данных.") return None filtered_df['Описание предложения'] = filtered_df['Описание предложения'].fillna('') # Используем модель для получения эмбеддингов model = SentenceTransformer('sergeyzh/rubert-tiny-turbo') descriptions = filtered_df['Описание предложения'].tolist() descriptions.insert(0, current_description) # Добавляем текущее описание embeddings = model.encode(descriptions) cosine_similarities = cosine_similarity([embeddings[0]], embeddings[1:]).flatten() # Находим максимальное косинусное сходство max_similarity = cosine_similarities.max() # Находим индексы с максимальным сходством max_similarity_indices = np.where(cosine_similarities == max_similarity)[0] # Получаем строки с максимальным сходством similar_rows = filtered_df.iloc[max_similarity_indices] # Обработка Timestamp if 'Timestamp' not in similar_rows.columns: print("Столбец 'Timestamp' отсутствует в данных.") similar_row = similar_rows.iloc[0] else: similar_rows = similar_rows.copy() similar_rows['Timestamp'] = pd.to_numeric(similar_rows['Timestamp'], errors='coerce') similar_rows = similar_rows.sort_values(by='Timestamp', ascending=False) similar_row = similar_rows.iloc[0] if pd.notnull(similar_row.get("Откорректированное сообщение", None)) and similar_row["Откорректированное сообщение"].strip(): reference_message = similar_row["Откорректированное сообщение"] else: reference_message = similar_row.get("Персонализированное сообщение", "") reference_message = re.sub(r'\n-{6,}\nКоличество знаков: \d+', '', reference_message).strip() return reference_message def adapt_messages_to_best_example( description, personalized_gigachat_pro, personalized_gigachat_lite, personalized_gigachat_plus, personalized_gpt4o, personalized_meta_llama_405b, key_message, approach, *selected_values ): # Извлечение параметров персонализации (без изменений) gender = selected_values[0] generation = selected_values[1] psychotype = selected_values[2] business_stage = selected_values[3] industry = selected_values[4] legal_form = selected_values[5] # Получение эталонного сообщения (без изменений) reference_message = get_reference_message(description, gender, generation, psychotype, business_stage, industry, legal_form) if not reference_message: # Если эталонное сообщение не найдено adapted_message = "Эталонное сообщение не найдено для выбранных параметров персонализации." yield adapted_message, adapted_message, adapted_message, adapted_message, adapted_message else: # Шаблон промпта (без изменений) prompt_template = ( "Сообщение для адаптации:\n\"{personalized_message}\"\n\n" "Эталонное сообщение (НЕ ИСПОЛЬЗУЙ ФАКТЫ ИЛИ ДАННЫЕ ИЗ НИЖЕПРИВЕДЕННОГО СООБЩЕНИЯ):\n\"{reference_message}\"\n\n" "1. Перепиши сообщение для адаптации, сохранив его смысл." "2. Используй стиль, построение предложений и лексику, максимально похожие на эталонное сообщение." "3. НЕ ДОБАВЛЯЙ факты, цифры, или любую информацию из эталонного сообщения." "4. Убедись, что итоговое сообщение содержит ТОЛЬКО информацию из сообщения для адаптации и адаптировано по стилю и структуре." "5. Проверь, что итоговое сообщение включает следующую информацию: \n\"{key_message}\"\n" ) # Инициализация пустых переменных для сообщений adapted_gigachat_pro = "" adapted_gigachat_lite = "" adapted_gigachat_plus = "" adapted_gpt4o = "" adapted_meta_llama_405b = "" # Адаптация сообщения для GigaChat-Pro prompt = prompt_template.format( reference_message=reference_message, key_message=key_message, personalized_message=personalized_gigachat_pro ) adapted_gigachat_pro = generate_message_gigachat_pro_with_retry(prompt) adapted_gigachat_pro_length = len(adapted_gigachat_pro) adapted_gigachat_pro_display = f"{adapted_gigachat_pro}\n\n------\nКоличество знаков: {adapted_gigachat_pro_length}" yield adapted_gigachat_pro_display, "", "", "", "" # Адаптация сообщения для GigaChat-Lite prompt = prompt_template.format( reference_message=reference_message, key_message=key_message, personalized_message=personalized_gigachat_lite ) adapted_gigachat_lite = generate_message_gigachat_lite_with_retry(prompt) adapted_gigachat_lite_length = len(adapted_gigachat_lite) adapted_gigachat_lite_display = f"{adapted_gigachat_lite}\n\n------\nКоличество знаков: {adapted_gigachat_lite_length}" yield adapted_gigachat_pro_display, adapted_gigachat_lite_display, "", "", "" # Адаптация сообщения для GigaChat-Plus prompt = prompt_template.format( reference_message=reference_message, key_message=key_message, personalized_message=personalized_gigachat_plus ) adapted_gigachat_plus = generate_message_gigachat_plus_with_retry(prompt) adapted_gigachat_plus_length = len(adapted_gigachat_plus) adapted_gigachat_plus_display = f"{adapted_gigachat_plus}\n\n------\nКоличество знаков: {adapted_gigachat_plus_length}" yield adapted_gigachat_pro_display, adapted_gigachat_lite_display, adapted_gigachat_plus_display, "", "" # Адаптация сообщения для GPT-4o prompt = prompt_template.format( reference_message=reference_message, key_message=key_message, personalized_message=personalized_gpt4o ) adapted_gpt4o = generate_message_gpt4o_with_retry(prompt) adapted_gpt4o_length = len(adapted_gpt4o) adapted_gpt4o_display = f"{adapted_gpt4o}\n\n------\nКоличество знаков: {adapted_gpt4o_length}" yield adapted_gigachat_pro_display, adapted_gigachat_lite_display, adapted_gigachat_plus_display, adapted_gpt4o_display, "" # Адаптация сообщения для Meta-Llama-3.1-405B prompt = prompt_template.format( reference_message=reference_message, key_message=key_message, personalized_message=personalized_meta_llama_405b ) adapted_meta_llama_405b = generate_message_meta_llama_3_1_405b_with_retry(prompt) adapted_meta_llama_405b_length = len(adapted_meta_llama_405b) adapted_meta_llama_405b_display = f"{adapted_meta_llama_405b}\n\n------\nКоличество знаков: {adapted_meta_llama_405b_length}" yield adapted_gigachat_pro_display, adapted_gigachat_lite_display, adapted_gigachat_plus_display, adapted_gpt4o_display, adapted_meta_llama_405b_display def update_best_example_prompt(description, *selected_values): # Extract personalization parameters gender = selected_values[0] generation = selected_values[1] psychotype = selected_values[2] business_stage = selected_values[3] industry = selected_values[4] legal_form = selected_values[5] # Retrieve the reference message reference_message = get_reference_message(description, gender, generation, psychotype, business_stage, industry, legal_form) if not reference_message: # No reference message found best_prompt = "Эталонное сообщение не найдено для выбранных параметров персонализации." else: best_prompt = ( "Эталонное сообщение (НЕ ИСПОЛЬЗУЙ ФАКТЫ ИЛИ ДАННЫЕ ИЗ НИЖЕПРИВЕДЕННОГО СООБЩЕНИЯ):\n\"{reference_message}\"\n\n" "1. Перепиши сообщение для адаптации, сохранив его смысл.\n" "2. Используй стиль, построение предложений и лексику, максимально похожие на эталонное сообщение.\n" "3. НЕ ДОБАВЛЯЙ факты, цифры, или любую информацию из эталонного сообщения.\n" "4. Убедись, что итоговое сообщение содержит ТОЛЬКО информацию из сообщения для адаптации и адаптировано по стилю и структуре." ).format(reference_message=reference_message) return best_prompt def adapt_messages_and_perform_checks( description_input, personalized_gigachat_pro, personalized_gigachat_lite, personalized_gigachat_plus, personalized_gpt4o, personalized_meta_llama_405b, key_message, approach, *selected_values ): adaptation_generator = adapt_messages_to_best_example( description_input, personalized_gigachat_pro, personalized_gigachat_lite, personalized_gigachat_plus, personalized_gpt4o, personalized_meta_llama_405b, key_message, approach, *selected_values ) last_adaptation_result = None for adaptation_result in adaptation_generator: last_adaptation_result = adaptation_result yield ( adaptation_result[0], adaptation_result[1], adaptation_result[2], adaptation_result[3], adaptation_result[4], "", "", "", "", "" # Пустые строки для проверок ) if last_adaptation_result: # Выполнение проверок на адаптированных сообщениях checks_gigachat_pro = perform_checks(last_adaptation_result[0]) checks_gigachat_lite = perform_checks(last_adaptation_result[1]) checks_gigachat_plus = perform_checks(last_adaptation_result[2]) checks_gpt4o = perform_checks(last_adaptation_result[3]) checks_meta_llama_405b = perform_checks(last_adaptation_result[4]) formatted_checks = [ format_checks(checks_gigachat_pro), format_checks(checks_gigachat_lite), format_checks(checks_gigachat_plus), format_checks(checks_gpt4o), format_checks(checks_meta_llama_405b) ] yield ( last_adaptation_result[0], last_adaptation_result[1], last_adaptation_result[2], last_adaptation_result[3], last_adaptation_result[4], formatted_checks[0], formatted_checks[1], formatted_checks[2], formatted_checks[3], formatted_checks[4] ) # Функция для генерации стандартного промпта def generate_standard_prompt(description, advantages, key_message, approach, *selected_values): if approach == "Призыв к действию": prompt = "Сгенерируй смс-сообщение для клиента. Начни сообщение с призыва к действию с продуктом.\n" elif approach == "Указание на пользу": prompt = "Сгенерируй смс-сообщение для клиента. Начни сообщение с указания на пользу продукта. Используй глагол в побудительном наклонении.\n" elif approach == "Вопрос": prompt = "Сгенерируй смс-сообщение для клиента. Начни сообщение с вопроса, который указывает на пользу продукта для клиента.\n" elif approach == "None": prompt = "Сгенерируй смс-сообщение для клиента.\n" prompt += ( f"Описание предложения: {description}\n" f"Преимущества: {advantages}\n" "В тексте смс запрещено использование:\n" "- Запрещенные слова: № один, номер один, № 1, вкусный, дешёвый, продукт, спам, банкротство, долги, займ, срочно, лучший, главный, номер 1, гарантия, успех, лидер;\n" "- Обращение к клиенту;\n" "- Приветствие клиента;\n" "- Обещания и гарантии;\n" "- Использовать составные конструкции из двух глаголов;\n" "- Причастия и причастные обороты;\n" "- Деепричастия и деепричастные обороты;\n" "- Превосходная степень прилагательных;\n" "- Страдательный залог;\n" "- Порядковые числительные от 10 прописью;\n" "- Цепочки с придаточными предложениями;\n" "- Разделительные повторяющиеся союзы;\n" "- Вводные конструкции;\n" "- Усилители;\n" "- Паразиты времени;\n" "- Несколько существительных подряд, в том числе отглагольных;\n" "- Производные предлоги;\n" "- Сложные предложения, в которых нет связи между частями;\n" "- Сложноподчинённые предложения;\n" "- Даты прописью;\n" "- Близкие по смыслу однородные члены предложения;\n" "- Шокирующие, экстравагантные, кликбейтные фразы;\n" "- Абстрактные заявления без поддержки фактами и отсутствие доказательства пользы для клиента;\n" "- Гарантирующие фразы;\n" "- Узкоспециализированные термины;\n" "- Фразы, способные создать двойственное ощущение, обидеть;\n" "- Речевые клише, рекламные штампы, канцеляризмы;\n" "Убедись, что в готовом тексте до 250 знаков с пробелами.\n" ) if approach == "Призыв к действию": prompt += "Убедись, что готовый текст начинается с призыва к действию с продуктом.\n" elif approach == "Указание на пользу": prompt += "Убедись, что готовый текст начинается с указания на пользу продукта и использования глагола в побудительном наклонении.\n" elif approach == "Вопрос": prompt += "Убедись, что готовый текст начинается с вопроса, который указывает на пользу продукта для клиента.\n" elif approach == "None": prompt += "" if key_message.strip(): prompt += f"Убедись, что в готовом тексте есть следующая ключевая информация: {key_message.strip()}" return prompt # Функции для генерации сообщений def generate_message_gpt4o(prompt): try: headers = { "Content-Type": "application/json", "Authorization": f"Bearer {openai_api_key}" } data = { "model": "chatgpt-4o-latest", "messages": [{"role": "system", "content": prompt}], "max_tokens": 101, "temperature": 1.1 } response = requests.post("https://api.openai.com/v1/chat/completions", json=data, headers=headers) response_data = response.json() return response_data["choices"][0]["message"]["content"].strip() except Exception as e: return f"Ошибка при обращении к ChatGPT-4o-Latest: {e}" def clean_message(message): # Если сообщение не заканчивается на точку, восклицательный знак или вопросительный знак, обрезаем его до последнего такого знака if not message.endswith(('.', '!', '?')): last_period = max(message.rfind('.'), message.rfind('!'), message.rfind('?')) if last_period != -1: message = message[:last_period + 1] return message # Обновленные функции генерации сообщений с учетом обрезки незаконченных предложений def generate_message_gigachat_pro(prompt): try: messages = [SystemMessage(content=prompt)] res = chat_pro(messages) cleaned_message = clean_message(res.content.strip()) return cleaned_message except Exception as e: return f"Ошибка при обращении к GigaChat-Pro: {e}" def generate_message_gigachat_lite(prompt): try: time.sleep(2) messages = [SystemMessage(content=prompt)] res = chat_lite(messages) cleaned_message = clean_message(res.content.strip()) return cleaned_message except Exception as e: return f"Ошибка при обращении к GigaChat-Lite: {e}" def generate_message_gigachat_plus(prompt): try: time.sleep(2) messages = [SystemMessage(content=prompt)] res = chat_plus(messages) cleaned_message = clean_message(res.content.strip()) return cleaned_message except Exception as e: return f"Ошибка при обращении к GigaChat-Plus: {e}" def generate_message_meta_llama_3_1_405b(prompt): try: response = client.chat.completions.create( model="meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo", messages=[{"role": "user", "content": prompt}], max_tokens=74, temperature=0.8 ) cleaned_message = clean_message(response.choices[0].message.content.strip()) return cleaned_message except Exception as e: return f"Ошибка при обращении к Meta-Llama-3.1-405B: {e}" def generate_message_gpt4o_with_retry(prompt): for _ in range(10): # Максимум 10 попыток message = generate_message_gpt4o(prompt) if len(message) <= 250: return correct_dash_usage(message) return message # Возвращаем последнее сгенерированное сообщение, если все попытки не удались def generate_message_gigachat_pro_with_retry(prompt): for _ in range(10): message = generate_message_gigachat_pro(prompt) if len(message) <= 250: return correct_dash_usage(message) return message def generate_message_gigachat_lite_with_retry(prompt): for _ in range(10): message = generate_message_gigachat_lite(prompt) if len(message) <= 250: return correct_dash_usage(message) return message def generate_message_gigachat_plus_with_retry(prompt): for _ in range(10): message = generate_message_gigachat_plus(prompt) if len(message) <= 250: return correct_dash_usage(message) return message def generate_message_meta_llama_3_1_405b_with_retry(prompt): for _ in range(10): message = generate_message_meta_llama_3_1_405b(prompt) if len(message) <= 250: return correct_dash_usage(message) return message def generate_messages(description, advantages, key_message, approach, *selected_values): save_user_request_to_github(description, advantages, key_message, approach, selected_values) standard_prompt = generate_standard_prompt(description, advantages, key_message, approach, *selected_values) results = { "prompt": standard_prompt, "gigachat_pro": None, "gigachat_lite": None, "gigachat_plus": None, "gpt4o": None, "meta_llama_3_1_405b": None } yield results["prompt"], "", "", "", "", "" # Generating messages using existing models (as before) results["gigachat_pro"] = generate_message_gigachat_pro_with_retry(standard_prompt) gigachat_pro_length = len(results["gigachat_pro"]) gigachat_pro_display = f"{results['gigachat_pro']}\n\n------\nКоличество знаков: {gigachat_pro_length}" yield results["prompt"], gigachat_pro_display, "", "", "", "" results["gigachat_lite"] = generate_message_gigachat_lite_with_retry(standard_prompt) gigachat_lite_length = len(results["gigachat_lite"]) gigachat_lite_display = f"{results['gigachat_lite']}\n\n------\nКоличество знаков: {gigachat_lite_length}" yield results["prompt"], gigachat_pro_display, gigachat_lite_display, "", "", "" time.sleep(2) results["gigachat_plus"] = generate_message_gigachat_plus_with_retry(standard_prompt) gigachat_plus_length = len(results["gigachat_plus"]) gigachat_plus_display = f"{results['gigachat_plus']}\n\n------\nКоличество знаков: {gigachat_plus_length}" yield results["prompt"], gigachat_pro_display, gigachat_lite_display, gigachat_plus_display, "", "" time.sleep(2) results["gpt4o"] = generate_message_gpt4o_with_retry(standard_prompt) gpt4o_length = len(results["gpt4o"]) gpt4o_display = f"{results['gpt4o']}\n\n------\nКоличество знаков: {gpt4o_length}" yield results["prompt"], gigachat_pro_display, gigachat_lite_display, gigachat_plus_display, gpt4o_display, "" time.sleep(2) results["meta_llama_3_1_405b"] = generate_message_meta_llama_3_1_405b_with_retry(standard_prompt) meta_llama_405b_length = len(results["meta_llama_3_1_405b"]) meta_llama_405b_display = f"{results['meta_llama_3_1_405b']}\n\n------\nКоличество знаков: {meta_llama_405b_length}" yield results["prompt"], gigachat_pro_display, gigachat_lite_display, gigachat_plus_display, gpt4o_display, meta_llama_405b_display time.sleep(2) return results # Функция для генерации персонализированного промпта def generate_personalization_prompt(key_message, approach, *selected_values): prompt = "Адаптируй, не превышая длину сообщения в 250 знаков с пробелами, текст с учетом следующих особенностей:\n" gender, generation, psychotype = selected_values[0], selected_values[1], selected_values[2] combined_instruction = "" additional_instructions = "" print(f"Выбранные значения: Пол={gender}, Поколение={generation}, Психотип={psychotype}") # Проверяем, выбраны ли все три параметра: Пол, Поколение, Психотип if gender and generation and psychotype: # Получаем данные с листа "Пол Поколение Психотип" sheet = features.get("Пол Поколение Психотип", {}) # Ищем ключ, соответствующий комбинации "Пол", "Поколение", "Психотип" key = (gender, generation, psychotype) if key in sheet: combined_instruction = sheet[key] print(f"Найдена комбинированная инструкция: {combined_instruction}") else: print(f"Комбинированная инструкция для ключа {key} не найдена.") # Если не найдена комбинированная инструкция, добавляем индивидуальные инструкции if not combined_instruction: print("Добавляем индивидуальные инструкции для Пол, Поколение, Психотип.") for i, feature in enumerate(["Пол", "Поколение", "Психотип"]): if selected_values[i]: try: instruction = features[feature][selected_values[i]] additional_instructions += f"{instruction}\n" print(f"Добавлена инструкция из {feature}: {instruction}") except KeyError: return f"Ошибка: выбранное значение {selected_values[i]} не найдено в данных." # Добавляем инструкции для остальных параметров (например, Отрасль) for i, feature in enumerate(features.keys()): if feature not in ["Пол", "Поколение", "Психотип", "Пол Поколение Психотип"]: if i < len(selected_values) and selected_values[i]: try: instruction = features[feature][selected_values[i]] additional_instructions += f"{instruction}\n" print(f"Добавлена инструкция из {feature}: {instruction}") except KeyError: return f"Ошибка: выбранное значение {selected_values[i]} не найдено в данных." # Формируем итоговый промпт if combined_instruction: prompt += combined_instruction # Добавляем комбинированную инструкцию, если она есть if additional_instructions: prompt += additional_instructions # Добавляем остальные инструкции prompt += "Убедись, что в готовом тексте до 250 знаков с пробелами.\n" if approach == "Призыв к действию": prompt += "Убедись, что готовый текст начинается с призыва к действию с продуктом.\n" elif approach == "Указание на пользу": prompt += "Убедись, что готовый текст начинается с указания на пользу продукта и использования глагола в побудительном наклонении.\n" elif approach == "Вопрос": prompt += "Убедись, что готовый текст начинается с вопроса, который указывает на пользу продукта для клиента.\n" elif approach == "None": prompt += "" prompt += f"Убедись, что в готовом тексте есть следующая ключевая информация: {key_message.strip()}" if "призыва к действию" in prompt and "минимум прямых призывов к действию" in prompt: prompt = re.sub(r"Убедись, что готовый текст начинается с призыва к действию с продуктом.\n", "", prompt) return prompt.strip() # Функция для выполнения персонализации на основе сгенерированного промпта и сообщения def perform_personalization(standard_message, personalization_prompt): full_prompt = f"{personalization_prompt}\n\nТекст для адаптации:\n{standard_message}" return generate_message_gpt4o_with_retry(full_prompt) # Также обновляем функции персонализации def perform_personalization_gigachat(standard_message, personalization_prompt, model): full_prompt = f"{personalization_prompt}\n\nТекст для адаптации:\n{standard_message}" if model == "gigachat_pro": result = generate_message_gigachat_pro_with_retry(full_prompt) elif model == "gigachat_lite": result = generate_message_gigachat_lite_with_retry(full_prompt) elif model == "gigachat_plus": result = generate_message_gigachat_plus_with_retry(full_prompt) return clean_message(result) def perform_personalization_meta_llama_405b(standard_message, personalization_prompt): full_prompt = f"{personalization_prompt}\n\nТекст для адаптации:\n{standard_message}" return generate_message_meta_llama_3_1_405b_with_retry(full_prompt) # Updated function to include additional models in personalization def personalize_messages_with_yield( gigachat_pro_message, gigachat_lite_message, gigachat_plus_message, gpt4o_message, meta_llama_405b_message, key_message, approach, *selected_values ): personalization_prompt = generate_personalization_prompt(key_message, approach, *selected_values) yield personalization_prompt, "", "", "", "", "" personalized_message_gigachat_pro = perform_personalization_gigachat(gigachat_pro_message, personalization_prompt, "gigachat_pro") gigachat_pro_length = len(personalized_message_gigachat_pro) gigachat_pro_display = f"{personalized_message_gigachat_pro}\n\n------\nКоличество знаков: {gigachat_pro_length}" yield personalization_prompt, gigachat_pro_display, "", "", "", "" personalized_message_gigachat_lite = perform_personalization_gigachat(gigachat_lite_message, personalization_prompt, "gigachat_lite") gigachat_lite_length = len(personalized_message_gigachat_lite) gigachat_lite_display = f"{personalized_message_gigachat_lite}\n\n------\nКоличество знаков: {gigachat_lite_length}" yield personalization_prompt, gigachat_pro_display, gigachat_lite_display, "", "", "" personalized_message_gigachat_plus = perform_personalization_gigachat(gigachat_plus_message, personalization_prompt, "gigachat_plus") gigachat_plus_length = len(personalized_message_gigachat_plus) gigachat_plus_display = f"{personalized_message_gigachat_plus}\n\n------\nКоличество знаков: {gigachat_plus_length}" yield personalization_prompt, gigachat_pro_display, gigachat_lite_display, gigachat_plus_display, "", "" personalized_message_gpt4o = perform_personalization(gpt4o_message, personalization_prompt) gpt4o_length = len(personalized_message_gpt4o) gpt4o_display = f"{personalized_message_gpt4o}\n\n------\nКоличество знаков: {gpt4o_length}" yield personalization_prompt, gigachat_pro_display, gigachat_lite_display, gigachat_plus_display, gpt4o_display, "" personalized_message_meta_llama_405b = perform_personalization_meta_llama_405b(meta_llama_405b_message, personalization_prompt) meta_llama_405b_length = len(personalized_message_meta_llama_405b) meta_llama_405b_display = f"{personalized_message_meta_llama_405b}\n\n------\nКоличество знаков: {meta_llama_405b_length}" yield personalization_prompt, gigachat_pro_display, gigachat_lite_display, gigachat_plus_display, gpt4o_display, meta_llama_405b_display # Добавьте проверки в personalize_messages_with_yield is_valid_gigachat_pro = check_forbidden_words(personalized_message_gigachat_pro) is_valid_gigachat_lite = check_forbidden_words(personalized_message_gigachat_lite) is_valid_gigachat_plus = check_forbidden_words(personalized_message_gigachat_plus) is_valid_gpt4o = check_forbidden_words(personalized_message_gpt4o) is_valid_meta_llama_405b = check_forbidden_words(personalized_message_meta_llama_405b) # Функция для генерации промпта проверки текста def generate_error_check_prompt(): prompt = ( "Проверь текст SMS-сообщения на соответствие установленным правилам и ограничениям, касающимся его формирования. На основе выявленных несоответствий предоставь рекомендации по исправлению текста. " "Особое внимание удели проверке: количества символов в тексте SMS-сообщения, орфографическим и пунктуационным ошибкам, определению частей речи (причастия, деепричастия, причастный оборот, деепричастный оборот). " "Анализируй только текст SMS-сообщения, ничего не придумывай и не добавляй лишнего. " "Правила и ограничения, которым должен соответствовать текст SMS-сообщения:\n" "1. Количество символов в SMS-сообщении должно быть до 250 знаков с учетом пробелов.\n" "2. В тексте должен быть призыв к действию с использованием глагола в повелительном наклонении (например: оформите, получите, разместите, размещайте, откройте, подключите, подайте заявку).\n" "3. Должно соблюдаться соответствие фактов о продукте.\n" "4. В генерациях смс запрещено использовать обещания и гарантии.\n" "5. В генерациях смс запрещено использовать составные конструкции из двух глаголов.\n" "6. В генерациях смс запрещено использовать причастия и причастные обороты.\n" "7. В генерациях смс запрещено использовать деепричастия и деепричастные обороты.\n" "8. В генерациях смс запрещено использовать превосходную степень прилагательных.\n" "9. В генерациях смс запрещено использовать страдательный залог.\n" "10. В генерациях смс запрещено использовать порядковые числительные от 10 прописью.\n" "11. В генерациях смс запрещено использовать цепочки с придаточными предложениями.\n" "12. В генерациях смс запрещено использовать разделительные повторяющиеся союзы.\n" "13. В генерациях смс запрещено использовать вводные конструкции.\n" "14. В генерациях смс запрещено использовать усилители.\n" "15. В генерациях смс запрещено использовать паразиты времени.\n" "16. В генерациях смс запрещено использовать несколько существительных подряд, в том числе отглагольных.\n" "17. В генерациях смс запрещено использовать производные предлоги.\n" "18. В генерациях смс запрещено использовать сложные предложения, в которых нет связи между частями.\n" "19. В генерациях смс запрещено использовать сложноподчинённые предложения.\n" "20. В генерациях смс запрещено использовать даты прописью.\n" "21. В генерациях смс запрещено использовать близкие по смыслу однородные члены.\n" "22. В генерациях смс запрещено использовать шокирующие, экстравагантные, кликбейтные фразы.\n" "23. В генерациях смс запрещено использовать абстрактные заявления без поддержки фактами и отсутствие доказательства пользы для клиента.\n" "24. В генерациях смс запрещено использовать гарантирующие фразы.\n" "25. В генерациях смс запрещено использовать узкоспециализированные термины.\n" "26. В генерациях смс запрещено использовать фразы, способные создать двойственное ощущение, обидеть.\n" "27. В генерациях смс запрещено использовать речевые клише, рекламные штампы, канцеляризмы.\n" "28. В генерациях смс запрещено использовать запрещенные слова: № один, номер один, № 1, вкусный, дешёвый, продукт, спам, банкротство, долги, займ, срочно, лучший, главный, номер 1, успех, лидер.\n" "29. Сообщение должно быть написано без орфографических и грамматических ошибок.\n" "30. Запрещены повторы слов.\n" "31. В тексте должны использоваться правильные знаки препинания.\n" "32. Если в тексте используются кавычки, они должны быть в форме «кавычки-ёлочки».\n" "33. В тексте SMS сообщения должны обязательно присутствовать: название продукта, условия использования продукта / Преимущества продукта / Шаги для подключения или начала использования / Условия акции (если предложение по продукту акционное).\n" "Форма ответа: [Ответ должен быть кратким, должен содержать только рекомендации по устранению найденных несоответствий, соответствия каждому пункту правил описывать категорически запрещено]." ) return prompt def save_to_github(adapted_message, personalized_message, model_name, comment, corrected_message, description, advantages, non_personalized_prompt, non_personalized_message, personalization_prompt, gender, generation, psychotype, business_stage, industry, legal_form, key_message, approach): # Собираем все данные в один словарь data_to_save = { "Модель": model_name, "Адаптированное сообщение": adapted_message, "Персонализированное сообщение": personalized_message, "Комментарий": comment, "Откорректированное сообщение": corrected_message, "Описание предложения": description, "Преимущества": advantages, "Ключевое сообщение": key_message, "Подход": approach, "Неперсонализированный промпт": non_personalized_prompt, "Неперсонализированное сообщение": non_personalized_message, "Персонализированный промпт": personalization_prompt, "Пол": gender, "Поколение": generation, "Психотип": psychotype, "Стадия бизнеса": business_stage, "Отрасль": industry, "ОПФ": legal_form } # Преобразуем контент в JSON-строку и кодируем в base64 file_content_encoded = base64.b64encode(json.dumps(data_to_save).encode()).decode() # Параметры для GitHub API repo = "fruitpicker01/Storage_dev" path = f"file_{int(time.time())}.json" url = f"https://api.github.com/repos/{repo}/contents/{path}" headers = { "Authorization": f"token {token}", "Content-Type": "application/json" } data = { "message": f"Добавлен новый файл {path}", "content": file_content_encoded } # Отправка POST-запроса на GitHub API для создания файла в репозитории response = requests.put(url, headers=headers, data=json.dumps(data)) if response.status_code == 201: print("Данные успешно сохранены на GitHub") else: print(f"Ошибка при сохранении данных на GitHub: {response.status_code} {response.text}") def personalize_and_save( gigachat_pro_message, gigachat_lite_message, gigachat_plus_message, gpt4o_message, meta_llama_405b_message, description, advantages, key_message, approach, *selected_values ): # Персонализация с использованием yield для последовательного вывода personalization_generator = personalize_messages_with_yield( gigachat_pro_message, gigachat_lite_message, gigachat_plus_message, gpt4o_message, meta_llama_405b_message, key_message, approach, *selected_values ) last_personalization_result = None for personalization_result in personalization_generator: last_personalization_result = personalization_result yield ( personalization_result[0], # personalization_prompt personalization_result[1], # gigachat_pro_message personalization_result[2], # gigachat_lite_message personalization_result[3], # gigachat_plus_message personalization_result[4], # gpt4o_message personalization_result[5], # meta_llama_405b_message "", "", "", "", "" # Пустые строки для проверок ) # После завершения персонализации, сохраняем результаты if last_personalization_result: checks_gigachat_pro = perform_checks(last_personalization_result[1]) checks_gigachat_lite = perform_checks(last_personalization_result[2]) checks_gigachat_plus = perform_checks(last_personalization_result[3]) checks_gpt4o = perform_checks(last_personalization_result[4]) checks_meta_llama_405b = perform_checks(last_personalization_result[5]) # Форматирование результатов проверок formatted_checks = [ format_checks(checks_gigachat_pro), format_checks(checks_gigachat_lite), format_checks(checks_gigachat_plus), format_checks(checks_gpt4o), format_checks(checks_meta_llama_405b) ] yield ( last_personalization_result[0], # personalization_prompt last_personalization_result[1], # gigachat_pro_message last_personalization_result[2], # gigachat_lite_message last_personalization_result[3], # gigachat_plus_message last_personalization_result[4], # gpt4o_message last_personalization_result[5], # meta_llama_405b_message formatted_checks[0], # validation_display_1 formatted_checks[1], # validation_display_2 formatted_checks[2], # validation_display_3 formatted_checks[3], # validation_display_4 formatted_checks[4] # validation_display_5 ) save_user_request_to_github(description, advantages, key_message, approach, selected_values) def clear_outputs(*args): return ('',) * len(args) def prepare_button_text(): return gr.update(value="Сохраняется...", visible=True) def update_button_text(): return gr.update(value="Сохранено!", visible=True) def reset_button_text(): time.sleep(2) # Задержка в 2 секунды return gr.update(value="Сохранить в базу", visible=True) def regen_message_gpt4o(description, advantages, key_message, approach, *selected_values): standard_prompt = generate_standard_prompt(description, advantages, key_message, approach, *selected_values) gpt4o_message = generate_message_gpt4o_with_retry(standard_prompt) gpt4o_length = len(gpt4o_message) return f"{gpt4o_message}\n\n------\nКоличество знаков: {gpt4o_length}" def regen_message_gigachat_pro(description, advantages, key_message, approach, *selected_values): standard_prompt = generate_standard_prompt(description, advantages, key_message, approach, *selected_values) gigachat_pro_message = generate_message_gigachat_pro_with_retry(standard_prompt) gigachat_pro_length = len(gigachat_pro_message) return f"{gigachat_pro_message}\n\n------\nКоличество знаков: {gigachat_pro_length}" def regen_message_gigachat_lite(description, advantages, key_message, approach, *selected_values): standard_prompt = generate_standard_prompt(description, advantages, key_message, approach, *selected_values) gigachat_lite_message = generate_message_gigachat_lite_with_retry(standard_prompt) gigachat_lite_length = len(gigachat_lite_message) return f"{gigachat_lite_message}\n\n------\nКоличество знаков: {gigachat_lite_length}" def regen_message_gigachat_plus(description, advantages, key_message, approach, *selected_values): standard_prompt = generate_standard_prompt(description, advantages, key_message, approach, *selected_values) gigachat_plus_message = generate_message_gigachat_plus_with_retry(standard_prompt) gigachat_plus_length = len(gigachat_plus_message) return f"{gigachat_plus_message}\n\n------\nКоличество знаков: {gigachat_plus_length}" def regen_message_meta_llama_405b(description, advantages, key_message, approach, *selected_values): standard_prompt = generate_standard_prompt(description, advantages, key_message, approach, *selected_values) meta_llama_405b_message = generate_message_meta_llama_3_1_405b_with_retry(standard_prompt) meta_llama_405b_length = len(meta_llama_405b_message) return f"{meta_llama_405b_message}\n\n------\nКоличество знаков: {meta_llama_405b_length}" def personalize_message_gigachat_pro(gigachat_pro_message, key_message, approach, *selected_values): personalization_prompt = generate_personalization_prompt(key_message, approach, *selected_values) personalized_message = perform_personalization_gigachat(gigachat_pro_message, personalization_prompt, "gigachat_pro") gigachat_pro_length = len(personalized_message) # Выполняем проверку сгенерированного сообщения checks = perform_checks(personalized_message) formatted_checks = format_checks(checks) return f"{personalized_message}\n\n------\nКоличество знаков: {gigachat_pro_length}", formatted_checks def personalize_message_gigachat_lite(gigachat_lite_message, key_message, approach, *selected_values): personalization_prompt = generate_personalization_prompt(key_message, approach, *selected_values) personalized_message = perform_personalization_gigachat(gigachat_lite_message, personalization_prompt, "gigachat_lite") gigachat_lite_length = len(personalized_message) # Выполняем проверку сгенерированного сообщения checks = perform_checks(personalized_message) formatted_checks = format_checks(checks) return f"{personalized_message}\n\n------\nКоличество знаков: {gigachat_lite_length}", formatted_checks def personalize_message_gigachat_plus(gigachat_plus_message, key_message, approach, *selected_values): personalization_prompt = generate_personalization_prompt(key_message, approach, *selected_values) personalized_message = perform_personalization_gigachat(gigachat_plus_message, personalization_prompt, "gigachat_plus") gigachat_plus_length = len(personalized_message) # Выполняем проверку сгенерированного сообщения checks = perform_checks(personalized_message) formatted_checks = format_checks(checks) return f"{personalized_message}\n\n------\nКоличество знаков: {gigachat_plus_length}", formatted_checks def personalize_message_gpt4o(gpt4o_message, key_message, approach, *selected_values): personalization_prompt = generate_personalization_prompt(key_message, approach, *selected_values) personalized_message = perform_personalization(gpt4o_message, personalization_prompt) gpt4o_length = len(personalized_message) # Выполняем проверку сгенерированного сообщения checks = perform_checks(personalized_message) formatted_checks = format_checks(checks) return f"{personalized_message}\n\n------\nКоличество знаков: {gpt4o_length}", formatted_checks def personalize_message_meta_llama_405b(meta_llama_405b_message, key_message, approach, *selected_values): personalization_prompt = generate_personalization_prompt(key_message, approach, *selected_values) personalized_message = perform_personalization_meta_llama_405b(meta_llama_405b_message, personalization_prompt) meta_llama_405b_length = len(personalized_message) # Выполняем проверку сгенерированного сообщения checks = perform_checks(personalized_message) formatted_checks = format_checks(checks) return f"{personalized_message}\n\n------\nКоличество знаков: {meta_llama_405b_length}", formatted_checks def generate_explanation_gigachat_pro(prompt): messages = [SystemMessage(content=prompt)] res = chat_pro_explain(messages) return res.content.strip() def generate_explanation_gigachat_lite(prompt): messages = [SystemMessage(content=prompt)] res = chat_lite_explain(messages) return res.content.strip() def generate_explanation_gigachat_plus(prompt): messages = [SystemMessage(content=prompt)] res = chat_plus_explain(messages) return res.content.strip() def generate_explanation_gpt4o(prompt): try: headers = { "Content-Type": "application/json", "Authorization": f"Bearer {openai_api_key}" } data = { "model": "chatgpt-4o-latest", "messages": [{"role": "system", "content": prompt}], "temperature": 1.1 } response = requests.post("https://api.openai.com/v1/chat/completions", json=data, headers=headers) response_data = response.json() return response_data["choices"][0]["message"]["content"].strip() except Exception as e: return f"Ошибка при обращении к ChatGPT-4o-Latest: {e}" def generate_explanation_meta_llama_405b(prompt): response = client.chat.completions.create( model="meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo", messages=[{"role": "user", "content": prompt}], temperature=0.8 ) return response.choices[0].message.content.strip() def explain_compliance_gigachat_pro(personalized_message, personalization_prompt): prompt = ( f"Есть инструкция по персонализации: {personalization_prompt}\n" "Сообщи, учтены ли данные инструкции в тексте ниже, и укажи как они были учтены:\n" f"Текст сообщения: {personalized_message}\n" ) return generate_explanation_gigachat_pro(prompt) def explain_compliance_gigachat_lite(personalized_message, personalization_prompt): prompt = ( f"Есть инструкция по персонализации: {personalization_prompt}\n" "Сообщи, учтены ли данные инструкции в тексте ниже, и укажи как они были учтены:\n" f"Текст сообщения: {personalized_message}\n" ) return generate_explanation_gigachat_lite(prompt) def explain_compliance_gigachat_plus(personalized_message, personalization_prompt): prompt = ( f"Есть инструкция по персонализации: {personalization_prompt}\n" "Сообщи, учтены ли данные инструкции в тексте ниже, и укажи как они были учтены:\n" f"Текст сообщения: {personalized_message}\n" ) return generate_explanation_gigachat_plus(prompt) def explain_compliance_gpt4o(personalized_message, personalization_prompt): prompt = ( f"Есть инструкция по персонализации: {personalization_prompt}\n" "Сообщи, учтены ли данные инструкции в тексте ниже, и укажи как они были учтены:\n" f"Текст сообщения: {personalized_message}\n" ) return generate_explanation_gpt4o(prompt) def explain_compliance_meta_llama_405b(personalized_message, personalization_prompt): prompt = ( f"Есть инструкция по персонализации: {personalization_prompt}\n" "Сообщи, учтены ли данные инструкции в тексте ниже, и укажи как они были учтены:\n" f"Текст сообщения: {personalized_message}\n" ) return generate_explanation_meta_llama_405b(prompt) def perform_analysis_with_yield( gigachat_pro_message, gigachat_lite_message, gigachat_plus_message, gpt4o_message, meta_llama_405b_message, personalization_prompt ): # Start yielding results progressively gigachat_pro_analysis = explain_compliance_gigachat_pro(gigachat_pro_message, personalization_prompt) yield gigachat_pro_analysis, "", "", "", "" gigachat_lite_analysis = explain_compliance_gigachat_lite(gigachat_lite_message, personalization_prompt) yield gigachat_pro_analysis, gigachat_lite_analysis, "", "", "" gigachat_plus_analysis = explain_compliance_gigachat_plus(gigachat_plus_message, personalization_prompt) yield gigachat_pro_analysis, gigachat_lite_analysis, gigachat_plus_analysis, "", "" gpt4o_analysis = explain_compliance_gpt4o(gpt4o_message, personalization_prompt) yield gigachat_pro_analysis, gigachat_lite_analysis, gigachat_plus_analysis, gpt4o_analysis, "" meta_llama_405b_analysis = explain_compliance_meta_llama_405b(meta_llama_405b_message, personalization_prompt) yield gigachat_pro_analysis, gigachat_lite_analysis, gigachat_plus_analysis, gpt4o_analysis, meta_llama_405b_analysis # ФУНКЦИИ ПРОВЕРОК (НАЧАЛО) # 1. Запрещенные слова def check_forbidden_words(message): morph = pymorphy2.MorphAnalyzer() # Перечень запрещённых слов и фраз forbidden_patterns = [ r'№\s?1\b', r'номер\sодин\b', r'номер\s1\b', r'вкусный', r'дешёвый', r'продукт', r'спам', r'банкротство', r'долг[и]?', r'займ', r'срочный', r'главный', r'гарантия', r'успех', r'лидер' ] # Удаляем знаки препинания для корректного анализа message_without_punctuation = message.translate(str.maketrans('', '', string.punctuation)) # Проверка на наличие подстроки "лучш" (без учета регистра) if re.search(r'лучш', message_without_punctuation, re.IGNORECASE): return False # Лемматизация слов сообщения words = message_without_punctuation.split() lemmas = [morph.parse(word)[0].normal_form for word in words] normalized_message = ' '.join(lemmas) # Проверка на запрещённые фразы и леммы for pattern in forbidden_patterns: if re.search(pattern, normalized_message, re.IGNORECASE): return False return True # 2 и #3. Обращение к клиенту и приветствие клиента def check_no_greeting(message): morph = pymorphy2.MorphAnalyzer() # Список типичных обращений и приветствий greeting_patterns = [ r"привет\b", r"здравствуй", r"добрый\s(день|вечер|утро)", r"дорогой\b", r"уважаемый\b", r"дорогая\b", r"уважаемая\b", r"господин\b", r"госпожа\b", r"друг\b", r"коллега\b", r"товарищ\b", r"приятель\b", r"друг\b", r"подруга\b" ] # Компилируем все шаблоны в один регулярное выражение greeting_regex = re.compile('|'.join(greeting_patterns), re.IGNORECASE) # Проверяем, начинается ли сообщение с шаблона приветствия или обращения if greeting_regex.search(message.strip()): return False return True # 4. Обещания и гарантии def check_no_promises(message): morph = pymorphy2.MorphAnalyzer() promise_patterns = [ "обещать", "обещание", "гарантировать", "обязаться", "обязать", "обязательство", "обязательный" ] words = message.split() lemmas = [morph.parse(word)[0].normal_form for word in words] for pattern in promise_patterns: if pattern in lemmas: return False return True # 5. Составные конструкции из двух глаголов def check_no_double_verbs(message): morph = pymorphy2.MorphAnalyzer() # Разделяем текст по пробелам и знакам препинания words = re.split(r'\s+|[.!?]', message) morphs = [morph.parse(word)[0] for word in words] for i in range(len(morphs) - 1): # Проверяем, что оба слова являются глаголами (в любой форме, включая инфинитивы) if (morphs[i].tag.POS in {'VERB', 'INFN'}) and (morphs[i+1].tag.POS in {'VERB', 'INFN'}): # Проверяем, является ли первый глагол "хотеть" или "начинать" if morphs[i].normal_form in ['хотеть', 'начинать', 'начать']: return True else: return False return True # 6. Причастия и причастные обороты def check_no_participles(message): morph = pymorphy2.MorphAnalyzer() words = message.split() morphs = [morph.parse(word)[0] for word in words] for morph in morphs: if 'PRTF' in morph.tag: return False return True # 7. Деепричастия и деепричастные обороты def check_no_adverbial_participles(message): morph = pymorphy2.MorphAnalyzer() words = message.split() morphs = [morph.parse(word)[0] for word in words] for morph in morphs: if 'GRND' in morph.tag: return False return True # 8. Превосходная степень прилагательных def check_no_superlative_adjectives(message): morph = pymorphy2.MorphAnalyzer() words = message.split() morphs = [morph.parse(word)[0] for word in words] for morph in morphs: if 'COMP' in morph.tag or 'Supr' in morph.tag: return False return True # 9. Страдательный залог def check_no_passive_voice(message): morph = pymorphy2.MorphAnalyzer() words = message.split() morphs = [morph.parse(word)[0] for word in words] for morph in morphs: if 'PRTF' in morph.tag and ('passive' in morph.tag or 'в' in morph.tag): return False return True # 10. Порядковые числительные от 10 прописью def check_no_written_out_ordinals(message): morph = pymorphy2.MorphAnalyzer() ordinal_words = [ "десятый", "одиннадцатый", "двенадцатый", "тринадцатый", "четырнадцатый", "пятнадцатый", "шестнадцатый", "семнадцатый", "восемнадцатый", "девятнадцатый", "двадцатый" ] words = message.split() lemmas = [morph.parse(word)[0].normal_form for word in words] for word in ordinal_words: if word in lemmas: return False return True # 11. Цепочки с придаточными предложениями def check_no_subordinate_clauses_chain(message): # Регулярное выражение, которое ищет последовательности придаточных предложений subordinate_clause_patterns = [ r'\b(который|которая|которое|которые)\b', r'\b(если|потому что|так как|что|когда)\b', r'\b(хотя|несмотря на то что)\b' ] count = 0 for pattern in subordinate_clause_patterns: if re.search(pattern, message): count += 1 # Если в предложении найдено более одного придаточного предложения подряд, возвращаем False return count < 2 # 12. Разделительные повторяющиеся союзы def check_no_repeating_conjunctions(message): # Регулярное выражение для поиска разделительных повторяющихся союзов с запятой перед вторым союзом repeating_conjunctions_patterns = r'\b(и|ни|то|не то|или|либо)\b\s*(.*?)\s*,\s*\b\1\b' # Разделяем сообщение на предложения по точке, вопросительному и восклицательному знакам sentences = re.split(r'[.!?]\s*', message) # Проверяем каждое предложение отдельно for sentence in sentences: if re.search(repeating_conjunctions_patterns, sentence, re.IGNORECASE): return False return True # 13. Вводные конструкции def check_no_introductory_phrases(message): introductory_phrases = [ r'\b(во-первых|во-вторых|с одной стороны|по сути|по правде говоря)\b', r'\b(может быть|кстати|конечно|естественно|безусловно|возможно)\b' ] for pattern in introductory_phrases: if re.search(pattern, message, re.IGNORECASE): return False return True # 14. Усилители def check_no_amplifiers(message): amplifiers = [ r'\b(очень|крайне|чрезвычайно|совсем|полностью|чисто)\b' ] for pattern in amplifiers: if re.search(pattern, message, re.IGNORECASE): return False return True # 15. Паразиты времени def check_no_time_parasites(message): time_parasites = [ r'\b(немедленно|срочно|в данный момент|теперь)\b' ] for pattern in time_parasites: if re.search(pattern, message, re.IGNORECASE): return False return True # 16. Несколько существительных подряд def check_no_multiple_nouns(message): noun_count = 0 words = re.split(r'\s+|[.!?]', message) # Разбиваем по пробелам и знакам препинания morph = pymorphy2.MorphAnalyzer() for word in words: parsed_word = morph.parse(word)[0] # Если слово — существительное if 'NOUN' in parsed_word.tag: noun_count += 1 # Если встречен конец предложения (точка, вопросительный знак, восклицательный знак) elif re.match(r'[.!?]', word): noun_count = 0 else: noun_count = 0 if noun_count > 2: return False return True # 17. Производные предлоги def check_no_derived_prepositions(message): derived_prepositions = [ r'\b(в течение|в ходе|вследствие|в связи с|по мере|при помощи|согласно|вопреки|на основании|на случай|в продолжение|по причине|вблизи|вдалеке|вокруг|внутри|вдоль|посередине|вне|снаружи|благодаря|невзирая на|исходя из)\b' ] for pattern in derived_prepositions: if re.search(pattern, message, re.IGNORECASE): return False return True # 19. Сложноподчиненные предложения def check_no_compound_sentences(message): subordinating_conjunctions = [ r'\bкогда\b', r'\bкак только\b', r'\bпока\b', r'\bпосле того как\b', r'\bпотому что\b', r'\bтак как\b', r'\bоттого что\b', r'\bблагодаря тому что\b', r'\bчтобы\b', r'\bдля того чтобы\b', r'\bесли\b', r'\bкогда бы\b', r'\bесли бы\b', r'\bхотя\b', r'\bнесмотря на то что\b', r'\bкак\b', r'\bбудто\b', r'\bсловно\b', r'\bкак будто\b' ] # Убедимся, что слово "как" используется не в вопросе for pattern in subordinating_conjunctions: if re.search(pattern, message) and not re.search(r'\?', message): return False return True # 20. Даты прописью def check_no_dates_written_out(message): # Ищем упоминания месяцев или слов, связанных с датами months = [ "января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря" ] # Слова для проверки чисел прописью date_written_out_patterns = [ r'\b(первого|второго|третьего|четвертого|пятого|шестого|седьмого|восьмого|девятого|десятого|одиннадцатого|двенадцатого|тринадцатого|четырнадцатого|пятнадцатого|шестнадцатого|семнадцатого|восемнадцатого|девятнадцатого|двадцатого|двадцать первого|двадцать второго|двадцать третьего|двадцать четвертого|двадцать пятого|двадцать шестого|двадцать седьмого|двадцать восьмого|двадцать девятого|тридцатого|тридцать первого)\b' ] for month in months: for pattern in date_written_out_patterns: if re.search(f'{pattern}\\s{month}', message, re.IGNORECASE): return False return True # Доп правило. Повторы слов def check_no_word_repetitions(message): morph = pymorphy2.MorphAnalyzer() # Список союзов и предлогов, которые мы будем игнорировать ignore_words = set([ 'и', 'а', 'но', 'или', 'да', 'ни', 'как', 'так', 'в', 'на', 'под', 'над', 'за', 'к', 'до', 'по', 'из', 'у', 'о', 'про', 'для', 'не', 'вот', 'это', 'тот', 'тем', 'при', 'чем', 'же', 'ли', 'бы', 'то', ]) # Разбиваем текст на слова, удаляя знаки препинания words = re.findall(r'\b\w+\b', message.lower()) # Словарь для хранения нормализованных форм слов normalized_words = {} for word in words: if word not in ignore_words: # Получаем нормальную форму слова normal_form = morph.parse(word)[0].normal_form # Если слово уже встречалось, возвращаем False if normal_form in normalized_words: return False # Добавляем слово в словарь normalized_words[normal_form] = True # Если мы дошли до этой точки, повторов не было return True # ФУНКЦИИ ПРОВЕРОК (КОНЕЦ) def safe_check(func, message): try: return func(message) except Exception as e: # Optionally, you can log the exception here if needed return None # Indicate that the check could not be performed def perform_checks(message): checks = { "forbidden_words": safe_check(check_forbidden_words, message), "client_addressing": safe_check(check_no_greeting, message), "promises": safe_check(check_no_promises, message), "double_verbs": safe_check(check_no_double_verbs, message), "participles": safe_check(check_no_participles, message), "adverbial_participles": safe_check(check_no_adverbial_participles, message), "superlative_adjectives": safe_check(check_no_superlative_adjectives, message), "passive_voice": safe_check(check_no_passive_voice, message), "written_out_ordinals": safe_check(check_no_written_out_ordinals, message), "subordinate_clauses_chain": safe_check(check_no_subordinate_clauses_chain, message), "repeating_conjunctions": safe_check(check_no_repeating_conjunctions, message), "introductory_phrases": safe_check(check_no_introductory_phrases, message), "amplifiers": safe_check(check_no_amplifiers, message), "time_parasites": safe_check(check_no_time_parasites, message), "multiple_nouns": safe_check(check_no_multiple_nouns, message), "derived_prepositions": safe_check(check_no_derived_prepositions, message), "compound_sentences": safe_check(check_no_compound_sentences, message), "dates_written_out": safe_check(check_no_dates_written_out, message), "no_word_repetitions": safe_check(check_no_word_repetitions, message) } return checks def format_checks(checks): translation = { "forbidden_words": "Запрещенные слова", "client_addressing": "Обращение к клиенту", "promises": "Обещания и гарантии", "double_verbs": "Два глагола подряд", "participles": "Причастия", "adverbial_participles": "Деепричастия", "superlative_adjectives": "Превосходная степень", "passive_voice": "Страдательный залог", "written_out_ordinals": "Порядковые числительные", "subordinate_clauses_chain": "Цепочки с придаточными предложениями", "repeating_conjunctions": "Разделительные повторяющиеся союзы", "introductory_phrases": "Вводные конструкции", "amplifiers": "Усилители", "time_parasites": "Паразиты времени", "multiple_nouns": "Несколько существительных подряд", "derived_prepositions": "Производные предлоги", "compound_sentences": "Сложноподчиненные предложения", "dates_written_out": "Даты прописью", "no_word_repetitions": "Повторы слов" } formatted_results = [] for rule, result in checks.items(): if result is True: symbol = '✔️' elif result is False: symbol = '❌' else: symbol = '❓' # Indicates that the check could not be performed formatted_results.append(f"{translation[rule]}: {symbol}") return " \n".join(formatted_results) # Создание интерфейса Gradio with gr.Blocks() as demo: gr.Markdown("# Генерация SMS-сообщений по заданным признакам") with gr.Tabs() as tabs: # Вкладка 1: Рабочее поле with gr.TabItem("Рабочее поле", id=0): with gr.Row(): with gr.Column(scale=1): description_input = gr.Textbox( label="Описание предложения (предзаполненный пример можно поменять на свой)", lines=13, value=( "Необходимо предложить клиенту оформить дебетовую премиальную бизнес-карту Mastercard Preffered. " "Обслуживание карты стоит 700 рублей в месяц, но клиент может пользоваться ей бесплатно. " "Что необходимо сделать, чтобы воспользоваться предложением:\n" "1. Оформить премиальную бизнес-карту в офисе банка или онлайн в интернет-банке СберБизнес.\n" "2. Забрать карту.\n" "3. В течение календарного месяца совершить по ней покупки на сумму от 100 000 рублей.\n" "4. В течение следующего месяца пользоваться ей бесплатно." ) ) advantages_input = gr.Textbox( label="Преимущества (предзаполненный пример можно поменять на свой)", lines=6, value=( "Предложение по бесплатному обслуживанию — бессрочное.\n" "Оплата покупок без отчётов и платёжных поручений.\n" "Платёжные документы без комиссии.\n" "Лимиты на расходы сотрудников.\n" "Мгновенные переводы на карты любых банков." ) ) key_message_input = gr.Textbox( label="Ключевое сообщение (предзаполненный пример можно поменять на свой)", lines=3, value="Бесплатное обслуживание при покупках от 100 000 рублей в месяц." ) approach_input = gr.Dropdown( label="Подход", choices=["None", "Призыв к действию", "Указание на пользу", "Вопрос"], value="None" # Default value ) selections = [] gr.Markdown("**Персонализация**") for feature in features.keys(): if feature not in ["Пол Поколение Психотип"]: # Исключаем этот лист из выбора selections.append(gr.Dropdown(choices=[None] + list(features[feature].keys()), label=f"Выберите {feature}")) with gr.Column(scale=2): prompt_display = gr.Textbox( label="Неперсонализированный промпт", lines=41, value=( "Сгенерируй смс-сообщение для клиента.\n" "Описание предложения: " "Необходимо предложить клиенту оформить дебетовую премиальную бизнес-карту Mastercard Preffered. " "Обслуживание карты стоит 700 рублей в месяц, но клиент может пользоваться ей бесплатно. " "Что необходимо сделать, чтобы воспользоваться предложением:\n" "1. Оформить премиальную бизнес-карту в офисе банка или онлайн в интернет-банке СберБизнес.\n" "2. Забрать карту.\n" "3. В течение календарного месяца совершить по ней покупки на сумму от 100 000 рублей.\n" "4. В течение следующего месяца пользоваться ей бесплатно.\n" "Преимущества: " "Предложение по бесплатному обслуживанию — бессрочное.\n" "Оплата покупок без отчётов и платёжных поручений.\n" "Платёжные документы без комиссии.\n" "Лимиты на расходы сотрудников.\n" "Мгновенные переводы на карты любых банков.\n " "В тексте смс запрещено использование:\n" "- Запрещенные слова: № один, номер один, № 1, вкусный, дешёвый, продукт, спам, банкротство, долги, займ, срочно, лучший, главный, номер 1, гарантия, успех, лидер;\n" "- Обращение к клиенту;\n" "- Приветствие клиента;\n" "- Обещания и гарантии;\n" "- Использовать составные конструкции из двух глаголов;\n" "- Причастия и причастные обороты;\n" "- Деепричастия и деепричастные обороты;\n" "- Превосходная степень прилагательных;\n" "- Страдательный залог;\n" "- Порядковые числительные от 10 прописью;\n" "- Цепочки с придаточными предложениями;\n" "- Разделительные повторяющиеся союзы;\n" "- Вводные конструкции;\n" "- Усилители;\n" "- Паразиты времени;\n" "- Несколько существительных подряд, в том числе отглагольных;\n" "- Производные предлоги;\n" "- Сложные предложения, в которых нет связи между частями;\n" "- Сложноподчинённые предложения;\n" "- Даты прописью;\n" "- Близкие по смыслу однородные члены предложения;\n" "- Шокирующие, экстравагантные, кликбейтные фразы;\n" "- Абстрактные заявления без поддержки фактами и отсутствие доказательства пользы для клиента;\n" "- Гарантирующие фразы;\n" "- Узкоспециализированные термины;\n" "- Фразы, способные создать двойственное ощущение, обидеть;\n" "- Речевые клише, рекламные штампы, канцеляризмы;\n" "Убедись, что в готовом тексте до 250 знаков с пробелами.\n" "Убедись, что готовый текст начинается с призыва к действию с продуктом.\n" "Убедись, что в готовом тексте есть следующая ключевая информация: Бесплатное обслуживание при покупках от 100 000 рублей в месяц." ), interactive=False) personalization_prompt = gr.Textbox(label="Персонализированный промпт", lines=11, interactive=False) best_example_prompt = gr.Textbox(label="Промпт для адаптации под лучший пример", lines=7, interactive=False) with gr.Row(): submit_btn = gr.Button("1. Создать неперсонализированное сообщение") personalize_btn = gr.Button("2. Выполнить персонализацию (нажимать только после кнопки 1)", elem_id="personalize_button") best_example_btn = gr.Button("3. Выполнить адаптацию под лучший пример (нажимать только после кнопки 2)", elem_id="best_example_button") load_btn = gr.Button("Вернуть параметры предыдущего запроса") gr.Markdown("---") # Добавляет горизонтальную линию # Ряд кнопок "Перегенерировать" with gr.Row(): regen_gigachat_pro_btn = gr.Button("Перегенерировать") regen_gigachat_lite_btn = gr.Button("Перегенерировать") regen_gigachat_plus_btn = gr.Button("Перегенерировать") regen_gpt4o_btn = gr.Button("Перегенерировать") regen_meta_llama_405b_btn = gr.Button("Перегенерировать") # Первый ряд: неперсонализированные сообщения with gr.Row(): output_text_gigachat_pro = gr.Textbox(label="Неперсонализированное сообщение 1", lines=3, interactive=False) output_text_gigachat_lite = gr.Textbox(label="Неперсонализированное сообщение 2", lines=3, interactive=False) output_text_gigachat_plus = gr.Textbox(label="Неперсонализированное сообщение 3", lines=3, interactive=False) output_text_gpt4o = gr.Textbox(label="Неперсонализированное сообщение 4", lines=3, interactive=False) output_text_meta_llama_405b = gr.Textbox(label="Неперсонализированное сообщение 5", lines=3, interactive=False) # Ряд кнопок "Персонализировать" with gr.Row(): personalize_gigachat_pro_btn = gr.Button("Персонализировать") personalize_gigachat_lite_btn = gr.Button("Персонализировать") personalize_gigachat_plus_btn = gr.Button("Персонализировать") personalize_gpt4o_btn = gr.Button("Персонализировать") personalize_meta_llama_405b_btn = gr.Button("Персонализировать") # Второй ряд: персонализированные сообщения with gr.Row(): personalized_output_text_gigachat_pro = gr.Textbox(label="Персонализированное сообщение 1", lines=3, interactive=False) personalized_output_text_gigachat_lite = gr.Textbox(label="Персонализированное сообщение 2", lines=3, interactive=False) personalized_output_text_gigachat_plus = gr.Textbox(label="Персонализированное сообщение 3", lines=3, interactive=False) personalized_output_text_gpt4o = gr.Textbox(label="Персонализированное сообщение 4", lines=3, interactive=False) personalized_output_text_meta_llama_405b = gr.Textbox(label="Персонализированное сообщение 5", lines=3, interactive=False) # Второй (с половиной:) ряд: адаптированные сообщения with gr.Row(): adapted_output_text_gigachat_pro = gr.Textbox(label="Адаптированное сообщение 1", lines=3, interactive=False) adapted_output_text_gigachat_lite = gr.Textbox(label="Адаптированное сообщение 2", lines=3, interactive=False) adapted_output_text_gigachat_plus = gr.Textbox(label="Адаптированное сообщение 3", lines=3, interactive=False) adapted_output_text_gpt4o = gr.Textbox(label="Адаптированное сообщение 4", lines=3, interactive=False) adapted_output_text_meta_llama_405b = gr.Textbox(label="Адаптированное сообщение 5", lines=3, interactive=False) # Третий ряд: комментарии with gr.Row(): comment_gigachat_pro = gr.Textbox(label="Комментарий к сообщению 1", lines=3) comment_gigachat_lite = gr.Textbox(label="Комментарий к сообщению 2", lines=3) comment_gigachat_plus = gr.Textbox(label="Комментарий к сообщению 3", lines=3) comment_gpt4o = gr.Textbox(label="Комментарий к сообщению 4", lines=3) comment_meta_llama_405b = gr.Textbox(label="Комментарий к сообщению 5", lines=3) # Четвертый ряд: откорректированные сообщения with gr.Row(): corrected_gigachat_pro = gr.Textbox(label="Откорректированное сообщение 1", lines=3) corrected_gigachat_lite = gr.Textbox(label="Откорректированное сообщение 2", lines=3) corrected_gigachat_plus = gr.Textbox(label="Откорректированное сообщение 3", lines=3) corrected_gpt4o = gr.Textbox(label="Откорректированное сообщение 4", lines=3) corrected_meta_llama_405b = gr.Textbox(label="Откорректированное сообщение 5", lines=3) # Пятый ряд: кнопки сохранения with gr.Row(): save_gigachat_pro_btn = gr.Button("Сохранить в базу") save_gigachat_lite_btn = gr.Button("Сохранить в базу") save_gigachat_plus_btn = gr.Button("Сохранить в базу") save_gpt4o_btn = gr.Button("Сохранить в базу") save_meta_llama_405b_btn = gr.Button("Сохранить в базу") gr.Markdown("---") with gr.Row(): validation_display_1 = gr.Markdown() validation_display_2 = gr.Markdown() validation_display_3 = gr.Markdown() validation_display_4 = gr.Markdown() validation_display_5 = gr.Markdown() gr.Markdown("---") # Вкладка 2: Аналитика with gr.TabItem("Аналитика", id=1): with gr.Row(): download_btn = gr.Button("Выгрузить актуальную базу сообщений (~ 45 сек)") download_link = gr.Markdown(value="", label="Ссылка для скачивания") gr.Markdown("---") gr.Markdown("## Аналитика") total_messages_display = gr.Markdown(value="", label="Общее количество сообщений") total_clean_messages_display = gr.Markdown(value="", label="Общее количество сообщений без необходимости корректировок") with gr.Row(): model_pie_chart = gr.Plot(label="График 1") clean_model_pie_chart = gr.Plot(label="График 2") contributor_pie_chart = gr.Plot(label="График 3") date_message_chart = gr.Plot(label="График 4") cumulative_model_chart = gr.Plot(label="График 5") cumulative_clean_model_chart = gr.Plot(label="График 6") cumulative_author_chart = gr.Plot(label="График 7") character_count_chart = gr.Plot(label="График 8") sentence_count_chart = gr.Plot(label="График 9") gr.Markdown("---") with gr.TabItem("Инструкция", id=2): gr.Markdown(""" ### Инструкция Функционал адаптации сообщений под лучший пример — в beta-версии. Если вы сгенерировали адаптированное сообщение, и оно вам понравилось (вы хотите сохранить его в базу), то скопируйте его, пожалуйста, в поле "Откорректированное сообщение" (а поле "Комментарий" оставьте пустым). Когда вы нажимаете адаптировать, то результаты проверок ниже обновляются и приводятся для адаптированных (а не персонализированных) сообщений. """) # Очистка всех полей кроме prompt_display description_input.change( fn=clear_outputs, # Сначала вызываем функцию очистки полей inputs=[ output_text_gigachat_pro, output_text_gigachat_lite, output_text_gigachat_plus, output_text_gpt4o, output_text_meta_llama_405b, personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b, validation_display_1, validation_display_2, validation_display_3, validation_display_4, validation_display_5 ], outputs=[ output_text_gigachat_pro, output_text_gigachat_lite, output_text_gigachat_plus, output_text_gpt4o, output_text_meta_llama_405b, personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b, validation_display_1, validation_display_2, validation_display_3, validation_display_4, validation_display_5 ] ).then( fn=generate_standard_prompt, # После очистки вызываем функцию для обновления промпта inputs=[description_input, advantages_input, key_message_input, approach_input] + selections, outputs=prompt_display # Мгновенно обновляем поле неперсонализированного промпта ).then( fn=update_best_example_prompt, inputs=[description_input] + selections, outputs=best_example_prompt ) # Очистка всех полей кроме prompt_display advantages_input.change( fn=clear_outputs, # Сначала вызываем функцию очистки полей inputs=[ output_text_gigachat_pro, output_text_gigachat_lite, output_text_gigachat_plus, output_text_gpt4o, output_text_meta_llama_405b, personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b, validation_display_1, validation_display_2, validation_display_3, validation_display_4, validation_display_5 ], outputs=[ output_text_gigachat_pro, output_text_gigachat_lite, output_text_gigachat_plus, output_text_gpt4o, output_text_meta_llama_405b, personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b, validation_display_1, validation_display_2, validation_display_3, validation_display_4, validation_display_5 ] ).then( fn=generate_standard_prompt, # После очистки вызываем функцию для обновления промпта inputs=[description_input, advantages_input, key_message_input, approach_input] + selections, outputs=prompt_display # Мгновенно обновляем поле неперсонализированного промпта ) # Очистка всех полей кроме prompt_display key_message_input.change( fn=clear_outputs, # Сначала вызываем функцию очистки полей inputs=[ output_text_gigachat_pro, output_text_gigachat_lite, output_text_gigachat_plus, output_text_gpt4o, output_text_meta_llama_405b, personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b, validation_display_1, validation_display_2, validation_display_3, validation_display_4, validation_display_5 ], outputs=[ output_text_gigachat_pro, output_text_gigachat_lite, output_text_gigachat_plus, output_text_gpt4o, output_text_meta_llama_405b, personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b, validation_display_1, validation_display_2, validation_display_3, validation_display_4, validation_display_5 ] ).then( fn=generate_standard_prompt, # После очистки вызываем функцию для обновления промпта inputs=[description_input, advantages_input, key_message_input, approach_input] + selections, outputs=prompt_display # Мгновенно обновляем поле неперсонализированного промпта ) # Очистка всех полей кроме prompt_display approach_input.change( fn=clear_outputs, # Сначала вызываем функцию очистки полей inputs=[ output_text_gigachat_pro, output_text_gigachat_lite, output_text_gigachat_plus, output_text_gpt4o, output_text_meta_llama_405b, personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b, validation_display_1, validation_display_2, validation_display_3, validation_display_4, validation_display_5 ], outputs=[ output_text_gigachat_pro, output_text_gigachat_lite, output_text_gigachat_plus, output_text_gpt4o, output_text_meta_llama_405b, personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b, validation_display_1, validation_display_2, validation_display_3, validation_display_4, validation_display_5 ] ).then( fn=generate_standard_prompt, # После очистки вызываем функцию для обновления промпта inputs=[description_input, advantages_input, key_message_input, approach_input] + selections, outputs=prompt_display # Мгновенно обновляем поле неперсонализированного промпта ).then( fn=generate_personalization_prompt, # Вызываем генерацию персонализированного промпта после изменения inputs=[key_message_input, approach_input] + selections, # Передаем все нужные параметры outputs=personalization_prompt # Обновляем поле с персонализированным промптом ) # Добавляем обработчики для каждого поля в selections for selection in selections: # Очищаем все персонализированные сообщения и результаты проверок selection.change( fn=clear_outputs, inputs=[ personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b, validation_display_1, validation_display_2, validation_display_3, validation_display_4, validation_display_5], outputs=[ personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b, validation_display_1, validation_display_2, validation_display_3, validation_display_4, validation_display_5 ] ).then( fn=generate_personalization_prompt, # Вызываем генерацию персонализированного промпта после изменения inputs=[key_message_input, approach_input] + selections, # Передаем все нужные параметры outputs=personalization_prompt # Обновляем поле с персонализированным промптом ).then( fn=update_best_example_prompt, inputs=[description_input] + selections, outputs=best_example_prompt ) # Добавление функционала для кнопок submit_btn.click( clear_outputs, inputs=[ personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b, validation_display_1, # Очистка результатов проверок validation_display_2, validation_display_3, validation_display_4, validation_display_5 ], outputs=[ personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b, validation_display_1, # Очистка результатов проверок validation_display_2, validation_display_3, validation_display_4, validation_display_5 ] ) submit_btn.click( generate_messages, inputs=[description_input, advantages_input, key_message_input, approach_input] + selections, outputs=[ prompt_display, output_text_gigachat_pro, output_text_gigachat_lite, output_text_gigachat_plus, output_text_gpt4o, output_text_meta_llama_405b ] ) personalize_btn.click( fn=clear_outputs, inputs=[ personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b ], outputs=[ personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b ] ) personalize_btn.click( fn=personalize_and_save, inputs=[ output_text_gigachat_pro, output_text_gigachat_lite, output_text_gigachat_plus, output_text_gpt4o, output_text_meta_llama_405b, description_input, advantages_input, key_message_input, approach_input, ] + selections, outputs=[ personalization_prompt, personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, validation_display_1, validation_display_2, validation_display_3, validation_display_4, validation_display_5, ] ) best_example_btn.click( fn=adapt_messages_and_perform_checks, inputs=[ description_input, personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, key_message_input, approach_input, ] + selections, outputs=[ adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, validation_display_1, validation_display_2, validation_display_3, validation_display_4, validation_display_5 ] ) # Обработка клика по кнопке восстановления load_btn.click( fn=lambda: load_previous_user_request_from_github(), inputs=[], outputs=[ description_input, # Описание предложения advantages_input, # Преимущества key_message_input, # Ключевое сообщение approach_input, # Подход *selections, # Параметры персонализации (Пол, Поколение и т.д.) ] ).then( fn=clear_outputs, inputs=[ prompt_display, personalization_prompt, # Очищаем personalization_prompt output_text_gigachat_pro, output_text_gigachat_lite, output_text_gigachat_plus, output_text_gpt4o, output_text_meta_llama_405b, personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b, validation_display_1, # Очистка результатов проверок validation_display_2, validation_display_3, validation_display_4, validation_display_5 ], outputs=[ prompt_display, personalization_prompt, # Очищаем personalization_prompt output_text_gigachat_pro, output_text_gigachat_lite, output_text_gigachat_plus, output_text_gpt4o, output_text_meta_llama_405b, personalized_output_text_gigachat_pro, personalized_output_text_gigachat_lite, personalized_output_text_gigachat_plus, personalized_output_text_gpt4o, personalized_output_text_meta_llama_405b, adapted_output_text_gigachat_pro, adapted_output_text_gigachat_lite, adapted_output_text_gigachat_plus, adapted_output_text_gpt4o, adapted_output_text_meta_llama_405b, comment_gigachat_pro, corrected_gigachat_pro, comment_gigachat_lite, corrected_gigachat_lite, comment_gigachat_plus, corrected_gigachat_plus, comment_gpt4o, corrected_gpt4o, comment_meta_llama_405b, corrected_meta_llama_405b, validation_display_1, # Очистка результатов проверок validation_display_2, validation_display_3, validation_display_4, validation_display_5 ] ).then( fn=generate_standard_prompt, # Генерация неперсонализированного промпта на основе загруженных данных inputs=[description_input, advantages_input, key_message_input, approach_input] + selections, outputs=prompt_display # Обновляем поле с неперсонализированным промптом ).then( fn=generate_personalization_prompt, # Генерация персонализированного промпта inputs=[key_message_input, approach_input] + selections, outputs=personalization_prompt # Обновляем поле с персонализированным промптом ) regen_gigachat_pro_btn.click( fn=lambda: ("", "", ""), # Очищаем текст персонализированного сообщения и проверку inputs=[], outputs=[personalized_output_text_gigachat_pro, adapted_output_text_gigachat_pro, validation_display_1] ).then( fn=regen_message_gigachat_pro, inputs=[description_input, advantages_input, key_message_input, approach_input] + selections, outputs=output_text_gigachat_pro ) regen_gigachat_lite_btn.click( fn=lambda: ("", "", ""), # Очищаем текст персонализированного сообщения и проверку inputs=[], outputs=[personalized_output_text_gigachat_lite, adapted_output_text_gigachat_lite, validation_display_2] ).then( fn=regen_message_gigachat_lite, inputs=[description_input, advantages_input, key_message_input, approach_input] + selections, outputs=output_text_gigachat_lite ) regen_gigachat_plus_btn.click( fn=lambda: ("", "", ""), # Очищаем текст персонализированного сообщения и проверку inputs=[], outputs=[personalized_output_text_gigachat_plus, adapted_output_text_gigachat_plus, validation_display_3] ).then( fn=regen_message_gigachat_plus, inputs=[description_input, advantages_input, key_message_input, approach_input] + selections, outputs=output_text_gigachat_plus ) regen_gpt4o_btn.click( fn=lambda: ("", "", ""), # Очищаем текст персонализированного сообщения и проверку inputs=[], outputs=[personalized_output_text_gpt4o, adapted_output_text_gpt4o, validation_display_4] ).then( fn=regen_message_gpt4o, inputs=[description_input, advantages_input, key_message_input, approach_input] + selections, outputs=output_text_gpt4o ) regen_meta_llama_405b_btn.click( fn=lambda: ("", "", ""), # Очищаем текст персонализированного сообщения и проверку inputs=[], outputs=[personalized_output_text_meta_llama_405b, adapted_output_text_meta_llama_405b, validation_display_5] ).then( fn=regen_message_meta_llama_405b, inputs=[description_input, advantages_input, key_message_input, approach_input] + selections, outputs=output_text_meta_llama_405b ) personalize_gigachat_pro_btn.click( personalize_message_gigachat_pro, inputs=[output_text_gigachat_pro, key_message_input, approach_input] + selections, outputs=[personalized_output_text_gigachat_pro, validation_display_1] ).then( fn=lambda: (""), inputs=[], outputs=[adapted_output_text_gigachat_pro] ).then( fn=generate_personalization_prompt, # Вызов генерации промпта inputs=[key_message_input, approach_input] + selections, # Передача нужных данных outputs=personalization_prompt # Вывод в поле с промптом ) personalize_gigachat_lite_btn.click( personalize_message_gigachat_lite, inputs=[output_text_gigachat_lite, key_message_input, approach_input] + selections, outputs=[personalized_output_text_gigachat_lite, validation_display_2] # Поле для проверки ).then( fn=lambda: (""), inputs=[], outputs=[adapted_output_text_gigachat_lite] ).then( fn=generate_personalization_prompt, # Вызов генерации промпта inputs=[key_message_input, approach_input] + selections, # Передача нужных данных outputs=personalization_prompt # Вывод в поле с промптом ) personalize_gigachat_plus_btn.click( personalize_message_gigachat_plus, inputs=[output_text_gigachat_plus, key_message_input, approach_input] + selections, outputs=[personalized_output_text_gigachat_plus, validation_display_3] # Добавляем результат проверки ).then( fn=lambda: (""), inputs=[], outputs=[adapted_output_text_gigachat_plus] ).then( fn=generate_personalization_prompt, # Вызов генерации промпта inputs=[key_message_input, approach_input] + selections, # Передача нужных данных outputs=personalization_prompt # Вывод в поле с промптом ) personalize_gpt4o_btn.click( personalize_message_gpt4o, inputs=[output_text_gpt4o, key_message_input, approach_input] + selections, outputs=[personalized_output_text_gpt4o, validation_display_4] # Добавляем результат проверки ).then( fn=lambda: (""), inputs=[], outputs=[adapted_output_text_gpt4o] ).then( fn=generate_personalization_prompt, # Вызов генерации промпта inputs=[key_message_input, approach_input] + selections, # Передача нужных данных outputs=personalization_prompt # Вывод в поле с промптом ) personalize_meta_llama_405b_btn.click( personalize_message_meta_llama_405b, inputs=[output_text_meta_llama_405b, key_message_input, approach_input] + selections, outputs=[personalized_output_text_meta_llama_405b, validation_display_5] # Добавляем результат проверки ).then( fn=lambda: (""), inputs=[], outputs=[adapted_output_text_meta_llama_405b] ).then( fn=generate_personalization_prompt, # Вызов генерации промпта inputs=[key_message_input, approach_input] + selections, # Передача нужных данных outputs=personalization_prompt # Вывод в поле с промптом ) # Привязка кнопок к функциям сохранения save_gigachat_pro_btn.click( fn=prepare_button_text, inputs=[], outputs=[save_gigachat_pro_btn] ).then( fn=lambda adapted_message, personalized_message, comment, corrected_message, description, advantages, non_personalized_prompt, non_personalized_message, personalization_prompt, gender, generation, psychotype, business_stage, industry, legal_form, key_message, approach: save_both(adapted_message, personalized_message, "GigaChat-Pro", comment, corrected_message, description, advantages, non_personalized_prompt, non_personalized_message, personalization_prompt, gender, generation, psychotype, business_stage, industry, legal_form, key_message, approach), inputs=[ adapted_output_text_gigachat_pro, personalized_output_text_gigachat_pro, comment_gigachat_pro, corrected_gigachat_pro, description_input, advantages_input, prompt_display, output_text_gigachat_pro, personalization_prompt, selections[0], # Пол selections[1], # Поколение selections[2], # Психотип selections[3], # Стадия бизнеса selections[4], # Отрасль selections[5], # ОПФ key_message_input, # Ключевое сообщение approach_input # Подход ], outputs=None ).then( fn=update_button_text, outputs=[save_gigachat_pro_btn] ).then( fn=reset_button_text, outputs=[save_gigachat_pro_btn] ) # Повторяем аналогично для других кнопок: save_gigachat_lite_btn.click( fn=prepare_button_text, inputs=[], outputs=[save_gigachat_lite_btn] ).then( fn=lambda adapted_message, personalized_message, comment, corrected_message, description, advantages, non_personalized_prompt, non_personalized_message, personalization_prompt, gender, generation, psychotype, business_stage, industry, legal_form, key_message, approach: save_both(adapted_message, personalized_message, "GigaChat-Lite", comment, corrected_message, description, advantages, non_personalized_prompt, non_personalized_message, personalization_prompt, gender, generation, psychotype, business_stage, industry, legal_form, key_message, approach), inputs=[ adapted_output_text_gigachat_lite, personalized_output_text_gigachat_lite, comment_gigachat_lite, corrected_gigachat_lite, description_input, advantages_input, prompt_display, output_text_gigachat_lite, personalization_prompt, selections[0], selections[1], selections[2], selections[3], selections[4], selections[5], key_message_input, approach_input ], outputs=None ).then( fn=update_button_text, outputs=[save_gigachat_lite_btn] ).then( fn=reset_button_text, outputs=[save_gigachat_lite_btn] ) save_gigachat_plus_btn.click( fn=prepare_button_text, inputs=[], outputs=[save_gigachat_plus_btn] ).then( fn=lambda adapted_message, personalized_message, comment, corrected_message, description, advantages, non_personalized_prompt, non_personalized_message, personalization_prompt, gender, generation, psychotype, business_stage, industry, legal_form, key_message, approach: save_both(adapted_message, personalized_message, "Vikhr-Nemo-12B", comment, corrected_message, description, advantages, non_personalized_prompt, non_personalized_message, personalization_prompt, gender, generation, psychotype, business_stage, industry, legal_form, key_message, approach), inputs=[ adapted_output_text_gigachat_plus, personalized_output_text_gigachat_plus, comment_gigachat_plus, corrected_gigachat_plus, description_input, advantages_input, prompt_display, output_text_gigachat_plus, personalization_prompt, selections[0], selections[1], selections[2], selections[3], selections[4], selections[5], key_message_input, approach_input ], outputs=None ).then( fn=update_button_text, outputs=[save_gigachat_plus_btn] ).then( fn=reset_button_text, outputs=[save_gigachat_plus_btn] ) save_gpt4o_btn.click( fn=prepare_button_text, inputs=[], outputs=[save_gpt4o_btn] ).then( fn=lambda adapted_message, personalized_message, comment, corrected_message, description, advantages, non_personalized_prompt, non_personalized_message, personalization_prompt, gender, generation, psychotype, business_stage, industry, legal_form, key_message, approach: save_both(adapted_message, personalized_message, "GPT-4o", comment, corrected_message, description, advantages, non_personalized_prompt, non_personalized_message, personalization_prompt, gender, generation, psychotype, business_stage, industry, legal_form, key_message, approach), inputs=[ adapted_output_text_gpt4o, personalized_output_text_gpt4o, comment_gpt4o, corrected_gpt4o, description_input, advantages_input, prompt_display, output_text_gpt4o, personalization_prompt, selections[0], selections[1], selections[2], selections[3], selections[4], selections[5], key_message_input, approach_input ], outputs=None ).then( fn=update_button_text, outputs=[save_gpt4o_btn] ).then( fn=reset_button_text, outputs=[save_gpt4o_btn] ) save_meta_llama_405b_btn.click( fn=prepare_button_text, inputs=[], outputs=[save_meta_llama_405b_btn] ).then( fn=lambda adapted_message, personalized_message, comment, corrected_message, description, advantages, non_personalized_prompt, non_personalized_message, personalization_prompt, gender, generation, psychotype, business_stage, industry, legal_form, key_message, approach: save_both(adapted_message, personalized_message, "Meta-Llama-3.1-405B", comment, corrected_message, description, advantages, non_personalized_prompt, non_personalized_message, personalization_prompt, gender, generation, psychotype, business_stage, industry, legal_form, key_message, approach), inputs=[ adapted_output_text_meta_llama_405b, personalized_output_text_meta_llama_405b, comment_meta_llama_405b, corrected_meta_llama_405b, description_input, advantages_input, prompt_display, output_text_meta_llama_405b, personalization_prompt, selections[0], selections[1], selections[2], selections[3], selections[4], selections[5], key_message_input, approach_input ], outputs=None ).then( fn=update_button_text, outputs=[save_meta_llama_405b_btn] ).then( fn=reset_button_text, outputs=[save_meta_llama_405b_btn] ) # Связываем кнопку с функцией download_btn.click( fn=update_download_link, inputs=[], outputs=[ download_link, total_messages_display, total_clean_messages_display, model_pie_chart, clean_model_pie_chart, contributor_pie_chart, date_message_chart, cumulative_model_chart, cumulative_clean_model_chart, cumulative_author_chart, character_count_chart, sentence_count_chart ] ) demo.launch()