SPB Git forge

spb/uqo-chat

Public
14commits 1branches 0releases
1.4 MBsize
maindefault branch
17 days agolast push
Python 64.6% TypeScript 33.7% CSS 0.8%

fix(ui): plain-text course excerpts, scroll button clear of composer on mobile

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Simon-Pierre Boucher committed 18 days ago (Sep 6, 2026) parent a783830

2 changed files +11 −2

modified backend/app/tools/search_course.py +10 −1
@@ -2,6 +2,7 @@
2 2
3 3 from __future__ import annotations
4 4
5 +import re
5 6 from typing import Any
6 7
7 8 from pydantic import BaseModel, Field
@@ -12,6 +13,14 @@ from app.rag import retriever
12 13 from app.tools.registry import ToolContext, registry
13 14
14 15
16 +def _excerpt(text: str, limit: int = 280) -> str:
17 + """Plain-text excerpt for the UI card: drop LaTeX delimiters/commands and headings."""
18 + t = re.sub(r"\$\$?(.*?)\$\$?", lambda m: re.sub(r"\\[a-zA-Z]+|[{}]", "", m.group(1)), text, flags=re.S)
19 + t = re.sub(r"^#+\s*", "", t, flags=re.M).replace("**", "")
20 + t = re.sub(r"\s+", " ", t).strip()
21 + return t if len(t) <= limit else t[: limit - 1] + "…"
22 +
23 +
15 24 class SearchCourseArgs(BaseModel):
16 25 query: str = Field(..., min_length=2, max_length=400)
17 26 course: str | None = Field(None, description="IMM1003, IMM1033 ou null pour les deux")
@@ -36,7 +45,7 @@ async def run(args: dict[str, Any], ctx: ToolContext) -> ToolResult:
36 45 sources = [{
37 46 "index": i + 1, "id": h.chunk_id, "course": h.course, "module": h.module,
38 47 "section": h.section, "page": h.page, "url": h.url,
39 − "excerpt": h.content[:280].replace("\n", " "), "score": round(h.score, 3),
48 + "excerpt": _excerpt(h.content), "score": round(h.score, 3),
40 49 } for i, h in enumerate(hits)]
41 50 return ToolResult(
42 51 content=retriever.format_for_model(hits),
modified frontend/src/components/chat/chat-view.tsx +1 −1
@@ -81,7 +81,7 @@ export function ChatView() {
81 81 </div>
82 82 {!atBottom && list.length > 0 && (
83 83 <button onClick={() => { setAtBottom(true); scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight, behavior: 'smooth' }); }}
84 − className="absolute right-4 bottom-[132px] h-10 w-10 rounded-full bg-white border border-neutral-line shadow-card inline-flex items-center justify-center text-uqo-blue" aria-label="Aller en bas">
84 + className="absolute right-4 bottom-[196px] sm:bottom-[150px] h-10 w-10 rounded-full bg-white border border-neutral-line shadow-card inline-flex items-center justify-center text-uqo-blue" aria-label="Aller en bas">
85 85 <ArrowDown size={18} />
86 86 </button>
87 87 )}
88 88