Commit 867bda9d authored by Kantz's avatar Kantz
Browse files

tip und Lösungsbutton zum Feedbackmode hinzugefügt

parent 6c2341ba
...@@ -20,6 +20,10 @@ class ContextRequest(BaseModel): ...@@ -20,6 +20,10 @@ class ContextRequest(BaseModel):
draft: Optional[str] = None draft: Optional[str] = None
class DraftRequest(BaseModel):
draft: str = Field(..., min_length=1)
@router.post("/api/context/retrieval") @router.post("/api/context/retrieval")
def get_retrieval_context(request: ContextRequest) -> List[dict]: def get_retrieval_context(request: ContextRequest) -> List[dict]:
if not request or not request.messages: if not request or not request.messages:
...@@ -35,3 +39,14 @@ def get_retrieval_context(request: ContextRequest) -> List[dict]: ...@@ -35,3 +39,14 @@ def get_retrieval_context(request: ContextRequest) -> List[dict]:
if not sources: if not sources:
return [] return []
return [source.model_dump() for source in sources] return [source.model_dump() for source in sources]
@router.post("/api/context/solution")
def get_context_solution(request: DraftRequest) -> dict[str, str]:
sheet = context_store.load_sheet(request.draft)
if not sheet:
raise HTTPException(status_code=404, detail="context sheet not found")
return {
"solution": context_store.context_store_new.get_solution(sheet),
}
...@@ -9,6 +9,8 @@ type ChatWindowProps = { ...@@ -9,6 +9,8 @@ type ChatWindowProps = {
draft: string; draft: string;
onDraftChange: (value: string) => void; onDraftChange: (value: string) => void;
onSend: () => void; onSend: () => void;
onTip?: () => void;
onRevealSolution?: () => void;
isSending?: boolean; isSending?: boolean;
onHistoryNavigate?: (direction: "older" | "newer") => boolean; onHistoryNavigate?: (direction: "older" | "newer") => boolean;
onToggleCanvas?: () => void; onToggleCanvas?: () => void;
...@@ -23,6 +25,8 @@ export default function ChatWindow({ ...@@ -23,6 +25,8 @@ export default function ChatWindow({
draft, draft,
onDraftChange, onDraftChange,
onSend, onSend,
onTip,
onRevealSolution,
isSending = false, isSending = false,
onHistoryNavigate, onHistoryNavigate,
onToggleCanvas, onToggleCanvas,
...@@ -44,6 +48,8 @@ export default function ChatWindow({ ...@@ -44,6 +48,8 @@ export default function ChatWindow({
value={draft} value={draft}
onChange={onDraftChange} onChange={onDraftChange}
onSend={onSend} onSend={onSend}
onTip={onTip}
onRevealSolution={onRevealSolution}
isSending={isSending} isSending={isSending}
onHistoryNavigate={onHistoryNavigate} onHistoryNavigate={onHistoryNavigate}
onToggleCanvas={onToggleCanvas} onToggleCanvas={onToggleCanvas}
......
...@@ -6,6 +6,8 @@ type MessageInputProps = { ...@@ -6,6 +6,8 @@ type MessageInputProps = {
value: string; value: string;
onChange: (value: string) => void; onChange: (value: string) => void;
onSend: () => void; onSend: () => void;
onTip?: () => void;
onRevealSolution?: () => void;
isSending?: boolean; isSending?: boolean;
onHistoryNavigate?: (direction: "older" | "newer") => boolean; onHistoryNavigate?: (direction: "older" | "newer") => boolean;
onToggleCanvas?: () => void; onToggleCanvas?: () => void;
...@@ -16,6 +18,8 @@ export default function MessageInput({ ...@@ -16,6 +18,8 @@ export default function MessageInput({
value, value,
onChange, onChange,
onSend, onSend,
onTip,
onRevealSolution,
isSending = false, isSending = false,
onHistoryNavigate, onHistoryNavigate,
onToggleCanvas, onToggleCanvas,
...@@ -89,6 +93,30 @@ export default function MessageInput({ ...@@ -89,6 +93,30 @@ export default function MessageInput({
className="canvas-upload-input" className="canvas-upload-input"
onChange={handleUploadChange} onChange={handleUploadChange}
/> />
{onTip ? (
<button
className="btn"
type="button"
onClick={onTip}
disabled={isSending}
aria-label={t("tip")}
title={t("tip")}
>
{t("tip")}
</button>
) : null}
{onRevealSolution ? (
<button
className="btn"
type="button"
onClick={onRevealSolution}
disabled={isSending}
aria-label={t("revealSolution")}
title={t("revealSolution")}
>
{t("revealSolution")}
</button>
) : null}
<button <button
className="btn primary" className="btn primary"
type="button" type="button"
......
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
inspect: "Inspect", inspect: "Inspect",
cite: "Cite", cite: "Cite",
draw: "Draw", draw: "Draw",
tip: "Tip",
revealSolution: "Solution",
send: "Send", send: "Send",
roleUser: "user", roleUser: "user",
roleAssistant: "assistant", roleAssistant: "assistant",
...@@ -57,6 +59,7 @@ ...@@ -57,6 +59,7 @@
failedLoadTasks: "Could not load tasks.", failedLoadTasks: "Could not load tasks.",
failedLoadOrchestratorConfig: "Could not load orchestrator config. Fallback mode active.", failedLoadOrchestratorConfig: "Could not load orchestrator config. Fallback mode active.",
chatRequestFailed: "The chat request failed. Please check backend logs.", chatRequestFailed: "The chat request failed. Please check backend logs.",
noStoredSolution: "No stored solution is available for this task yet.",
retrievalFailed: "Source retrieval failed. Please check backend logs.", retrievalFailed: "Source retrieval failed. Please check backend logs.",
failedLoadSavedChats: "Could not load saved chats.", failedLoadSavedChats: "Could not load saved chats.",
failedLoadSelectedChat: "Could not load the selected chat.", failedLoadSelectedChat: "Could not load the selected chat.",
...@@ -137,6 +140,8 @@ ...@@ -137,6 +140,8 @@
inspect: "Ansehen", inspect: "Ansehen",
cite: "Zitieren", cite: "Zitieren",
draw: "Zeichnen", draw: "Zeichnen",
tip: "Tip",
revealSolution: "Lösung",
send: "Senden", send: "Senden",
roleUser: "nutzer", roleUser: "nutzer",
roleAssistant: "assistent", roleAssistant: "assistent",
...@@ -157,6 +162,8 @@ ...@@ -157,6 +162,8 @@
"Orchestrator-Konfiguration konnte nicht geladen werden. Fallback-Modus aktiv.", "Orchestrator-Konfiguration konnte nicht geladen werden. Fallback-Modus aktiv.",
chatRequestFailed: chatRequestFailed:
"Da ist wohl die Chat-Anfrage fehlgeschlagen. Gib gerne deinem Dozenten bescheid. In vielen Fällen hilft es die Seite neu zu laden.", "Da ist wohl die Chat-Anfrage fehlgeschlagen. Gib gerne deinem Dozenten bescheid. In vielen Fällen hilft es die Seite neu zu laden.",
noStoredSolution:
"Für diese Aufgabe ist aktuell keine gespeicherte Lösung verfügbar.",
retrievalFailed: retrievalFailed:
"Da ist wohl der Quellenabruf fehlgeschlagen. Gib gerne deinem Dozenten bescheid. In vielen Fällen hilft es die Seite neu zu laden.", "Da ist wohl der Quellenabruf fehlgeschlagen. Gib gerne deinem Dozenten bescheid. In vielen Fällen hilft es die Seite neu zu laden.",
failedLoadSavedChats: "Gespeicherte Chats konnten nicht geladen werden.", failedLoadSavedChats: "Gespeicherte Chats konnten nicht geladen werden.",
......
...@@ -619,12 +619,29 @@ export default function ChatPage() { ...@@ -619,12 +619,29 @@ export default function ChatPage() {
return true; return true;
}; };
const handleSend = async () => { const appendAssistantMessage = (text: string) => {
setMessages((prev) => [
...prev,
{
id: `m-${Date.now()}-assistant`,
role: "assistant",
text,
},
]);
};
const sendMessage = async ({
text,
clearDraft,
}: {
text: string;
clearDraft: boolean;
}) => {
if (isSending) { if (isSending) {
return; return;
} }
const trimmed = draft.trim(); const trimmed = text.trim();
if (!trimmed) { if (!trimmed) {
return; return;
} }
...@@ -636,8 +653,10 @@ export default function ChatPage() { ...@@ -636,8 +653,10 @@ export default function ChatPage() {
}; };
setMessages((prev) => [...prev, userMessage]); setMessages((prev) => [...prev, userMessage]);
setDraft(""); if (clearDraft) {
resetDraftHistoryNavigation(); setDraft("");
resetDraftHistoryNavigation();
}
setIsSending(true); setIsSending(true);
setRetrievalLoading(true); setRetrievalLoading(true);
...@@ -685,25 +704,11 @@ export default function ChatPage() { ...@@ -685,25 +704,11 @@ export default function ChatPage() {
const payload: { reply?: string } = await response.json(); const payload: { reply?: string } = await response.json();
const reply = payload.reply; const reply = payload.reply;
if (typeof reply === "string" && reply.length > 0) { if (typeof reply === "string" && reply.length > 0) {
setMessages((prev) => [ appendAssistantMessage(reply);
...prev,
{
id: `m-${Date.now()}-assistant`,
role: "assistant",
text: reply,
},
]);
} }
chatRequestSucceeded = true; chatRequestSucceeded = true;
} catch (error) { } catch (error) {
setMessages((prev) => [ appendAssistantMessage(t("chatRequestFailed"));
...prev,
{
id: `m-${Date.now()}-assistant`,
role: "assistant",
text: t("chatRequestFailed"),
},
]);
setRetrievalError(t("retrievalFailed")); setRetrievalError(t("retrievalFailed"));
void error; void error;
} finally { } finally {
...@@ -747,6 +752,57 @@ export default function ChatPage() { ...@@ -747,6 +752,57 @@ export default function ChatPage() {
setRetrievalLoading(false); setRetrievalLoading(false);
}; };
const handleSend = async () => {
await sendMessage({
text: draft,
clearDraft: true,
});
};
const handleFeedbackTip = async () => {
if (selectedOrchestrator !== "feedback") {
return;
}
await sendMessage({
text: "Gib mir einen Hinweis zum nächsten Schritt",
clearDraft: false,
});
};
const handleRevealSolution = async () => {
if (selectedOrchestrator !== "feedback" || isSending) {
return;
}
setIsSending(true);
try {
const response = await fetch(`/api/context/solution`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ draft: chatSessionId }),
});
if (response.status === 404) {
appendAssistantMessage(t("noStoredSolution"));
return;
}
if (!response.ok) {
throw new Error(`Solution failed: ${response.status}`);
}
const payload: { solution?: string } = await response.json();
const solution = typeof payload.solution === "string" ? payload.solution.trim() : "";
appendAssistantMessage(solution || t("noStoredSolution"));
} catch (error) {
appendAssistantMessage(t("chatRequestFailed"));
void error;
} finally {
setIsSending(false);
}
};
const handleToggleCanvas = () => { const handleToggleCanvas = () => {
setIsCanvasVisible((prev) => !prev); setIsCanvasVisible((prev) => !prev);
}; };
...@@ -1181,6 +1237,10 @@ export default function ChatPage() { ...@@ -1181,6 +1237,10 @@ export default function ChatPage() {
draft={draft} draft={draft}
onDraftChange={handleDraftChange} onDraftChange={handleDraftChange}
onSend={handleSend} onSend={handleSend}
onTip={selectedOrchestrator === "feedback" ? handleFeedbackTip : undefined}
onRevealSolution={
selectedOrchestrator === "feedback" ? handleRevealSolution : undefined
}
isSending={isSending} isSending={isSending}
onHistoryNavigate={handleHistoryNavigate} onHistoryNavigate={handleHistoryNavigate}
onToggleCanvas={handleToggleCanvas} onToggleCanvas={handleToggleCanvas}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment