Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -5,15 +5,10 @@ from transformers import pipeline, set_seed
|
|
5 |
import random
|
6 |
import re # Для регулярных выражений (очистка текста)
|
7 |
|
8 |
-
# --- Загрузка моделей ---
|
9 |
-
# 1. Генератор текста (для общего ответа и диалога)
|
10 |
-
# Замените 'distilgpt2' на нужную модель, если используете другую
|
11 |
-
# Попробуйте 'microsoft/DialoGPT-medium' - специально для диалогов (английский)
|
12 |
-
# Или русские аналоги, если найдете подходящие по размеру для CPU
|
13 |
try:
|
14 |
-
# generator = pipeline('text-generation', model='distilgpt2', max_length=100, num_return_sequences=1, truncation=True, pad_token_id=50256)
|
15 |
-
|
16 |
-
generator = pipeline('text-generation', model='sberbank-ai/rugpt3small_based_on_gpt2', max_length=100, num_return_sequences=1, truncation=True, pad_token_id=50256) # Попробуем русскую поменьше
|
17 |
print("Генератор текста загружен.")
|
18 |
GENERATOR_LOADED = True
|
19 |
except Exception as e:
|
@@ -21,11 +16,9 @@ except Exception as e:
|
|
21 |
generator = None
|
22 |
GENERATOR_LOADED = False
|
23 |
|
24 |
-
# 2. Модель для ответов на вопросы (Question Answering)
|
25 |
-
# Используем небольшую мультиязычную модель
|
26 |
try:
|
27 |
-
qa_pipeline = pipeline('question-answering', model='bert-large-uncased-whole-word-masking-finetuned-squad')
|
28 |
-
|
29 |
print("QA модель загружена.")
|
30 |
QA_LOADED = True
|
31 |
except Exception as e:
|
@@ -33,21 +26,42 @@ except Exception as e:
|
|
33 |
qa_pipeline = None
|
34 |
QA_LOADED = False
|
35 |
|
36 |
-
# ---
|
37 |
knowledge_base = {
|
|
|
38 |
"кто ты": "Я Nova, модель Alpha 0.95, работающая на платформе Hugging Face Spaces. Я использую нейросетевые модели для генерации ответов и ответов на вопросы.",
|
39 |
-
"что ты умеешь": "Я могу пытаться поддерживать диалог, отвечать на вопросы по
|
40 |
"как дела": "Как у программы, у меня все по плану! Готова обрабатывать ваши запросы.",
|
41 |
-
"помощь": "Спросите меня о чем-нибудь, или
|
42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
}
|
44 |
|
45 |
-
# --- Функция обработки запроса ---
|
46 |
|
47 |
def respond(message, chat_history):
|
48 |
-
"""
|
49 |
-
Главная функция обработки. Определяет тип запроса и выбирает стратегию ответа.
|
50 |
-
"""
|
51 |
print(f"Получено сообщение: {message}")
|
52 |
user_message_lower = message.lower().strip().replace("?","").replace(".","").replace("!","") # Очищенный ввод для команд
|
53 |
|
@@ -58,28 +72,24 @@ def respond(message, chat_history):
|
|
58 |
chat_history.append((message, bot_response))
|
59 |
return "", chat_history
|
60 |
|
61 |
-
# 2. Попытка ответа на вопрос с помощью QA модели
|
62 |
-
# Очень упрощенная логика: если есть "?" и QA модель загружена
|
63 |
if "?" in message and QA_LOADED and qa_pipeline:
|
64 |
-
# Используем историю чата как контекст (последние сообщения)
|
65 |
context = ""
|
66 |
if chat_history:
|
67 |
-
# Собираем текст из последних N обменов (N=2)
|
68 |
context_parts = []
|
69 |
-
for user_msg, bot_msg in chat_history[-2:]:
|
70 |
context_parts.append(f"Пользователь: {user_msg}")
|
71 |
context_parts.append(f"Бот: {bot_msg}")
|
72 |
context = "\n".join(context_parts)
|
73 |
|
74 |
-
if len(context) > 50: # Нужен минимальный контекст
|
75 |
print("Попытка ответа на вопрос через QA модель...")
|
76 |
-
print(f"Контекст: {context[:200]}...")
|
77 |
print(f"Вопрос: {message}")
|
78 |
try:
|
79 |
qa_result = qa_pipeline(question=message, context=context)
|
80 |
print(f"Результат QA: {qa_result}")
|
81 |
-
|
82 |
-
if qa_result and qa_result['score'] > 0.1: # Порог уверенности (нужно подбирать)
|
83 |
bot_response = qa_result['answer']
|
84 |
chat_history.append((message, bot_response))
|
85 |
print(f"Ответ от QA модели: {bot_response}")
|
@@ -88,62 +98,46 @@ def respond(message, chat_history):
|
|
88 |
print("QA модель не уверена в ответе.")
|
89 |
except Exception as e:
|
90 |
print(f"Ошибка при использовании QA модели: {e}")
|
91 |
-
# Если QA не сработала, переходим к генерации
|
92 |
|
93 |
-
# 3. Генерация ответа с помощью основной модели
|
94 |
if GENERATOR_LOADED and generator:
|
95 |
print("Генерация ответа с помощью основной модели...")
|
96 |
-
# Формируем промпт с историей
|
97 |
prompt_history = []
|
98 |
-
for user_msg, bot_msg in chat_history[-3:]: #
|
99 |
prompt_history.append(f"Пользователь: {user_msg}")
|
100 |
prompt_history.append(f"Бот: {bot_msg}")
|
101 |
prompt_history.append(f"Пользователь: {message}")
|
102 |
-
prompt_history.append("Бот:")
|
103 |
|
104 |
full_prompt = "\n".join(prompt_history)
|
105 |
-
print(f"Промпт для генератора: {full_prompt[-500:]}")
|
106 |
|
107 |
try:
|
108 |
-
# Уменьшаем max_length, если промпт уже длинный
|
109 |
-
# prompt_tokens = len(generator.tokenizer.encode(full_prompt)) # Подсчет токенов может быть медленным
|
110 |
-
# available_tokens = generator.model.config.max_length - prompt_tokens - 10 # Запас
|
111 |
-
# current_max_length = max(10, min(generator.model.config.max_length, prompt_tokens + 50)) # Генерация ~50 токенов
|
112 |
-
# print(f"Макс. длина для генерации: {current_max_length}")
|
113 |
-
|
114 |
generated_output = generator(full_prompt)[0]['generated_text']
|
115 |
-
|
116 |
-
# Очистка ответа
|
117 |
-
# Убираем промпт из начала
|
118 |
bot_response = generated_output
|
|
|
|
|
119 |
if generated_output.startswith(full_prompt):
|
120 |
bot_response = generated_output[len(full_prompt):].strip()
|
121 |
else:
|
122 |
-
# Если промпт не найден в начале (некоторые модели ведут себя иначе)
|
123 |
-
# Попробуем убрать последнее сообщение пользователя
|
124 |
last_user_line = f"Пользователь: {message}\nБот:"
|
125 |
-
if bot_response.strip().startswith(last_user_line.strip()):
|
126 |
bot_response = bot_response.strip()[len(last_user_line.strip()):].strip()
|
127 |
-
# Очень грубый способ убрать возможное эхо промпта
|
128 |
elif len(bot_response) > len(message) and message.lower() in bot_response[:len(message)*2].lower():
|
129 |
parts = bot_response.split('\n')
|
130 |
-
if len(parts)>1:
|
131 |
-
bot_response = '\n'.join(parts[1:]).strip()
|
132 |
-
|
133 |
|
134 |
-
# Дополнительная очистка (убираем возможные "Пользователь:", "Бот:")
|
135 |
bot_response = re.sub(r'^\s*(пользователь|user|бот|bot)\s*[:\-]?\s*', '', bot_response, flags=re.IGNORECASE).strip()
|
136 |
|
137 |
-
if not bot_response or len(bot_response) < 3:
|
138 |
-
bot_response = "Хм, не знаю, что на это ответить..."
|
139 |
print("Сге��ерирован слишком короткий ответ, используется заглушка.")
|
140 |
|
141 |
except Exception as e:
|
142 |
print(f"Ошибка при генерации: {e}")
|
143 |
-
bot_response = f"Упс, произошла ошибка при генерации: {e}"
|
144 |
|
145 |
else:
|
146 |
-
# Если ни одна модель не загружена
|
147 |
bot_response = "К сожалению, мои основные модули сейчас недоступны."
|
148 |
print("Ошибка: Генератор текста не загружен.")
|
149 |
|
@@ -152,36 +146,114 @@ def respond(message, chat_history):
|
|
152 |
return "", chat_history
|
153 |
|
154 |
|
155 |
-
# --- Создание интерфейса Gradio ---
|
156 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
157 |
gr.Markdown(
|
158 |
"""
|
159 |
-
# Nova Alpha 0.95
|
160 |
-
|
161 |
-
|
162 |
-
"""
|
163 |
)
|
164 |
|
165 |
-
chatbot = gr.Chatbot(label="Диалог", height=500)
|
166 |
-
with gr.Row():
|
167 |
msg = gr.Textbox(
|
168 |
label="Ваше сообщение",
|
169 |
-
placeholder="Спросите
|
170 |
-
scale=4
|
171 |
)
|
172 |
-
submit_btn = gr.Button("Отправить", variant="primary", scale=1)
|
173 |
-
clear_btn = gr.Button("Очистить", scale=1)
|
174 |
-
|
175 |
|
176 |
-
# Связываем обработчики:
|
177 |
-
# Отправка по Enter в Textbox
|
178 |
msg.submit(respond, [msg, chatbot], [msg, chatbot])
|
179 |
-
# Отправка по клику на кнопку
|
180 |
submit_btn.click(respond, [msg, chatbot], [msg, chatbot])
|
|
|
181 |
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
# Запуск (важно для Spaces!)
|
186 |
-
demo.queue() # Используем очередь для обработки запросов по одному (лучше для CPU)
|
187 |
-
demo.launch(debug=True) # debug=True покажет логи и ошибки в интерфейсе
|
|
|
5 |
import random
|
6 |
import re # Для регулярных выражений (очистка текста)
|
7 |
|
8 |
+
# --- Загрузка моделей (как в прошлый раз, выберите нужные) ---
|
|
|
|
|
|
|
|
|
9 |
try:
|
10 |
+
# generator = pipeline('text-generation', model='distilgpt2', max_length=100, num_return_sequences=1, truncation=True, pad_token_id=50256)
|
11 |
+
generator = pipeline('text-generation', model='sberbank-ai/rugpt3small_based_on_gpt2', max_length=100, num_return_sequences=1, truncation=True, pad_token_id=50256)
|
|
|
12 |
print("Генератор текста загружен.")
|
13 |
GENERATOR_LOADED = True
|
14 |
except Exception as e:
|
|
|
16 |
generator = None
|
17 |
GENERATOR_LOADED = False
|
18 |
|
|
|
|
|
19 |
try:
|
20 |
+
# qa_pipeline = pipeline('question-answering', model='bert-large-uncased-whole-word-masking-finetuned-squad')
|
21 |
+
qa_pipeline = pipeline('question-answering', model='timpal0l/mdeberta-v3-base-squad2') # Мультиязычная
|
22 |
print("QA модель загружена.")
|
23 |
QA_LOADED = True
|
24 |
except Exception as e:
|
|
|
26 |
qa_pipeline = None
|
27 |
QA_LOADED = False
|
28 |
|
29 |
+
# --- Встроенные знания и команды (РАСШИРЕНО для КОДИНГА) ---
|
30 |
knowledge_base = {
|
31 |
+
# Мета-информация
|
32 |
"кто ты": "Я Nova, модель Alpha 0.95, работающая на платформе Hugging Face Spaces. Я использую нейросетевые модели для генерации ответов и ответов на вопросы.",
|
33 |
+
"что ты умеешь": "Я могу пытаться поддерживать диалог, отвечать на вопросы по контексту, генерировать текст и давать базовую информацию по некоторым темам, включая программирование. Мои знания ограничены, и я не выполняю код.",
|
34 |
"как дела": "Как у программы, у меня все по плану! Готова обрабатывать ваши запросы.",
|
35 |
+
"помощь": "Спросите меня о чем-нибудь, например, 'что такое переменная в программировании?' или 'какие есть циклы?'. Я постараюсь ответить. Также знаю команды: 'кто ты', 'что ты умеешь'.",
|
36 |
+
|
37 |
+
# Основы Программирования
|
38 |
+
"что такое программирование": "Программирование - это процесс написания инструкций (ко��а) для компьютера, чтобы он выполнял определенные задачи. Это как составление очень точного рецепта для машины.",
|
39 |
+
"зачем нужно программирование": "Программирование позволяет создавать программы, веб-сайты, игры, автоматизировать задачи, анализировать данные и многое другое. Оно лежит в основе почти всех современных технологий.",
|
40 |
+
"что такое алгоритм": "Алгоритм - это пошаговая инструкция или набор правил для решения определенной задачи. Например, рецепт приготовления блюда - это алгоритм.",
|
41 |
+
"основные концепции программирования": "Ключевые идеи включают: переменные (хранение данных), типы данных (числа, строки), условные операторы (if/else - если/иначе), циклы (for, while - для повторения действий), функции (для организации кода).",
|
42 |
+
"что такое переменная": "Переменная в программировании - это как именованный контейнер или ячейка памяти, где можно хранить данные (число, текст, и т.д.), чтобы использовать их позже в программе. Например, `age = 30`.",
|
43 |
+
"что такое типы данных": "Типы данных определяют, какого рода информацию может хранить переменная и какие операции с ней можно выполнять. Распространенные типы: целые числа (integer), числа с плавающей точкой (float), строки (string - текст), булевы (boolean - истина/ложь).",
|
44 |
+
"что такое строка": "Строка (string) - это последовательность символов, обычно используемая для представления текста. В большинстве языков строки заключаются в кавычки (одинарные или двойные). Например, \"Привет, мир!\".",
|
45 |
+
"условный оператор if": "Оператор `if` (если) позволяет выполнить блок кода только в том случае, если определенное условие истинно. Часто используется вместе с `else` (иначе) для выполнения другого блока кода, если условие ложно.",
|
46 |
+
"что такое цикл": "Цикл - это конструкция, которая позволяет повторять выполнение блока кода несколько раз. Основные виды: `for` (для), который обычно используется для перебора элементов (например, в списке) или выполнения заданное число раз, и `while` (пока), который выполняется, пока истинно определенное условие.",
|
47 |
+
"цикл for": "Цикл `for` удобен, когда вы знаете, сколько раз нужно повторить действие, или когда нужно пройти по всем элементам коллекции (списка, строки).",
|
48 |
+
"цикл while": "Цикл `while` повторяет блок кода до тех пор, пока заданное условие остается истинным. Важно убедиться, что условие когда-нибудь станет ложным, иначе цикл будет бесконечным.",
|
49 |
+
"что такое функция": "Функция - это именованный блок кода, который выполняет определенную задачу. Функции помогают разбивать сложную программу на мелкие, управляемые части, избегать повторения кода и делать его более читаемым.",
|
50 |
+
"язык программирования": "Язык программирования - это формальный язык, предназначенный для записи компьютерных программ. Популярные языки: Python (хорош для новичков, науки о данных, веб-бэкенда), JavaScript (для веб-фронтенда и бэкенда), Java (для энтерпрайза, Android), C++ (для игр, системного программирования), C# (для Windows, игр на Unity).",
|
51 |
+
"python": "Python - популярный, высокоуровневый язык программирования с простым синтаксисом, подходящий для широкого круга задач: веб-разработка, наука о данных, машинное обучение, автоматизация.",
|
52 |
+
"javascript": "JavaScript (JS) - основной язык для создания интерактивных веб-страниц (фронтенд). Также используется на бэкенде (Node.js) и для мобильных приложений.",
|
53 |
+
"html": "HTML (HyperText Markup Language) - это не язык программирования, а язык разметки. Он используется для определения структуры и содержимого веб-страницы (заголовки, параграфы, картинки, ссылки).",
|
54 |
+
"css": "CSS (Cascading Style Sheets) - язык стилей, используемый для описания внешнего вида документа, написанного на языке разметки (обычно HTML). Определяет цвета, шрифты, отступы, расположение элементов.",
|
55 |
+
"что такое api": "API (Application Programming Interface) - это набор правил и протоколов, который позволяет разным программам 'общаться' друг с другом. Это как меню в ресторане: вы выбираете блюдо (функцию API), и кухня (другая программа) его готовит и отдает вам.",
|
56 |
+
"что такое git": "Git - это распределенная система контроля версий. Она помогает разработчикам отслеживать изменения в коде, возвращаться к предыдущим версиям, работать над проектом совместно и не терять изменения.",
|
57 |
+
"где учиться программировать": "Существует множество ресурсов: интерактивные онлайн-курсы (Codecademy, Coursera, Stepik, Яндекс.Практикум), документация языков, книги, видеоуроки на YouTube, форумы (Stack Overflow), сообщества разработчиков."
|
58 |
+
|
59 |
+
# Добавьте сюда больше вопросов и ответов по кодингу!
|
60 |
}
|
61 |
|
62 |
+
# --- Функция обработки запроса (логика остается той же) ---
|
63 |
|
64 |
def respond(message, chat_history):
|
|
|
|
|
|
|
65 |
print(f"Получено сообщение: {message}")
|
66 |
user_message_lower = message.lower().strip().replace("?","").replace(".","").replace("!","") # Очищенный ввод для команд
|
67 |
|
|
|
72 |
chat_history.append((message, bot_response))
|
73 |
return "", chat_history
|
74 |
|
75 |
+
# 2. Попытка ответа на вопрос с помощью QA модели (упрощенная логика)
|
|
|
76 |
if "?" in message and QA_LOADED and qa_pipeline:
|
|
|
77 |
context = ""
|
78 |
if chat_history:
|
|
|
79 |
context_parts = []
|
80 |
+
for user_msg, bot_msg in chat_history[-2:]: # Последние 2 обмена
|
81 |
context_parts.append(f"Пользователь: {user_msg}")
|
82 |
context_parts.append(f"Бот: {bot_msg}")
|
83 |
context = "\n".join(context_parts)
|
84 |
|
85 |
+
if len(context) > 50: # Нужен минимальный контекст
|
86 |
print("Попытка ответа на вопрос через QA модель...")
|
87 |
+
print(f"Контекст: {context[:200]}...")
|
88 |
print(f"Вопрос: {message}")
|
89 |
try:
|
90 |
qa_result = qa_pipeline(question=message, context=context)
|
91 |
print(f"Результат QA: {qa_result}")
|
92 |
+
if qa_result and qa_result['score'] > 0.15: # Немного повысим порог
|
|
|
93 |
bot_response = qa_result['answer']
|
94 |
chat_history.append((message, bot_response))
|
95 |
print(f"Ответ от QA модели: {bot_response}")
|
|
|
98 |
print("QA модель не уверена в ответе.")
|
99 |
except Exception as e:
|
100 |
print(f"Ошибка при использовании QA модели: {e}")
|
|
|
101 |
|
102 |
+
# 3. Генерация ответа с помощью основной модели
|
103 |
if GENERATOR_LOADED and generator:
|
104 |
print("Генерация ответа с помощью основной модели...")
|
|
|
105 |
prompt_history = []
|
106 |
+
for user_msg, bot_msg in chat_history[-3:]: # Последние 3 обмена
|
107 |
prompt_history.append(f"Пользователь: {user_msg}")
|
108 |
prompt_history.append(f"Бот: {bot_msg}")
|
109 |
prompt_history.append(f"Пользователь: {message}")
|
110 |
+
prompt_history.append("Бот:")
|
111 |
|
112 |
full_prompt = "\n".join(prompt_history)
|
113 |
+
print(f"Промпт для генератора: {full_prompt[-500:]}")
|
114 |
|
115 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
generated_output = generator(full_prompt)[0]['generated_text']
|
|
|
|
|
|
|
117 |
bot_response = generated_output
|
118 |
+
|
119 |
+
# Очистка
|
120 |
if generated_output.startswith(full_prompt):
|
121 |
bot_response = generated_output[len(full_prompt):].strip()
|
122 |
else:
|
|
|
|
|
123 |
last_user_line = f"Пользователь: {message}\nБот:"
|
124 |
+
if bot_response.strip().startswith(last_user_line.strip()):
|
125 |
bot_response = bot_response.strip()[len(last_user_line.strip()):].strip()
|
|
|
126 |
elif len(bot_response) > len(message) and message.lower() in bot_response[:len(message)*2].lower():
|
127 |
parts = bot_response.split('\n')
|
128 |
+
if len(parts)>1: bot_response = '\n'.join(parts[1:]).strip()
|
|
|
|
|
129 |
|
|
|
130 |
bot_response = re.sub(r'^\s*(пользователь|user|бот|bot)\s*[:\-]?\s*', '', bot_response, flags=re.IGNORECASE).strip()
|
131 |
|
132 |
+
if not bot_response or len(bot_response) < 3:
|
133 |
+
bot_response = knowledge_base.get("не найдено", "Хм, не знаю, что на это ответить...") # Используем "не найдено" из базы
|
134 |
print("Сге��ерирован слишком короткий ответ, используется заглушка.")
|
135 |
|
136 |
except Exception as e:
|
137 |
print(f"Ошибка при генерации: {e}")
|
138 |
+
bot_response = knowledge_base.get("ошибка генерации", f"Упс, произошла ошибка при генерации: {e}") # Используем текст ошибки из базы
|
139 |
|
140 |
else:
|
|
|
141 |
bot_response = "К сожалению, мои основные модули сейчас недоступны."
|
142 |
print("Ошибка: Генератор текста не загружен.")
|
143 |
|
|
|
146 |
return "", chat_history
|
147 |
|
148 |
|
149 |
+
# --- Создание интерфейса Gradio с УЛУЧШЕННЫМ CSS ---
|
150 |
+
|
151 |
+
# Определяем CSS стили
|
152 |
+
custom_css = """
|
153 |
+
/* Общий фон */
|
154 |
+
.gradio-container {
|
155 |
+
background: linear-gradient(to bottom right, #e0f7fa, #f1f8e9); /* Приятный градиент */
|
156 |
+
border-radius: 15px;
|
157 |
+
padding: 25px;
|
158 |
+
}
|
159 |
+
|
160 |
+
/* Заголовок */
|
161 |
+
h1 {
|
162 |
+
color: #004d40; /* Темно-бирюзовый */
|
163 |
+
text-align: center;
|
164 |
+
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
165 |
+
margin-bottom: 15px;
|
166 |
+
}
|
167 |
+
|
168 |
+
/* Контейнер чата */
|
169 |
+
#chatbot {
|
170 |
+
background-color: #ffffff; /* Белый фон для сообщений */
|
171 |
+
border-radius: 10px;
|
172 |
+
box-shadow: 0 2px 5px rgba(0,0,0,0.1); /* Легкая тень */
|
173 |
+
border: 1px solid #e0e0e0;
|
174 |
+
}
|
175 |
+
|
176 |
+
/* Сообщения пользователя */
|
177 |
+
#chatbot .user {
|
178 |
+
background-color: #e3f2fd; /* Голубоватый фон */
|
179 |
+
color: #0d47a1; /* Темно-синий текст */
|
180 |
+
border-radius: 15px 15px 0 15px; /* Скругление углов */
|
181 |
+
padding: 10px 15px;
|
182 |
+
margin: 5px;
|
183 |
+
align-self: flex-end; /* Выравнивание справа */
|
184 |
+
max-width: 85%;
|
185 |
+
}
|
186 |
+
|
187 |
+
/* Сообщения бота */
|
188 |
+
#chatbot .bot {
|
189 |
+
background-color: #f1f8e9; /* Светло-зеленоватый фон */
|
190 |
+
color: #33691e; /* Темно-зеленый текст */
|
191 |
+
border-radius: 15px 15px 15px 0; /* Скругление углов */
|
192 |
+
padding: 10px 15px;
|
193 |
+
margin: 5px;
|
194 |
+
align-self: flex-start; /* Выравнивание слева */
|
195 |
+
max-width: 85%;
|
196 |
+
}
|
197 |
+
|
198 |
+
/* Поле ввода текста */
|
199 |
+
textarea {
|
200 |
+
border: 1px solid #b0bec5; /* Сероватая рамка */
|
201 |
+
border-radius: 8px !important; /* !important нужен для переопределения стандартных стилей gradio */
|
202 |
+
padding: 12px !important;
|
203 |
+
background-color: #ffffff;
|
204 |
+
transition: border-color 0.3s ease;
|
205 |
+
}
|
206 |
+
textarea:focus {
|
207 |
+
border-color: #0277bd !important; /* Синяя рамка при фокусе */
|
208 |
+
box-shadow: 0 0 5px rgba(2, 119, 189, 0.3);
|
209 |
+
}
|
210 |
+
|
211 |
+
/* Кнопки */
|
212 |
+
button {
|
213 |
+
border-radius: 8px !important;
|
214 |
+
transition: background-color 0.3s ease, box-shadow 0.3s ease !important;
|
215 |
+
font-weight: 500 !important;
|
216 |
+
}
|
217 |
+
button.primary { /* Основная кнопка Отправить */
|
218 |
+
background: linear-gradient(to right, #007991, #78ffd6) !important; /* Бирюзовый градиент */
|
219 |
+
color: white !important;
|
220 |
+
border: none !important;
|
221 |
+
}
|
222 |
+
button.primary:hover {
|
223 |
+
box-shadow: 0 4px 8px rgba(0, 121, 145, 0.3);
|
224 |
+
background: linear-gradient(to right, #006073, #5fddb8) !important; /* Чуть темнее при наведении */
|
225 |
+
}
|
226 |
+
button.secondary { /* Кнопка Очистить */
|
227 |
+
background-color: #cfd8dc !important; /* Светло-серый */
|
228 |
+
color: #37474f !important;
|
229 |
+
border: 1px solid #b0bec5 !important;
|
230 |
+
}
|
231 |
+
button.secondary:hover {
|
232 |
+
background-color: #b0bec5 !important; /* Темнее при наведении */
|
233 |
+
}
|
234 |
+
"""
|
235 |
+
|
236 |
+
with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo: # Применяем CSS и мягкую тему
|
237 |
gr.Markdown(
|
238 |
"""
|
239 |
+
# 🤖 Nova Alpha 0.95 🎨
|
240 |
+
Улучшенный интерфейс! Задавайте вопросы или команды.
|
241 |
+
""", elem_id="title-markdown" # Можно задать ID для CSS
|
|
|
242 |
)
|
243 |
|
244 |
+
chatbot = gr.Chatbot(label="Диалог", height=500, elem_id="chatbot")
|
245 |
+
with gr.Row():
|
246 |
msg = gr.Textbox(
|
247 |
label="Ваше сообщение",
|
248 |
+
placeholder="Спросите о Python или скажите 'привет'...",
|
249 |
+
scale=4
|
250 |
)
|
251 |
+
submit_btn = gr.Button("Отправить", variant="primary", scale=1)
|
252 |
+
clear_btn = gr.Button("Очистить", variant="secondary", scale=1) # Добавили класс для CSS
|
|
|
253 |
|
|
|
|
|
254 |
msg.submit(respond, [msg, chatbot], [msg, chatbot])
|
|
|
255 |
submit_btn.click(respond, [msg, chatbot], [msg, chatbot])
|
256 |
+
clear_btn.click(lambda: (None, []), None, [msg, chatbot], queue=False)
|
257 |
|
258 |
+
demo.queue()
|
259 |
+
demo.launch(debug=True)
|
|
|
|
|
|
|
|