Skip to content

Commit

Permalink
feat: resetChatHistory function on a LlamaChatSession (#327)
Browse files Browse the repository at this point in the history
* feat: `resetChatHistory` function on a `LlamaChatSession`
* feat: copy model response in the example Electron app template
  • Loading branch information
giladgd authored Sep 21, 2024
1 parent cf791f1 commit ebc4e83
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 8 deletions.
14 changes: 12 additions & 2 deletions .vitepress/utils/parseCmakeListsTxtOptions.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
const maxLinesSpan = 10;

export function parseCmakeListsTxtOptions(cmakeListsTxtString: string) {
const lines = cmakeListsTxtString.split("\n");

return lines
.map((line, index) => {
const match = line.match(/^option\([\s\t\n\r]*(?<key>\S+)[\s\t\n\r]+"(?<description>(?:\\"|[^"])*)"[\s\t\n\r]+(?<defaultValue>\S+)[\s\t\n\r]*\)/);
if (match == null || match.groups == null)
const match = lines
.slice(index, index + maxLinesSpan)
.join("\n")
.match(
/^option\([\s\t\n\r]*(?<key>\S+)[\s\t\n\r]+"(?<description>(?:\\"|[^"])*)"[\s\t\n\r]+(?<defaultValue>\S+)[\s\t\n\r]*\)/
);
if (match == null || match.groups == null || match?.index !== 0)
return null;

const totalLines = match[0]?.split("\n")?.length ?? 1;

const {key, description, defaultValue} = match.groups;
if (key == null)
return null;

return {
lineNumber: index + 1,
totalLines,
key,
description: description != null
? description.replaceAll('\\"', '"')
Expand Down
5 changes: 4 additions & 1 deletion docs/guide/cmakeOptions.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ function renderCmakeOptionsTable(cmakeOptions: ReturnType<typeof parseCmakeOptio
"Default value"
].map(htmlEscape),
cmakeOptions.map((option) => {
const url = githubFileUrl + "#L" + option.lineNumber;
let url = githubFileUrl + "#L" + option.lineNumber;

if (option.totalLines > 1)
url += "-L" + (option.lineNumber + option.totalLines - 1);

return [
`<a href=${JSON.stringify(url)}>` +
Expand Down
39 changes: 39 additions & 0 deletions src/cli/recommendedModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,45 @@ export const recommendedModels: ModelRecommendation[] = [{
}
}]
}, */ {
name: "OLMoE 1b 7B MoE",
abilities: ["chat"],
description: "OLMoE models were created by AllenAI, and are fully open source models that utilize a Mixture of Experts architecture" +
"Mixtures of Experts (MoE) is a technique where different models, each skilled in solving a particular kind of problem, work together to the improve the overall performance on complex tasks.\n" +
"This model includes 64 expert models, with a total of 7 billion parameters.\n" +
"This model generates output extremely fast.",

fileOptions: [{
huggingFace: {
model: "allenai/OLMoE-1B-7B-0924-Instruct-GGUF",
branch: "main",
file: "olmoe-1b-7b-0924-instruct-q8_0.gguf"
}
}, {
huggingFace: {
model: "allenai/OLMoE-1B-7B-0924-Instruct-GGUF",
branch: "main",
file: "olmoe-1b-7b-0924-instruct-q6_k.gguf"
}
}, {
huggingFace: {
model: "allenai/OLMoE-1B-7B-0924-Instruct-GGUF",
branch: "main",
file: "olmoe-1b-7b-0924-instruct-q5_k_m.gguf"
}
}, {
huggingFace: {
model: "allenai/OLMoE-1B-7B-0924-Instruct-GGUF",
branch: "main",
file: "olmoe-1b-7b-0924-instruct-q4_k_s.gguf"
}
}, {
huggingFace: {
model: "allenai/OLMoE-1B-7B-0924-Instruct-GGUF",
branch: "main",
file: "olmoe-1b-7b-0924-instruct-q4_k_m.gguf"
}
}]
}, {
name: "Gemma 2 9B",
abilities: ["chat", "complete"],
description: "Gemma models were created by Google and are optimized suited for variety of text generation tasks, " +
Expand Down
22 changes: 20 additions & 2 deletions src/evaluator/LlamaChatSession/LlamaChatSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ export class LlamaChatSession {
/** @internal */ private readonly _disposeAggregator = new DisposeAggregator();
/** @internal */ private readonly _autoDisposeSequence: boolean;
/** @internal */ private readonly _contextShift?: LlamaChatSessionContextShiftOptions;
/** @internal */ private readonly _forceAddSystemPrompt: boolean;
/** @internal */ private readonly _systemPrompt?: string;
/** @internal */ private readonly _chatLock = {};
/** @internal */ private _chatHistory: ChatHistoryItem[];
/** @internal */ private _lastEvaluation?: LlamaChatResponse["lastEvaluation"];
Expand All @@ -315,6 +317,8 @@ export class LlamaChatSession {
throw new DisposedError();

this._contextShift = contextShift;
this._forceAddSystemPrompt = forceAddSystemPrompt;
this._systemPrompt = systemPrompt;

this._chat = new LlamaChat({
autoDisposeSequence,
Expand All @@ -323,8 +327,8 @@ export class LlamaChatSession {
});

const chatWrapperSupportsSystemMessages = this._chat.chatWrapper.settings.supportsSystemMessages;
if (chatWrapperSupportsSystemMessages == null || chatWrapperSupportsSystemMessages || forceAddSystemPrompt)
this._chatHistory = this._chat.chatWrapper.generateInitialChatHistory({systemPrompt});
if (chatWrapperSupportsSystemMessages == null || chatWrapperSupportsSystemMessages || this._forceAddSystemPrompt)
this._chatHistory = this._chat.chatWrapper.generateInitialChatHistory({systemPrompt: this._systemPrompt});
else
this._chatHistory = [];

Expand Down Expand Up @@ -815,6 +819,20 @@ export class LlamaChatSession {
this._lastEvaluation = undefined;
}

/** Clear the chat history and reset it to the initial state. */
public resetChatHistory() {
if (this._chat == null || this.disposed)
throw new DisposedError();

const chatWrapperSupportsSystemMessages = this._chat.chatWrapper.settings.supportsSystemMessages;
if (chatWrapperSupportsSystemMessages == null || chatWrapperSupportsSystemMessages || this._forceAddSystemPrompt)
this.setChatHistory(
this._chat.chatWrapper.generateInitialChatHistory({systemPrompt: this._systemPrompt})
);
else
this.setChatHistory([]);
}

/** @internal */
private _stopAllPreloadAndPromptCompletions() {
for (const abortController of this._preloadAndCompleteAbortControllers)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
margin-inline-end: 12px;
color: var(--user-message-text-color);
word-break: break-word;
max-width: calc(100% - 48px - 12px);
box-sizing: border-box;

&:not(:first-child) {
margin-top: 36px;
Expand All @@ -28,6 +30,12 @@
margin-inline-end: 48px;
padding-inline-start: 24px;
word-break: break-word;
max-width: calc(100% - 48px);
box-sizing: border-box;

&:hover + .buttons {
opacity: 1;
}

&.active {
&:empty:after,
Expand Down Expand Up @@ -58,6 +66,15 @@
margin-bottom: 0px;
}

h2 {
margin: 16px 0px;
padding-top: 24px;
}

h3 {
margin: 32px 0px 0px 0px;
}

table {
display: block;
border-style: hidden;
Expand Down Expand Up @@ -94,6 +111,20 @@
}
}
}

> .buttons {
display: flex;
flex-direction: row;
padding: 8px 18px;
opacity: 0;

transition: opacity 0.1s ease-in-out;

&:hover,
&:focus-visible {
opacity: 1;
}
}
}

@keyframes activeModelMessageIndicator {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import classNames from "classnames";
import {LlmState} from "../../../../electron/state/llmState.ts";
import {MarkdownContent} from "../MarkdownContent/MarkdownContent.js";
import {MessageCopyButton} from "./components/MessageCopyButton/MessageCopyButton.js";

import "./ChatHistory.css";

Expand All @@ -11,9 +12,16 @@ export function ChatHistory({simplifiedChat, generatingResult}: ChatHistoryProps
simplifiedChat.map((item, index) => {
if (item.type === "model") {
const isActive = index === simplifiedChat.length - 1 && generatingResult;
return <MarkdownContent key={index} className={classNames("message", "model", isActive && "active")}>
{item.message}
</MarkdownContent>;
return <>
<MarkdownContent key={index} className={classNames("message", "model", isActive && "active")}>
{item.message}
</MarkdownContent>
{
!isActive && <div className="buttons">
<MessageCopyButton text={item.message} />
</div>
}
</>;

} else if (item.type === "user")
return <MarkdownContent key={index} className="message user">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.appChatHistory > .buttons {
> .copyButton {
display: grid;
grid-template-areas: "icon";
padding: 6px;
border: none;

transition: background-color 0.1s ease-in-out;

&:not(:hover, :focus-visible) {
background-color: transparent;
}

&.copied {
> .icon.copy {
opacity: 0;
transition-delay: 0s;
}

> .icon.check {
opacity: 1;
transition-delay: 0.1s;
}
}

> .icon {
grid-area: icon;
width: 18px;
height: 18px;

transition: opacity 0.3s ease-in-out;

&.copy {
opacity: 1;
transition-delay: 0.1s;
}
&.check {
opacity: 0;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import classNames from "classnames";
import {useCallback, useState} from "react";
import {CopyIconSVG} from "../../../../../icons/CopyIconSVG.js";
import {CheckIconSVG} from "../../../../../icons/CheckIconSVG.js";

import "./MessageCopyButton.css";

const showCopiedTime = 1000 * 2;

export function MessageCopyButton({text}: MessageCopyButtonProps) {
const [copies, setCopies] = useState(0);

const onClick = useCallback(() => {
navigator.clipboard.writeText(text)
.then(() => {
setCopies(copies + 1);

setTimeout(() => {
setCopies(copies - 1);
}, showCopiedTime);
})
.catch((error) => {
console.error("Failed to copy text to clipboard", error);
});
}, [text]);

return <button
onClick={onClick}
className={classNames("copyButton", copies > 0 && "copied")}
>
<CopyIconSVG className="icon copy" />
<CheckIconSVG className="icon check" />
</button>;
}

type MessageCopyButtonProps = {
text: string
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {SVGProps} from "react";

export function CheckIconSVG(props: SVGProps<SVGSVGElement>) {
return <svg height="24px" viewBox="0 -960 960 960" width="24px" {...props}>
<path d="M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z"/>
</svg>;
}
7 changes: 7 additions & 0 deletions templates/electron-typescript-react/src/icons/CopyIconSVG.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {SVGProps} from "react";

export function CopyIconSVG(props: SVGProps<SVGSVGElement>) {
return <svg height="24px" viewBox="0 -960 960 960" width="24px" {...props}>
<path d="M360-240q-33 0-56.5-23.5T280-320v-480q0-33 23.5-56.5T360-880h360q33 0 56.5 23.5T800-800v480q0 33-23.5 56.5T720-240H360Zm0-80h360v-480H360v480ZM200-80q-33 0-56.5-23.5T120-160v-560h80v560h440v80H200Zm160-240v-480 480Z"/>
</svg>;
}

0 comments on commit ebc4e83

Please sign in to comment.