feat(training): drop info heading and show last training time

This commit is contained in:
admin committed 2026-10-29 20:20:32 +02:00
1 parent 60f41dd675
commit 2fd41d82b9
4 files changed
+46 -12

No files matched your search

+30 -8
View File
@@ -56,6 +56,7 @@ from user_store import (
get_recent_post_history_text,
get_tone_of_voice,
get_training_summary,
get_training_updated_at,
save_training_summary,
init_db,
is_subscribed,
@@ -597,6 +598,7 @@ async def _refresh_training_summary(user_id: int, profile: str, notes: list[str]
if not summary:
return
await asyncio.to_thread(save_training_summary, user_id, summary)
logger.info("Training summary updated for user %s", user_id)
TRAINING_INFO_TITLES = {
@@ -607,7 +609,10 @@ TRAINING_INFO_TITLES = {
}
def training_info_rich_html(summary: dict[str, str]) -> str:
TRAINING_INFO_TIMEZONE = datetime.timezone(datetime.timedelta(hours=2))
def training_info_rich_html(summary: dict[str, str], updated_at: str = "") -> str:
blocks: list[str] = []
for field, title in TRAINING_INFO_TITLES.items():
value = (summary.get(field) or "").strip()
@@ -616,12 +621,26 @@ def training_info_rich_html(summary: dict[str, str]) -> str:
blocks.append(f"<h3>{html.escape(title)}</h3><p>{html.escape(value)}</p>")
if not blocks:
return ""
return (
"<h2>🎓 Что я о тебе поняла</h2>"
+ "".join(blocks)
+ "<p>Это краткая выжимка: для генерации я использую полный профиль и все примеры постов.</p>"
"<p>Дополнить знания можно в любой момент — просто пришли новые посты или сведения.</p>"
)
footer = "<p>Это краткая выжимка: для генерации я использую полный профиль и все примеры постов.</p>"
stamp = training_time_label(updated_at)
if stamp:
footer += f"<p>Последнее обучение: {html.escape(stamp)}.</p>"
footer += "<p>Дополнить знания можно в любой момент — просто пришли новые посты или сведения.</p>"
return "".join(blocks) + footer
def training_time_label(updated_at: str) -> str:
"""Локальная дата и время последнего обучения; '' если время неизвестно."""
raw = (updated_at or "").strip()
if not raw:
return ""
try:
moment = datetime.datetime.fromisoformat(raw.replace("Z", "+00:00"))
except ValueError:
return ""
if moment.tzinfo is None:
moment = moment.replace(tzinfo=datetime.timezone.utc)
return moment.astimezone(TRAINING_INFO_TIMEZONE).strftime("%d.%m.%Y, %H:%M")
async def training_info_command(message: Message, state: FSMContext) -> None:
@@ -644,7 +663,10 @@ async def training_info_command(message: Message, state: FSMContext) -> None:
summary = await asyncio.to_thread(get_training_summary, message.from_user.id)
finally:
await status.finish(None)
rich_html = training_info_rich_html(summary)
rich_html = training_info_rich_html(
summary,
await asyncio.to_thread(get_training_updated_at, message.from_user.id),
)
if not rich_html:
await message.answer(
"🎓 <b>Пока не знаю о тебе почти ничего</b>\n\n"