Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -4,97 +4,68 @@ import gradio as gr
|
|
4 |
import re
|
5 |
import json
|
6 |
|
7 |
-
|
8 |
-
|
9 |
-
tokenizer = AutoTokenizer.from_pretrained(
|
10 |
-
"cointegrated/rut5-base-multitask",
|
11 |
-
legacy=False
|
12 |
-
)
|
13 |
-
model = T5ForConditionalGeneration.from_pretrained(
|
14 |
-
"cointegrated/rut5-base-multitask",
|
15 |
-
torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32
|
16 |
-
)
|
17 |
-
return tokenizer, model
|
18 |
|
19 |
-
|
|
|
|
|
|
|
20 |
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
Требования STRICT:
|
28 |
-
1. Title: ровно 55-60 символов, не обрезать слова
|
29 |
-
2. Description: ровно 150-160 символов, не обрезать слова
|
30 |
-
3. Обязательно включи:
|
31 |
-
- Для title: бренд, модель, тип товара
|
32 |
-
- Для description: главные преимущества
|
33 |
-
4. Используй продающий язык с упором на выгоды
|
34 |
-
5. Никаких технических подробностей в title
|
35 |
-
6. Не обрезай слова
|
36 |
|
37 |
-
|
38 |
-
|
|
|
39 |
|
40 |
-
|
41 |
{{"title": "...", "description": "..."}}
|
42 |
"""
|
43 |
-
|
44 |
-
|
45 |
-
with torch.no_grad():
|
46 |
-
outputs = model.generate(
|
47 |
-
**inputs,
|
48 |
-
max_new_tokens=200,
|
49 |
-
num_beams=7,
|
50 |
-
do_sample=False,
|
51 |
-
temperature=0.5,
|
52 |
-
early_stopping=True
|
53 |
-
)
|
54 |
-
|
55 |
-
# Обработка результата
|
56 |
-
result = tokenizer.decode(outputs[0], skip_special_tokens=True)
|
57 |
-
json_match = re.search(r'\{.*\}', result, re.DOTALL)
|
58 |
-
|
59 |
-
if json_match:
|
60 |
-
tags = json.loads(json_match.group())
|
61 |
-
# Проверяем и обрезаем длину
|
62 |
-
return {
|
63 |
-
"title": tags.get("title", "")[:60],
|
64 |
-
"description": tags.get("description", "")[:160]
|
65 |
-
}
|
66 |
|
67 |
-
|
68 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
|
77 |
-
# Интерфейс
|
78 |
-
with gr.Blocks(
|
79 |
-
gr.Markdown("## Генератор
|
80 |
-
|
|
|
81 |
with gr.Row():
|
82 |
-
|
83 |
-
|
84 |
-
label="Введите описание товара",
|
85 |
-
placeholder="Например: Смартфон Samsung Galaxy S23...",
|
86 |
-
lines=5
|
87 |
-
)
|
88 |
-
btn = gr.Button("Сгенерировать", variant="primary")
|
89 |
-
|
90 |
-
with gr.Column():
|
91 |
-
output_tags = gr.JSON(label="Результат")
|
92 |
|
93 |
-
btn.click(
|
94 |
-
fn=generate_meta_tags,
|
95 |
-
inputs=input_desc,
|
96 |
-
outputs=output_tags
|
97 |
-
)
|
98 |
|
99 |
-
|
100 |
-
app.launch(server_name="0.0.0.0", server_port=7860)
|
|
|
4 |
import re
|
5 |
import json
|
6 |
|
7 |
+
tokenizer = AutoTokenizer.from_pretrained("cointegrated/rut5-base-multitask", legacy=False)
|
8 |
+
model = T5ForConditionalGeneration.from_pretrained("cointegrated/rut5-base-multitask")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
+
def smart_truncate(text, max_len):
|
11 |
+
if len(text) <= max_len:
|
12 |
+
return text
|
13 |
+
return text[:text[:max_len+1].rfind(' ')].strip()
|
14 |
|
15 |
+
def generate_meta(description):
|
16 |
+
# Упрощенный промт с примерами
|
17 |
+
prompt = f"""
|
18 |
+
Описание: {description.strip()}
|
19 |
+
|
20 |
+
→ Сгенерируй SEO title (до 60 символов) и description (до 160 символов) в JSON.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
+
Примеры:
|
23 |
+
title: "Аккумулятор Fenix ARB-L18-4000U 18650 - 4000 мАч"
|
24 |
+
description: "Литий-ионный аккумулятор для фонарей Fenix. 3 вида зарядки, защита от перегрева."
|
25 |
|
26 |
+
Вывод ТОЛЬКО как JSON:
|
27 |
{{"title": "...", "description": "..."}}
|
28 |
"""
|
29 |
+
inputs = tokenizer(prompt, return_tensors="pt", max_length=512, truncation=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
|
31 |
+
with torch.no_grad():
|
32 |
+
outputs = model.generate(
|
33 |
+
**inputs,
|
34 |
+
max_new_tokens=200,
|
35 |
+
num_beams=5,
|
36 |
+
early_stopping=True,
|
37 |
+
no_repeat_ngram_size=2
|
38 |
+
)
|
39 |
|
40 |
+
try:
|
41 |
+
result = tokenizer.decode(outputs[0], skip_special_tokens=True)
|
42 |
+
json_data = json.loads(re.search(r'\{.*\}', result, re.DOTALL).group())
|
43 |
+
|
44 |
+
# Принудительная постобработка
|
45 |
+
if "Fenix" not in json_data["title"]:
|
46 |
+
json_data["title"] = f"Аккумулятор Fenix {json_data['title']}"
|
47 |
+
|
48 |
+
return {
|
49 |
+
"title": smart_truncate(json_data["title"], 60),
|
50 |
+
"description": smart_truncate(json_data["description"], 160)
|
51 |
+
}
|
52 |
+
except:
|
53 |
+
# Фоллбэк
|
54 |
+
clean_text = re.sub(r'\s+', ' ', description)
|
55 |
+
return {
|
56 |
+
"title": smart_truncate(f"Аккумулятор Fenix {clean_text}", 60),
|
57 |
+
"description": smart_truncate(clean_text, 160)
|
58 |
+
}
|
59 |
|
60 |
+
# Интерфейс
|
61 |
+
with gr.Blocks() as app:
|
62 |
+
gr.Markdown("## Генератор метатегов (контроль длины)")
|
63 |
+
inp = gr.Textbox(label="Описание товара", lines=7)
|
64 |
+
btn = gr.Button("Сгенерировать")
|
65 |
with gr.Row():
|
66 |
+
out_title = gr.Textbox(label="Title (до 60 символов)", interactive=False)
|
67 |
+
out_desc = gr.Textbox(label="Description (до 160 символов)", lines=3, interactive=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
|
69 |
+
btn.click(generate_meta, inputs=inp, outputs=[out_title, out_desc])
|
|
|
|
|
|
|
|
|
70 |
|
71 |
+
app.launch()
|
|