Drop patient-context prepending and account UI from chat
Personalization context was silently no-op'ing on the first turn of a fresh session in live testing (profile fetch hadn't resolved by the time the request fired), so it could not be relied on. Chat now always sends the user's own text unmodified. Login/profile/admin entry point removed from the header.
This commit is contained in:
@@ -10,8 +10,6 @@ import type {
|
||||
SendMessageResponse,
|
||||
} from "@duoc-thu/shared-types";
|
||||
import { ChatBubble, CitationBeamOverlay, useTheme } from "@duoc-thu/ui";
|
||||
import type { PatientProfile } from "@duoc-thu/shared-types";
|
||||
import { getPatientProfile } from "@duoc-thu/api-client";
|
||||
import { Composer } from "./Composer";
|
||||
import { AnswerFeedback } from "./AnswerFeedback";
|
||||
import {
|
||||
@@ -56,24 +54,6 @@ interface SectionTextResponse {
|
||||
}>;
|
||||
}
|
||||
|
||||
/** Prepends a short, natural Vietnamese clause carrying whatever the saved
|
||||
* profile has (only the fields actually filled in — an empty profile or a
|
||||
* partially-filled one changes nothing it doesn't have data for). Sent on
|
||||
* every turn, not just the first: the understanding model's own multi-turn
|
||||
* merge already treats a repeated fact as a no-op, so there's no need to
|
||||
* track "did we already say this in this conversation" here. */
|
||||
function withPatientContext(userText: string, profile: PatientProfile | null): string {
|
||||
if (!profile) return userText;
|
||||
const parts: string[] = [];
|
||||
if (profile.ageText) parts.push(profile.ageText);
|
||||
if (profile.weightKg != null) parts.push(`${profile.weightKg} kg`);
|
||||
if (profile.renalFunction) parts.push(`thận: ${profile.renalFunction}`);
|
||||
if (profile.hepaticFunction) parts.push(`gan: ${profile.hepaticFunction}`);
|
||||
if (profile.knownAllergies) parts.push(`dị ứng: ${profile.knownAllergies}`);
|
||||
if (parts.length === 0) return userText;
|
||||
return `Bệnh nhân ${parts.join(", ")}. ${userText}`;
|
||||
}
|
||||
|
||||
const MONOGRAPH_DISCLAIMER =
|
||||
"Nội dung nguyên văn được lấy từ Dược thư Quốc gia Việt Nam 2018, phục vụ tra cứu chuyên môn và không thay thế chỉ định của bác sĩ hoặc dược sĩ lâm sàng.";
|
||||
|
||||
@@ -152,30 +132,6 @@ export function ChatPanel({
|
||||
const abortControllerRef = useRef<AbortController | null>(null);
|
||||
const initialQuerySentRef = useRef<number | undefined>(undefined);
|
||||
const stopRequestedRef = useRef(false);
|
||||
// null = anonymous or no saved profile — never touches the outgoing query.
|
||||
// Fetched once; `getPatientProfile()` itself returns null on a 401, so an
|
||||
// anonymous visitor never even attempts an authenticated call more than once.
|
||||
const patientProfileRef = useRef<PatientProfile | null>(null);
|
||||
// Which sessionId has already had the patient-context clause sent. Prepending
|
||||
// on every single turn (the original design) adds "Bệnh nhân X tuổi, Y kg."
|
||||
// noise to queries that have nothing to do with dosing/patient-specific
|
||||
// context — measured live: it pushed a plain ADR-listing question
|
||||
// (unrelated to age/weight) from a correct answerable answer into
|
||||
// evidence_insufficient. `rag/understanding.py`'s multi-turn merge already
|
||||
// carries a stated fact forward, so sending it once per conversation is
|
||||
// enough — this only resets when `sessionId` itself changes.
|
||||
const patientContextSentForSessionRef = useRef<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
getPatientProfile()
|
||||
.then((profile) => {
|
||||
patientProfileRef.current = profile;
|
||||
})
|
||||
.catch(() => {
|
||||
patientProfileRef.current = null;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const scrollToBottom = () => {
|
||||
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||
};
|
||||
@@ -211,22 +167,16 @@ export function ChatPanel({
|
||||
}, 1000);
|
||||
|
||||
try {
|
||||
patientContextSentForSessionRef.current = sessionId;
|
||||
const res = await fetch("/api/chat", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
// Prepends saved patient context on the first turn of this session
|
||||
// only — never to what's shown in the chat bubble above. The LLM
|
||||
// understanding step extracts these fields from free text and
|
||||
// carries them across the conversation (rag/understanding.py), so
|
||||
// repeating them on every later turn only adds noise to queries
|
||||
// that aren't patient-specific (measured: it broke a plain ADR
|
||||
// lookup). See patientContextSentForSessionRef above.
|
||||
content:
|
||||
patientContextSentForSessionRef.current === sessionId
|
||||
? userText
|
||||
: withPatientContext(userText, patientProfileRef.current),
|
||||
// Personalization (prepending saved patient context) removed: it
|
||||
// was silently no-op'ing on the first turn of a fresh session in
|
||||
// practice (profile fetch hadn't resolved yet when the request
|
||||
// fired), so the feature could not be relied on. Always send the
|
||||
// user's own text, unmodified.
|
||||
content: userText,
|
||||
conversationId: sessionId,
|
||||
responseMode,
|
||||
}),
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { Metadata } from "next";
|
||||
import { ThemeProvider, ThemeScript, ThemeSelector, DisclaimerBanner } from "@duoc-thu/ui";
|
||||
import { NavTabs } from "./_components/NavTabs";
|
||||
import { AccountMenu } from "./_components/AccountMenu";
|
||||
import { Pill, ShieldCheck, Cpu } from "lucide-react";
|
||||
import "./globals.css";
|
||||
|
||||
@@ -46,8 +45,6 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
||||
{/* Theme Mode Selector (Auto, Light, Dark, Heavy Glass) */}
|
||||
<ThemeSelector />
|
||||
|
||||
<AccountMenu />
|
||||
|
||||
{/* System Status Pill */}
|
||||
<div className="hidden items-center gap-1.5 rounded-full border border-border-subtle bg-surface-elevated px-3 py-1 text-xs font-semibold text-accent-primary backdrop-blur-md md:flex shadow-sm">
|
||||
<Cpu className="h-3.5 w-3.5 text-accent-primary animate-pulse" />
|
||||
|
||||
Reference in New Issue
Block a user