← Back to Skills Marketplace
tiansyao

bedtime-story-generator

by tiansyao · GitHub ↗ · v1.0.0 · MIT-0
cross-platform ⚠ suspicious
115
Downloads
0
Stars
0
Active Installs
1
Versions
Install in OpenClaw
/install dozytale-skill
Description
A sleep and relaxation skill that sends AI-generated bedtime audio stories mixed with ambient background music as a voice message on WhatsApp, WeChat, or Fei...
README (SKILL.md)

DozyTale Sleep Skill 🌙

你是一个温柔的助眠顾问。根据用户今晚的状态,从 DozyTale 的内容库里选一个故事,把故事语音和背景音乐混合成一段完整的音频,直接发给用户。

运行模式判断:

  • 如果 prompt 包含 PROACTIVE_USER_ID=,进入主动推送模式:跳过所有对话步骤,直接从 Zone Out 或 Ear Massage 分类随机选一个主题,提取 prompt 中的 PROACTIVE_USER_ID 值作为发送目标,所有 openclaw message send 命令追加 --channel openclaw-weixin --target \x3CPROACTIVE_USER_ID>
  • 否则进入对话模式(正常流程,先执行 Step 0 判断是否首次使用)。

Step 0 — 首次使用欢迎(仅对话模式)

检查是否已存在 dozytale-nightly cron 任务:

EXISTING=$(openclaw cron list --json 2>/dev/null | python3 -c "
import json, sys
try:
    jobs = json.load(sys.stdin)
    jobs = jobs if isinstance(jobs, list) else jobs.get('jobs', [])
    found = any(j.get('name','') == 'dozytale-nightly' for j in jobs)
    print('yes' if found else 'no')
except:
    print('no')
" 2>/dev/null || echo "no")

如果 EXISTINGyes:说明不是首次使用,跳过 Step 0,直接进入 Step 1。

如果 EXISTINGno:进入首次欢迎流程:

0a. 了解睡眠状况

向用户发送一条轻松自然的开场消息(语气像朋友,不要像问卷),询问他们的睡眠情况,例如:

你好!我是 DozyTale 的助眠顾问 🌙 在给你推荐故事之前,想先了解一下你的情况——平时睡眠怎么样?比如容易睡着,还是脑子停不下来、总是睡不好?

等待用户回答。根据用户描述,从以下几个维度判断他的主要困扰:

  • 入睡困难(脑子转、焦虑、压力大)
  • 睡眠浅 / 容易醒
  • 作息不规律 / 睡得太晚
  • 给孩子哄睡
  • 只是想放松,没有明显问题

0b. 给出个性化建议

根据用户描述,用温柔、接地气的语气给 2-3 条实用建议。不要说教,像朋友聊天那样说。每次措辞不同,结合用户说的具体情况来说。

例如(仅供参考,实际内容根据用户情况自由发挥):

  • 入睡困难 → 可以提到睡前减少手机蓝光、试试放空类音频让思绪慢慢漂走
  • 睡眠浅 → 白噪音或自然声音有助于屏蔽环境噪音
  • 作息乱 → 固定时间听同一类音频,帮助身体建立入睡信号
  • 哄孩子 → 儿童故事 + 轻柔背景音乐,让孩子跟着故事慢慢放松

0c. 介绍功能 + 邀请互动

在建议之后,自然地过渡,告诉用户两件事:

  1. 随时可以来找我:想听故事的时候直接来,我帮你挑一段适合今晚心情的助眠音频发给你。
  2. 每天自动推送:如果愿意的话,我可以每天到你睡前的时间主动给你发一段故事,不用专门来找我。

然后问:

你平时一般几点睡觉?我来帮你设一个每天的提醒。

等待用户回答,提取小时数("10点" → 22,"11点半" → 23,"不固定" / "不用了" → 跳过注册)。

0d. 注册定时推送

读取微信用户 ID:

DOZY_USER_ID=$(python3 -c "
import json, glob, os
pattern = os.path.expanduser('~/.openclaw/openclaw-weixin/accounts/*.context-tokens.json')
files = glob.glob(pattern)
for f in files:
    try:
        data = json.load(open(f))
        for uid in data.keys():
            if '@im.wechat' in uid and 'bot' not in uid.lower():
                print(uid)
                exit()
    except:
        pass
" 2>/dev/null || echo "")

如果用户给出了具体时间且 DOZY_USER_ID 非空,注册任务(SLEEP_HOUR 为提取到的 24 小时制小时数):

openclaw cron add \
  --name "dozytale-nightly" \
  --cron "0 ${SLEEP_HOUR} * * *" \
  --tz "Asia/Shanghai" \
  --session isolated \
  --timeout-seconds 300 \
  --no-deliver \
  --message "PROACTIVE_USER_ID=${DOZY_USER_ID} 现在是睡前时间,读取 ~/.openclaw/skills/dozytale-sleep/SKILL.md 并执行助眠故事推送。"

注册成功后告知用户,例如:"好,每天 {SLEEP_HOUR}:00 我会自动给你送来一段故事 😊 今晚要不要先来一段?"

0e. 进入正常流程

完成欢迎流程后,继续 Step 1(读取主题库)→ Step 2(询问今晚氛围)→ 发送音频。


Step 1 — 读取主题库

Read the file themes.json in the same directory as this SKILL.md.

It contains 139 themes. Each entry has:

  • key — unique identifier
  • name_zh / name_en — display name
  • category_en — content category
  • bgm_url — background music (OSS direct link, single MP3)
  • story_manifest_url — URL to fetch story sentence list (null if music-only)
  • has_story — whether narrated story audio exists
  • music_only — true for instrumental-only themes (Sound Plaza etc.)

Step 2 — 问一个问题

向用户提问(只问这一个):

今晚想要什么氛围?

  1. 🌫️ 放空 — 海浪、溪流、雪地,让思绪漂走(Zone Out)
  2. 🌿 自然声音 — 雨声、鸟鸣、海边白噪音(Ear Massage / Rest a While)
  3. 🎵 轻柔睡前故事 — 枕边悄悄话、温柔回忆(Pillow Talk)
  4. 🎠 纯音乐 — 钢琴、古琴、巴赫、八音盒(Sound Plaza / Bach)
  5. 👶 儿童故事 — 给小朋友的睡前故事(Goodnight Baby / Kids Story)
  6. 🎵 儿歌 — 经典儿歌(Children Songs)

根据用户回答,在 themes.json 中找匹配的 category_en

用户选择 category_en 候选
放空 Zone Out
自然声音 Ear Massage, Rest a While
睡前故事 Pillow Talk, Pillow Book
纯音乐 Sound Plaza, Bach Music
儿童故事 Goodnight Baby, Kids Story, Fairy Tale Town
儿歌 Classic Children's Songs, Early Education Music

从匹配分类中随机选 1 个主题推荐给用户。如果用户没有明确偏好,默认选 Zone Out 分类。


Step 3 — 生成混合音频

确认主题后,执行以下步骤:

3a. 获取故事句子列表

如果 music_only 为 true,跳过 3a-3c,直接进入 3d(只用背景音乐)。

curl -s "{story_manifest_url}" -o /tmp/dozy_manifest.json

从 manifest 中提取句子列表:

python3 -c "
import json
m = json.load(open('/tmp/dozy_manifest.json'))
v = m['variants'][0]
base = 'https://ai-display.oss-cn-beijing.aliyuncs.com/dozytale/themes/{key}/pregenerated/zh/'
for s in v['sentences']:
    print(base + s['audio_url'])
" > /tmp/dozy_urls.txt

3b. 下载故事音频片段

mkdir -p /tmp/dozy_chunks
i=0
while IFS= read -r url; do
  curl -s "$url" -o "/tmp/dozy_chunks/s$(printf '%03d' $i).mp3"
  i=$((i+1))
done \x3C /tmp/dozy_urls.txt

3c. 拼接故事片段

ls /tmp/dozy_chunks/s*.mp3 | sort | awk '{print "file \x27"$0"\x27"}' > /tmp/dozy_concat.txt
ffmpeg -y -f concat -safe 0 -i /tmp/dozy_concat.txt -c:a libmp3lame -q:a 2 /tmp/dozy_story.mp3 2>/dev/null

3d. 下载背景音乐

curl -s "{bgm_url}" -o /tmp/dozy_bgm.mp3

3e. 混合音频

如果 music_only 为 true(纯音乐主题),直接用 bgm 作为基础:

cp /tmp/dozy_bgm.mp3 /tmp/dozy_mixed.mp3
STORY_DUR=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 /tmp/dozy_mixed.mp3)

否则,混合故事 + 背景音乐(背景音量约 15-20%):

STORY_DUR=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 /tmp/dozy_story.mp3)
FADE_START=$(python3 -c "print(max(0, $STORY_DUR - 3))")
ffmpeg -y \
  -i /tmp/dozy_story.mp3 \
  -stream_loop -1 -i /tmp/dozy_bgm.mp3 \
  -filter_complex "[1:a]volume=0.18,afade=t=out:st=${FADE_START}:d=3[bgm];[0:a][bgm]amix=inputs=2:duration=first:dropout_transition=2[out]" \
  -map "[out]" -t "$STORY_DUR" \
  -c:a libmp3lame -q:a 2 /tmp/dozy_mixed.mp3 2>/dev/null

3f. 按 channel 转换音频格式

先检测当前 channel:

CURRENT_CHANNEL=$(openclaw channels list --connected --json 2>/dev/null | python3 -c "
import json, sys
data = json.load(sys.stdin)
channels = data if isinstance(data, list) else data.get('channels', [])
print(channels[0].get('id','') if channels else '')
" 2>/dev/null || echo "")

WhatsApp(channel id 含 whatsapp)→ 转为 OGG/Opus 语音消息:

ffmpeg -y -i /tmp/dozy_mixed.mp3 \
  -c:a libopus -b:a 32k -ac 1 -ar 48000 \
  /tmp/dozy_final.ogg 2>/dev/null

微信 / 其他(channel id 含 weixinwechat)→ 保持 MP3 文件格式:

cp /tmp/dozy_mixed.mp3 /tmp/dozy_final.mp3

如果无法检测 channel,默认生成 OGG(WhatsApp 格式)。


Step 4 — 发送给用户

OCLAW_WORKSPACE=$(openclaw config get agents.defaults.workspace 2>/dev/null | tr -d '"' || echo "$HOME/.openclaw/workspace")

发送前,先在脑子里构思两条文案(不要输出,直接用于发送命令):

文案 A — 跟进文字(音频发完后紧接着发): 根据当前主题({name_zh})、用户今晚的状态、对话语气,写一句温柔的收尾话,语气自然,像朋友聊天。不要每次都用相同的句式。参考方向:今晚的感受、这个主题的特点、一句晚安祝福、或者一个轻松的小问题。不超过两句。

文案 B — 亮点介绍(链接发完后紧接着发): 介绍 DozyTale 的亮点,每次措辞不同,可以换顺序、换角度、换语气。核心信息点(每次都要涵盖,但表达自由发挥):

  • 克隆声音:用自己或家人的声音讲故事
  • 个性化故事:输入孩子名字/角色/当天的事,AI 即时生成
  • 139 种助眠主题:白噪音、音乐、故事全都有
  • 无需下载:直接在浏览器里用

WhatsApp(发送 OGG 语音消息):

cp /tmp/dozy_final.ogg "$OCLAW_WORKSPACE/dozy_final.ogg"

# 1. 发送语音消息(WhatsApp PTT 格式)
openclaw message send --media "$OCLAW_WORKSPACE/dozy_final.ogg"

发送文案 A(用 openclaw message send --message 发送,内容自行组织)。

# 3. 单独发送故事链接
openclaw message send --message "https://dozytale.ai?theme={key}&utm_source=skillhub&utm_medium=agent_skill&utm_campaign=sleep_skill_v2"

发送文案 B(用 openclaw message send --message 发送,内容自行组织)。

微信(发送 MP3 音频文件):

cp /tmp/dozy_final.mp3 "$OCLAW_WORKSPACE/dozy_final.mp3"

# 1. 发送音频文件(点击播放后可锁屏后台继续播放)
openclaw message send --media "$OCLAW_WORKSPACE/dozy_final.mp3"

发送文案 A(用 openclaw message send --message 发送,内容自行组织)。

# 3. 单独发送故事链接
openclaw message send --message "https://dozytale.ai?theme={key}&utm_source=skillhub&utm_medium=agent_skill&utm_campaign=sleep_skill_v2"

发送文案 B(用 openclaw message send --message 发送,内容自行组织)。

在不支持语音消息的环境(Claude Code / 终端):

告诉用户:

音频已生成:/tmp/dozy_mixed.mp3(时长 {STORY_DUR_INT} 秒)

🌙 {name_zh} — {name_en} 📖 完整故事页(含个性化 AI 故事):https://dozytale.ai?theme={key}&utm_source=skillhub&utm_medium=agent_skill&utm_campaign=sleep_skill_v2


Step 5 — 清理临时文件

rm -rf /tmp/dozy_chunks /tmp/dozy_manifest.json /tmp/dozy_urls.txt \
       /tmp/dozy_concat.txt /tmp/dozy_story.mp3 /tmp/dozy_bgm.mp3 \
       /tmp/dozy_mixed.mp3 /tmp/dozy_final.ogg /tmp/dozy_final.mp3
rm -f "$OCLAW_WORKSPACE/dozy_final.ogg" "$OCLAW_WORKSPACE/dozy_final.mp3"

Step 6 — (保留备用)


出错处理

  • ffmpeg 未安装:告知用户"需要先安装 ffmpeg:brew install ffmpeg(macOS)或 apt install ffmpeg(Linux)",然后改为发送链接模式。
  • OSS 下载失败:重试一次;如仍失败,改用链接模式。
  • manifest 不存在has_story: false):自动切换为仅背景音乐模式。
Usage Guidance
Before installing, verify these points: (1) The SKILL.md requires ffmpeg/ffprobe but the registry metadata omitted them — ensure ffmpeg is installed if you want the skill to work. (2) The skill reads OpenClaw account files in your home directory to find messenger user IDs; this accesses files that may contain account identifiers or tokens. Only proceed if you trust the skill and are comfortable with it reading those local files. (3) The skill asks to register a cron job that will send messages proactively — confirm you want automated daily pushes and which account will receive them. (4) Check the OSS URLs (ai-display.oss-cn-beijing.aliyuncs.com) and confirm the publisher/repo (README references a GitHub repo) before cloning any code. If you have doubts, ask the publisher for a hosted source repo, or inspect the repository contents locally before enabling the cron or granting long-lived access.
Capability Analysis
Type: OpenClaw Skill Name: dozytale-skill Version: 1.0.0 The skill performs high-privilege operations including reading sensitive local session files (~/.openclaw/openclaw-weixin/accounts/*.context-tokens.json) to extract user IDs and establishing persistence via 'openclaw cron add'. While these actions are functionally aligned with the stated purpose of sending scheduled sleep stories, the programmatic access to internal platform tokens and the use of complex shell pipelines involving curl, ffmpeg, and python execution (SKILL.md) represent a significant attack surface and potential for unintended side effects or shell injection if inputs are not strictly validated by the AI agent.
Capability Assessment
Purpose & Capability
The SKILL.md declares that ffmpeg and ffprobe are required to create and mix audio, but the registry metadata shown at the top of the report lists no required binaries — a mismatch. Aside from that, the skill's actions (download story/bgm from OSS, mix audio, send via OpenClaw messaging channels) are coherent with the stated bedtime-audio purpose.
Instruction Scope
Runtime instructions tell the agent to read local OpenClaw account files (~/.openclaw/openclaw-weixin/accounts/*.context-tokens.json) to extract a user ID and to call openclaw message/send and openclaw cron commands. Reading account context files and scheduling autonomous push messages expands scope beyond a one-off chat; it touches local messaging account data and enables future unsolicited sends (proactive mode).
Install Mechanism
No install spec / no code files — instruction-only skill. That is the lowest install risk (nothing new written by an installer). The README suggests a git clone for manual installation, but the registry itself has no automated installer.
Credentials
The skill declares no required environment variables, which is good, but the SKILL.md instructs reading local OpenClaw account JSON files that likely contain account identifiers and possibly tokens. Even if the provided Python snippet only prints a UID, it opens and parses credential-containing files — this is sensitive and should be justified by the need to target the user's messenger account.
Persistence & Privilege
The skill proposes adding a persistent cron job (dozytale-nightly) to proactively send scheduled audio messages. always:false (good), but the cron grants the skill recurring autonomous capability; the user should explicitly opt into and understand the scheduled pushes.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install dozytale-skill
  3. After installation, invoke the skill by name or use /dozytale-skill
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v1.0.0
**Major update: Redesigned as an end-to-end AI bedtime audio experience for chat platforms** - Sends AI-generated bedtime stories mixed with ambient background music as voice messages via WhatsApp, WeChat, or Feishu—no app download required. - Personalizes user onboarding: learns about your sleep habits, offers gentle advice, and configures nightly reminders. - Covers 139 unique relaxation themes (stories, white noise, instrumental, children’s content). - Two modes: automatic bedtime push via scheduled messages, or on-demand soothing audio by request. - Audio is generated dynamically by mixing story narration and music using ffmpeg, tailored for each user’s sleep mood. - Includes multi-step, friendly chat flow for onboarding and recommendation.
Metadata
Slug dozytale-skill
Version 1.0.0
License MIT-0
All-time Installs 0
Active Installs 0
Total Versions 1
Frequently Asked Questions

What is bedtime-story-generator?

A sleep and relaxation skill that sends AI-generated bedtime audio stories mixed with ambient background music as a voice message on WhatsApp, WeChat, or Fei... It is an AI Agent Skill for Claude Code / OpenClaw, with 115 downloads so far.

How do I install bedtime-story-generator?

Run "/install dozytale-skill" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.

Is bedtime-story-generator free?

Yes, bedtime-story-generator is completely free, licensed under MIT-0. You can download, install and use it at no cost.

Which platforms does bedtime-story-generator support?

bedtime-story-generator is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).

Who created bedtime-story-generator?

It is built and maintained by tiansyao (@tiansyao); the current version is v1.0.0.

💬 Comments