eslint fixes
parent
d9aa5aefbe
commit
7c5ffbbac7
|
@ -22,15 +22,13 @@ chatManager.on('title', async (id: string, title: string) => {
|
|||
|
||||
*/
|
||||
|
||||
export let backend: Backend | null = null;
|
||||
export let backend: {
|
||||
current?: Backend | null
|
||||
} = {};
|
||||
|
||||
export class Backend extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
register() {
|
||||
backend = this;
|
||||
backend.current = this;
|
||||
}
|
||||
|
||||
get isAuthenticated() {
|
||||
|
|
|
@ -8,7 +8,7 @@ import { createStreamingChatCompletion } from './openai';
|
|||
import { createTitle } from './titles';
|
||||
import { ellipsize, sleep } from './utils';
|
||||
import * as idb from './idb';
|
||||
import { getTokenCountForMessages, selectMessagesToSendSafely } from './tokenizer';
|
||||
import { selectMessagesToSendSafely } from './tokenizer';
|
||||
|
||||
export const channel = new BroadcastChannel('chats');
|
||||
|
||||
|
|
|
@ -158,7 +158,7 @@ export default function Header(props: HeaderProps) {
|
|||
Share
|
||||
</HeaderButton>}
|
||||
{backend && !context.authenticated && (
|
||||
<HeaderButton onClick={() => backend?.signIn()}>Sign in <span className="hide-on-mobile">to sync</span></HeaderButton>
|
||||
<HeaderButton onClick={() => backend.current?.signIn()}>Sign in <span className="hide-on-mobile">to sync</span></HeaderButton>
|
||||
)}
|
||||
<HeaderButton icon="plus" onClick={onNewChat} loading={loading} variant="light">
|
||||
New Chat
|
||||
|
|
|
@ -45,13 +45,13 @@ export default function MessageInput(props: MessageInputProps) {
|
|||
|
||||
const onChange = useCallback((e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
context.setMessage(e.target.value);
|
||||
}, [context.setMessage]);
|
||||
}, [context]);
|
||||
|
||||
const onSubmit = useCallback(async () => {
|
||||
if (await context.onNewMessage(context.message)) {
|
||||
context.setMessage('');
|
||||
}
|
||||
}, [context.message, context.onNewMessage, context.setMessage]);
|
||||
}, [context]);
|
||||
|
||||
const onKeyDown = useCallback((e: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
||||
if (e.key === 'Enter' && e.shiftKey === false && !props.disabled) {
|
||||
|
@ -71,8 +71,8 @@ export default function MessageInput(props: MessageInputProps) {
|
|||
);
|
||||
}, [onSubmit, props.disabled]);
|
||||
|
||||
const openSystemPromptPanel = useCallback(() => context.settings.open('options', 'system-prompt'), []);
|
||||
const openTemperaturePanel = useCallback(() => context.settings.open('options', 'temperature'), []);
|
||||
const openSystemPromptPanel = useCallback(() => context.settings.open('options', 'system-prompt'), [context.settings]);
|
||||
const openTemperaturePanel = useCallback(() => context.settings.open('options', 'temperature'), [context.settings]);
|
||||
|
||||
const messagesToDisplay = context.currentChat.messagesToDisplay;
|
||||
const disabled = context.generating
|
||||
|
|
|
@ -54,7 +54,7 @@ export default function ChatPage(props: any) {
|
|||
container?.scrollTo({ top: offset, behavior: 'smooth' });
|
||||
}, 500);
|
||||
}
|
||||
}, [context.currentChat?.chatLoadedAt, context.currentChat?.messagesToDisplay.length]);
|
||||
}, [context.currentChat?.chatLoadedAt, context.currentChat?.messagesToDisplay.length, props.share]);
|
||||
|
||||
const messagesToDisplay = context.currentChat.messagesToDisplay;
|
||||
|
||||
|
@ -67,7 +67,7 @@ export default function ChatPage(props: any) {
|
|||
title: (id && messagesToDisplay.length) ? context.currentChat.chat?.title : null,
|
||||
onShare: async () => {
|
||||
if (context.currentChat.chat) {
|
||||
const id = await backend?.shareChat(context.currentChat.chat);
|
||||
const id = await backend.current?.shareChat(context.currentChat.chat);
|
||||
if (id) {
|
||||
const slug = context.currentChat.chat.title
|
||||
? '/' + slugify(context.currentChat.chat.title.toLocaleLowerCase())
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import styled from '@emotion/styled';
|
||||
import { Button } from '@mantine/core';
|
||||
import MessageInput from '../input';
|
||||
import SettingsDrawer from '../settings';
|
||||
import { useAppContext } from '../../context';
|
||||
import { Page } from '../page';
|
||||
|
||||
|
|
|
@ -167,7 +167,7 @@ export default function SettingsDrawer(props: SettingsDrawerProps) {
|
|||
setParameters({ ...parameters, apiKey: event.currentTarget.value });
|
||||
context.apiKeys.setOpenAIApiKey(event.currentTarget.value);
|
||||
}} />
|
||||
<p><a href="https://platform.openai.com/account/api-keys" target="_blank">Find your API key here.</a> Your API key is stored only on this device and never transmitted to anyone except OpenAI.</p>
|
||||
<p><a href="https://platform.openai.com/account/api-keys" target="_blank" rel="noreferrer">Find your API key here.</a> Your API key is stored only on this device and never transmitted to anyone except OpenAI.</p>
|
||||
<p>OpenAI API key usage is billed at a pay-as-you-go rate, separate from your ChatGPT subscription.</p>
|
||||
</section>
|
||||
</Grid.Col>
|
||||
|
@ -211,7 +211,7 @@ export default function SettingsDrawer(props: SettingsDrawerProps) {
|
|||
<section className={context.settings.option === 'elevenlabs-api-key' ? 'focused' : ''}>
|
||||
<h3>Your ElevenLabs Text-to-Speech API Key (optional)</h3>
|
||||
<TextInput placeholder="Paste your API key here" value={context.apiKeys.elevenlabs || ''} onChange={event => context.apiKeys.setElevenLabsApiKey(event.currentTarget.value)} />
|
||||
<p>Give ChatGPT a realisic human voice by connecting your ElevenLabs account (preview the available voices below). <a href="https://beta.elevenlabs.io" target="_blank">Click here to sign up.</a></p>
|
||||
<p>Give ChatGPT a realisic human voice by connecting your ElevenLabs account (preview the available voices below). <a href="https://beta.elevenlabs.io" target="_blank" rel="noreferrer">Click here to sign up.</a></p>
|
||||
<p>You can find your API key by clicking your avatar or initials in the top right of the ElevenLabs website, then clicking Profile. Your API key is stored only on this device and never transmitted to anyone except ElevenLabs.</p>
|
||||
</section>
|
||||
</Grid.Col>
|
||||
|
|
|
@ -50,16 +50,16 @@ export function useCreateAppContext(): Context {
|
|||
|
||||
const chatManager = useRef(ChatManagerInstance);
|
||||
const currentChat = useChat(chatManager.current, id, isShare);
|
||||
const [authenticated, setAuthenticated] = useState(backend?.isAuthenticated || false);
|
||||
const [authenticated, setAuthenticated] = useState(backend.current?.isAuthenticated || false);
|
||||
|
||||
const updateAuth = useCallback((authenticated: boolean) => setAuthenticated(authenticated), []);
|
||||
|
||||
useEffect(() => {
|
||||
backend?.on('authenticated', updateAuth);
|
||||
backend.current?.on('authenticated', updateAuth);
|
||||
return () => {
|
||||
backend?.off('authenticated', updateAuth)
|
||||
backend.current?.off('authenticated', updateAuth)
|
||||
};
|
||||
}, [backend]);
|
||||
}, [updateAuth]);
|
||||
|
||||
const [openaiApiKey, setOpenAIApiKey] = useState<string | null>(
|
||||
localStorage.getItem('openai-api-key') || ''
|
||||
|
@ -150,7 +150,7 @@ export function useCreateAppContext(): Context {
|
|||
setTimeout(() => setGenerating(false), 4000);
|
||||
|
||||
return true;
|
||||
}, [chatManager, openaiApiKey, id, parameters, message, currentChat.leaf]);
|
||||
}, [chatManager, openaiApiKey, id, parameters, currentChat.leaf, navigate, isShare]);
|
||||
|
||||
const regenerateMessage = useCallback(async (message: Message) => {
|
||||
if (isShare) {
|
||||
|
@ -173,7 +173,7 @@ export function useCreateAppContext(): Context {
|
|||
setTimeout(() => setGenerating(false), 4000);
|
||||
|
||||
return true;
|
||||
}, [chatManager, openaiApiKey, id, parameters]);
|
||||
}, [chatManager, openaiApiKey, parameters, isShare]);
|
||||
|
||||
const editMessage = useCallback(async (message: Message, content: string) => {
|
||||
if (isShare) {
|
||||
|
@ -219,7 +219,7 @@ export function useCreateAppContext(): Context {
|
|||
setTimeout(() => setGenerating(false), 4000);
|
||||
|
||||
return true;
|
||||
}, [chatManager, openaiApiKey, id, parameters, message, currentChat.leaf]);
|
||||
}, [chatManager, openaiApiKey, id, parameters, isShare, navigate]);
|
||||
|
||||
const context = useMemo<Context>(() => ({
|
||||
authenticated,
|
||||
|
@ -258,7 +258,8 @@ export function useCreateAppContext(): Context {
|
|||
regenerateMessage,
|
||||
editMessage,
|
||||
}), [chatManager, authenticated, openaiApiKey, elevenLabsApiKey, settingsTab, option, voiceID,
|
||||
generating, message, parameters, onNewMessage, regenerateMessage, editMessage, currentChat]);
|
||||
generating, message, parameters, onNewMessage, regenerateMessage, editMessage, currentChat,
|
||||
id, isShare]);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
|
|
@ -273,24 +273,26 @@ export default class ElevenLabsReader extends EventEmitter {
|
|||
export function ElevenLabsReaderButton(props: { selector: string }) {
|
||||
const context = useAppContext();
|
||||
const [status, setStatus] = useState<'idle' | 'init' | 'playing' | 'buffering'>('idle');
|
||||
const [error, setError] = useState(false);
|
||||
// const [error, setError] = useState(false);
|
||||
const reader = useRef(new ElevenLabsReader());
|
||||
|
||||
useEffect(() => {
|
||||
reader.current.on('init', () => setStatus('init'));
|
||||
reader.current.on('playing', () => setStatus('playing'));
|
||||
reader.current.on('buffering', () => setStatus('buffering'));
|
||||
reader.current.on('error', () => {
|
||||
const currentReader = reader.current;
|
||||
|
||||
currentReader.on('init', () => setStatus('init'));
|
||||
currentReader.on('playing', () => setStatus('playing'));
|
||||
currentReader.on('buffering', () => setStatus('buffering'));
|
||||
currentReader.on('error', () => {
|
||||
setStatus('idle');
|
||||
setError(true);
|
||||
// setError(true);
|
||||
});
|
||||
reader.current.on('done', () => setStatus('idle'));
|
||||
currentReader.on('done', () => setStatus('idle'));
|
||||
|
||||
return () => {
|
||||
reader.current.removeAllListeners();
|
||||
reader.current.stop();
|
||||
currentReader.removeAllListeners();
|
||||
currentReader.stop();
|
||||
};
|
||||
}, [reader.current, props.selector]);
|
||||
}, [props.selector]);
|
||||
|
||||
const onClick = useCallback(() => {
|
||||
if (status === 'idle') {
|
||||
|
|
|
@ -3,12 +3,10 @@ import * as idb from 'idb-keyval';
|
|||
let supported = true;
|
||||
const inMemoryCache = new Map<string, any>();
|
||||
|
||||
{
|
||||
var db = indexedDB.open('idb-test');
|
||||
db.onerror = () => {
|
||||
const testDB = indexedDB.open('idb-test');
|
||||
testDB.onerror = () => {
|
||||
supported = false;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export async function keys() {
|
||||
if (supported) {
|
||||
|
|
|
@ -10,7 +10,7 @@ export function useChatSpotlightProps() {
|
|||
|
||||
useEffect(() => {
|
||||
context.chat.on('update', () => setVersion(v => v + 1));
|
||||
}, []);
|
||||
}, [context.chat]);
|
||||
|
||||
const search = useCallback((query: string) => {
|
||||
return context.chat.search.query(query)
|
||||
|
@ -18,7 +18,7 @@ export function useChatSpotlightProps() {
|
|||
...result,
|
||||
onTrigger: () => navigate('/chat/' + result.chatID + (result.messageID ? '#msg-' + result.messageID : '')),
|
||||
}))
|
||||
}, [navigate, version]);
|
||||
}, [context.chat, navigate, version]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const props = useMemo(() => ({
|
||||
shortcut: ['mod + P'],
|
||||
|
|
|
@ -11,7 +11,7 @@ export default class SSE {
|
|||
|
||||
public headers = this.options.headers || {};
|
||||
public payload = this.options.payload !== undefined ? this.options.payload : '';
|
||||
public method = this.options.method || (this.payload && 'POST' || 'GET');
|
||||
public method = this.options.method ? this.options.method : (this.payload ? 'POST' : 'GET');
|
||||
public withCredentials = !!this.options.withCredentials;
|
||||
|
||||
public FIELD_SEPARATOR = ':';
|
||||
|
@ -109,7 +109,7 @@ export default class SSE {
|
|||
return;
|
||||
}
|
||||
|
||||
if (this.readyState == this.CONNECTING) {
|
||||
if (this.readyState === this.CONNECTING) {
|
||||
this.dispatchEvent(new CustomEvent('open'));
|
||||
this._setReadyState(this.OPEN);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { useCallback, useEffect, useState } from "react";
|
||||
import { backend } from "./backend";
|
||||
import { ChatManager } from "./chat-manager";
|
||||
import { useAppContext } from "./context";
|
||||
import { Chat, Message } from './types';
|
||||
|
||||
export interface UseChatResult {
|
||||
|
@ -14,7 +13,7 @@ export interface UseChatResult {
|
|||
|
||||
export function useChat(chatManager: ChatManager, id: string | undefined | null, share = false): UseChatResult {
|
||||
const [chat, setChat] = useState<Chat | null | undefined>(null);
|
||||
const [version, setVersion] = useState(0);
|
||||
const [_, setVersion] = useState(0);
|
||||
|
||||
// used to prevent auto-scroll when chat is first opened
|
||||
const [chatLoadedAt, setLoadedAt] = useState(0);
|
||||
|
@ -29,7 +28,7 @@ export function useChat(chatManager: ChatManager, id: string | undefined | null,
|
|||
return;
|
||||
}
|
||||
} else {
|
||||
const c = await backend?.getSharedChat(id);
|
||||
const c = await backend.current?.getSharedChat(id);
|
||||
if (c) {
|
||||
setChat(c);
|
||||
setVersion(v => v + 1);
|
||||
|
@ -38,7 +37,7 @@ export function useChat(chatManager: ChatManager, id: string | undefined | null,
|
|||
}
|
||||
}
|
||||
setChat(null);
|
||||
}, [id, share]);
|
||||
}, [id, share, chatManager]);
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
|
@ -55,7 +54,7 @@ export function useChat(chatManager: ChatManager, id: string | undefined | null,
|
|||
chatManager.off(id, update);
|
||||
}
|
||||
};
|
||||
}, [id, update]);
|
||||
}, [id, update, chatManager]);
|
||||
|
||||
const leaf = chat?.messages.mostRecentLeaf();
|
||||
|
||||
|
|
Loading…
Reference in New Issue