mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-03-26 17:51:54 +01:00
New prompt + show quotes on hover (#404)
This commit is contained in:
parent
5977a28f58
commit
6a79ddce37
@ -1,9 +1,13 @@
|
||||
import abc
|
||||
import json
|
||||
from collections.abc import Iterator
|
||||
from copy import copy
|
||||
|
||||
import tiktoken
|
||||
from langchain.schema.messages import AIMessage
|
||||
from langchain.schema.messages import BaseMessage
|
||||
from langchain.schema.messages import HumanMessage
|
||||
from langchain.schema.messages import SystemMessage
|
||||
|
||||
from danswer.chunking.models import InferenceChunk
|
||||
from danswer.direct_qa.interfaces import AnswerQuestionReturn
|
||||
@ -13,11 +17,16 @@ from danswer.direct_qa.interfaces import DanswerAnswerPiece
|
||||
from danswer.direct_qa.interfaces import DanswerQuotes
|
||||
from danswer.direct_qa.interfaces import QAModel
|
||||
from danswer.direct_qa.qa_prompts import JsonChatProcessor
|
||||
from danswer.direct_qa.qa_prompts import SAMPLE_JSON_RESPONSE
|
||||
from danswer.direct_qa.qa_prompts import UNCERTAINTY_PAT
|
||||
from danswer.direct_qa.qa_prompts import WeakModelFreeformProcessor
|
||||
from danswer.direct_qa.qa_utils import process_model_tokens
|
||||
from danswer.llm.llm import LLM
|
||||
from danswer.llm.utils import dict_based_prompt_to_langchain_prompt
|
||||
from danswer.llm.utils import str_prompt_to_langchain_prompt
|
||||
from danswer.utils.logger import setup_logger
|
||||
|
||||
logger = setup_logger()
|
||||
|
||||
|
||||
class QAHandler(abc.ABC):
|
||||
@ -84,6 +93,51 @@ class SimpleChatQAHandler(QAHandler):
|
||||
)
|
||||
|
||||
|
||||
class JsonChatQAUnshackledHandler(QAHandler):
|
||||
def build_prompt(
|
||||
self, query: str, context_chunks: list[InferenceChunk]
|
||||
) -> list[BaseMessage]:
|
||||
prompt: list[BaseMessage] = []
|
||||
|
||||
complete_answer_not_found_response = (
|
||||
'{"answer": "' + UNCERTAINTY_PAT + '", "quotes": []}'
|
||||
)
|
||||
prompt.append(
|
||||
SystemMessage(
|
||||
content=(
|
||||
"Use the following pieces of context to answer the users question. Your response "
|
||||
"should be in JSON format and contain an answer and (optionally) quotes that help support the answer. "
|
||||
"Your responses should be informative, detailed, and consider all possibilities and edge cases. "
|
||||
f"If you don't know the answer, respond with '{complete_answer_not_found_response}'\n"
|
||||
f"Sample response:\n\n{json.dumps(SAMPLE_JSON_RESPONSE)}"
|
||||
)
|
||||
)
|
||||
)
|
||||
prompt.append(
|
||||
SystemMessage(
|
||||
content='Start by reading the following documents and responding with "Acknowledged".'
|
||||
)
|
||||
)
|
||||
for chunk in context_chunks:
|
||||
prompt.append(SystemMessage(content=chunk.content))
|
||||
prompt.append(AIMessage(content="Acknowledged"))
|
||||
|
||||
prompt.append(HumanMessage(content=f"Question: {query}\n"))
|
||||
|
||||
return prompt
|
||||
|
||||
def process_response(
|
||||
self,
|
||||
tokens: Iterator[str],
|
||||
context_chunks: list[InferenceChunk],
|
||||
) -> AnswerQuestionStreamReturn:
|
||||
yield from process_model_tokens(
|
||||
tokens=tokens,
|
||||
context_docs=context_chunks,
|
||||
is_json_prompt=True,
|
||||
)
|
||||
|
||||
|
||||
def _tiktoken_trim_chunks(
|
||||
chunks: list[InferenceChunk], max_chunk_toks: int = 512
|
||||
) -> list[InferenceChunk]:
|
||||
|
@ -29,6 +29,8 @@ import {
|
||||
FiChevronRight,
|
||||
FiChevronLeft,
|
||||
FiAlertTriangle,
|
||||
FiZoomIn,
|
||||
FiCopy,
|
||||
} from "react-icons/fi";
|
||||
import { SiBookstack } from "react-icons/si";
|
||||
import Image from "next/image";
|
||||
@ -227,6 +229,20 @@ export const TriangleAlertIcon = ({
|
||||
return <FiAlertTriangle size={size} className={className} />;
|
||||
};
|
||||
|
||||
export const ZoomInIcon = ({
|
||||
size = 16,
|
||||
className = defaultTailwindCSS,
|
||||
}: IconProps) => {
|
||||
return <FiZoomIn size={size} className={className} />;
|
||||
};
|
||||
|
||||
export const CopyIcon = ({
|
||||
size = 16,
|
||||
className = defaultTailwindCSS,
|
||||
}: IconProps) => {
|
||||
return <FiCopy size={size} className={className} />;
|
||||
};
|
||||
|
||||
//
|
||||
// COMPANY LOGOS
|
||||
//
|
||||
|
@ -1,6 +1,79 @@
|
||||
import { Quote } from "@/lib/search/interfaces";
|
||||
import { ResponseSection, StatusOptions } from "./ResponseSection";
|
||||
import { getSourceIcon } from "@/components/source";
|
||||
import { CheckmarkIcon, CopyIcon } from "@/components/icons/icons";
|
||||
import { useState } from "react";
|
||||
|
||||
const QuoteDisplay = ({ quoteInfo }: { quoteInfo: Quote }) => {
|
||||
const [detailIsOpen, setDetailIsOpen] = useState(false);
|
||||
const [copyClicked, setCopyClicked] = useState(false);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative"
|
||||
onMouseEnter={() => {
|
||||
setDetailIsOpen(true);
|
||||
}}
|
||||
onMouseLeave={() => setDetailIsOpen(false)}
|
||||
>
|
||||
{detailIsOpen && (
|
||||
<div className="absolute top-0 mt-10 pt-2 z-50">
|
||||
<div className="rounded-lg shadow bg-gray-800 w-96 p-3 text-sm leading-relaxed text-gray-200">
|
||||
<div className="flex mt-1">
|
||||
<div>
|
||||
<b>Quote:</b> <i>{quoteInfo.quote}</i>
|
||||
</div>
|
||||
<div
|
||||
className="my-auto ml-1"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(quoteInfo.quote);
|
||||
setCopyClicked(true);
|
||||
setTimeout(() => {
|
||||
setCopyClicked(false);
|
||||
}, 1000);
|
||||
}}
|
||||
>
|
||||
{copyClicked ? (
|
||||
<CheckmarkIcon
|
||||
className="my-auto flex flex-shrink-0 text-gray-500 hover:text-gray-400 cursor-pointer"
|
||||
size={20}
|
||||
/>
|
||||
) : (
|
||||
<CopyIcon
|
||||
className="my-auto flex flex-shrink-0 text-gray-500 hover:text-gray-400 cursor-pointer"
|
||||
size={20}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<button className="text-sm flex w-fit">
|
||||
<a
|
||||
className="flex max-w-[300px] shrink box-border p-2 border border-gray-800 rounded-lg hover:bg-gray-800"
|
||||
href={quoteInfo.link || undefined}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{getSourceIcon(quoteInfo.source_type, 20)}
|
||||
<p className="truncate break-all ml-2 mr-2">
|
||||
{quoteInfo.semantic_identifier || quoteInfo.document_id}
|
||||
</p>
|
||||
</a>
|
||||
|
||||
{/* <div
|
||||
className="cursor-pointer h-full pt-2 pb-2 px-1 border-t border-b border-r border-gray-800 rounded-r-lg hover:bg-gray-800"
|
||||
onClick={() => setDetailIsOpen(!detailIsOpen)}
|
||||
>
|
||||
<div className="pt-0.5 mx-auto h-[20px]">
|
||||
<ZoomInIcon className="text-gray-500" size={14} />
|
||||
</div>
|
||||
</div> */}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface QuotesSectionProps {
|
||||
quotes: Quote[] | null;
|
||||
@ -37,20 +110,9 @@ const QuotesBody = ({ quotes, isFetching }: QuotesSectionProps) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{quotes!.map((quoteInfo) => (
|
||||
<a
|
||||
key={quoteInfo.document_id}
|
||||
className="p-2 mr-1 border border-gray-800 rounded-lg text-sm flex max-w-[280px] hover:bg-gray-800 w-fit"
|
||||
href={quoteInfo.link || undefined}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{getSourceIcon(quoteInfo.source_type, 20)}
|
||||
<p className="truncate break-all ml-2 mr-1">
|
||||
{quoteInfo.semantic_identifier || quoteInfo.document_id}
|
||||
</p>
|
||||
</a>
|
||||
<QuoteDisplay quoteInfo={quoteInfo} key={quoteInfo.document_id} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user