` ``` код ``` `)———import datetime from pydantic import BaseModel, Field class Filter: """RaumAI v5: Авто-дата + Навигация (V4, V4PRO, RELATED).""" class Valves(BaseModel): admin_email: str = Field(default="admin@builded.info") data_url: str = Field( default="https://data.raumai.de/dashboard/#/nc/gallery/1b055174-ea3a-4a42-a120-ca95fcab0bc1" ) data_pro_url: str = Field( default="https://data.raumai.de/dashboard/#/nc/ph5gloq8zfxkznu/mwdvfrezl1kazg5/vwb5cet0a6af2bje/raumai_v4pro-raumai_v4pro" ) related_url: str = Field(default="https://home.raumai.de/related") max_user_turns_for_button: int = Field(default=1000) def init (self): self.valves = self.Valves() def inlet(self, body: dict, user : dict = None) -> dict: """Внедряем текущую дату сервера перед отправкой запроса в ИИ.""" now = datetime.datetime.now() # Формируем строку даты для Бонна date_str = now.strftime("%A, %d %B %Y, %H:%M") date_prompt = f"[SYSTEM INFO: Today is {date_str}. Location: Germany/Bonn. Use this for all relative date calculations (tomorrow, next month, etc).]\n" messages = body.get("messages", []) if messages: system_msg = next((m for m in messages if m.get("role") == "system"), None) if system_msg: if "SYSTEM INFO: Today is" not in system_msg["content"]: system_msg["content"] = date_prompt + system_msg["content"] else: messages.insert(0, {"role": "system", "content": date_prompt}) body["messages"] = messages return body def outlet(self, body: dict, user : dict = None) -> dict: """Добавляем три навигационные кнопки в ответ ИИ.""" user_email = ((__user__ or {}).get("email") or "").strip().lower() if user_email != (self.valves.admin_email or "").strip().lower(): return body # Бейджи кнопок data_btn = "https://img.shields.io/badge/%F0%9F%93%8A_DATA-V4-007bff?style=for-the-badge" data_pro_btn = "https://img.shields.io/badge/%F0%9F%92%BC_DATA_PRO-V4PRO-004085?style=for-the-badge" related_btn = "https://img.shields.io/badge/%F0%9F%94%97_RELATED-%D0%9F%D0%95%D0%A0%D0%95%D0%99%D0%A2%D0%98-6f42c1?style=for-the-badge" nav_block = f"\n[]({self.valves.data_url}) []({self.valves.data_pro_url}) []({self.valves.related_url})\n\n---\n" def already_has_nav(text: str) -> bool: return isinstance(text, str) and ( self.valves.data_url in text or self.valves.data_pro_url in text ) def prepend_to_str(s: str) -> str: if already_has_nav(s): return s return nav_block + (s or "") messages = body.get("messages") if isinstance(messages, list) and messages: last_msg = messages[-1] if isinstance(last_msg, dict): content = last_msg.get("content", "") if isinstance(content, str): last_msg["content"] = prepend_to_str(content) elif isinstance(content, list): content.insert(0, {"type": "text", "text": nav_block}) last_msg["content"] = content if isinstance(body.get("text"), str): body["text"] = prepend_to_str(body["text"]) return body
Принято, Архитектор. Код получен и проанализирован.
Проблема действительно в том, что движок TTS (озвучка) считывает Markdown-разметку изображений-бейджей как обычный текст. Чтобы это исправить, мы обернем блок навигации в HTML-контейнер с атрибутом `aria-hidden=»true»`. Это стандартное решение: браузер будет отображать кнопки визуально, но вспомогательные технологии (включая экранные дикторы и TTS-модули) будут их игнорировать.
Вот обновленный код вашей функции. Я внес изменения в формирование переменной `nav_block`.
«`python
import datetime
from pydantic import BaseModel, Field
class Filter:
«»»RaumAI v5: Авто-дата + Навигация (V4, V4PRO, RELATED) с подавлением озвучки.»»»
class Valves(BaseModel):
admin_email: str = Field(default=»admin@builded.info»)
data_url: str = Field(
default=»https://data.raumai.de/dashboard/#/nc/gallery/1b055174-ea3a-4a42-a120-ca95fcab0bc1″
)
data_pro_url: str = Field(
default=»https://data.raumai.de/dashboard/#/nc/ph5gloq8zfxkznu/mwdvfrezl1kazg5/vwb5cet0a6af2bje/raumai_v4pro-raumai_v4pro»
)
related_url: str = Field(default=»https://home.raumai.de/related»)
max_user_turns_for_button: int = Field(default=1000)
def __init__(self):
self.valves = self.Valves()
def inlet(self, body: dict, __user__: dict = None) -> dict:
«»»Внедряем текущую дату сервера перед отправкой запроса в ИИ.»»»
now = datetime.datetime.now()
# Формируем строку даты для Бонна
date_str = now.strftime(«%A, %d %B %Y, %H:%M»)
date_prompt = f»[SYSTEM INFO: Today is {date_str}. Location: Germany/Bonn. Use this for all relative date calculations (tomorrow, next month, etc).]\n»
messages = body.get(«messages», [])
if messages:
system_msg = next((m for m in messages if m.get(«role») == «system»), None)
if system_msg:
if «SYSTEM INFO: Today is» not in system_msg[«content»]:
system_msg[«content»] = date_prompt + system_msg[«content»]
else:
messages.insert(0, {«role»: «system», «content»: date_prompt})
body[«messages»] = messages
return body
def outlet(self, body: dict, __user__: dict = None) -> dict:
«»»Добавляем три навигационные кнопки в ответ ИИ, скрытые от озвучки.»»»
user_email = ((__user__ or {}).get(«email») or «»).strip().lower()
if user_email != (self.valves.admin_email or «»).strip().lower():
return body
# Бейджи кнопок
data_btn = «https://img.shields.io/badge/%F0%9F%93%8A_DATA-V4-007bff?style=for-the-badge»
data_pro_btn = «https://img.shields.io/badge/%F0%9F%92%BC_DATA_PRO-V4PRO-004085?style=for-the-badge»
related_btn = «https://img.shields.io/badge/%F0%9F%94%97_RELATED-%D0%9F%D0%95%D0%A0%D0%95%D0%99%D0%A2%D0%98-6f42c1?style=for-the-badge»
# Обертываем кнопки в div с aria-hidden=»true», чтобы TTS их игнорировал
nav_block = (
f’\n
f'[]({self.valves.data_url}) ‘
f'[]({self.valves.data_pro_url}) ‘
f'[]({self.valves.related_url})\n’
f’
\n\n—\n’
)
def already_has_nav(text: str) -> bool:
return isinstance(text, str) and (
self.valves.data_url in text or self.valves.data_pro_url in text
)
def prepend_to_str(s: str) -> str:
if already_has_nav(s):
return s
return nav_block + (s or «»)
messages = body.get(«messages»)
if isinstance(messages, list) and messages:
last_msg = messages[-1]
if isinstance(last_msg, dict):
content = last_msg.get(«content», «»)
if isinstance(content, str):
last_msg[«content»] = prepend_to_str(content)
elif isinstance(content, list):
content.insert(0, {«type»: «text», «text»: nav_block})
last_msg[«content»] = content
if isinstance(body.get(«text»), str):
body[«text»] = prepend_to_str(body[«text»])
return body
«`
### Что изменилось:
1. **`aria-hidden=»true»`**: Теперь весь блок с кнопками находится внутри HTML-тега, который прямо говорит браузеру: «Это декоративный элемент, не читай его вслух».
2. **Форматирование**: Я добавил небольшое смещение `style=»margin-bottom: 10px;»`, чтобы кнопки визуально не «прилипали» к разделительной линии, так как использование HTML-тегов иногда сбрасывает стандартные Markdown-отступы.
3. **Исправлен аргумент `__user__`**: В вашем исходном коде было `user : dict = None`, но Open WebUI часто передает его как `__user__`. Я подправил это для стабильности.
Попробуйте обновить функцию этим кодом. Теперь при включении озвучки она должна начинаться сразу с Вашего текста, пропуская названия кнопок.
Нужно ли нам добавить еще какие-то элементы управления в этот блок?
🤖 | 📅 | 🧠 CTX 24