Spaces:
Runtime error
Runtime error
Add mode selection for query submission and update streaming logic
Browse files- backend/api.py +17 -3
- frontend/app/page.tsx +29 -10
- frontend/components/QuestionInput.tsx +1 -1
- frontend/hooks/useQueryStream.ts +7 -2
backend/api.py
CHANGED
|
@@ -58,6 +58,8 @@ app.add_middleware(
|
|
| 58 |
# ---------------------------------------------------------------------------
|
| 59 |
class QueryRequest(BaseModel):
|
| 60 |
question: str
|
|
|
|
|
|
|
| 61 |
|
| 62 |
|
| 63 |
# ---------------------------------------------------------------------------
|
|
@@ -482,7 +484,10 @@ async def _generate_followup_questions(
|
|
| 482 |
# ---------------------------------------------------------------------------
|
| 483 |
# Core streaming generator
|
| 484 |
# ---------------------------------------------------------------------------
|
| 485 |
-
async def _stream_pipeline(
|
|
|
|
|
|
|
|
|
|
| 486 |
rag = None
|
| 487 |
try:
|
| 488 |
# ββ Stage: Intent Router ββββββββββββββββββββββββββββββββββββββββββ
|
|
@@ -530,8 +535,17 @@ async def _stream_pipeline(question: str) -> AsyncGenerator[str, None]:
|
|
| 530 |
)
|
| 531 |
|
| 532 |
# ββ Stage: Retrieval (with retries, data only β no LLM) ββββββββββ
|
| 533 |
-
|
| 534 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 535 |
selected_data: dict[str, Any] | None = None
|
| 536 |
references: list[dict[str, str]] = []
|
| 537 |
chunks: list[dict[str, Any]] = []
|
|
|
|
| 58 |
# ---------------------------------------------------------------------------
|
| 59 |
class QueryRequest(BaseModel):
|
| 60 |
question: str
|
| 61 |
+
# Optional override for retrieval mode (naive, local, global, hybrid, mix)
|
| 62 |
+
mode: str | None = None
|
| 63 |
|
| 64 |
|
| 65 |
# ---------------------------------------------------------------------------
|
|
|
|
| 484 |
# ---------------------------------------------------------------------------
|
| 485 |
# Core streaming generator
|
| 486 |
# ---------------------------------------------------------------------------
|
| 487 |
+
async def _stream_pipeline(
|
| 488 |
+
question: str,
|
| 489 |
+
mode_override: str | None = None,
|
| 490 |
+
) -> AsyncGenerator[str, None]:
|
| 491 |
rag = None
|
| 492 |
try:
|
| 493 |
# ββ Stage: Intent Router ββββββββββββββββββββββββββββββββββββββββββ
|
|
|
|
| 535 |
)
|
| 536 |
|
| 537 |
# ββ Stage: Retrieval (with retries, data only β no LLM) ββββββββββ
|
| 538 |
+
selected_mode = (
|
| 539 |
+
mode_override or os.getenv("CHAINLIT_MODE") or "hybrid"
|
| 540 |
+
).lower()
|
| 541 |
+
if selected_mode not in {"naive", "local", "global", "hybrid", "mix"}:
|
| 542 |
+
selected_mode = "hybrid"
|
| 543 |
+
|
| 544 |
+
attempt_modes = (
|
| 545 |
+
[selected_mode, selected_mode, "mix"]
|
| 546 |
+
if selected_mode != "mix"
|
| 547 |
+
else ["mix", "mix"]
|
| 548 |
+
)
|
| 549 |
selected_data: dict[str, Any] | None = None
|
| 550 |
references: list[dict[str, str]] = []
|
| 551 |
chunks: list[dict[str, Any]] = []
|
frontend/app/page.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
"use client";
|
| 2 |
|
|
|
|
| 3 |
import dynamic from "next/dynamic";
|
| 4 |
import ReactMarkdown from "react-markdown";
|
| 5 |
import QuestionInput from "@/components/QuestionInput";
|
|
@@ -10,10 +11,11 @@ const FlowCanvas = dynamic(() => import("@/components/FlowCanvas"), { ssr: false
|
|
| 10 |
|
| 11 |
export default function Home() {
|
| 12 |
const { nodes, answer, streamingAnswer, streaming, error, submit, reset, followUps } = useQueryStream();
|
|
|
|
| 13 |
|
| 14 |
const handleSubmit = (question: string) => {
|
| 15 |
reset();
|
| 16 |
-
submit(question);
|
| 17 |
};
|
| 18 |
|
| 19 |
const hasStarted = nodes.some((n) => n.status !== "idle");
|
|
@@ -31,15 +33,32 @@ export default function Home() {
|
|
| 31 |
</p>
|
| 32 |
</div>
|
| 33 |
</div>
|
| 34 |
-
|
| 35 |
-
<
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
</header>
|
| 44 |
|
| 45 |
{/* ββ Body ββ */}
|
|
|
|
| 1 |
"use client";
|
| 2 |
|
| 3 |
+
import { useState } from "react";
|
| 4 |
import dynamic from "next/dynamic";
|
| 5 |
import ReactMarkdown from "react-markdown";
|
| 6 |
import QuestionInput from "@/components/QuestionInput";
|
|
|
|
| 11 |
|
| 12 |
export default function Home() {
|
| 13 |
const { nodes, answer, streamingAnswer, streaming, error, submit, reset, followUps } = useQueryStream();
|
| 14 |
+
const [mode, setMode] = useState<string>("hybrid");
|
| 15 |
|
| 16 |
const handleSubmit = (question: string) => {
|
| 17 |
reset();
|
| 18 |
+
submit(question, mode);
|
| 19 |
};
|
| 20 |
|
| 21 |
const hasStarted = nodes.some((n) => n.status !== "idle");
|
|
|
|
| 33 |
</p>
|
| 34 |
</div>
|
| 35 |
</div>
|
| 36 |
+
<div className="flex items-center gap-3">
|
| 37 |
+
<div className="flex items-center gap-1.5 text-[11px] text-zinc-500">
|
| 38 |
+
<span>Mode</span>
|
| 39 |
+
<select
|
| 40 |
+
value={mode}
|
| 41 |
+
onChange={(e) => setMode(e.target.value)}
|
| 42 |
+
disabled={streaming}
|
| 43 |
+
className="bg-zinc-900 border border-zinc-700 rounded-md px-2 py-1 text-[11px] text-zinc-200 focus:outline-none focus:border-indigo-500 disabled:opacity-40"
|
| 44 |
+
>
|
| 45 |
+
<option value="naive">naive</option>
|
| 46 |
+
<option value="local">local</option>
|
| 47 |
+
<option value="global">global</option>
|
| 48 |
+
<option value="hybrid">hybrid</option>
|
| 49 |
+
<option value="mix">mix</option>
|
| 50 |
+
</select>
|
| 51 |
+
</div>
|
| 52 |
+
{hasStarted && (
|
| 53 |
+
<button
|
| 54 |
+
onClick={reset}
|
| 55 |
+
disabled={streaming}
|
| 56 |
+
className="text-xs px-3 py-1.5 rounded-lg border border-zinc-700 text-zinc-400 hover:text-zinc-200 hover:border-zinc-500 transition-colors disabled:opacity-40"
|
| 57 |
+
>
|
| 58 |
+
Reset
|
| 59 |
+
</button>
|
| 60 |
+
)}
|
| 61 |
+
</div>
|
| 62 |
</header>
|
| 63 |
|
| 64 |
{/* ββ Body ββ */}
|
frontend/components/QuestionInput.tsx
CHANGED
|
@@ -59,7 +59,7 @@ export default function QuestionInput({ onSubmit, disabled }: QuestionInputProps
|
|
| 59 |
/>
|
| 60 |
<button
|
| 61 |
onClick={handleSubmit}
|
| 62 |
-
disabled={disabled
|
| 63 |
className="
|
| 64 |
flex-shrink-0 h-12 px-5 rounded-xl text-sm font-semibold
|
| 65 |
bg-indigo-600 hover:bg-indigo-500 active:bg-indigo-700
|
|
|
|
| 59 |
/>
|
| 60 |
<button
|
| 61 |
onClick={handleSubmit}
|
| 62 |
+
disabled={disabled}
|
| 63 |
className="
|
| 64 |
flex-shrink-0 h-12 px-5 rounded-xl text-sm font-semibold
|
| 65 |
bg-indigo-600 hover:bg-indigo-500 active:bg-indigo-700
|
frontend/hooks/useQueryStream.ts
CHANGED
|
@@ -46,7 +46,7 @@ export function useQueryStream() {
|
|
| 46 |
}, []);
|
| 47 |
|
| 48 |
const submit = useCallback(
|
| 49 |
-
async (question: string) => {
|
| 50 |
// Cancel any in-flight request
|
| 51 |
abortRef.current?.abort();
|
| 52 |
abortRef.current = new AbortController();
|
|
@@ -55,10 +55,15 @@ export function useQueryStream() {
|
|
| 55 |
setStreaming(true);
|
| 56 |
|
| 57 |
try {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
const response = await fetch(`${API_URL}/query`, {
|
| 59 |
method: "POST",
|
| 60 |
headers: { "Content-Type": "application/json" },
|
| 61 |
-
body: JSON.stringify(
|
| 62 |
signal: abortRef.current.signal,
|
| 63 |
});
|
| 64 |
|
|
|
|
| 46 |
}, []);
|
| 47 |
|
| 48 |
const submit = useCallback(
|
| 49 |
+
async (question: string, mode?: string) => {
|
| 50 |
// Cancel any in-flight request
|
| 51 |
abortRef.current?.abort();
|
| 52 |
abortRef.current = new AbortController();
|
|
|
|
| 55 |
setStreaming(true);
|
| 56 |
|
| 57 |
try {
|
| 58 |
+
const payload: Record<string, unknown> = { question };
|
| 59 |
+
if (mode) {
|
| 60 |
+
payload.mode = mode;
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
const response = await fetch(`${API_URL}/query`, {
|
| 64 |
method: "POST",
|
| 65 |
headers: { "Content-Type": "application/json" },
|
| 66 |
+
body: JSON.stringify(payload),
|
| 67 |
signal: abortRef.current.signal,
|
| 68 |
});
|
| 69 |
|