{"version":3,"file":"AskAI-BM1CBYnc.cjs","sources":["../app/components/askai/AskAI.tsx"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport ReactMarkdown from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\n\ntype AskResponse = {\n  answer: string;\n  answerMarkdown?: string;\n  sources?: Array<{ title?: string; url?: string }>;\n  provider: \"ollama\" | \"tavily\" | \"duckduckgo\" | \"wikipedia\" | \"stackexchange\";\n  model?: string;\n};\n\nexport default function AskAI() {\n  const [question, setQuestion] = useState(\"\");\n  const [loading, setLoading] = useState(false);\n  const [error, setError] = useState<string | null>(null);\n  const [response, setResponse] = useState<AskResponse | null>(null);\n  const abortRef = useRef<AbortController | null>(null);\n  const textAreaRef = useRef<HTMLInputElement | null>(null);\n\n  // Prefill from current selection for quick questions\n  useEffect(() => {\n    function handleSelectionChange() {\n      const sel = window.getSelection?.();\n      if (!sel) return;\n      const value = (sel.toString?.() ?? \"\").trim();\n      if (!value) return;\n      // Only prefill if input is empty to avoid clobbering\n      setQuestion((prev) => (prev ? prev : value));\n    }\n    document.addEventListener(\"selectionchange\", handleSelectionChange);\n    return () =>\n      document.removeEventListener(\"selectionchange\", handleSelectionChange);\n  }, []);\n\n  const canAsk = question.trim().length > 0 && !loading;\n\n  const submit = useCallback(async () => {\n    const q = question.trim();\n    if (!q) return;\n    abortRef.current?.abort();\n    const controller = new AbortController();\n    abortRef.current = controller;\n    setLoading(true);\n    setError(null);\n    setResponse(null);\n    try {\n      const res = await fetch(\"/api/ask\", {\n        method: \"POST\",\n        headers: { \"Content-Type\": \"application/json\" },\n        body: JSON.stringify({ question: q }),\n        signal: controller.signal,\n      });\n      if (!res.ok) {\n        throw new Error(`Request failed: ${res.status}`);\n      }\n      const data = (await res.json()) as AskResponse;\n      setResponse(data);\n    } catch (err) {\n      if (\n        err &&\n        typeof err === \"object\" &&\n        (err as { name?: string }).name === \"AbortError\"\n      )\n        return;\n      setError(\"Unable to get an answer. Please try again.\");\n    } finally {\n      setLoading(false);\n    }\n  }, [question]);\n\n  const onKeyDown = useCallback(\n    (e: React.KeyboardEvent<HTMLInputElement>) => {\n      if (e.key === \"Enter\") {\n        e.preventDefault();\n        if (canAsk) void submit();\n      }\n    },\n    [canAsk, submit]\n  );\n\n  const copyAnswer = useCallback(async () => {\n    const text = response?.answer ?? \"\";\n    if (!text) return;\n    try {\n      await navigator.clipboard.writeText(text);\n    } catch {}\n  }, [response]);\n\n  return (\n    <div className=\" flex h-full w-full flex-col gap-3 p-3\">\n      <div className=\"flex items-center gap-2\">\n        <label htmlFor=\"askai-input\" className=\"sr-only\">\n          Ask a question\n        </label>\n        <input\n          id=\"askai-input\"\n          ref={textAreaRef}\n          type=\"text\"\n          className=\"min-w-[220px] flex-1 rounded-md border border-border bg-surface px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n          placeholder=\"Ask a short question and press Enter…\"\n          value={question}\n          onChange={(e) => setQuestion(e.target.value)}\n          onKeyDown={onKeyDown}\n        />\n        <button\n          className=\"h-9 rounded-md bg-accent px-4 text-sm text-accent-foreground hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n          onClick={() => canAsk && submit()}\n          disabled={!canAsk}\n          aria-disabled={!canAsk}\n        >\n          Ask\n        </button>\n      </div>\n\n      <div className=\"relative flex-1 overflow-auto rounded-lg border border-border bg-background\">\n        {loading ? (\n          <div className=\"p-4 text-sm\">Thinking…</div>\n        ) : error ? (\n          <div className=\"p-4 text-sm text-red-500\">{error}</div>\n        ) : !response ? (\n          <div className=\"p-4 text-sm text-foreground/70\">\n            Type your question above and press Enter to get a quick answer.\n          </div>\n        ) : (\n          <div className=\"p-3 space-y-3\">\n            <div className=\"flex items-center justify-between\">\n              <div className=\"text-xs uppercase tracking-wide text-foreground/60\">\n                Answer\n              </div>\n              <button\n                className=\"h-8 rounded-md bg-surface px-3 text-xs hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent\"\n                onClick={copyAnswer}\n              >\n                Copy\n              </button>\n            </div>\n            <div className=\"text-xs text-foreground/60\">\n              Provider:{\" \"}\n              <span className=\"rounded bg-surface px-2 py-0.5\">\n                {response.provider}\n                {response.model ? ` · ${response.model}` : \"\"}\n              </span>\n            </div>\n            <div className=\"prose prose-invert max-w-none text-sm leading-6\">\n              <ReactMarkdown\n                remarkPlugins={[remarkGfm]}\n                components={{\n                  a: (props) => (\n                    <a\n                      {...props}\n                      className=\"text-accent underline-offset-2 hover:underline\"\n                      target=\"_blank\"\n                      rel=\"noreferrer\"\n                    />\n                  ),\n                  code: (props) => {\n                    const { children, ...rest } = props;\n                    return (\n                      <code\n                        {...rest}\n                        className=\"rounded bg-surface px-1 py-0.5 text-[0.85em]\"\n                      >\n                        {children}\n                      </code>\n                    );\n                  },\n                  pre: (props) => {\n                    const { children, ...rest } = props;\n                    return (\n                      <pre\n                        {...rest}\n                        className=\"rounded-md bg-surface p-3 overflow-auto text-xs leading-5 my-2\"\n                      >\n                        {children}\n                      </pre>\n                    );\n                  },\n                  p: (props) => <p {...props} className=\"my-2\" />,\n                  ul: (props) => (\n                    <ul {...props} className=\"my-2 list-disc pl-5\" />\n                  ),\n                  ol: (props) => (\n                    <ol {...props} className=\"my-2 list-decimal pl-5\" />\n                  ),\n                  h1: (props) => (\n                    <h1 {...props} className=\"text-base font-semibold mt-2\" />\n                  ),\n                  h2: (props) => (\n                    <h2 {...props} className=\"text-sm font-semibold mt-2\" />\n                  ),\n                }}\n              >\n                {response.answerMarkdown ?? response.answer}\n              </ReactMarkdown>\n            </div>\n            {response.sources && response.sources.length > 0 ? (\n              <div className=\"pt-2\">\n                <div className=\"mb-1 text-xs uppercase tracking-wide text-foreground/60\">\n                  Sources\n                </div>\n                <ul className=\"list-disc pl-5 space-y-1 text-xs\">\n                  {response.sources.slice(0, 5).map((s, i) => (\n                    <li key={`src-${i}`}>\n                      {s.url ? (\n                        <a\n                          href={s.url}\n                          target=\"_blank\"\n                          rel=\"noreferrer\"\n                          className=\"text-accent underline-offset-2 hover:underline\"\n                        >\n                          {s.title || s.url}\n                        </a>\n                      ) : (\n                        <span>{s.title}</span>\n                      )}\n                    </li>\n                  ))}\n                </ul>\n              </div>\n            ) : null}\n          </div>\n        )}\n      </div>\n    </div>\n  );\n}\n"],"names":["AskAI","question","setQuestion","useState","loading","setLoading","error","setError","response","setResponse","abortRef","useRef","textAreaRef","useEffect","handleSelectionChange","sel","value","prev","canAsk","submit","useCallback","q","controller","res","data","err","onKeyDown","copyAnswer","text","jsxs","jsx","ReactMarkdown","remarkGfm","props","children","rest","s","i"],"mappings":"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"}