diff --git a/src/components/conversation/conversationcontrols.tsx b/src/components/conversation/conversationcontrols.tsx index 854b960..50fb336 100644 --- a/src/components/conversation/conversationcontrols.tsx +++ b/src/components/conversation/conversationcontrols.tsx @@ -54,7 +54,7 @@ function formatRequestError(error: string): string { `${error}`.toLowerCase() === 'timeout' || `${error}`.toLowerCase().includes('timeout fetching') ) { - return 'Error: Timeout - Unable to reach NovelAI servers. Please wait for a moment and try again' + return 'Error: Timeout - Unable to reach Naifu servers. Please wait for a moment and try again' } if (`${error}`.toLowerCase().includes('worker timeout')) { return `${error} - Please try again, or if this issue persists, \ diff --git a/src/components/tip.tsx b/src/components/tip.tsx index 708b41d..b42fade 100644 --- a/src/components/tip.tsx +++ b/src/components/tip.tsx @@ -744,7 +744,7 @@ const help_tips = [ [ 'Privacy', 'Encryption', - 'AES-256 is used to encrypt your Stories before being sent to the NovelAI servers. No one can access them without your encryption key.', + 'AES-256 is used to encrypt your Stories before being sent to the Naifu servers. No one can access them without your encryption key.', ], */ [ @@ -969,7 +969,7 @@ const help_tips = [ [ 'Settings', 'Default Storage Location', - 'Choose to keep your Stories on your device, or upload them to the NovelAI servers. Local stories rely on your browser cache, which can be cleared on occasion. All Stories on the NovelAI servers are specially encrypted so only you can view them.', + 'Choose to keep your Stories on your device, or upload them to the Naifu servers. Local stories rely on your browser cache, which can be cleared on occasion. All Stories on the Naifu servers are specially encrypted so only you can view them.', ], [ 'Settings', diff --git a/src/data/request/remoterequest.ts b/src/data/request/remoterequest.ts index 8dd5562..2f35078 100644 --- a/src/data/request/remoterequest.ts +++ b/src/data/request/remoterequest.ts @@ -510,7 +510,7 @@ export class RemoteGenerationRequest implements IGenerationRequest { onError({ status: 408, message: - 'Error: Timeout - Unable to reach NovelAI servers. Please wait for a moment and try again', + 'Error: Timeout - Unable to reach Naifu servers. Please wait for a moment and try again', }) }, 3600 * 1000) @@ -1159,15 +1159,15 @@ export class RemoteImageGenerationRequest { try { let errorData = await bind.json() - + onError({ status: bind.status ?? 500, message: errorData.error, }) - } catch(err) { + } catch (err) { onError({ status: bind.status ?? 500, - message: `Error: HTTP ${bind.status} - Unable to reach NovelAI servers. Please wait for a moment and try again`, + message: `Error: HTTP ${bind.status} - Unable to reach Naifu servers. Please wait for a moment and try again`, }) } return @@ -1191,25 +1191,26 @@ export class RemoteImageGenerationRequest { }), } - const bind = await fetchWithTimeout(BackendURLGetTaskInfo, requestGetTask) - if (!bind.ok) { - logError(bind, false) + let res: any = {}; + try { + const bind = await fetchWithTimeout(BackendURLGetTaskInfo, requestGetTask) + if (!bind.ok) { + logError(bind, false) - try { let errorData = await bind.json() - + onError({ status: bind.status ?? 500, message: errorData.error, }) return - } catch(err) { - // don't stop generate when http error } + res = await bind.json() + } catch (err) { + // don't stop generate when http error } - let res = await bind.json() // console.log('task info', res) - + let progress = 0; if (res.status === "finished") { onProgress(100, 0) @@ -1236,7 +1237,7 @@ export class RemoteImageGenerationRequest { onError({ status: 408, message: - 'Error: Timeout - Unable to reach NovelAI servers. Please wait for a moment and try again', + 'Error: Timeout - Unable to reach Naifu servers. Please wait for a moment and try again', }) }, 30 * 1000) diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 61fb239..f31909c 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -462,9 +462,29 @@ function ImageGenContent(): JSX.Element { const [params, actualSetParams] = useState( getModelDefaultParams(ImageGenerationModels.stableDiffusion) ) + const [initialized, setInitialized] = useState(false) const [prompt, setPrompt] = useState([''] as string[]) const [promptLines, setPromptLines] = useState([1] as number[]) + const [savedPrompt, setSavedPrompt] = useRememberedValue('imagegen-prompt', [''] as string[]) const [negPrompt, setNegPrompt] = useRememberedValue('imagegen-negativeprompt', '') + const [notiEnabled, setNotiEnabled] = useRememberedValue('imagegen-enable-notification', false) + + // Sync prompt and savedPrompt + useEffect(() => { + if (!initialized) { + setInitialized(true) + return // Ignore default value + } + + if (prompt != savedPrompt) { + setSavedPrompt(prompt) + } + }, [prompt]) + useEffect(() => { + if (savedPrompt != prompt) { + setPrompt(savedPrompt) + } + }, [savedPrompt]) // Queue remaining toast const queueToastId = React.useRef(null); @@ -675,7 +695,7 @@ function ImageGenContent(): JSX.Element { }) .catch((error) => { logError(error) - toast.error(`Error: ${error.message} - Unable to reach NovelAI servers. Please wait for a moment and try again`, { + toast.error(`Error: ${error.message} - Unable to reach Naifu servers. Please wait for a moment and try again`, { toastId: 'promptSuggesionError' }) }) @@ -1049,6 +1069,18 @@ function ImageGenContent(): JSX.Element { setImages([newImages, ...images]) } lastGenerationParams = paramString + + if (notiEnabled) { + const notification = new Notification('Naifu', { + body: 'Image generation completed', + icon: newImages[0].url, + image: newImages[0].url, + tag: 'imagegen-complete' + }) + notification.onclick = () => { + window.focus() + } + } } } ) @@ -1136,6 +1168,18 @@ function ImageGenContent(): JSX.Element { setImages([newImages, ...images]) setRerollImageInfo(newImages[0]) lastGenerationParams = paramString + + if (notiEnabled) { + const notification = new Notification('Naifu', { + body: 'Image generation completed', + icon: newImages[0].url, + image: newImages[0].url, + tag: 'imagegen-complete' + }) + notification.onclick = () => { + window.focus() + } + } } resolve({ images: newImages, seeds: masks.map((m) => m.seed) }) } @@ -2596,6 +2640,8 @@ function ImageGenContent(): JSX.Element { params={params} setParams={setParams} model={selectedModel} + notiEnabled={notiEnabled} + setNotiEnabled={setNotiEnabled} initImage={initImage} setInitImage={setInitImage} negPrompt={negPrompt} @@ -3234,6 +3280,8 @@ function GenerationOptions(props: { params: any setParams: React.Dispatch> children?: JSX.Element | JSX.Element[] + notiEnabled: boolean + setNotiEnabled: (b: boolean) => void initImage: Buffer | undefined setInitImage: React.Dispatch> negPrompt: string @@ -3243,6 +3291,31 @@ function GenerationOptions(props: { }): JSX.Element { const [selectedResolution, setSelectedResolution] = useState(0) const siteTheme = useRecoilValue(SiteTheme) + const [notiEnabled, setLocalNotiEnabled] = useState(false) + + useEffect(() => { + setLocalNotiEnabled(props.notiEnabled) + }, [props.notiEnabled]) + + const setNotiEnabled = useCallback((b: boolean) => { + if (typeof window !== "undefined") { + if (window.Notification.permission === 'denied') { + toast.warn("You've disabled Notification in browser settings.") + } else { + if (window.Notification.permission !== 'granted' && b) { + window.Notification.requestPermission().then((res) => { + if (res === 'granted') { + props.setNotiEnabled(true) + } else { + props.setNotiEnabled(false) + } + }) + } else { + props.setNotiEnabled(b) + } + } + } + }, []) useEffect(() => { if (props.params.width && props.params.height) { @@ -3267,6 +3340,21 @@ function GenerationOptions(props: { const stableDiffusionSettings = ( <> + + + Notification + + + + + Image Resolution