New prompt + show quotes on hover (#404)

This commit is contained in:
Chris Weaver 2023-09-06 01:44:48 -07:00 committed by GitHub
parent 5977a28f58
commit 6a79ddce37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 145 additions and 13 deletions

View File

@ -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]:

View File

@ -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
//

View File

@ -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>
);