Merge pull request #124 from danny-avila/bing-styles

Bing styles
This commit is contained in:
Danny Avila 2023-03-25 10:01:19 -04:00 committed by GitHub
commit e49adaa314
17 changed files with 444 additions and 198 deletions

View file

@ -2,7 +2,7 @@ require('dotenv').config();
const { KeyvFile } = require('keyv-file'); const { KeyvFile } = require('keyv-file');
const askBing = async ({ text, onProgress, convo }) => { const askBing = async ({ text, onProgress, convo }) => {
const { BingAIClient } = (await import('@waylaidwanderer/chatgpt-api')); const { BingAIClient } = await import('@waylaidwanderer/chatgpt-api');
const bingAIClient = new BingAIClient({ const bingAIClient = new BingAIClient({
// "_U" cookie from bing.com // "_U" cookie from bing.com
@ -11,7 +11,7 @@ const askBing = async ({ text, onProgress, convo }) => {
// cookies: '', // cookies: '',
debug: false, debug: false,
cache: { store: new KeyvFile({ filename: './data/cache.json' }) }, cache: { store: new KeyvFile({ filename: './data/cache.json' }) },
proxy: process.env.PROXY || null, proxy: process.env.PROXY || null
}); });
let options = { onProgress }; let options = { onProgress };
@ -19,8 +19,15 @@ const askBing = async ({ text, onProgress, convo }) => {
options = { ...options, ...convo }; options = { ...options, ...convo };
} }
if (options?.jailbreakConversationId == 'false') if (options?.jailbreakConversationId == 'false') {
options.jailbreakConversationId = false options.jailbreakConversationId = false;
}
if (convo.toneStyle) {
options.toneStyle = convo.toneStyle;
}
console.log('bing options', options);
const res = await bingAIClient.sendMessage(text, options); const res = await bingAIClient.sendMessage(text, options);

View file

@ -22,6 +22,10 @@ const askSydney = async ({ text, onProgress, convo }) => {
options = { ...options, jailbreakConversationId: convo.jailbreakConversationId, parentMessageId: convo.parentMessageId }; options = { ...options, jailbreakConversationId: convo.jailbreakConversationId, parentMessageId: convo.parentMessageId };
} }
if (convo.toneStyle) {
options.toneStyle = convo.toneStyle;
}
console.log('sydney options', options); console.log('sydney options', options);
const res = await sydneyClient.sendMessage(text, options const res = await sydneyClient.sendMessage(text, options

View file

@ -32,6 +32,10 @@ const convoSchema = mongoose.Schema(
invocationId: { invocationId: {
type: String type: String
}, },
toneStyle: {
type: String,
default: null
},
chatGptLabel: { chatGptLabel: {
type: String, type: String,
default: null default: null

123
client/package-lock.json generated
View file

@ -13,7 +13,7 @@
"@radix-ui/react-dialog": "^1.0.2", "@radix-ui/react-dialog": "^1.0.2",
"@radix-ui/react-dropdown-menu": "^2.0.2", "@radix-ui/react-dropdown-menu": "^2.0.2",
"@radix-ui/react-label": "^2.0.0", "@radix-ui/react-label": "^2.0.0",
"@radix-ui/react-tabs": "^1.0.2", "@radix-ui/react-tabs": "^1.0.3",
"@reduxjs/toolkit": "^1.9.2", "@reduxjs/toolkit": "^1.9.2",
"axios": "^1.3.4", "axios": "^1.3.4",
"class-variance-authority": "^0.4.0", "class-variance-authority": "^0.4.0",
@ -41,6 +41,7 @@
"swr": "^2.0.3", "swr": "^2.0.3",
"tailwind-merge": "^1.9.1", "tailwind-merge": "^1.9.1",
"tailwindcss-animate": "^1.0.5", "tailwindcss-animate": "^1.0.5",
"tailwindcss-radix": "^2.8.0",
"url": "^0.11.0", "url": "^0.11.0",
"uuidv4": "^6.2.13" "uuidv4": "^6.2.13"
}, },
@ -2897,9 +2898,9 @@
} }
}, },
"node_modules/@radix-ui/react-tabs": { "node_modules/@radix-ui/react-tabs": {
"version": "1.0.2", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.3.tgz",
"integrity": "sha512-gOUwh+HbjCuL0UCo8kZ+kdUEG8QtpdO4sMQduJ34ZEz0r4922g9REOBM+vIsfwtGxSug4Yb1msJMJYN2Bk8TpQ==", "integrity": "sha512-4CkF/Rx1GcrusI/JZ1Rvyx4okGUs6wEenWA0RG/N+CwkRhTy7t54y7BLsWUXrAz/GRbBfHQg/Odfs/RoW0CiRA==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.13.10", "@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0", "@radix-ui/primitive": "1.0.0",
@ -2907,8 +2908,58 @@
"@radix-ui/react-direction": "1.0.0", "@radix-ui/react-direction": "1.0.0",
"@radix-ui/react-id": "1.0.0", "@radix-ui/react-id": "1.0.0",
"@radix-ui/react-presence": "1.0.0", "@radix-ui/react-presence": "1.0.0",
"@radix-ui/react-primitive": "1.0.1", "@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-roving-focus": "1.0.2", "@radix-ui/react-roving-focus": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.0"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-collection": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.2.tgz",
"integrity": "sha512-s8WdQQ6wNXpaxdZ308KSr8fEWGrg4un8i4r/w7fhiS4ElRNjk5rRcl0/C6TANG2LvLOGIxtzo/jAg6Qf73TEBw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-slot": "1.0.1"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.2.tgz",
"integrity": "sha512-zY6G5Qq4R8diFPNwtyoLRZBxzu1Z+SXMlfYpChN7Dv8gvmx9X3qhDqiLWvKseKVJMuedFeU/Sa0Sy/Ia+t06Dw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-slot": "1.0.1"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-roving-focus": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.3.tgz",
"integrity": "sha512-stjCkIoMe6h+1fWtXlA6cRfikdBzCLp3SnVk7c48cv/uy3DTGoXhN76YaOYUJuy3aEDvDIKwKR5KSmvrtPvQPQ==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
"@radix-ui/react-collection": "1.0.2",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-direction": "1.0.0",
"@radix-ui/react-id": "1.0.0",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-use-callback-ref": "1.0.0",
"@radix-ui/react-use-controllable-state": "1.0.0" "@radix-ui/react-use-controllable-state": "1.0.0"
}, },
"peerDependencies": { "peerDependencies": {
@ -11886,6 +11937,11 @@
"tailwindcss": ">=3.0.0 || insiders" "tailwindcss": ">=3.0.0 || insiders"
} }
}, },
"node_modules/tailwindcss-radix": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tailwindcss-radix/-/tailwindcss-radix-2.8.0.tgz",
"integrity": "sha512-1k1UfoIYgVyBl13FKwwoKavjnJ5VEaUClCTAsgz3VLquN4ay/lyaMPzkbqD71sACDs2fRGImytAUlMb4TzOt1A=="
},
"node_modules/tailwindcss/node_modules/color-name": { "node_modules/tailwindcss/node_modules/color-name": {
"version": "1.1.4", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
@ -15035,9 +15091,9 @@
} }
}, },
"@radix-ui/react-tabs": { "@radix-ui/react-tabs": {
"version": "1.0.2", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.2.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.3.tgz",
"integrity": "sha512-gOUwh+HbjCuL0UCo8kZ+kdUEG8QtpdO4sMQduJ34ZEz0r4922g9REOBM+vIsfwtGxSug4Yb1msJMJYN2Bk8TpQ==", "integrity": "sha512-4CkF/Rx1GcrusI/JZ1Rvyx4okGUs6wEenWA0RG/N+CwkRhTy7t54y7BLsWUXrAz/GRbBfHQg/Odfs/RoW0CiRA==",
"requires": { "requires": {
"@babel/runtime": "^7.13.10", "@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0", "@radix-ui/primitive": "1.0.0",
@ -15045,9 +15101,49 @@
"@radix-ui/react-direction": "1.0.0", "@radix-ui/react-direction": "1.0.0",
"@radix-ui/react-id": "1.0.0", "@radix-ui/react-id": "1.0.0",
"@radix-ui/react-presence": "1.0.0", "@radix-ui/react-presence": "1.0.0",
"@radix-ui/react-primitive": "1.0.1", "@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-roving-focus": "1.0.2", "@radix-ui/react-roving-focus": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.0" "@radix-ui/react-use-controllable-state": "1.0.0"
},
"dependencies": {
"@radix-ui/react-collection": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.2.tgz",
"integrity": "sha512-s8WdQQ6wNXpaxdZ308KSr8fEWGrg4un8i4r/w7fhiS4ElRNjk5rRcl0/C6TANG2LvLOGIxtzo/jAg6Qf73TEBw==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-slot": "1.0.1"
}
},
"@radix-ui/react-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.2.tgz",
"integrity": "sha512-zY6G5Qq4R8diFPNwtyoLRZBxzu1Z+SXMlfYpChN7Dv8gvmx9X3qhDqiLWvKseKVJMuedFeU/Sa0Sy/Ia+t06Dw==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-slot": "1.0.1"
}
},
"@radix-ui/react-roving-focus": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.3.tgz",
"integrity": "sha512-stjCkIoMe6h+1fWtXlA6cRfikdBzCLp3SnVk7c48cv/uy3DTGoXhN76YaOYUJuy3aEDvDIKwKR5KSmvrtPvQPQ==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
"@radix-ui/react-collection": "1.0.2",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-direction": "1.0.0",
"@radix-ui/react-id": "1.0.0",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-use-callback-ref": "1.0.0",
"@radix-ui/react-use-controllable-state": "1.0.0"
}
}
} }
}, },
"@radix-ui/react-use-callback-ref": { "@radix-ui/react-use-callback-ref": {
@ -21553,6 +21649,11 @@
"integrity": "sha512-UU3qrOJ4lFQABY+MVADmBm+0KW3xZyhMdRvejwtXqYOL7YjHYxmuREFAZdmVG5LPe5E9CAst846SLC4j5I3dcw==", "integrity": "sha512-UU3qrOJ4lFQABY+MVADmBm+0KW3xZyhMdRvejwtXqYOL7YjHYxmuREFAZdmVG5LPe5E9CAst846SLC4j5I3dcw==",
"requires": {} "requires": {}
}, },
"tailwindcss-radix": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tailwindcss-radix/-/tailwindcss-radix-2.8.0.tgz",
"integrity": "sha512-1k1UfoIYgVyBl13FKwwoKavjnJ5VEaUClCTAsgz3VLquN4ay/lyaMPzkbqD71sACDs2fRGImytAUlMb4TzOt1A=="
},
"tapable": { "tapable": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",

View file

@ -23,7 +23,7 @@
"@radix-ui/react-dialog": "^1.0.2", "@radix-ui/react-dialog": "^1.0.2",
"@radix-ui/react-dropdown-menu": "^2.0.2", "@radix-ui/react-dropdown-menu": "^2.0.2",
"@radix-ui/react-label": "^2.0.0", "@radix-ui/react-label": "^2.0.0",
"@radix-ui/react-tabs": "^1.0.2", "@radix-ui/react-tabs": "^1.0.3",
"@reduxjs/toolkit": "^1.9.2", "@reduxjs/toolkit": "^1.9.2",
"axios": "^1.3.4", "axios": "^1.3.4",
"class-variance-authority": "^0.4.0", "class-variance-authority": "^0.4.0",
@ -51,6 +51,7 @@
"swr": "^2.0.3", "swr": "^2.0.3",
"tailwind-merge": "^1.9.1", "tailwind-merge": "^1.9.1",
"tailwindcss-animate": "^1.0.5", "tailwindcss-animate": "^1.0.5",
"tailwindcss-radix": "^2.8.0",
"url": "^0.11.0", "url": "^0.11.0",
"uuidv4": "^6.2.13" "uuidv4": "^6.2.13"
}, },

View file

@ -23,7 +23,6 @@ export default function Conversation({
}) { }) {
const [renaming, setRenaming] = useState(false); const [renaming, setRenaming] = useState(false);
const [titleInput, setTitleInput] = useState(title); const [titleInput, setTitleInput] = useState(title);
const { modelMap } = useSelector((state) => state.models);
const { stopStream } = useSelector((state) => state.submit); const { stopStream } = useSelector((state) => state.submit);
const inputRef = useRef(null); const inputRef = useRef(null);
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -49,7 +48,8 @@ export default function Conversation({
conversationSignature, conversationSignature,
jailbreakConversationId, jailbreakConversationId,
clientId, clientId,
invocationId invocationId,
toneStyle,
} = bingData; } = bingData;
dispatch( dispatch(
setConversation({ setConversation({
@ -59,6 +59,7 @@ export default function Conversation({
conversationSignature, conversationSignature,
clientId, clientId,
invocationId, invocationId,
toneStyle,
latestMessage: null latestMessage: null
}) })
); );
@ -71,6 +72,7 @@ export default function Conversation({
conversationSignature: null, conversationSignature: null,
clientId: null, clientId: null,
invocationId: null, invocationId: null,
toneStyle: null,
latestMessage: null latestMessage: null
}) })
); );
@ -85,13 +87,6 @@ export default function Conversation({
dispatch(setCustomModel(null)); dispatch(setCustomModel(null));
} }
// if (modelMap[chatGptLabel.toLowerCase()]) {
// console.log('custom model', chatGptLabel);
// dispatch(setCustomModel(chatGptLabel.toLowerCase()));
// } else {
// dispatch(setCustomModel(null));
// }
dispatch(setMessages(data)); dispatch(setMessages(data));
dispatch(setCustomGpt(convo)); dispatch(setCustomGpt(convo));
dispatch(setText('')); dispatch(setText(''));

View file

@ -14,7 +14,8 @@ export default function Conversations({ conversations, conversationId, moveToTop
conversationSignature: convo.conversationSignature, conversationSignature: convo.conversationSignature,
parentMessageId: convo.parentMessageId || null, parentMessageId: convo.parentMessageId || null,
clientId: convo.clientId, clientId: convo.clientId,
invocationId: convo.invocationId invocationId: convo.invocationId,
toneStyle: convo.toneStyle,
} }
: null; : null;

View file

@ -0,0 +1,61 @@
import React, { useState, useEffect, forwardRef } from 'react';
import { Tabs, TabsList, TabsTrigger } from '../ui/Tabs.tsx';
import { useDispatch, useSelector } from 'react-redux';
import { setConversation } from '~/store/convoSlice';
function BingStyles(props, ref) {
const dispatch = useDispatch();
const [value, setValue] = useState('fast');
const { model } = useSelector((state) => state.submit);
const { conversationId } = useSelector((state) => state.convo);
const { messages } = useSelector((state) => state.messages);
const isBing = model === 'bingai' || model === 'sydney';
useEffect(() => {
if (isBing && !conversationId) {
dispatch(setConversation({ toneStyle: value }));
}
}, [isBing, conversationId, model, value, dispatch]);
const show = isBing && (!conversationId || messages?.length === 0);
const defaultClasses = 'p-2 rounded-md font-normal bg-white/[.60] dark:bg-gray-700 text-black';
const defaultSelected = defaultClasses + 'font-medium data-[state=active]:text-white';
const selectedClass = (val) => val + '-tab ' + defaultSelected;
const changeHandler = value => {
setValue(value);
dispatch(setConversation({ toneStyle: value }));
};
return (
<Tabs
defaultValue={value}
className={`shadow-md mb-1 bing-styles ${show ? 'show' : ''}`}
onValueChange={changeHandler}
ref={ref}
>
<TabsList className="bg-white/[.60] dark:bg-gray-700">
<TabsTrigger
value="creative"
className={`${value === 'creative' ? selectedClass(value) : defaultClasses}`}
>
{'Creative'}
</TabsTrigger>
<TabsTrigger
value="fast"
className={`${value === 'fast' ? selectedClass(value) : defaultClasses}`}
>
{'Balanced'}
</TabsTrigger>
<TabsTrigger
value="precise"
className={`${value === 'precise' ? selectedClass(value) : defaultClasses}`}
>
{'Precise'}
</TabsTrigger>
</TabsList>
</Tabs>
);
}
export default forwardRef(BingStyles);

View file

@ -0,0 +1,16 @@
import React from 'react';
export default function RowButton({ onClick, children, text, className }) {
return (
<button
onClick={onClick}
className={`input-panel-button btn btn-neutral flex justify-center gap-2 border-0 md:border ${className}`}
type="button"
>
{children}
<span className="hidden md:block">{text}</span>
{/* <RegenerateIcon />
<span className="hidden md:block">Regenerate response</span> */}
</button>
);
}

View file

@ -1,38 +1,30 @@
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { SSE } from '~/utils/sse'; import { SSE } from '~/utils/sse';
import SubmitButton from './SubmitButton'; import SubmitButton from './SubmitButton';
import Regenerate from './Regenerate'; // import Regenerate from './Regenerate'; // not used as of Wentao's update
import BingStyles from './BingStyles';
import ModelMenu from '../Models/ModelMenu'; import ModelMenu from '../Models/ModelMenu';
import Footer from './Footer'; import Footer from './Footer';
import TextareaAutosize from 'react-textarea-autosize'; import TextareaAutosize from 'react-textarea-autosize';
import createPayload from '~/utils/createPayload'; import createPayload from '~/utils/createPayload';
import resetConvo from '~/utils/resetConvo';
import RegenerateIcon from '../svg/RegenerateIcon'; import RegenerateIcon from '../svg/RegenerateIcon';
import StopGeneratingIcon from '../svg/StopGeneratingIcon'; import StopGeneratingIcon from '../svg/StopGeneratingIcon';
import { useSelector, useDispatch } from 'react-redux'; import { setConversation, setError, refreshConversation } from '~/store/convoSlice';
import {
setConversation,
setNewConvo,
setError,
refreshConversation
} from '~/store/convoSlice';
import { setMessages } from '~/store/messageSlice'; import { setMessages } from '~/store/messageSlice';
import { setSubmitState, toggleCursor } from '~/store/submitSlice'; import { setSubmitState, toggleCursor } from '~/store/submitSlice';
import { setText } from '~/store/textSlice'; import { setText } from '~/store/textSlice';
import { useMessageHandler } from '../../utils/handleSubmit'; import { useMessageHandler } from '../../utils/handleSubmit';
export default function TextChat({ messages }) { export default function TextChat({ messages }) {
const [errorMessage, setErrorMessage] = useState('');
const inputRef = useRef(null); const inputRef = useRef(null);
const bingStylesRef = useRef(null);
const isComposing = useRef(false); const isComposing = useRef(false);
const dispatch = useDispatch(); const dispatch = useDispatch();
const { user } = useSelector((state) => state.user); const convo = useSelector(state => state.convo);
const convo = useSelector((state) => state.convo); const { isSubmitting, stopStream, submission, disabled } = useSelector(state => state.submit);
const { initial } = useSelector((state) => state.models); const { text } = useSelector(state => state.text);
const { isSubmitting, stopStream, submission, disabled, model, chatGptLabel, promptPrefix } = const { latestMessage } = convo;
useSelector((state) => state.submit);
const { text } = useSelector((state) => state.text);
const { error, latestMessage } = convo;
const { ask, regenerate, stopGenerating } = useMessageHandler(); const { ask, regenerate, stopGenerating } = useMessageHandler();
const isNotAppendable = latestMessage?.cancelled || latestMessage?.error; const isNotAppendable = latestMessage?.cancelled || latestMessage?.error;
@ -42,8 +34,24 @@ export default function TextChat({ messages }) {
inputRef.current?.focus(); inputRef.current?.focus();
}, [convo?.conversationId]); }, [convo?.conversationId]);
// controls the height of Bing tone style tabs
useEffect(() => {
if (!inputRef.current) {
return; // wait for the ref to be available
}
const resizeObserver = new ResizeObserver(() => {
const newHeight = inputRef.current.clientHeight;
if (newHeight >= 24) { // 24 is the default height of the input
bingStylesRef.current.style.bottom = 15 + newHeight + 'px';
}
});
resizeObserver.observe(inputRef.current);
return () => resizeObserver.disconnect();
}, [inputRef]);
const messageHandler = (data, currentState, currentMsg) => { const messageHandler = (data, currentState, currentMsg) => {
const { messages, _currentMsg, message, sender, isRegenerate } = currentState; const { messages, message, sender, isRegenerate } = currentState;
if (isRegenerate) if (isRegenerate)
dispatch( dispatch(
@ -75,7 +83,7 @@ export default function TextChat({ messages }) {
}; };
const cancelHandler = (data, currentState, currentMsg) => { const cancelHandler = (data, currentState, currentMsg) => {
const { messages, _currentMsg, message, sender, isRegenerate } = currentState; const { messages, message, sender, isRegenerate } = currentState;
if (isRegenerate) if (isRegenerate)
dispatch( dispatch(
@ -116,11 +124,9 @@ export default function TextChat({ messages }) {
); );
}; };
const convoHandler = (data, currentState, currentMsg) => { const convoHandler = (data, currentState) => {
const { requestMessage, responseMessage } = data; const { requestMessage, responseMessage } = data;
const { conversationId } = requestMessage; const { messages, message, isCustomModel, isRegenerate } = currentState;
const { messages, _currentMsg, message, isCustomModel, sender, isRegenerate } =
currentState;
const { model, chatGptLabel, promptPrefix } = message; const { model, chatGptLabel, promptPrefix } = message;
if (isRegenerate) dispatch(setMessages([...messages, responseMessage])); if (isRegenerate) dispatch(setMessages([...messages, responseMessage]));
else dispatch(setMessages([...messages, requestMessage, responseMessage])); else dispatch(setMessages([...messages, requestMessage, responseMessage]));
@ -199,14 +205,13 @@ export default function TextChat({ messages }) {
}; };
const errorHandler = (data, currentState, currentMsg) => { const errorHandler = (data, currentState, currentMsg) => {
const { initialResponse, messages, _currentMsg, message } = currentState; const { messages, message } = currentState;
console.log('Error:', data); console.log('Error:', data);
const errorResponse = { const errorResponse = {
...data, ...data,
error: true, error: true,
parentMessageId: currentMsg?.messageId parentMessageId: currentMsg?.messageId
}; };
setErrorMessage(data?.text);
dispatch(setSubmitState(false)); dispatch(setSubmitState(false));
dispatch(setMessages([...messages, currentMsg, errorResponse])); dispatch(setMessages([...messages, currentMsg, errorResponse]));
dispatch(setText(message?.text)); dispatch(setText(message?.text));
@ -229,7 +234,7 @@ export default function TextChat({ messages }) {
let latestResponseText = ''; let latestResponseText = '';
const { server, payload } = createPayload(submission); const { server, payload } = createPayload(submission);
const onMessage = (e) => { const onMessage = e => {
if (stopStream) { if (stopStream) {
return; return;
} }
@ -237,7 +242,7 @@ export default function TextChat({ messages }) {
const data = JSON.parse(e.data); const data = JSON.parse(e.data);
if (data.final) { if (data.final) {
convoHandler(data, currentState, currentMsg); convoHandler(data, currentState);
dispatch(toggleCursor()); dispatch(toggleCursor());
console.log('final', data); console.log('final', data);
} }
@ -268,7 +273,7 @@ export default function TextChat({ messages }) {
events.onmessage = onMessage; events.onmessage = onMessage;
events.oncancel = (e) => { events.oncancel = () => {
dispatch(toggleCursor(true)); dispatch(toggleCursor(true));
cancelHandler(latestResponseText, currentState, currentMsg); cancelHandler(latestResponseText, currentState, currentMsg);
}; };
@ -304,7 +309,7 @@ export default function TextChat({ messages }) {
stopGenerating(); stopGenerating();
}; };
const handleKeyDown = (e) => { const handleKeyDown = e => {
if (e.key === 'Enter' && !e.shiftKey) { if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault(); e.preventDefault();
} }
@ -314,7 +319,11 @@ export default function TextChat({ messages }) {
} }
}; };
const handleKeyUp = (e) => { const handleKeyUp = e => {
if (e.keyCode === 8 && e.target.value.trim() === '') {
dispatch(setText(e.target.value));
}
if (e.key === 'Enter' && e.shiftKey) { if (e.key === 'Enter' && e.shiftKey) {
return console.log('Enter + Shift'); return console.log('Enter + Shift');
} }
@ -324,15 +333,15 @@ export default function TextChat({ messages }) {
} }
}; };
const handleCompositionStart = (e) => { const handleCompositionStart = () => {
isComposing.current = true; isComposing.current = true;
}; };
const handleCompositionEnd = (e) => { const handleCompositionEnd = () => {
isComposing.current = false; isComposing.current = false;
}; };
const changeHandler = (e) => { const changeHandler = e => {
const { value } = e.target; const { value } = e.target;
// if (isSubmitting && (value === '' || value === '\n')) { // if (isSubmitting && (value === '' || value === '\n')) {
@ -341,85 +350,88 @@ export default function TextChat({ messages }) {
dispatch(setText(value)); dispatch(setText(value));
}; };
const tryAgain = (e) => { // const tryAgain = (e) => {
e.preventDefault(); // e.preventDefault();
dispatch(setError(false)); // dispatch(setError(false));
}; // };
const isSearchView = messages?.[0]?.searchResult === true; const isSearchView = messages?.[0]?.searchResult === true;
const getPlaceholderText = () => { const getPlaceholderText = () => {
if (isSearchView) { if (isSearchView) {
return 'Click a message title to open its conversation.' return 'Click a message title to open its conversation.';
} }
if (disabled) { if (disabled) {
return 'Choose another model or customize GPT again'; return 'Choose another model or customize GPT again';
} }
if (isNotAppendable) { if (isNotAppendable) {
return 'Edit your message or Regenerate.' return 'Edit your message or Regenerate.';
} }
return ''; return '';
}; };
return ( return (
<div className="input-panel md:bg-vert-light-gradient dark:md:bg-vert-dark-gradient fixed bottom-0 left-0 w-full border-t bg-white py-2 dark:border-white/20 dark:bg-gray-800 md:absolute md:border-t-0 md:border-transparent md:bg-transparent md:dark:border-transparent md:dark:bg-transparent"> <>
<form className="stretch mx-2 flex flex-row gap-3 last:mb-2 md:pt-2 md:last:mb-6 lg:mx-auto lg:max-w-3xl lg:pt-6"> <div className="input-panel md:bg-vert-light-gradient dark:md:bg-vert-dark-gradient fixed bottom-0 left-0 w-full border-t bg-white py-2 dark:border-white/20 dark:bg-gray-800 md:absolute md:border-t-0 md:border-transparent md:bg-transparent md:dark:border-transparent md:dark:bg-transparent">
<div className="relative flex h-full flex-1 md:flex-col"> <form className="stretch mx-2 flex flex-row gap-3 last:mb-2 md:pt-2 md:last:mb-6 lg:mx-auto lg:max-w-3xl lg:pt-6">
<span className="order-last ml-1 flex justify-center gap-0 md:order-none md:m-auto md:mb-2 md:w-full md:gap-2"> <div className="relative flex h-full flex-1 md:flex-col">
{isSubmitting && !isSearchView ? ( <span className="order-last ml-1 flex justify-center gap-0 md:order-none md:m-auto md:mb-2 md:w-full md:gap-2">
<button <BingStyles ref={bingStylesRef}/>
onClick={handleStopGenerating} {isSubmitting && !isSearchView ? (
className="input-panel-button btn btn-neutral flex justify-center gap-2 border-0 md:border" <button
type="button" onClick={handleStopGenerating}
> className="input-panel-button btn btn-neutral flex justify-center gap-2 border-0 md:border"
<StopGeneratingIcon /> type="button"
<span className="hidden md:block">Stop generating</span> >
</button> <StopGeneratingIcon />
) : latestMessage && !latestMessage?.isCreatedByUser && !isSearchView ? ( <span className="hidden md:block">Stop generating</span>
<button </button>
onClick={handleRegenerate} ) : latestMessage && !latestMessage?.isCreatedByUser && !isSearchView ? (
className="input-panel-button btn btn-neutral flex justify-center gap-2 border-0 md:border" <button
type="button" onClick={handleRegenerate}
> className="input-panel-button btn btn-neutral flex justify-center gap-2 border-0 md:border"
<RegenerateIcon /> type="button"
<span className="hidden md:block">Regenerate response</span> >
</button> <RegenerateIcon />
) : null} <span className="hidden md:block">Regenerate response</span>
</span> </button>
<div ) : null}
className={`relative flex flex-grow flex-col rounded-md border border-black/10 ${ </span>
disabled ? 'bg-gray-100' : 'bg-white' <div
} py-2 shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:border-gray-900/50 ${ className={`relative flex flex-grow flex-col rounded-md border border-black/10 ${
disabled ? 'dark:bg-gray-900' : 'dark:bg-gray-700' disabled ? 'bg-gray-100' : 'bg-white'
} dark:text-white dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] md:py-3 md:pl-4`} } py-2 shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:border-gray-900/50 ${
> disabled ? 'dark:bg-gray-900' : 'dark:bg-gray-700'
<ModelMenu /> } dark:text-white dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] md:py-3 md:pl-4`}
<TextareaAutosize >
tabIndex="0" <ModelMenu />
autoFocus <TextareaAutosize
ref={inputRef} tabIndex="0"
// style={{maxHeight: '200px', height: '24px', overflowY: 'hidden'}} autoFocus
rows="1" ref={inputRef}
value={disabled || isNotAppendable ? '' : text} // style={{maxHeight: '200px', height: '24px', overflowY: 'hidden'}}
onKeyUp={handleKeyUp} rows="1"
onKeyDown={handleKeyDown} value={disabled || isNotAppendable ? '' : text}
onChange={changeHandler} onKeyUp={handleKeyUp}
onCompositionStart={handleCompositionStart} onKeyDown={handleKeyDown}
onCompositionEnd={handleCompositionEnd} onChange={changeHandler}
placeholder={getPlaceholderText()} onCompositionStart={handleCompositionStart}
disabled={disabled || isNotAppendable} onCompositionEnd={handleCompositionEnd}
className="m-0 h-auto max-h-52 resize-none overflow-auto border-0 bg-transparent p-0 pl-12 pr-8 leading-6 placeholder:text-sm placeholder:text-gray-600 dark:placeholder:text-gray-500 focus:outline-none focus:ring-0 focus-visible:ring-0 dark:bg-transparent md:pl-8" placeholder={getPlaceholderText()}
/> disabled={disabled || isNotAppendable}
<SubmitButton className="m-0 h-auto max-h-52 resize-none overflow-auto border-0 bg-transparent p-0 pl-12 pr-8 leading-6 placeholder:text-sm placeholder:text-gray-600 focus:outline-none focus:ring-0 focus-visible:ring-0 dark:bg-transparent dark:placeholder:text-gray-500 md:pl-8"
submitMessage={submitMessage} />
disabled={disabled || isNotAppendable} <SubmitButton
/> submitMessage={submitMessage}
disabled={disabled || isNotAppendable}
/>
</div>
</div> </div>
</div> </form>
</form> <Footer />
<Footer /> </div>
</div> </>
); );
} }

View file

@ -46,7 +46,7 @@ const inLineWrap = (parts) => {
}); });
}; };
export default function TextWrapper({ text, generateCursor }) { function TextWrapper({ text, generateCursor }) {
let embedTest = false; let embedTest = false;
let result = null; let result = null;
@ -158,3 +158,5 @@ export default function TextWrapper({ text, generateCursor }) {
</> </>
); );
} }
export default React.memo(TextWrapper);

View file

@ -14,7 +14,7 @@ const TabsList = React.forwardRef<
<TabsPrimitive.List <TabsPrimitive.List
ref={ref} ref={ref}
className={cn( className={cn(
"inline-flex items-center justify-center rounded-md bg-slate-100 p-1 dark:bg-slate-800", "inline-flex items-center justify-center rounded-md bg-gray-100 p-1 dark:bg-gray-800",
className className
)} )}
{...props} {...props}
@ -28,7 +28,7 @@ const TabsTrigger = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<TabsPrimitive.Trigger <TabsPrimitive.Trigger
className={cn( className={cn(
"inline-flex min-w-[100px] items-center justify-center rounded-[0.185rem] px-3 py-1.5 text-sm font-medium text-slate-700 transition-all disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm dark:text-slate-200 dark:data-[state=active]:bg-slate-900 dark:data-[state=active]:text-slate-100", "inline-flex min-w-[100px] items-center justify-center rounded-[0.185rem] px-3 py-1.5 text-sm font-medium text-gray-700 transition-all disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:text-gray-900 data-[state=active]:shadow-sm dark:text-gray-200 dark:data-[state=active]:bg-gray-700 dark:data-[state=active]:text-gray-100",
className className
)} )}
{...props} {...props}
@ -43,7 +43,7 @@ const TabsContent = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<TabsPrimitive.Content <TabsPrimitive.Content
className={cn( className={cn(
"mt-2 rounded-md border border-slate-200 p-6 dark:border-slate-700", "mt-2 rounded-md border border-gray-200 p-6 dark:border-gray-700",
className className
)} )}
{...props} {...props}

View file

@ -9,6 +9,7 @@ const initialState = {
conversationSignature: null, conversationSignature: null,
clientId: null, clientId: null,
invocationId: null, invocationId: null,
toneStyle: null,
chatGptLabel: null, chatGptLabel: null,
promptPrefix: null, promptPrefix: null,
convosLoading: false, convosLoading: false,
@ -58,6 +59,7 @@ const currentSlice = createSlice({
state.conversationSignature = null; state.conversationSignature = null;
state.clientId = null; state.clientId = null;
state.invocationId = null; state.invocationId = null;
state.toneStyle = null;
state.chatGptLabel = null; state.chatGptLabel = null;
state.promptPrefix = null; state.promptPrefix = null;
state.convosLoading = false; state.convosLoading = false;

View file

@ -28,6 +28,41 @@
transition: all 1s ease-in-out; transition: all 1s ease-in-out;
} */ } */
.bing-styles {
position: absolute;
left: 0;
right: 0;
opacity: 0;
bottom: 39px;
z-index: 995;
margin-left: auto;
margin-right: auto;
width: 308px; /* Need a specific value to work */
transition: all 0.5s ease-in-out;
pointer-events: none;
transform: translateY(-60px);
}
.bing-styles.show {
/* bottom: -20px; */
opacity: 1;
pointer-events: all;
transform: translateY(-20px);
}
.creative-tab {
/* background: linear-gradient(90deg, #904887 10.79%, #8B257E 87.08%); */
background: linear-gradient(90deg, #904887 10.79%, #8B257E 87.08%);
}
.fast-tab {
background: linear-gradient(90deg, #2870EA 10.79%, #1B4AEF 87.08%);
}
.precise-tab {
background: linear-gradient(90deg, #006880 10.79%, #005366 87.08%)
}
p > small { p > small {
opacity: 0; opacity: 0;
animation: fadein 3s forwards; animation: fadein 3s forwards;

View file

@ -13,6 +13,10 @@ export default function createPayload({ convo, message }) {
} }
const isBing = model === 'bingai' || model === 'sydney'; const isBing = model === 'bingai' || model === 'sydney';
if (isBing && !convo?.conversationId) {
payload.toneStyle = convo.toneStyle || 'fast';
}
if (isBing && convo?.conversationId) { if (isBing && convo?.conversationId) {
payload = { payload = {
...payload, ...payload,
@ -20,7 +24,8 @@ export default function createPayload({ convo, message }) {
conversationId: convo.conversationId, conversationId: convo.conversationId,
conversationSignature: convo.conversationSignature, conversationSignature: convo.conversationSignature,
clientId: convo.clientId, clientId: convo.clientId,
invocationId: convo.invocationId invocationId: convo.invocationId,
toneStyle: convo.toneStyle,
}; };
} }
@ -28,4 +33,4 @@ export default function createPayload({ convo, message }) {
server = model === 'bingai' ? server + '/bing' : server; server = model === 'bingai' ? server + '/bing' : server;
server = model === 'sydney' ? server + '/sydney' : server; server = model === 'sydney' ? server + '/sydney' : server;
return { server, payload }; return { server, payload };
}; }

View file

@ -1,4 +1,3 @@
import { SSE } from './sse';
import resetConvo from './resetConvo'; import resetConvo from './resetConvo';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { setNewConvo } from '~/store/convoSlice'; import { setNewConvo } from '~/store/convoSlice';
@ -14,7 +13,6 @@ const useMessageHandler = () => {
const { initial } = useSelector((state) => state.models); const { initial } = useSelector((state) => state.models);
const { messages } = useSelector((state) => state.messages); const { messages } = useSelector((state) => state.messages);
const { model, chatGptLabel, promptPrefix, isSubmitting } = useSelector((state) => state.submit); const { model, chatGptLabel, promptPrefix, isSubmitting } = useSelector((state) => state.submit);
const { text } = useSelector((state) => state.text);
const { latestMessage, error } = convo; const { latestMessage, error } = convo;
const ask = ({ text, parentMessageId=null, conversationId=null, messageId=null}, { isRegenerate=false }={}) => { const ask = ({ text, parentMessageId=null, conversationId=null, messageId=null}, { isRegenerate=false }={}) => {
@ -76,7 +74,7 @@ const useMessageHandler = () => {
if (parentMessage && parentMessage.isCreatedByUser) if (parentMessage && parentMessage.isCreatedByUser)
ask({ ...parentMessage }, { isRegenerate: true }) ask({ ...parentMessage }, { isRegenerate: true })
else else
console.error('Failed to regenerate the message: parentMessage not found or not created by user.', message); console.error('Failed to regenerate the message: parentMessage not found or not created by user.');
} }
const stopGenerating = () => { const stopGenerating = () => {
@ -88,78 +86,79 @@ const useMessageHandler = () => {
export { useMessageHandler }; export { useMessageHandler };
export default function handleSubmit({ // deprecated
model, // export default function handleSubmit({
text, // model,
convo, // text,
messageHandler, // convo,
convoHandler, // messageHandler,
errorHandler, // convoHandler,
chatGptLabel, // errorHandler,
promptPrefix // chatGptLabel,
}) { // promptPrefix
const endpoint = `/api/ask`; // }) {
let payload = { model, text, chatGptLabel, promptPrefix }; // const endpoint = `/api/ask`;
if (convo.conversationId && convo.parentMessageId) { // let payload = { model, text, chatGptLabel, promptPrefix };
payload = { // if (convo.conversationId && convo.parentMessageId) {
...payload, // payload = {
conversationId: convo.conversationId, // ...payload,
parentMessageId: convo.parentMessageId // conversationId: convo.conversationId,
}; // parentMessageId: convo.parentMessageId
} // };
// }
const isBing = model === 'bingai' || model === 'sydney'; // const isBing = model === 'bingai' || model === 'sydney';
if (isBing && convo.conversationId) { // if (isBing && convo.conversationId) {
payload = { // payload = {
...payload, // ...payload,
jailbreakConversationId: convo.jailbreakConversationId, // jailbreakConversationId: convo.jailbreakConversationId,
conversationId: convo.conversationId, // conversationId: convo.conversationId,
conversationSignature: convo.conversationSignature, // conversationSignature: convo.conversationSignature,
clientId: convo.clientId, // clientId: convo.clientId,
invocationId: convo.invocationId, // invocationId: convo.invocationId,
}; // };
} // }
let server = endpoint; // let server = endpoint;
server = model === 'bingai' ? server + '/bing' : server; // server = model === 'bingai' ? server + '/bing' : server;
server = model === 'sydney' ? server + '/sydney' : server; // server = model === 'sydney' ? server + '/sydney' : server;
const events = new SSE(server, { // const events = new SSE(server, {
payload: JSON.stringify(payload), // payload: JSON.stringify(payload),
headers: { 'Content-Type': 'application/json' } // headers: { 'Content-Type': 'application/json' }
}); // });
events.onopen = function () { // events.onopen = function () {
console.log('connection is opened'); // console.log('connection is opened');
}; // };
events.onmessage = function (e) { // events.onmessage = function (e) {
const data = JSON.parse(e.data); // const data = JSON.parse(e.data);
let text = data.text || data.response; // let text = data.text || data.response;
if (data.message) { // if (data.message) {
messageHandler(text, events); // messageHandler(text, events);
} // }
if (data.final) { // if (data.final) {
convoHandler(data); // convoHandler(data);
console.log('final', data); // console.log('final', data);
} else { // } else {
// console.log('dataStream', data); // // console.log('dataStream', data);
} // }
}; // };
events.onerror = function (e) { // events.onerror = function (e) {
console.log('error in opening conn.'); // console.log('error in opening conn.');
events.close(); // events.close();
errorHandler(e); // errorHandler(e);
}; // };
events.addEventListener('stop', () => { // events.addEventListener('stop', () => {
// Close the SSE stream // // Close the SSE stream
console.log('stop event received'); // console.log('stop event received');
events.close(); // events.close();
}); // });
events.stream(); // events.stream();
} // }

View file

@ -45,6 +45,7 @@ module.exports = {
}, },
plugins: [ plugins: [
require('tailwindcss-animate'), require('tailwindcss-animate'),
require("tailwindcss-radix")(),
// require('@tailwindcss/typography'), // require('@tailwindcss/typography'),
] ]
}; };