> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rumik.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# silk muga 1

> our expressive text-to-speech voice.

export const VoiceSample = ({tone, label, note, description, text, src}) => {
  const TONE_PILL = {
    happy: "bg-amber-100 text-amber-700 dark:bg-amber-500/10 dark:text-amber-300",
    excited: "bg-orange-100 text-orange-700 dark:bg-orange-500/10 dark:text-orange-300",
    sad: "bg-sky-100 text-sky-700 dark:bg-sky-500/10 dark:text-sky-300",
    whisper: "bg-indigo-100 text-indigo-700 dark:bg-indigo-500/10 dark:text-indigo-300",
    angry: "bg-red-100 text-red-700 dark:bg-red-500/10 dark:text-red-300",
    neutral: "bg-gray-100 text-gray-600 dark:bg-white/10 dark:text-gray-300"
  };
  const PLAY_EVENT = "voicesample:play";
  const fmtTime = s => {
    if (!s || !isFinite(s)) return "0:00";
    const m = Math.floor(s / 60);
    const sec = Math.floor(s % 60).toString().padStart(2, "0");
    return m + ":" + sec;
  };
  const audioRef = React.useRef(null);
  const idRef = React.useRef(null);
  if (idRef.current === null) idRef.current = Math.random();
  const [playing, setPlaying] = React.useState(false);
  const [cur, setCur] = React.useState(0);
  const [dur, setDur] = React.useState(0);
  const [copied, setCopied] = React.useState(false);
  React.useEffect(() => {
    const onOther = e => {
      if (e.detail !== idRef.current && audioRef.current) {
        audioRef.current.pause();
        setPlaying(false);
      }
    };
    window.addEventListener(PLAY_EVENT, onOther);
    return () => window.removeEventListener(PLAY_EVENT, onOther);
  }, []);
  const toggle = () => {
    const a = audioRef.current;
    if (!a) return;
    if (playing) {
      a.pause();
      setPlaying(false);
    } else {
      window.dispatchEvent(new CustomEvent(PLAY_EVENT, {
        detail: idRef.current
      }));
      a.play();
      setPlaying(true);
    }
  };
  const copyValue = description ? "description: " + description + "\ntext: " + text : text;
  const copy = () => {
    if (navigator.clipboard) navigator.clipboard.writeText(copyValue);
    setCopied(true);
    setTimeout(() => setCopied(false), 1500);
  };
  const seekTo = (clientX, el) => {
    const a = audioRef.current;
    if (!a || !dur) return;
    const rect = el.getBoundingClientRect();
    const ratio = Math.min(1, Math.max(0, (clientX - rect.left) / rect.width));
    a.currentTime = ratio * dur;
    setCur(a.currentTime);
  };
  const pct = dur ? cur / dur * 100 : 0;
  const pill = label ? TONE_PILL.neutral : TONE_PILL[tone] || TONE_PILL.neutral;
  const pillLabel = label || "[" + (tone || "neutral") + "]";
  const lbl = "text-gray-400 dark:text-gray-500";
  return <div className="not-prose my-3 flex flex-col gap-3 rounded-2xl border border-gray-200 bg-white p-4 dark:border-white/10 dark:bg-white/[0.03]">
      <div className="flex items-start justify-between gap-3">
        <div className="flex flex-wrap items-center gap-x-2 gap-y-1">
          <span className={"rounded-md px-2 py-0.5 font-mono text-xs font-semibold " + pill}>
            {pillLabel}
          </span>
          {note && <span className="text-xs text-gray-500 dark:text-gray-400">{note}</span>}
        </div>
        <button type="button" onClick={copy} aria-label={copied ? "Copied" : "Copy prompt"} className="flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-xs text-gray-500 transition hover:bg-gray-100 hover:text-gray-800 focus:outline-none focus-visible:ring-2 focus-visible:ring-gray-400 dark:text-gray-400 dark:hover:bg-white/10 dark:hover:text-gray-200">
          {copied ? <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <path d="M20 6 9 17l-5-5" />
            </svg> : <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <rect x="9" y="9" width="13" height="13" rx="2" />
              <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
            </svg>}
          {copied ? "copied" : "copy"}
        </button>
      </div>

      <div className="overflow-hidden rounded-lg bg-gray-50 px-3 py-2.5 font-mono text-xs leading-relaxed break-words whitespace-pre-wrap text-gray-700 dark:bg-white/5 dark:text-gray-300">
        {description ? <>
            <span className={lbl}>description:</span> {description}
            {"\n"}
            <span className={lbl}>text:</span> {text}
          </> : text}
      </div>

      <audio ref={audioRef} src={src} preload="metadata" onLoadedMetadata={e => setDur(e.currentTarget.duration)} onTimeUpdate={e => setCur(e.currentTarget.currentTime)} onEnded={() => {
    setPlaying(false);
    setCur(0);
    if (audioRef.current) audioRef.current.currentTime = 0;
  }} />

      <div className="flex items-center gap-3">
        <button type="button" onClick={toggle} aria-label={playing ? "Pause" : "Play " + (label || tone || "voice") + " sample"} className="flex size-9 shrink-0 items-center justify-center rounded-full bg-gray-900 text-white transition hover:bg-gray-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-gray-900 focus-visible:ring-offset-2 dark:bg-white dark:text-gray-900 dark:focus-visible:ring-white dark:focus-visible:ring-offset-gray-900">
          {playing ? <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
              <rect x="6" y="5" width="4" height="14" rx="1" />
              <rect x="14" y="5" width="4" height="14" rx="1" />
            </svg> : <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
              <path d="M8 5v14l11-7z" />
            </svg>}
        </button>

        <div role="slider" aria-label="Seek" aria-valuemin={0} aria-valuemax={Math.round(dur) || 0} aria-valuenow={Math.round(cur)} tabIndex={0} onClick={e => seekTo(e.clientX, e.currentTarget)} onKeyDown={e => {
    const a = audioRef.current;
    if (!a || !dur) return;
    if (e.key === "ArrowRight") {
      a.currentTime = Math.min(dur, a.currentTime + 2);
      setCur(a.currentTime);
    } else if (e.key === "ArrowLeft") {
      a.currentTime = Math.max(0, a.currentTime - 2);
      setCur(a.currentTime);
    }
  }} className="relative h-1.5 flex-1 cursor-pointer rounded-full bg-gray-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-gray-400 dark:bg-white/15">
          <div className="absolute inset-y-0 left-0 rounded-full bg-gray-900 dark:bg-white" style={{
    width: pct + "%"
  }} />
        </div>

        <span className="shrink-0 font-mono text-xs tabular-nums text-gray-500 dark:text-gray-400">
          {fmtTime(cur)} / {fmtTime(dur)}
        </span>
      </div>
    </div>;
};

**silk muga 1** is our expressive text-to-speech voice. you set the mood with one
`[tone]` tag and drop in inline events like a laugh or a sigh. it's tuned for short,
natural, spoken delivery: reactions, banter, support replies, storytelling.

<VoiceSample tone="happy" note="hear muga" text="[happy] <laugh> Yaar tumne phir wahi joke maara!" src="/audio/muga/hero.mp3" />

## at a glance

| field    | value                                                                                                      |
| -------- | ---------------------------------------------------------------------------------------------------------- |
| model id | `muga`                                                                                                     |
| language | english with romanised hinglish (latin script). write `kaise ho`, not `कैसे हो`. multilingual coming soon. |
| best for | short expressive lines: reactions, banter, support, storytelling                                           |
| length   | 2 to 40 seconds per utterance                                                                              |
| not for  | devanagari input, or very long passages (past \~40s)                                                       |

## quickstart

one call, one `.wav` file:

```bash theme={null}
curl -X POST https://silk-api.rumik.ai/v1/tts \
  -H "Authorization: Bearer rk_live_•••••••••" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "muga",
    "text": "[happy] <laugh> Yaar tumne phir wahi joke maara!",
    "temperature": 0.7
  }' \
  --output muga.wav
```

a request is a `[tone]`, an optional `<event>`, and your words. the full request
schema is in the [API reference](/api-reference).

## tones

six moods. pick by ear:

| tone    | tag         | sounds like                      |
| ------- | ----------- | -------------------------------- |
| neutral | `[neutral]` | flat, even, no affect            |
| happy   | `[happy]`   | bright, smiling, mid-energy      |
| excited | `[excited]` | loud, fast, pitch up             |
| sad     | `[sad]`     | slow, breathy, low               |
| angry   | `[angry]`   | tight, clipped, sharp            |
| whisper | `[whisper]` | quiet, breathy, no voiced energy |

## parameters

`muga` is steered mainly by the tone tag in your `text`. it also accepts the shared
sampling parameters:

| field                | default | notes                                                        |
| -------------------- | ------- | ------------------------------------------------------------ |
| `text`               | n/a     | required. up to 2000 characters. must start with a `[tone]`. |
| `temperature`        | `0.6`   | **set `0.7` for muga.** most consistent run to run.          |
| `top_p`              | `0.95`  | nucleus sampling                                             |
| `top_k`              | `50`    | top-k sampling                                               |
| `repetition_penalty` | `1.2`   | penalise repeated tokens                                     |
| `max_new_tokens`     | `2048`  | output length cap                                            |

→ to write good prompts, read the [prompting guide](/prompting-muga).
