Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -201,12 +201,167 @@ def clean_message(message):
|
|
201 |
message = message[:last_period + 1]
|
202 |
return message
|
203 |
|
204 |
-
def
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
205 |
last_message = ""
|
|
|
206 |
for _ in range(10):
|
207 |
msg = call_model(model_prompt)
|
208 |
msg = correct_dash_usage(msg)
|
209 |
msg = clean_message(msg)
|
|
|
210 |
length = len(msg)
|
211 |
if 160 <= length <= 250:
|
212 |
msg += f"\n\n------\nКоличество знаков: {length}"
|
|
|
201 |
message = message[:last_period + 1]
|
202 |
return message
|
203 |
|
204 |
+
def tokenize_words(text):
|
205 |
+
"""
|
206 |
+
Разбивает текст на слова, игнорируя знаки препинания.
|
207 |
+
"""
|
208 |
+
return re.findall(r'\w+', text, re.UNICODE)
|
209 |
+
|
210 |
+
def normalize(word):
|
211 |
+
"""
|
212 |
+
Возвращает начальную форму слова с помощью pymorphy3.
|
213 |
+
Приводит к нижнему регистру для унификации.
|
214 |
+
"""
|
215 |
+
parsed = morph.parse(word)
|
216 |
+
if parsed:
|
217 |
+
return parsed[0].normal_form.lower()
|
218 |
+
return word.lower()
|
219 |
+
|
220 |
+
def find_word_matches(normalized_msg, normalized_prod):
|
221 |
+
"""
|
222 |
+
Находит индексы начала совпадений названия продукта в нормализованных словах.
|
223 |
+
"""
|
224 |
+
matches = []
|
225 |
+
prod_len = len(normalized_prod)
|
226 |
+
for i in range(len(normalized_msg) - prod_len + 1):
|
227 |
+
window = normalized_msg[i:i+prod_len]
|
228 |
+
if window == normalized_prod:
|
229 |
+
matches.append(i)
|
230 |
+
return matches
|
231 |
+
|
232 |
+
def get_word_positions(message):
|
233 |
+
"""
|
234 |
+
Возвращает список кортежей (слово, start_index, end_index) для каждого слова в сообщении.
|
235 |
+
"""
|
236 |
+
word_positions = []
|
237 |
+
for match in re.finditer(r'\w+', message):
|
238 |
+
word = match.group(0)
|
239 |
+
start = match.start()
|
240 |
+
end = match.end()
|
241 |
+
word_positions.append((word, start, end))
|
242 |
+
return word_positions
|
243 |
+
|
244 |
+
def capitalize_sentences(text):
|
245 |
+
"""
|
246 |
+
Капитализирует первую букву каждого предложения в тексте.
|
247 |
+
Предложения считаются разделенными точками, восклицательными или вопросительными знаками.
|
248 |
+
"""
|
249 |
+
# Разделяем текст на предложения
|
250 |
+
sentence_endings = re.compile(r'([.!?])')
|
251 |
+
parts = sentence_endings.split(text)
|
252 |
+
|
253 |
+
# Объединяем разделенные части и капитализируем первые буквы
|
254 |
+
sentences = []
|
255 |
+
for i in range(0, len(parts)-1, 2):
|
256 |
+
sentence = parts[i].strip()
|
257 |
+
punctuation = parts[i+1]
|
258 |
+
if sentence:
|
259 |
+
sentence = sentence[0].upper() + sentence[1:]
|
260 |
+
sentences.append(sentence + punctuation)
|
261 |
+
|
262 |
+
# Обработка возможного остатка текста без завершающего знака
|
263 |
+
if len(parts) % 2 != 0 and parts[-1].strip():
|
264 |
+
last_sentence = parts[-1].strip()
|
265 |
+
last_sentence = last_sentence[0].upper() + last_sentence[1:]
|
266 |
+
sentences.append(last_sentence)
|
267 |
+
|
268 |
+
# Объединяем обратно в текст
|
269 |
+
return ' '.join(sentences)
|
270 |
+
|
271 |
+
def process_message(message, product_name):
|
272 |
+
"""
|
273 |
+
Обрабатывает сообщение, заменяя название продукта.
|
274 |
+
- Первое слово сохраняется в инфлектированной форме, как в сообщении.
|
275 |
+
- Остальные слова заменяются на оригинальные слова из названия продукта, сохраняя их капитализацию.
|
276 |
+
Возвращает обработанное сообщение.
|
277 |
+
"""
|
278 |
+
# Токенизация сообщения (без пунктуации)
|
279 |
+
message_words = tokenize_words(message)
|
280 |
+
normalized_message = [normalize(word) for word in message_words]
|
281 |
+
|
282 |
+
# Токенизация названия продукта
|
283 |
+
product_words_original = tokenize_words(product_name) # Оригинальные слова с капитализацией
|
284 |
+
normalized_product = [normalize(word) for word in product_words_original]
|
285 |
+
|
286 |
+
# Поиск совпадений
|
287 |
+
matches = find_word_matches(normalized_message, normalized_product)
|
288 |
+
|
289 |
+
if not matches:
|
290 |
+
# Если совпадений нет, вернуть исходное сообщение с капитализацией предложений
|
291 |
+
return capitalize_sentences(message)
|
292 |
+
|
293 |
+
# Получаем позиции всех слов в сообщении
|
294 |
+
word_positions = get_word_positions(message)
|
295 |
+
|
296 |
+
# Обработка каждого совпадения
|
297 |
+
# Для избежания смещения индексов при множественных заменах, обрабатываем с конца
|
298 |
+
matches_sorted = sorted(matches, reverse=True)
|
299 |
+
|
300 |
+
final_message = message
|
301 |
+
|
302 |
+
for match in matches_sorted:
|
303 |
+
# Индексы слов
|
304 |
+
start_word_idx = match
|
305 |
+
end_word_idx = match + len(product_words_original) - 1
|
306 |
+
|
307 |
+
# Проверка, чтобы индексы не выходили за пределы списка
|
308 |
+
if end_word_idx >= len(word_positions):
|
309 |
+
continue # Пропускаем некоррект��ые совпадения
|
310 |
+
|
311 |
+
# Получаем позиции слов
|
312 |
+
start_char = word_positions[start_word_idx][1]
|
313 |
+
end_char = word_positions[end_word_idx][2]
|
314 |
+
|
315 |
+
# Проверяем, есть ли знаки препинания перед совпадением
|
316 |
+
if start_char > 0 and final_message[start_char -1] in ['«', '»', '-', '–', '.', ',', '!', '?', ';', ':']:
|
317 |
+
start_char -=1 # Включаем знак препинания в изменяемую часть
|
318 |
+
|
319 |
+
# Проверяем, есть ли знаки препинания после совпадения
|
320 |
+
if end_char < len(final_message) and final_message[end_char] in ['«', '»', '-', '–', '.', ',', '!', '?', ';', ':']:
|
321 |
+
end_char +=1 # Включаем знак препинания в изменяемую часть
|
322 |
+
|
323 |
+
# Извлечение изменяемой части
|
324 |
+
matched_substring = final_message[start_char:end_char]
|
325 |
+
|
326 |
+
# Извлечение неизменяемой части
|
327 |
+
before = final_message[:start_char]
|
328 |
+
after = final_message[end_char:]
|
329 |
+
|
330 |
+
# Разделяем изменяемую часть на слова
|
331 |
+
words = matched_substring.replace('«', '').replace('»', '').strip().split()
|
332 |
+
|
333 |
+
if len(words) < len(product_words_original):
|
334 |
+
# Несоответствие количества слов, пропускаем замену
|
335 |
+
continue
|
336 |
+
|
337 |
+
# Сохраняем первое слово как есть (инфлектированное)
|
338 |
+
first_word = words[0]
|
339 |
+
|
340 |
+
# Остальные слова берем из оригинального названия продукта
|
341 |
+
replaced_words = [first_word] + product_words_original[1:]
|
342 |
+
|
343 |
+
# Собираем обратно измененную часть
|
344 |
+
processed = ' '.join(replaced_words)
|
345 |
+
|
346 |
+
# Воссоединяем части сообщения
|
347 |
+
final_message = before + processed + after
|
348 |
+
|
349 |
+
# Удаляем лишние пробелы
|
350 |
+
final_message = re.sub(r'\s+', ' ', final_message).strip()
|
351 |
+
|
352 |
+
# Капитализируем предложения
|
353 |
+
final_message = capitalize_sentences(final_message)
|
354 |
+
|
355 |
+
return final_message
|
356 |
+
|
357 |
+
def generate_message_with_retry(model_prompt, product_name):
|
358 |
last_message = ""
|
359 |
+
morph = pymorphy3.MorphAnalyzer()
|
360 |
for _ in range(10):
|
361 |
msg = call_model(model_prompt)
|
362 |
msg = correct_dash_usage(msg)
|
363 |
msg = clean_message(msg)
|
364 |
+
msg = process_message(msg)
|
365 |
length = len(msg)
|
366 |
if 160 <= length <= 250:
|
367 |
msg += f"\n\n------\nКоличество знаков: {length}"
|