91 lines
2.6 KiB
TypeScript
91 lines
2.6 KiB
TypeScript
import { app } from '../ai';
|
|
import { Sender, XProvider, Bubble } from '@ant-design/x';
|
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
import { postChat } from './chat';
|
|
import { Nav } from '../nav';
|
|
import { ToastContainer } from 'react-toastify';
|
|
import { useHomeStore } from './store';
|
|
import { nanoid } from 'nanoid';
|
|
import { Beian } from '../beian';
|
|
const useFocus = () => {
|
|
const inputRef = useRef<HTMLInputElement>(null);
|
|
useEffect(() => {
|
|
// Focus the input element inside Sender component
|
|
const focusInput = () => {
|
|
if (inputRef.current) {
|
|
const input = inputRef.current.querySelector('input, textarea') as HTMLInputElement | HTMLTextAreaElement;
|
|
if (input) {
|
|
input.focus();
|
|
}
|
|
}
|
|
};
|
|
|
|
// Focus on mount
|
|
focusInput();
|
|
|
|
// Also focus after a short delay to ensure everything is rendered
|
|
const timeoutId = setTimeout(focusInput, 100);
|
|
|
|
return () => clearTimeout(timeoutId);
|
|
}, []);
|
|
|
|
return inputRef;
|
|
}
|
|
|
|
export const App = () => {
|
|
const inputRef = useFocus();
|
|
const [content, setContent] = useState<string>('');
|
|
const { inputValue, setInputValue, isLoading, setLoading, messages, addMessage } = useHomeStore();
|
|
|
|
const msg = useMemo(() => {
|
|
return <Bubble.List items={messages} autoScroll ></Bubble.List>
|
|
}, [messages]);
|
|
return <div className='container mx-auto px-4 py-4 md:p-4 flex flex-col' style={{ height: 'calc(100vh - 64px)' }}>
|
|
<div className='flex-shrink-0 mb-4 w-full mx-auto px-4 md:px-0' ref={inputRef}>
|
|
<Sender
|
|
allowSpeech
|
|
value={inputValue}
|
|
onChange={setInputValue}
|
|
loading={isLoading}
|
|
onSubmit={async (message) => {
|
|
console.log('Submitted', message);
|
|
setLoading(true);
|
|
addMessage({ role: 'user', content: message, key: nanoid() });
|
|
|
|
const res = await postChat(message);
|
|
setContent(res || ' ');
|
|
setLoading(false);
|
|
addMessage({ role: 'assistant', content: res || ' ', key: nanoid() });
|
|
}}
|
|
/>
|
|
</div>
|
|
<div className='flex-1 overflow-y-auto px-2 md:px-0 mb-4'>
|
|
{msg}
|
|
</div>
|
|
</div >;
|
|
}
|
|
|
|
|
|
export const AppProvider = () => {
|
|
return <XProvider
|
|
theme={{
|
|
token: {
|
|
colorPrimary: '#000000',
|
|
colorBgBase: '#ffffff',
|
|
colorTextBase: '#000000',
|
|
colorBorder: '#d9d9d9',
|
|
colorBgContainer: '#ffffff',
|
|
colorBgElevated: '#ffffff',
|
|
colorBgLayout: '#ffffff',
|
|
colorText: '#000000',
|
|
colorTextSecondary: '#666666',
|
|
colorTextTertiary: '#999999',
|
|
}
|
|
}}
|
|
>
|
|
<Nav />
|
|
<App />
|
|
<ToastContainer />
|
|
<Beian />
|
|
</XProvider>;
|
|
} |