PikaStream Video Meeting
Script : SKILL_DIR=skills/pikastream-video-meeting
Configuration initiale
À exécuter une seule fois au premier chargement du skill :
pip install -r $SKILL_DIR/requirements.txt
1. Avatar
Vérifier que identity/videomeeting-avatar.png existe et fait plus de 1 KB. Si ce n'est PAS le cas (ou le fichier est trop petit) :
- Demander à l'utilisateur :
I need an avatar image for the video meeting (a headshot or portrait). Send me an image, or say "generate" and I'll create one for you. - Ne pas continuer tant que l'utilisateur n'a pas répondu. Ne pas générer automatiquement.
- L'utilisateur envoie une image : la sauvegarder dans
identity/videomeeting-avatar.png. - L'utilisateur dit "generate" : exécuter :
python $SKILL_DIR/scripts/pikastreaming_videomeeting.py generate-avatar \ --output identity/videomeeting-avatar.pngSi l'utilisateur décrit ce qu'il veut (par ex. « a cartoon cat »), transmettre
--prompt "<description>, portrait headshot suitable for video calls". Afficher l'image générée. Demander :Want to keep this avatar or regenerate?Attendre la réponse. - Autre réponse : répéter la question de l'étape 1.
Le bot doit avoir un avatar avant de rejoindre une réunion.
2. Voice
Vérifier que life/voice_id.txt existe et n'est pas vide.
S'il existe : lire life/voice_config.json. S'il est lisible, vérifier cloned_at — si c'était il y a 6+ jours, avertir l'utilisateur :
Your voice clone was created on {date} and may have expired (cloned voices are deleted after 7 days of non-use). Want to re-clone with a new recording, or try the existing one?
- Re-cloner : aller à « S'il n'existe pas » ci-dessous.
- Le garder : utiliser l'ID voice existant.
Si life/voice_config.json est manquant ou illisible, utiliser l'ID voice de life/voice_id.txt tel quel.
S'il n'existe pas (ou l'utilisateur a choisi de re-cloner) :
- Demander à l'utilisateur :
I don't have a voice clone yet. You can: (a) send me a voice recording (10s-5min, clear speech) and I'll clone it, or (b) say "skip" to use a default voice. - Ne pas continuer tant que l'utilisateur n'a pas répondu.
- L'utilisateur dit "skip" : utiliser
English_radiant_girl. - L'utilisateur envoie un fichier audio : exécuter :
python $SKILL_DIR/scripts/pikastreaming_videomeeting.py clone-voice \ --audio <file> --name <bot-name> --noise-reduction- Exit 0 : lire
life/voice_id.txt. Dire à l'utilisateur :Voice cloned. Using {voice_id} for this meeting. - Exit non-zéro : informer l'utilisateur que le clonage a échoué (inclure stderr). Demander :
Try again with a different file, or skip and use the default voice?
- Exit 0 : lire
- Fichier invalide (pas audio) : répondre
That doesn't look like a supported audio file. Send an mp3, m4a, wav, ogg, flac, or aac file (10s-5min of clear speech).Attendre une nouvelle tentative ou « skip ».
Join Flow
Step 1 — Valider & collecter le contexte
Avatar : vérifier que identity/videomeeting-avatar.png existe et fait > 1 KB. Sinon, exécuter la Configuration initiale ci-dessus.
Voice : vérifier que life/voice_id.txt existe. Sinon, exécuter la section Voice de la Configuration initiale ci-dessus.
Contexte : toujours collecter un contexte frais — ne pas réutiliser un fichier périmé d'une session précédente.
- Lire les fichiers de workspace (MEMORY.md, logs quotidiens, fichiers d'identité, etc.).
- Si aucune donnée de workspace n'est disponible, demander à l'utilisateur :
What name should the bot use in this meeting?Utiliser sa réponse pour le champName:. Remplir les autres sections en fonction de la conversation. - Synthétiser une fiche de référence concise dans
/tmp/meeting_system_prompt.txt. Utiliser{name}comme nom d'affichage du bot (aussi utilisé comme--bot-name). Si les données sont minces (par ex. juste un nom), rester bref — ne pas surcharger avec du remplissage.
Synthesize the raw data below into a concise reference card for {name} to use during a voice/video call. Use third-person ("{name}") throughout. Prioritize CONCRETE DETAILS.
PRIORITY ORDER:
1. SPECIFIC FACTS: names, places, dates, numbers, events
2. RECENT ACTIVITY: what happened today/this week — actions, not vibes
3. RELATIONSHIPS: who matters, specific interactions
4. PERSONALITY: 1-2 sentences MAX
CURATION RULES:
- KEEP: anything with a proper noun, a number, a date, or a concrete action
- DROP: vague descriptions, routine status updates, empty entries
- MERGE: if multiple entries say similar things, pick the most vivid one
OUTPUT FORMAT:
**{name}**: [1 sentence — tone/vibe]
**Known facts** (concrete only, max 10):
- [specific fact with names/dates/numbers]
**Recent activity**:
- [built X, fixed Y, went to Z]
**Right now**: [1 line — current activity]
**People**: [name — 1 specific detail each]
RULES:
- Concrete > abstract
- Actions > descriptions
- Do not invent facts
- If data is thin, keep it short
Step 2 — Rejoindre
python $SKILL_DIR/scripts/pikastreaming_videomeeting.py join \
--meet-url <url> --bot-name <name> \
--image identity/videomeeting-avatar.png \
--system-prompt-file /tmp/meeting_system_prompt.txt \
--voice-id <id> [--meeting-password <pw>]
Informer l'utilisateur que vous avez rejoint la réunion. Dire leave pour quitter. Ne pas mentionner les session IDs.
Codes de sortie : 0 = rejoint. 6 = crédits insuffisants (le JSON en stdout contient une checkout_url — la montrer à l'utilisateur).
Leave
python $SKILL_DIR/scripts/pikastreaming_videomeeting.py leave \
--session-id <id from join output>
Vérifier
- Une vraie session/salle a été créée via l'API et son ID/URL est capturé, pas simulé
- Au moins un événement de join/leave d'un participant a été observé dans les logs ou les payloads webhook
- Les pistes audio et vidéo ont été confirmées en flux (track stats, bytes-sent > 0), pas supposées à partir de l'état de la connexion
- Les fonctionnalités d'enregistrement / transcription / chat utilisées ont été vérifiées comme arrivant en stockage avec une URL ou un ID récupérable
- L'échec réseau a été simulé ou considéré : le comportement de reconnexion / fallback est documenté