Fix layout/styling of the factchecker app

This commit is contained in:
sabaimran
2024-08-02 19:06:01 +05:30
committed by Debanjum Singh Solanky
parent 1bb746aaed
commit 5f8b76c8f2
4 changed files with 144 additions and 137 deletions

View File

@@ -13,6 +13,11 @@ input.factVerification {
font-size: large; font-size: large;
} }
div.factCheckerContainer {
width: 75vw;
margin: auto;
}
input.factVerification:focus { input.factVerification:focus {
outline: none; outline: none;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2); box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
@@ -123,6 +128,12 @@ div.dot2 {
animation-delay: -1.0s; animation-delay: -1.0s;
} }
@media screen and (max-width: 768px) {
div.factCheckerContainer {
width: 95vw;
}
}
@-webkit-keyframes sk-rotate { @-webkit-keyframes sk-rotate {
100% { 100% {
-webkit-transform: rotate(360deg) -webkit-transform: rotate(360deg)

View File

@@ -1,10 +0,0 @@
.factCheckerLayout {
max-width: 70vw;
margin: auto;
}
@media screen and (max-width: 700px) {
.factCheckerLayout {
max-width: 90vw;
}
}

View File

@@ -1,7 +1,4 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
import NavMenu from '../components/navMenu/navMenu';
import styles from './factCheckerLayout.module.css';
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Khoj AI - Fact Checker", title: "Khoj AI - Fact Checker",
@@ -17,8 +14,7 @@ export default function RootLayout({
children: React.ReactNode; children: React.ReactNode;
}>) { }>) {
return ( return (
<div className={styles.factCheckerLayout}> <div>
<NavMenu selected="none" />
{children} {children}
</div> </div>
); );

View File

@@ -19,6 +19,7 @@ import {
CardTitle, CardTitle,
} from "@/components/ui/card" } from "@/components/ui/card"
import Link from 'next/link'; import Link from 'next/link';
import SidePanel from '../components/sidePanel/chatHistorySidePanel';
@@ -76,41 +77,41 @@ async function verifyStatement(
setIsLoading: (loading: boolean) => void, setIsLoading: (loading: boolean) => void,
setInitialResponse: (response: string) => void, setInitialResponse: (response: string) => void,
setInitialReferences: (references: ResponseWithReferences) => void) { setInitialReferences: (references: ResponseWithReferences) => void) {
setIsLoading(true); setIsLoading(true);
// Send a message to the chat server to verify the fact // Send a message to the chat server to verify the fact
let verificationMessage = `${verificationPrecursor} ${message}`; let verificationMessage = `${verificationPrecursor} ${message}`;
const apiURL = `${chatURL}?q=${encodeURIComponent(verificationMessage)}&client=web&stream=true&conversation_id=${conversationId}`; const apiURL = `${chatURL}?q=${encodeURIComponent(verificationMessage)}&client=web&stream=true&conversation_id=${conversationId}`;
try { try {
const response = await fetch(apiURL); const response = await fetch(apiURL);
if (!response.body) throw new Error("No response body found"); if (!response.body) throw new Error("No response body found");
const reader = response.body?.getReader(); const reader = response.body?.getReader();
let decoder = new TextDecoder(); let decoder = new TextDecoder();
let result = ""; let result = "";
while (true) { while (true) {
const { done, value } = await reader.read(); const { done, value } = await reader.read();
if (done) break; if (done) break;
let chunk = decoder.decode(value, { stream: true }); let chunk = decoder.decode(value, { stream: true });
if (chunk.includes("### compiled references:")) { if (chunk.includes("### compiled references:")) {
const references = handleCompiledReferences(chunk, result); const references = handleCompiledReferences(chunk, result);
if (references.response) { if (references.response) {
result = references.response; result = references.response;
setInitialResponse(references.response); setInitialResponse(references.response);
setInitialReferences(references); setInitialReferences(references);
}
} else {
result += chunk;
setInitialResponse(result);
} }
} else {
result += chunk;
setInitialResponse(result);
} }
} catch (error) {
console.error("Error verifying statement: ", error);
} finally {
setIsLoading(false);
} }
} catch (error) {
console.error("Error verifying statement: ", error);
} finally {
setIsLoading(false);
}
} }
@@ -145,7 +146,7 @@ function ReferenceVerification(props: ReferenceVerificationProps) {
setInitialResponse(props.prefilledResponse); setInitialResponse(props.prefilledResponse);
setIsLoading(false); setIsLoading(false);
} else { } else {
verifyStatement(verificationStatement, props.conversationId, setIsLoading, setInitialResponse, () => {}); verifyStatement(verificationStatement, props.conversationId, setIsLoading, setInitialResponse, () => { });
} }
setIsMobileWidth(window.innerWidth < 768); setIsMobileWidth(window.innerWidth < 768);
@@ -454,7 +455,7 @@ export default function FactChecker() {
additionalLink={additionalLink} additionalLink={additionalLink}
setChildReferencesCallback={setChildReferencesCallback} /> setChildReferencesCallback={setChildReferencesCallback} />
); );
}).filter(Boolean); }).filter(Boolean);
}; };
const renderSupplementalReferences = (references: SupplementReferences[]) => { const renderSupplementalReferences = (references: SupplementReferences[]) => {
@@ -489,102 +490,111 @@ export default function FactChecker() {
} }
return ( return (
<div className={styles.factCheckerContainer}> <>
<h1 className={`${styles.response} font-large outline-slate-800 dark:outline-slate-200`}> <div className='relative md:fixed h-full'>
AI Fact Checker <SidePanel
</h1> conversationId={null}
<footer className={`${styles.footer} mt-4`}> uploadedFiles={[]}
This is an experimental AI tool. It may make mistakes. isMobileWidth={isMobileWidth}
</footer> />
{ </div>
initialResponse && initialReferences && childReferences <div className={styles.factCheckerContainer}>
? <h1 className={`${styles.response} pt-8 md:pt-4 font-large outline-slate-800 dark:outline-slate-200`}>
<div className={styles.reportActions}> AI Fact Checker
<Button asChild variant='secondary'> </h1>
<Link href="/factchecker" target="_blank" rel="noopener noreferrer"> <footer className={`${styles.footer} mt-4`}>
Try Another This is an experimental AI tool. It may make mistakes.
</Link> </footer>
</Button> {
<ShareLink initialResponse && initialReferences && childReferences
buttonTitle='Share report' ?
title="AI Fact Checking Report" <div className={styles.reportActions}>
description="Share this fact checking report with others. Anyone who has this link will be able to view the report." <Button asChild variant='secondary'>
url={constructShareUrl()} <Link href="/factchecker" target="_blank" rel="noopener noreferrer">
onShare={loadedFromStorage ? () => {} : storeData} /> Try Another
</div> </Link>
: <div className={styles.newReportActions}> </Button>
<div className={`${styles.inputFields} mt-4`}> <ShareLink
<Input buttonTitle='Share report'
type="text" title="AI Fact Checking Report"
maxLength={200} description="Share this fact checking report with others. Anyone who has this link will be able to view the report."
placeholder="Enter a falsifiable statement to verify" url={constructShareUrl()}
disabled={isLoading} onShare={loadedFromStorage ? () => { } : storeData} />
onChange={(e) => setFactToVerify(e.target.value)} </div>
value={factToVerify} : <div className={styles.newReportActions}>
onKeyDown={(e) => { <div className={`${styles.inputFields} mt-4`}>
if (e.key === "Enter") { <Input
onClickVerify(); type="text"
} maxLength={200}
}} placeholder="Enter a falsifiable statement to verify"
onFocus={(e) => e.target.placeholder = ""} disabled={isLoading}
onBlur={(e) => e.target.placeholder = "Enter a falsifiable statement to verify"} /> onChange={(e) => setFactToVerify(e.target.value)}
<Button disabled={clickedVerify} onClick={() => onClickVerify()}>Verify</Button> value={factToVerify}
</div> onKeyDown={(e) => {
<h3 className={`mt-4 mb-4`}> if (e.key === "Enter") {
Try with a particular model. You must be <a href="/settings" className="font-medium text-blue-600 dark:text-blue-500 hover:underline">subscribed</a> to configure the model. onClickVerify();
</h3> }
</div> }}
} onFocus={(e) => e.target.placeholder = ""}
<ModelPicker disabled={isLoading || loadedFromStorage} setModelUsed={setModelUsed} initialModel={initialModel} /> onBlur={(e) => e.target.placeholder = "Enter a falsifiable statement to verify"} />
{isLoading && <div className={styles.loading}> <Button disabled={clickedVerify} onClick={() => onClickVerify()}>Verify</Button>
</div>
<h3 className={`mt-4 mb-4`}>
Try with a particular model. You must be <a href="/settings" className="font-medium text-blue-600 dark:text-blue-500 hover:underline">subscribed</a> to configure the model.
</h3>
</div>
}
<ModelPicker disabled={isLoading || loadedFromStorage} setModelUsed={setModelUsed} initialModel={initialModel} />
{isLoading && <div className={styles.loading}>
<LoadingSpinner /> <LoadingSpinner />
</div>} </div>}
{ {
initialResponse && initialResponse &&
<Card className={`mt-4`}> <Card className={`mt-4`}>
<CardHeader> <CardHeader>
<CardTitle>{officialFactToVerify}</CardTitle> <CardTitle>{officialFactToVerify}</CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className={styles.responseText}> <div className={styles.responseText}>
<ChatMessage chatMessage={ <ChatMessage chatMessage={
{
automationId: "",
by: "AI",
message: initialResponse,
context: [],
created: (new Date()).toISOString(),
onlineContext: {}
}
} isMobileWidth={isMobileWidth} />
</div>
</CardContent>
<CardFooter>
{
initialReferences && initialReferences.online && Object.keys(initialReferences.online).length > 0 && (
<div className={styles.subLinks}>
{ {
Object.entries(initialReferences.online).map(([key, onlineData], index) => { automationId: "",
const webpages = onlineData?.webpages || []; by: "AI",
return renderWebpages(webpages); message: initialResponse,
}) context: [],
created: (new Date()).toISOString(),
onlineContext: {}
} }
</div> } isMobileWidth={isMobileWidth} />
)}
</CardFooter> </div>
</Card> </CardContent>
} <CardFooter>
{ {
initialReferences && initialReferences && initialReferences.online && Object.keys(initialReferences.online).length > 0 && (
<div className={styles.referenceContainer}> <div className={styles.subLinks}>
<h2 className="mt-4 mb-4">Supplements</h2> {
<div className={styles.references}> Object.entries(initialReferences.online).map(([key, onlineData], index) => {
{ initialReferences.online !== undefined && const webpages = onlineData?.webpages || [];
renderReferences(conversationID, initialReferences, officialFactToVerify, loadedFromStorage, childReferences)} return renderWebpages(webpages);
})
}
</div>
)}
</CardFooter>
</Card>
}
{
initialReferences &&
<div className={styles.referenceContainer}>
<h2 className="mt-4 mb-4">Supplements</h2>
<div className={styles.references}>
{initialReferences.online !== undefined &&
renderReferences(conversationID, initialReferences, officialFactToVerify, loadedFromStorage, childReferences)}
</div>
</div> </div>
</div> }
} </div>
</div> </>
) )
} }