Skip to content

Commit

Permalink
fix typescript errors
Browse files Browse the repository at this point in the history
  • Loading branch information
mruwnik committed Oct 2, 2023
1 parent 40b518d commit edb4a89
Show file tree
Hide file tree
Showing 16 changed files with 508 additions and 341 deletions.
9 changes: 7 additions & 2 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
"scripts": {
"build": "next build",
"dev": "next dev",
"lint": "next lint",
"start": "next start"
"start": "next start",
"eslint": "eslint --ignore-pattern .gitignore \"**/*.ts*\"",
"eslint:fix": "eslint --fix --ignore-pattern .gitignore \"**/*.ts*\"",
"prettier": "prettier --check --ignore-path .gitignore \"**/*.{ts*,js,css,md,html}\"",
"prettier:fix": "prettier --write --ignore-path .gitignore \"**/*.{ts*,js,css,md,html}\"",
"lint": "tsc && npm run prettier && npm run eslint",
"lint:fix": "tsc && npm run prettier:fix && npm run eslint:fix"
},
"dependencies": {
"autosize": "^6.0.1",
Expand Down
35 changes: 19 additions & 16 deletions web/src/components/assistant.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
import { useState } from "react";
import { ShowCitation, CitationsBlock } from "./citations";
import { GlossarySpan } from "./glossary";
import type { Citation, AssistantEntry as AssistantType} from "../types";
import type { Citation, AssistantEntry as AssistantType } from "../types";

export const AssistantEntry: React.FC<{entry: AssistantType}> = ({entry}) => {
export const AssistantEntry: React.FC<{ entry: AssistantType }> = ({
entry,
}) => {
return (
<div className="mt-3 mb-8">
{ entry.content.split("\n").map(paragraph => (
<CitationsBlock
text={paragraph}
citations={entry.citationsMap}
textRenderer={(t) => (<GlossarySpan content={t}/>)}
/>
{entry.content.split("\n").map((paragraph, i) => (
<CitationsBlock
key={i}
text={paragraph}
citations={entry.citationsMap}
textRenderer={(t) => <GlossarySpan content={t} />}
/>
))}
<ul className="mt-5">
{
// show citations
Array.from(entry.citationsMap.values()).map((citation) => (
<li key={citation.index}>
<ShowCitation citation={citation} />
</li>
))
}
<ul className="mt-5">
{ // show citations
Array.from(entry.citationsMap.values()).map(citation => (
<li key={citation.index}>
<ShowCitation citation={citation} />
</li>
))
}
</ul>
</div>
);
Expand Down
143 changes: 84 additions & 59 deletions web/src/components/citations.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { Citation } from "../types";
import { Colours, A } from "./html";


export const formatCitations: (text: string) => string = (text) => {
// ---------------------- normalize citation form ----------------------
// the general plan here is just to add parsing cases until we can respond
Expand All @@ -10,39 +9,44 @@ export const formatCitations: (text: string) => string = (text) => {

// transform all things that look like [a, b, c] into [a][b][c]
let response = text.replace(
/\[((?:[a-z]+,\s*)*[a-z]+)\]/g, // identify groups of this form

/\[((?:[a-z]+,\s*)*[a-z]+)\]/g, // identify groups of this form

(block: string) => block.split(',')
.map((x) => x.trim())
.join("][")
)
(block: string) =>
block
.split(",")
.map((x) => x.trim())
.join("][")
);

// transform all things that look like [(a), (b), (c)] into [(a)][(b)][(c)]
response = response.replace(

/\[((?:\([a-z]+\),\s*)*\([a-z]+\))\]/g, // identify groups of this form

(block: string) => block.split(',')
.map((x) => x.trim())
.join("][")
)
(block: string) =>
block
.split(",")
.map((x) => x.trim())
.join("][")
);

// transform all things that look like [(a)] into [a]
response = response.replace(
/\[\(([a-z]+)\)\]/g,
(_match: string, x: string) => `[${x}]`
)
);

// transform all things that look like [ a ] into [a]
response = response.replace(
/\[\s*([a-z]+)\s*\]/g,
(_match: string, x: string) => `[${x}]`
)
);
return response;
}
};

export const findCitations: (text: string, citations: Citations[]) => Map<string, Citation> = (text, citations) => {
export const findCitations: (
text: string,
citations: Citation[]
) => Map<string, Citation> = (text, citations) => {
// figure out what citations are in the response, and map them appropriately
const cite_map = new Map<string, Citation>();

Expand All @@ -53,64 +57,85 @@ export const findCitations: (text: string, citations: Citations[]) => Map<string
let match;
while ((match = regex.exec(text)) !== null) {
const letter = match[1];
const citation = citations[letter.charCodeAt(0) - 'a'.charCodeAt(0)]
if (!cite_map.has(letter!)) {
cite_map.set(letter!, citation);
}
}
return cite_map
}
if (!letter || cite_map.has(letter!)) continue;

export const ShowCitation: React.FC<{citation: Citation}> = ({citation}) => {
const citation = citations[letter.charCodeAt(0) - "a".charCodeAt(0)];
if (!citation) continue;

cite_map.set(letter!, citation);
}
return cite_map;
};

export const ShowCitation: React.FC<{ citation: Citation }> = ({
citation,
}) => {
var c_str = citation.title;

if (citation.authors && citation.authors.length > 0)
c_str += " - " + citation.authors.join(', ');
if (citation.date && citation.date !== "")
c_str += " - " + citation.date;
c_str += " - " + citation.authors.join(", ");
if (citation.date && citation.date !== "") c_str += " - " + citation.date;

// if we don't have a url, link to a duckduckgo search for the title instead
const url = citation.url && citation.url !== ""
? citation.url
: `https://duckduckgo.com/?q=${encodeURIComponent(citation.title)}`;
const url =
citation.url && citation.url !== ""
? citation.url
: `https://duckduckgo.com/?q=${encodeURIComponent(citation.title)}`;

return (
<A className={Colours[(citation.index - 1) % Colours.length] + " border-2 flex items-center rounded my-2 text-sm no-underline w-fit"}
href={url}>
<A
className={
Colours[(citation.index - 1) % Colours.length] +
" my-2 flex w-fit items-center rounded border-2 text-sm no-underline"
}
href={url}
>
<span className="mx-1"> [{citation.index}] </span>
<p className="mx-1 my-0"> {c_str} </p>
</A>
);
};

export const CitationRef: React.FC<{citation: Citation}> = ({citation}) => {
const url = citation.url && citation.url !== ""
? citation.url
: `https://duckduckgo.com/?q=${encodeURIComponent(citation.title)}`;
return (
<A className={Colours[(citation.index - 1) % Colours.length] + " border-2 rounded text-sm no-underline w-min px-0.5 pb-0.5 ml-1 mr-0.5"}
href={url}>
[{citation.index}]
</A>
);
};
export const CitationRef: React.FC<{ citation?: Citation }> = ({
citation,
}) => {
if (!citation) return null;

const url =
citation.url && citation.url !== ""
? citation.url
: `https://duckduckgo.com/?q=${encodeURIComponent(citation.title)}`;
return (
<A
className={
Colours[(citation.index - 1) % Colours.length] +
" ml-1 mr-0.5 w-min rounded border-2 px-0.5 pb-0.5 text-sm no-underline"
}
href={url}
>
[{citation.index}]
</A>
);
};

export const CitationsBlock: React.FC<{text: string, citations: Map<string, Citation>, textRenderer: (t: str) => any}> = ({text, citations, textRenderer}) => {
const regex = /\[([a-z]+)\]/g;
return (
<p> {
text.split(regex).map((part, i) => {
// When splitting, the even parts are basic text sections, while the odd ones are
// citations
if (i % 2 == 0) {
return textRenderer(part)
} else {
return (<CitationRef citation={citations.get(part)} />)
}
})
export const CitationsBlock: React.FC<{
text: string;
citations: Map<string, Citation>;
textRenderer: (t: string) => any;
}> = ({ text, citations, textRenderer }) => {
const regex = /\[([a-z]+)\]/g;
return (
<p>
{" "}
{text.split(regex).map((part, i) => {
// When splitting, the even parts are basic text sections, while the odd ones are
// citations
if (i % 2 == 0) {
return textRenderer(part);
} else {
return <CitationRef citation={citations.get(part)} key={i} />;
}
</p>
)
}
})}
</p>
);
};
9 changes: 6 additions & 3 deletions web/src/components/entry.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ import { AssistantEntry } from "./assistant";
import { GlossarySpan } from "./glossary";
import Image from "next/image";
import logo from "../logo.svg";
import TextareaAutosize from 'react-textarea-autosize';
import TextareaAutosize from "react-textarea-autosize";

export const User = ({ entry }: { entry: UserEntry }) => {
return (
<li className="flex mt-1 mb-2">
<TextareaAutosize className="border border-gray-300 px-1 flex-1 resize-none" value={entry.content} />
<li className="mt-1 mb-2 flex">
<TextareaAutosize
className="flex-1 resize-none border border-gray-300 px-1"
value={entry.content}
/>
</li>
);
};
Expand Down
41 changes: 23 additions & 18 deletions web/src/components/glossary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,21 @@ type GlossaryItem = {

export type Glossary = Map<string, GlossaryItem>;

export const GlossaryContext = createContext<{g: Glossary, r: RegExp} | null>(null);
export const GlossaryContext = createContext<{ g: Glossary; r: RegExp } | null>(
null
);

// A component which wraps arbitrary html in a span, and injects glossary terms
// into it as hoverable pop-up links. The text is immediately rendered normally,
// but after the glossary is loaded (which happens once per page, asynchronously),
// the glossary terms are replaced with elements.

export const GlossarySpan: React.FC<{content: string}> = ({content}) => {

export const GlossarySpan: React.FC<{ content: string }> = ({ content }) => {
const g = useContext(GlossaryContext);

// If the glossary hasn't loaded yet, just render the text normally.
if (g == null) {
return <span dangerouslySetInnerHTML={{__html: content}} />;
return <span dangerouslySetInnerHTML={{ __html: content }} />;
}

const glossary = g.g;
Expand All @@ -33,29 +34,33 @@ export const GlossarySpan: React.FC<{content: string}> = ({content}) => {
// but I think it should be faster to compile a regex state machine
// once and use that instead.

return <span dangerouslySetInnerHTML={{__html: content.replace(glossaryRegex!, (match) => {

const item = glossary.get(match.toLowerCase());
if (item == undefined) return match;
return (
<span
dangerouslySetInnerHTML={{
__html: content.replace(glossaryRegex!, (match) => {
const item = glossary.get(match.toLowerCase());
if (item == undefined) return match;

const hover_content = item.contents;
const pageid = item.pageid;
const hover_content = item.contents;
const pageid = item.pageid;

if (pageid == undefined || pageid.trim() == "") {
return `
if (pageid == undefined || pageid.trim() == "") {
return `
<div class="glossary-hover" nowrap>${hover_content}</div>
<span class="glossary-link">${match}</span>
`;
} else {
return `
} else {
return `
<div class="glossary-hover" nowrap>${hover_content}</div>
<a href="https://aisafety.info/?state=${pageid}"
target="_blank"
class="glossary-link">
${match}
</a>
`;
}

})}} />;
}
}
}),
}}
/>
);
};
37 changes: 20 additions & 17 deletions web/src/components/header.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
import React from "react";
import Link from "next/link";
import Image from 'next/image';
import logo from "../logo.svg"
import Image from "next/image";
import logo from "../logo.svg";

const Header: React.FC<{page: "index" | "semantic"}> = ({page}) => {
const sidebar = page === "index" ? (
<span className="flex flex-col font-semibold flex-1 justify-start text-right">
<Link href="/semantic">Show Sources</Link>
</span>
) : (
<span className="flex flex-col font-semibold flex-1 justify-start text-right">
<Link href="/">Go Chat</Link>
</span>
);
const Header: React.FC<{ page: "index" | "semantic" }> = ({ page }) => {
const sidebar =
page === "index" ? (
<span className="flex flex-1 flex-col justify-start text-right font-semibold">
<Link href="/semantic">Show Sources</Link>
</span>
) : (
<span className="flex flex-1 flex-col justify-start text-right font-semibold">
<Link href="/">Go Chat</Link>
</span>
);

return (<div className="flex my-4">
<Image src={logo} alt="aisafety.info logo" width={36}/>
<h1 className="flex-1 my-0">AI Safety Chatbot</h1>
{sidebar}
</div>);
return (
<div className="my-4 flex">
<Image src={logo} alt="aisafety.info logo" width={36} />
<h1 className="my-0 flex-1">AI Safety Chatbot</h1>
{sidebar}
</div>
);
};

export default Header;
Loading

0 comments on commit edb4a89

Please sign in to comment.