@coreexl/mentor
v0.2.5
Published
A fully customizable, reusable mentor/chat interface component built with React, LiveKit, and TypeScript
Readme
@coreexl/mentor
v0.2.4 — React UI package for SchoolExl's AI mentor — chat, voice, and avatar video powered by LiveKit Agents.
Installation
npm install @coreexl/mentor
# or
pnpm add @coreexl/mentorNo CSS import needed. Styles inject automatically when the component mounts.
If your project uses Tailwind v4, add one @source directive to your globals.css:
@source "../node_modules/@coreexl/mentor/src/**/*.{ts,tsx}";Components
<MentorPage>
The main all-in-one mentor interface. Renders a chat panel with optional voice and avatar modes.
import { MentorPage } from '@coreexl/mentor'
<MentorPage
accessKey="your-access-key"
serverUrl="https://your-server.com"
agentName="Coach Sarah"
systemPrompt="You are a helpful tutor..."
language="en-US"
gender="female"
/>Key props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| accessKey | string | required | Server access key |
| serverUrl | string | env NEXT_PUBLIC_COREEXL_MENTOR_SERVER | Backend URL |
| systemPrompt | string | — | Agent personality / instructions |
| agentName | string | "Coach Timothy" | Display name |
| agentTitle | string | "Concept Coach" | Subtitle |
| language | string | "en-IN" | BCP-47 language code for TTS + STT |
| gender | "female" \| "male" | "female" | Voice gender |
| voiceName | string | — | Specific Google Chirp3-HD voice name (e.g. "Aoede", "Fenrir") |
| ttsProvider | "google" \| "chatterbox" | "google" | TTS engine — Google Chirp3 HD or Chatterbox Turbo (voice cloning) |
| chatterboxVoice | string | — | Named voice on the Chatterbox server (e.g. "jamaican_female", "jamaican_male") |
| mode | "chat" \| "avatar" | "chat" | UI mode |
| videoMode | boolean | false | Enable Ditto avatar video (use with mode="avatar") |
| avatarId | string | "imogen" | Avatar ID registered on the Ditto server |
| avatarService | "ditto" \| "tavus" \| "bey" | "ditto" | Avatar backend |
| overlay | boolean | false | Render as floating draggable overlay widget |
| presentContent | ReactNode | — | Content for the Present tab |
| userId | string | auto-generated | Stable user identity |
| debug | boolean | false | Enable verbose logging |
| tools | Tool[] | — | OpenAI-format tool definitions forwarded to the agent |
| onToolCall | OnToolCallHandler | — | Handler called when agent invokes a tool |
| onConnect | () => void | — | Called on successful connection |
| onDisconnect | () => void | — | Called on disconnection |
<AvatarPanel>
A standalone avatar-only component — just the video frame and a connect button.
import { AvatarPanel } from '@coreexl/mentor'
<AvatarPanel
accessKey="your-access-key"
serverUrl="https://your-server.com"
avatarId="imogen"
language="hi-IN"
gender="female"
width={340}
height={512}
borderRadius={20}
resizable
/>| Prop | Type | Default | Description |
|------|------|---------|-------------|
| accessKey | string | required | Server access key |
| serverUrl | string | env | Backend URL |
| avatarId | string | "imogen" | Avatar ID |
| avatarService | string | "ditto" | Avatar backend |
| language | string | "en-IN" | BCP-47 language code |
| gender | "female" \| "male" | "female" | Voice gender |
| ttsProvider | "google" \| "chatterbox" | "google" | TTS engine |
| chatterboxVoice | string | — | Named Chatterbox voice |
| systemPrompt | string | — | Agent instructions |
| avatarPreviewUrl | string | — | Image shown blurred before connecting |
| cameraMode | boolean | false | Enable camera toggle button |
| width | string \| number | "100%" | Frame width |
| height | string \| number | "100%" | Frame height |
| borderRadius | string \| number | 16 | Frame corner radius |
| resizable | boolean | false | Show drag-to-resize handle |
TTS Providers
Google Chirp3 HD (default)
High-quality neural voices in 50+ languages. Auto-selects based on language + gender, or pin a specific voice with voiceName.
<MentorPage ttsProvider="google" language="en-US" gender="female" voiceName="Aoede" />Chatterbox Turbo (voice cloning)
Local GPU-based TTS with voice cloning. Requires a running Chatterbox server configured via CHATTERBOX_URL on the backend.
Supports paralinguistic tags in generated speech: [laughs], [sighs], [excited], [curious], [chuckle], [gasp], [whispers].
<MentorPage ttsProvider="chatterbox" chatterboxVoice="jamaican_female" />Jamaican voices
When chatterboxVoice contains "jamaican", the agent automatically applies a Jamaican voice style:
- Authentic expressions: wah gwaan, irie, mi deh yah, bless up, everyting criss, nuh true?
- Emotion tags placed naturally inline:
[laughs],[sighs],[excited] - Rhythm punctuation — ellipses
…for pauses, CAPS for emphasis - Short punchy conversational sentences
// Warm Jamaican female mentor
<MentorPage
ttsProvider="chatterbox"
chatterboxVoice="jamaican_female"
agentName="Paulette"
systemPrompt="You are Paulette, a warm Jamaican tutor..."
/>
// Deep Jamaican male mentor
<MentorPage
ttsProvider="chatterbox"
chatterboxVoice="jamaican_male"
agentName="Denzel"
gender="male"
systemPrompt="You are Denzel, a confident Jamaican mentor..."
/>Uploading a custom voice
POST a WAV or MP3 to your Chatterbox server once — saved permanently by name:
curl -X POST https://your-chatterbox-server/voices/upload \
-F "name=my_voice" \
-F "[email protected]"Then use it: <MentorPage ttsProvider="chatterbox" chatterboxVoice="my_voice" />
Typical layout: Avatar + Chat side by side
import { AvatarPanel, MentorPage } from '@coreexl/mentor'
export default function TutorPage() {
return (
<div style={{ display: 'flex', height: '100vh', gap: 16, padding: 16 }}>
<AvatarPanel
accessKey={process.env.NEXT_PUBLIC_ACCESS_KEY!}
serverUrl={process.env.NEXT_PUBLIC_MENTOR_SERVER}
avatarId="imogen"
language="en-US"
gender="female"
width={340}
height="100%"
borderRadius={20}
/>
<div style={{ flex: 1 }}>
<MentorPage
accessKey={process.env.NEXT_PUBLIC_ACCESS_KEY!}
serverUrl={process.env.NEXT_PUBLIC_MENTOR_SERVER}
agentName="Coach Sarah"
language="en-US"
gender="female"
mode="chat"
/>
</div>
</div>
)
}Language Support
| Language | Code | Female Voice | Male Voice |
|----------|------|-------------|-----------|
| English (India) | en-IN | Despina | Charon |
| English (US) | en-US | Puck | Fenrir |
| English (UK) | en-GB | Aoede | Charon |
| English (Australia) | en-AU | Zephyr | Fenrir |
| Hindi | hi-IN | Leda | Orus |
| Punjabi | pa-IN | Leda | Orus |
| Urdu | ur-IN | Aoede | Charon |
| Bengali | bn-IN | Aoede | Orus |
| Gujarati | gu-IN | Aoede | Orus |
| Kannada | kn-IN | Aoede | Rasalgethi |
| Malayalam | ml-IN | Aoede | Charon |
| Marathi | mr-IN | Aoede | Iapetus |
| Tamil | ta-IN | Aoede | Orus |
| Telugu | te-IN | Aoede | Orus |
| French | fr-FR | Kore | Orus |
| French (Canada) | fr-CA | Aoede | Charon |
| German | de-DE | Aoede | Orus |
| Spanish | es-ES | Zephyr | Fenrir |
| Spanish (US) | es-US | Leda | Fenrir |
| Portuguese (Brazil) | pt-BR | Aoede | Orus |
| Portuguese (Portugal) | pt-PT | Leda | Charon |
| Arabic | ar-XA | Zephyr | Rasalgethi |
| Japanese | ja-JP | Autonoe | Fenrir |
| Korean | ko-KR | Aoede | Iapetus |
| Chinese (Simplified) | zh-CN | Aoede | Gacrux |
| Chinese (Traditional) | zh-TW | Leda | Umbriel |
| Chinese (Cantonese) | yue-HK | Aoede | Orus |
| Italian | it-IT | Aoede | Orus |
| Dutch | nl-NL | Aoede | Charon |
| Polish | pl-PL | Erinome | Orus |
| Russian | ru-RU | Callirrhoe | Fenrir |
| Turkish | tr-TR | Aoede | Achird |
| Swedish | sv-SE | Aoede | Charon |
| Danish | da-DK | Aoede | Orus |
| Finnish | fi-FI | Aoede | Charon |
| Czech | cs-CZ | Aoede | Algenib |
| Indonesian | id-ID | Aoede | Orus |
| Thai | th-TH | Aoede | Orus |
| Vietnamese | vi-VN | Aoede | Fenrir |
Overlay mode
<MentorPage accessKey="..." overlay agentName="Tutor" />Renders as a floating minimizable widget in the bottom-right corner.
Tool calling
<MentorPage
accessKey="..."
tools={[{
type: 'function',
function: {
name: 'show_hint',
description: 'Show a hint to the student',
parameters: {
type: 'object',
properties: { hint: { type: 'string' } },
required: ['hint'],
},
},
}]}
onToolCall={async (toolCall) => {
if (toolCall.name === 'show_hint') {
setHint(toolCall.arguments.hint as string)
return { success: true }
}
}}
/>Environment variables
| Variable | Description |
|----------|-------------|
| NEXT_PUBLIC_COREEXL_MENTOR_SERVER | Default backend URL (used if serverUrl prop is omitted) |
| NEXT_PUBLIC_ACCESS_KEY | Default access key (used if accessKey prop is omitted) |
Troubleshooting
Black borders on other elements — Tailwind v4 sets border-color: currentColor. Fix:
*, ::before, ::after { border-color: transparent; }Styles not applying — Add the @source directive (see Installation). Do not import the CSS manually.
Language not supported — Pass a valid BCP-47 code via language (see Language Support table).
