PersonaPlex
نموذج حوار كلام إلى كلام ثنائي الاتجاه كامل مبني على بنية Moshi (Kyutai). يولّد PersonaPlex 7B ردودًا منطوقة مباشرةً من المدخل المنطوق — دون خط أنابيب نصّي وسيط. يأتي النموذج مع 18 إعدادًا صوتيًا مسبقًا، ومتوفّر بتكميم 8-bit (المُوصى به) و4-bit. إعداد 8-bit هو الافتراضي — فهو أسرع بنسبة 30 % وينتج ردودًا متماسكة، بينما يُضعف 4-bit جودة المخرجات.
البنية المعمارية
PersonaPlex نموذج انحداري ذاتي متعدّد المسارات يضمّ ثلاثة مكوّنات أساسية:
| المكوّن | التفاصيل |
|---|---|
| Temporal Transformer | 32 طبقة، dim=4096، 32 رأسًا، SwiGLU (hidden_scale=4.125)، RoPE، مكمَّم إلى 8-bit (افتراضيًا) |
| Depformer | 6 طبقات، dim=1024، 16 رأسًا، MultiLinear (weights_per_step=true)، dep_q=16 |
| Mimi Codec | 16 codebook، معدّل إطارات 12.5 Hz، مخرج صوتي بتردّد 24 kHz |
يعالج النموذج 17 مسارًا في آنٍ واحد: مسار نصّي واحد + 8 مسارات صوتية للمستخدم + 8 مسارات صوتية للوكيل. تتيح هذه البنية محادثة ثنائية الاتجاه كاملة يمكن فيها للنموذج أن يستمع ويتحدّث في الوقت ذاته.
الإعدادات الصوتية المسبقة
يحتوي PersonaPlex على 18 إعدادًا صوتيًا مدمجًا بأساليب طبيعية ومتنوّعة:
| الفئة | الإعدادات |
|---|---|
| أنثوي طبيعي | NATF0, NATF1, NATF2, NATF3 |
| ذكوري طبيعي | NATM0, NATM1, NATM2, NATM3 |
| أنثوي متنوّع | VARF0, VARF1, VARF2, VARF3, VARF4 |
| ذكوري متنوّع | VARM0, VARM1, VARM2, VARM3, VARM4 |
المونولوج الداخلي
يولّد PersonaPlex مسارين متوازيين في كلّ خطوة: 8 رموز codebook صوتية لـ Mimi codec ورمز نصّي واحد للمونولوج الداخلي للنموذج. مسار النصّ هو ما “يفكّر” به النموذج أثناء حديثه — قد يتباعد قليلًا عن الصوت النهائي، لكنّه في الواقع يعكس الردّ المنطوق بدقّة كافية لاستخدامه تفريغًا مباشرًا.
تعود رموز النصّ على هيئة معرّفات قِطَع SentencePiece خام. فكّكها باستخدام SentencePieceDecoder الذي يأتي مع PersonaPlex:
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 mono Float32
في وضع البثّ، يُصدر respondStream أجزاء textTokens فور إنتاجها — فكّكها تدريجيًا لتغذية عرض ترجمات حيّ بينما لا يزال الصوت يتولّد. يفعل خيار --transcript في الـ CLI هذا تمامًا خلف الكواليس.
لماذا هذا مهمّ: يُبنى SentencePieceDecoder على قارئ protobuf المشترك AudioCommon.SentencePieceModel، لذلك يفكّك PersonaPlex وOmnilingualASR وأيّ نموذج مستقبلي مبني على SentencePiece عبر نفس تنفيذ المُرمِّز. راجع مرجع SentencePieceModel.
تلقينات النظام
مرّر أيّ تلقين نظام مخصّص كسلسلة نصّية بسيطة — دون حاجة إلى ترميز خارجي:
let response = model.respond(
userAudio: audio,
voice: .NATM0,
systemPrompt: "You enjoy having a good conversation."
)
أو استخدم إعدادًا مدمجًا:
assistant— مساعد متعدّد الأغراض ومفيد (الافتراضي)focused— ردود موجزة ومباشرةcustomer-service— وكيل دعم مهذّب ومُوجَّه نحو الحلولteacher— أسلوب تعليمي صبور وتوضيحي
استخدام CLI
توليد ردّ منطوق من مُدخل صوتي:
# Basic speech-to-speech
.build/release/speech respond --input question.wav
# Choose a voice preset
.build/release/speech respond --input question.wav --voice NATM0
# Stream audio output during generation
.build/release/speech respond --input question.wav --stream
# Custom system prompt text
.build/release/speech respond --input question.wav --system-prompt-text "You enjoy having a good conversation."
# Use a preset system prompt
.build/release/speech respond --input question.wav --system-prompt customer-service
# Get transcript alongside audio
.build/release/speech respond --input question.wav --transcript
# JSON output with metadata
.build/release/speech 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 | درجة حرارة اعتيان رموز الصوت |
--audio-top-k | 250 | اعتيان top-k لرموز الصوت |
--text-temp | 0.7 | درجة حرارة اعتيان رموز النصّ |
--text-top-k | 25 | اعتيان top-k لرموز النصّ |
البثّ
يُفعِّل خيار --stream إخراج الصوت في الزمن الحقيقي. تُصدَر أجزاء الصوت بمجرّد توليدها، فيمكن بدء التشغيل قبل اكتمال الردّ كاملًا. وهذا مفيد بشكل خاصّ للتطبيقات التفاعلية التي يهمّ فيها الزمن المنخفض.
الأداء
| المقياس | القيمة |
|---|---|
| عامل الزمن الحقيقي (RTF) | ~1.4 (8-bit، قريب من الزمن الحقيقي) |
| زمن الخطوة | ~112 ms/خطوة على M2 Max (8-bit) |
| حجم النموذج (8-bit) | ~9.1 GB |
| ذروة الذاكرة (8-bit) | ~11 GB |
| حجم النموذج (4-bit) | ~4.9 GB |
| ذروة الذاكرة (4-bit) | ~7 GB |
يتطلّب PersonaPlex 7B (8-bit) ما لا يقلّ عن 24 GB من الذاكرة. تتّسع نسخة 4-bit للأجهزة ذات 16 GB لكنّها تنتج مخرجات أدنى جودة. على الأجهزة ذات 8 GB لن تتّسع أيّ نسخة. استخدم --compile للحصول على أفضل أداء على العتاد المدعوم.
متغيّرات النموذج
| النموذج | الحجم | HuggingFace |
|---|---|---|
| PersonaPlex-7B (8-bit) مُوصى به | 9.1 GB | aufklarer/PersonaPlex-7B-MLX-8bit |
| PersonaPlex-7B (4-bit) | 4.9 GB | aufklarer/PersonaPlex-7B-MLX-4bit |
واجهة Swift
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")