PersonaPlex
Moshi 아키텍처(Kyutai) 기반의 전이중 음성-음성 대화 모델입니다. PersonaPlex 7B는 음성 입력에서 직접 음성 응답을 생성하며, 중간 텍스트 파이프라인이 필요하지 않습니다. 모델은 18개의 음색 프리셋과 함께 제공되며 8비트(권장)와 4비트 양자화로 이용할 수 있습니다. 8비트가 기본입니다 — 30% 더 빠르고 일관된 응답을 생성하는 반면 4비트는 출력 품질이 저하됩니다.
아키텍처
PersonaPlex는 세 가지 핵심 구성 요소를 가진 멀티 스트림 자기회귀 모델입니다:
| 구성 요소 | 세부 내용 |
|---|---|
| Temporal Transformer | 32 레이어, dim=4096, 32 헤드, SwiGLU (hidden_scale=4.125), RoPE, 8비트 양자화 (기본) |
| Depformer | 6 레이어, dim=1024, 16 헤드, MultiLinear (weights_per_step=true), dep_q=16 |
| Mimi Codec | 16 코드북, 12.5 Hz 프레임 속도, 24 kHz 오디오 출력 |
모델은 동시에 17개 스트림을 처리합니다: 텍스트 스트림 1개 + 사용자 오디오 스트림 8개 + agent 오디오 스트림 8개. 이 아키텍처는 모델이 듣고 말하는 것을 동시에 할 수 있는 전이중 대화를 가능하게 합니다.
음색 프리셋
PersonaPlex는 자연스러운 스타일과 다양한 스타일에 걸쳐 18개의 내장 음색 프리셋을 포함합니다:
| 카테고리 | 프리셋 |
|---|---|
| 자연스러운 여성 | NATF0, NATF1, NATF2, NATF3 |
| 자연스러운 남성 | NATM0, NATM1, NATM2, NATM3 |
| 다양한 여성 | VARF0, VARF1, VARF2, VARF3, VARF4 |
| 다양한 남성 | VARM0, VARM1, VARM2, VARM3, VARM4 |
내부 독백
PersonaPlex는 매 스텝마다 두 개의 병렬 스트림을 생성합니다: Mimi 코덱용 8개 오디오 코드북 토큰과 모델의 내부 독백을 위한 텍스트 토큰 1개. 텍스트 스트림은 모델이 말하면서 “생각”하는 것입니다 — 최종 오디오와 약간 다를 수 있지만, 실제로는 음성 응답과 충분히 가까워서 라이브 전사로 사용할 수 있습니다.
텍스트 토큰은 raw SentencePiece piece ID로 돌아옵니다. PersonaPlex가 제공하는 SentencePieceDecoder로 디코딩하세요:
import PersonaPlex
import AudioCommon
let model = try await PersonaPlexModel.fromPretrained()
let decoder = try model.makeTextDecoder() // SentencePieceDecoder
let result = model.respondWithTranscript(userAudio: userSamples, voice: .NATM0)
let transcript = decoder.decode(result.textTokens)
print(transcript) // "Sure, I can help with that..."
playAudio(result.audio) // 24 kHz 모노 Float32
스트리밍 모드에서 respondStream은 생성되는 대로 textTokens 청크를 방출합니다 — 오디오가 아직 생성 중인 동안 이를 점진적으로 디코딩하여 라이브 캡션 뷰를 구동합니다. --transcript CLI 플래그는 내부적으로 이 동작을 수행합니다.
왜 중요한가: SentencePieceDecoder는 공유 AudioCommon.SentencePieceModel protobuf 리더 위에 구축되므로 PersonaPlex, OmnilingualASR, 그리고 향후의 SentencePiece 기반 모델이 모두 동일한 토크나이저 구현을 통해 디코딩합니다. SentencePieceModel 레퍼런스를 참조하세요.
시스템 프롬프트
외부 토크나이제이션 없이 일반 문자열로 어떤 커스텀 시스템 프롬프트든 전달하세요:
let response = model.respond(
userAudio: audio,
voice: .NATM0,
systemPrompt: "You enjoy having a good conversation."
)
또는 내장 프리셋을 사용하세요:
assistant— 범용적으로 도움이 되는 어시스턴트 (기본)focused— 간결하고 직접적인 응답customer-service— 정중하고 솔루션 중심의 지원 agentteacher— 참을성 있고 설명적인 교수 스타일
CLI 사용법
오디오 입력에서 음성 응답을 생성합니다:
# 기본 음성-음성 변환
.build/release/audio respond --input question.wav
# 음색 프리셋 선택
.build/release/audio respond --input question.wav --voice NATM0
# 생성 중 오디오 출력 스트리밍
.build/release/audio respond --input question.wav --stream
# 커스텀 시스템 프롬프트 텍스트
.build/release/audio respond --input question.wav --system-prompt-text "You enjoy having a good conversation."
# 프리셋 시스템 프롬프트 사용
.build/release/audio respond --input question.wav --system-prompt customer-service
# 오디오와 함께 전사 획득
.build/release/audio respond --input question.wav --transcript
# 메타데이터를 포함한 JSON 출력
.build/release/audio respond --input question.wav --json
옵션
| 옵션 | 설명 |
|---|---|
--input | 입력 오디오 파일 (WAV, 필수) |
--voice | 음색 프리셋 이름 (예: NATM0, VARF2) |
--system-prompt | 시스템 프롬프트 프리셋: assistant, focused, customer-service, teacher |
--system-prompt-text | 커스텀 시스템 프롬프트 텍스트 (--system-prompt 재정의) |
--max-steps | 최대 생성 스텝 |
--stream | 생성 중 오디오 청크 방출 |
--compile | 더 빠른 생성을 위해 MLX 컴파일된 추론 사용 |
--transcript | 오디오와 함께 텍스트 전사 출력 |
--json | 메타데이터를 포함한 JSON 출력 |
샘플링 파라미터도 재정의할 수 있습니다:
| 옵션 | 기본값 | 설명 |
|---|---|---|
--audio-temp | 0.8 | 오디오 토큰 샘플링 temperature |
--audio-top-k | 250 | 오디오 토큰 top-k 샘플링 |
--text-temp | 0.7 | 텍스트 토큰 샘플링 temperature |
--text-top-k | 25 | 텍스트 토큰 top-k 샘플링 |
스트리밍
--stream 플래그는 실시간 오디오 출력을 활성화합니다. 오디오 청크가 생성되는 대로 방출되므로 전체 응답이 완성되기 전에 재생을 시작할 수 있습니다. 이는 지연이 중요한 인터랙티브 애플리케이션에 특히 유용합니다.
성능
| 지표 | 값 |
|---|---|
| 실시간 계수 (RTF) | 약 1.4 (8비트, 실시간에 근접) |
| 스텝 지연 | M2 Max에서 약 112 ms/step (8비트) |
| 모델 크기 (8비트) | 약 9.1 GB |
| 피크 RAM (8비트) | 약 11 GB |
| 모델 크기 (4비트) | 약 4.9 GB |
| 피크 RAM (4비트) | 약 7 GB |
PersonaPlex 7B (8비트)는 최소 24 GB의 RAM이 필요합니다. 4비트 변형은 16 GB 기기에 맞지만 저하된 출력을 생성합니다. 8 GB 기기에서는 두 변형 모두 맞지 않습니다. 지원되는 하드웨어에서 최상의 성능을 위해 --compile을 사용하세요.
모델 변형
| 모델 | 크기 | HuggingFace |
|---|---|---|
| PersonaPlex-7B (8비트) 권장 | 9.1 GB | aufklarer/PersonaPlex-7B-MLX-8bit |
| PersonaPlex-7B (4비트) | 4.9 GB | aufklarer/PersonaPlex-7B-MLX-4bit |
Swift API
import PersonaPlex
let model = try await PersonaPlexModel.loadFromHub()
let response = try await model.respond(
audioFile: "question.wav",
voice: .NATM0,
systemPrompt: .assistant
)
try response.audio.write(to: "answer.wav")