Skip to content

Commit

Permalink
feat(history): use localstorage for query local result
Browse files Browse the repository at this point in the history
  • Loading branch information
m1911star committed Jan 30, 2024
1 parent 420aa69 commit c9519d8
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 14 deletions.
35 changes: 35 additions & 0 deletions web/src/app/components/history.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"use client";
import { historyQueryKey } from "@/app/utils/local-storage";
import { LocalHistory } from "@/app/interfaces/history";
import { Answer } from "@/app/components/answer";
import { Sources } from "@/app/components/sources";
import { Relates } from "@/app/components/relates";
import { Title } from "@/app/components/title";
import { Fragment } from "react";

export const HistoryResult = () => {
const history = window.localStorage.getItem(historyQueryKey);
if (!history) return null;
let historyRecord: LocalHistory[];
try {
historyRecord = JSON.parse(history);
} catch {
historyRecord = [];
}
return historyRecord.map(
({ query, rid, sources, markdown, relates, timestamp }) => {
return (
<Fragment key={`${rid}-${timestamp}`}>
<div className={"mt-6 border-t pt-4"}>
<Title query={query} />
</div>
<div className="flex flex-col gap-8">
<Answer markdown={markdown} sources={sources}></Answer>
<Sources sources={sources}></Sources>
<Relates relates={relates}></Relates>
</div>
</Fragment>
);
},
);
};
21 changes: 20 additions & 1 deletion web/src/app/components/result.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,33 @@ import { Relates } from "@/app/components/relates";
import { Sources } from "@/app/components/sources";
import { Relate } from "@/app/interfaces/relate";
import { Source } from "@/app/interfaces/source";
import { LocalHistory } from "@/app/interfaces/history";
import { parseStreaming } from "@/app/utils/parse-streaming";
import { Annoyed } from "lucide-react";
import { FC, useEffect, useState } from "react";
import { FC, useCallback, useEffect, useState } from "react";
import { historyQueryKey } from "@/app/utils/local-storage";

export const Result: FC<{ query: string; rid: string }> = ({ query, rid }) => {
const [sources, setSources] = useState<Source[]>([]);
const [markdown, setMarkdown] = useState<string>("");
const [relates, setRelates] = useState<Relate[] | null>(null);
const [error, setError] = useState<number | null>(null);
const handleFinish = useCallback(
(result: LocalHistory) => {
const localHistory = window.localStorage.getItem(historyQueryKey);
let history: LocalHistory[];
try {
history = JSON.parse(localHistory || "[]");
} catch {
history = [];
}
window.localStorage.setItem(
historyQueryKey,
JSON.stringify([result, ...history]),
);
},
[rid, query],
);
useEffect(() => {
const controller = new AbortController();
void parseStreaming(
Expand All @@ -22,6 +40,7 @@ export const Result: FC<{ query: string; rid: string }> = ({ query, rid }) => {
setSources,
setMarkdown,
setRelates,
handleFinish,
setError,
);
return () => {
Expand Down
11 changes: 11 additions & 0 deletions web/src/app/interfaces/history.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Relate } from "@/app/interfaces/relate";
import { Source } from "@/app/interfaces/source";

export interface LocalHistory {
markdown: string;
relates: Relate[];
sources: Source[];
rid: string;
query: string;
timestamp: number;
}
2 changes: 2 additions & 0 deletions web/src/app/search/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Result } from "@/app/components/result";
import { Search } from "@/app/components/search";
import { Title } from "@/app/components/title";
import { useSearchParams } from "next/navigation";
import { HistoryResult } from "@/app/components/history";
export default function SearchPage() {
const searchParams = useSearchParams();
const query = decodeURIComponent(searchParams.get("q") || "");
Expand All @@ -14,6 +15,7 @@ export default function SearchPage() {
<div className="px-4 md:px-8 pt-6 pb-24 rounded-2xl ring-8 ring-zinc-300/20 border border-zinc-200 h-full overflow-auto">
<Title query={query}></Title>
<Result key={rid} query={query} rid={rid}></Result>
<HistoryResult />
</div>
<div className="h-80 pointer-events-none w-full rounded-b-2xl backdrop-filter absolute bottom-0 bg-gradient-to-b from-transparent to-white [mask-image:linear-gradient(to_top,white,transparent)]"></div>
<div className="absolute z-10 flex items-center justify-center bottom-6 px-4 md:px-8 w-full">
Expand Down
1 change: 1 addition & 0 deletions web/src/app/utils/local-storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const historyQueryKey = "lepton_previous_query";
40 changes: 27 additions & 13 deletions web/src/app/utils/parse-streaming.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Relate } from "@/app/interfaces/relate";
import { Source } from "@/app/interfaces/source";
import { fetchStream } from "@/app/utils/fetch-stream";
import { LocalHistory } from "@/app/interfaces/history";

const LLM_SPLIT = "__LLM_RESPONSE__";
const RELATED_SPLIT = "__RELATED_QUESTIONS__";
Expand All @@ -12,6 +13,7 @@ export const parseStreaming = async (
onSources: (value: Source[]) => void,
onMarkdown: (value: string) => void,
onRelates: (value: Relate[]) => void,
onFinish: (result: LocalHistory) => void,
onError?: (status: number) => void,
) => {
const decoder = new TextDecoder();
Expand All @@ -30,18 +32,19 @@ export const parseStreaming = async (
search_uuid,
}),
});
let finalRelates: Relate[] = [];
let finalMarkdown: string = "";
let finalSources: Source[] = [];
if (response.status !== 200) {
onError?.(response.status);
return;
}
const markdownParse = (text: string) => {
onMarkdown(
text
.replace(/\[\[([cC])itation/g, "[citation")
.replace(/[cC]itation:(\d+)]]/g, "citation:$1]")
.replace(/\[\[([cC]itation:\d+)]](?!])/g, `[$1]`)
.replace(/\[[cC]itation:(\d+)]/g, "[citation]($1)"),
);
return text
.replace(/\[\[([cC])itation/g, "[citation")
.replace(/[cC]itation:(\d+)]]/g, "citation:$1]")
.replace(/\[\[([cC]itation:\d+)]](?!])/g, `[$1]`)
.replace(/\[[cC]itation:(\d+)]/g, "[citation]($1)");
};
fetchStream(
response,
Expand All @@ -52,27 +55,38 @@ export const parseStreaming = async (
const [sources, rest] = chunks.split(LLM_SPLIT);
if (!sourcesEmitted) {
try {
onSources(JSON.parse(sources));
finalSources = JSON.parse(sources);
} catch (e) {
onSources([]);
finalSources = [];
}
onSources(finalSources);
}
sourcesEmitted = true;
if (rest.includes(RELATED_SPLIT)) {
const [md] = rest.split(RELATED_SPLIT);
markdownParse(md);
finalMarkdown = markdownParse(md);
} else {
markdownParse(rest);
finalMarkdown = markdownParse(rest);
}
onMarkdown(finalMarkdown);
}
},
() => {
const [_, relates] = chunks.split(RELATED_SPLIT);
try {
onRelates(JSON.parse(relates));
finalRelates = JSON.parse(relates);
} catch (e) {
onRelates([]);
finalRelates = [];
}
onRelates(finalRelates);
onFinish({
markdown: finalMarkdown,
sources: finalSources,
relates: finalRelates,
rid: search_uuid,
query,
timestamp: new Date().valueOf(),
});
},
);
};

0 comments on commit c9519d8

Please sign in to comment.