Add full-featured AIChat component
AIChat (elements/ai/AIChat) is a complete LLM chat UI built on new hooks: - useAIChat: streaming conversation state (send, stop, regenerate, edit, feedback); `send` may return a string, async iterable, ReadableStream or fetch Response - useAIChatHistory: saved conversations with optional localStorage persistence and generated titles, shown in AIChatSidebar - useAIChatSpeech: read aloud via browser speech synthesis or a custom `speak` returning audio - useAIChatDictation: voice input via browser recognition or a custom `transcribe` Also adds a model picker, message editing, thumbs up/down, markdown export, scoped markdown styles in base.css, the twuiReadTextStream, twuiStripMarkdown and twuiGroupByRecency utils (with tests), and a playground page. AIPromptBlock is kept and marked deprecated. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -25,7 +25,7 @@ Only install these if you use the matching components:
|
||||
| `editors/AceEditor` | `ace-builds` |
|
||||
| `elements/RemoteCodeBlock`, `mdx/markdown/*` | `next-mdx-remote`, `remark-gfm`, `rehype-prism-plus` |
|
||||
| `mdx/mdx-components`, `next-js/hooks/useMDXComponents` | `@types/mdx` (dev) |
|
||||
| `elements/ai/*` | `openai` (types), `react-markdown` |
|
||||
| `elements/ai/*` | `react-markdown`, `remark-gfm` (+ `openai` types for the legacy `AIPrompt*` blocks) |
|
||||
|
||||
`editors/TinyMCE` loads TinyMCE from a URL at runtime. Set it with the `base_url` prop, or with the `NEXT_PUBLIC_TINYMCE_BASE_URL` / `BUNEXT_PUBLIC_TINYMCE_BASE_URL` public env vars.
|
||||
|
||||
@@ -67,6 +67,39 @@ import TinyMCEEditor from "@moduletrace/twui/editors/TinyMCE";
|
||||
|
||||
Editors, MDX, Next.js helpers, the AI blocks and `RemoteCodeBlock` are **deep-import only**, so the root entry never pulls in optional peers.
|
||||
|
||||
### AI chat
|
||||
|
||||
`elements/ai/AIChat` is a complete chat UI. Give it a height and a `send` function. `send` can return a string, an async iterable of chunks, a `ReadableStream`, or a fetch `Response`:
|
||||
|
||||
```tsx
|
||||
import AIChat from "@moduletrace/twui/elements/ai/AIChat";
|
||||
|
||||
<AIChat
|
||||
className="h-[80vh]"
|
||||
history={{ storageKey: "my-app-chats" }}
|
||||
models={["gpt-5", "claude-opus-5-5"]}
|
||||
send={({ messages, model, signal }) =>
|
||||
fetch("/api/chat", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ messages, model }),
|
||||
signal,
|
||||
})
|
||||
}
|
||||
/>;
|
||||
```
|
||||
|
||||
| Feature | Props |
|
||||
| --- | --- |
|
||||
| Streaming replies, stop, regenerate, retry | built in |
|
||||
| Saved conversations (sidebar, search, pin, rename, delete) | `history` (`true`, options, or a `useAIChatHistory()` result), `generateTitle` in the options |
|
||||
| Read aloud (text-to-speech) | `speech` (browser voice by default, or `{ speak }` returning audio), `autoSpeak` |
|
||||
| Voice input (speech-to-text) | `dictation` (browser recognition by default, or `{ transcribe }`) |
|
||||
| Model picker | `models`, `model`, `onModelChange` |
|
||||
| Edit messages, thumbs up/down, markdown export | `editable`, `feedback` / `onFeedback`, `exportable` |
|
||||
| Empty state, avatars, custom rendering | `suggestions`, `emptyState`, `userImageUrl`, `renderMessageContent`, `renderMessageActions` |
|
||||
|
||||
To drive the chat from outside, call `useAIChat` (and `useAIChatHistory`) yourself and pass the results as `chat` and `history`. The pieces (`AIChatMessage`, `AIChatComposer`, `AIChatSidebar`, `useAIChatSpeech`, `useAIChatDictation`) are exported from `elements/ai/` for custom layouts.
|
||||
|
||||
Component modules are marked `"use client"`, so they work in the Next.js App Router.
|
||||
|
||||
## Development
|
||||
|
||||
Reference in New Issue
Block a user