Perform various data analysis on SEC 13-F and obtain some insights of fund activities such as number of holdings, AUM, and change of holdings between two quarters.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Create audiobooks from web content or text files. Handles content fetching, text processing, and TTS conversion with automatic fallback between ElevenLabs, OpenAI TTS, and gTTS.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치 방법 보기설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
Create audiobooks from web articles, essays, or text files. This skill covers the full pipeline: content fetching, text processing, and audio generation.
import os
# 1. Check which TTS API is available
def get_tts_provider():
if os.environ.get("ELEVENLABS_API_KEY"):
return "elevenlabs"
elif os.environ.get("OPENAI_API_KEY"):
return "openai"
else:
return "gtts" # Free, no API key needed
provider = get_tts_provider()
print(f"Using TTS provider: {provider}")
WebFetch and similar tools may return summaries instead of full text. Always verify:
import subprocess
def fetch_article_content(url):
"""Fetch article content using curl for reliability."""
# Use curl to get raw HTML - more reliable than web fetch tools
result = subprocess.run(
["curl", "-s", url],
capture_output=True,
text=True
)
html = result.stdout
# Strip HTML tags (basic approach)
import re
text = re.sub(r'<script[^>]*>.*?</script>', '', html, flags=re.DOTALL)
text = re.sub(r'<style[^>]*>.*?</style>', '', html, flags=re.DOTALL)
text = re.sub(r'<[^>]+>', ' ', text)
text = re.sub(r'\s+', ' ', text).strip()
return text
Before converting to audio, verify:
def verify_content(text, expected_min_chars=1000):
"""Basic verification that content is complete."""
if len(text) < expected_min_chars:
print(f"WARNING: Content may be truncated ({len(text)} chars)")
return False
if "summary" in text.lower()[:500] or "key points" in text.lower()[:500]:
print("WARNING: Content appears to be a summary, not full text")
return False
return True
import re
def clean_text_for_tts(text):
"""Clean text for better TTS output."""
# Remove URLs
text = re.sub(r'http[s]?://\S+', '', text)
# Remove footnote markers like [1], [2]
text = re.sub(r'\[\d+\]', '', text)
# Normalize whitespace
text = re.sub(r'\s+', ' ', text)
# Remove special characters that confuse TTS
text = re.sub(r'[^\w\s.,!?;:\'"()-]', '', text)
return text.strip()
def chunk_text(text, max_chars=4000):
"""Split text into chunks at sentence boundaries."""
sentences = re.split(r'(?<=[.!?])\s+', text)
chunks = []
current_chunk = ""
for sentence in sentences:
if len(current_chunk) + len(sentence) < max_chars:
current_chunk += sentence + " "
else:
if current_chunk:
chunks.append(current_chunk.strip())
current_chunk = sentence + " "
if current_chunk:
chunks.append(current_chunk.strip())
return chunks
import os
import subprocess
def create_audiobook(text, output_path):
"""Convert text to audiobook with automatic TTS provider selection."""
# Check available providers
has_elevenlabs = bool(os.environ.get("ELEVENLABS_API_KEY"))
has_openai = bool(os.environ.get("OPENAI_API_KEY"))
if has_elevenlabs:
print("Using ElevenLabs TTS (highest quality)")
return create_with_elevenlabs(text, output_path)
elif has_openai:
print("Using OpenAI TTS (high quality)")
return create_with_openai(text, output_path)
else:
print("Using gTTS (free, no API key required)")
return create_with_gtts(text, output_path)
import requests
def create_with_elevenlabs(text, output_path):
"""Generate audiobook using ElevenLabs API."""
api_key = os.environ.get("ELEVENLABS_API_KEY")
voice_id = "21m00Tcm4TlvDq8ikWAM" # Rachel - calm female voice
chunks = chunk_text(text, max_chars=4500)
audio_files = []
for i, chunk in enumerate(chunks):
chunk_file = f"/tmp/chunk_{i:03d}.mp3"
response = requests.post(
f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}",
headers={
"xi-api-key": api_key,
"Content-Type": "application/json"
},
json={
"text": chunk,
"model_id": "eleven_turbo_v2_5",
"voice_settings": {"stability": 0.5, "similarity_boost": 0.75}
}
)
if response.status_code == 200:
with open(chunk_file, "wb") as f:
f.write(response.content)
audio_files.append(chunk_file)
else:
print(f"Error: {response.status_code} - {response.text}")
return False
return concatenate_audio(audio_files, output_path)
def create_with_openai(text, output_path):
"""Generate audiobook using OpenAI TTS API."""
api_key = os.environ.get("OPENAI_API_KEY")
chunks = chunk_text(text, max_chars=4000)
audio_files = []
for i, chunk in enumerate(chunks):
chunk_file = f"/tmp/chunk_{i:03d}.mp3"
response = requests.post(
"https://api.openai.com/v1/audio/speech",
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
},
json={
"model": "tts-1",
"input": chunk,
"voice": "onyx", # Deep male voice, good for essays
"response_format": "mp3"
}
)
if response.status_code == 200:
with open(chunk_file, "wb") as f:
f.write(response.content)
audio_files.append(chunk_file)
else:
print(f"Error: {response.status_code} - {response.text}")
return False
return concatenate_audio(audio_files, output_path)
def create_with_gtts(text, output_path):
"""Generate audiobook using gTTS (free, no API key)."""
from gtts import gTTS
from pydub import AudioSegment
chunks = chunk_text(text, max_chars=4500)
audio_files = []
for i, chunk in enumerate(chunks):
chunk_file = f"/tmp/chunk_{i:03d}.mp3"
tts = gTTS(text=chunk, lang='en', slow=False)
tts.save(chunk_file)
audio_files.append(chunk_file)
return concatenate_audio(audio_files, output_path)
def concatenate_audio(audio_files, output_path):
"""Concatenate multiple audio files using ffmpeg."""
if not audio_files:
return False
# Create file list for ffmpeg
list_file = "/tmp/audio_list.txt"
with open(list_file, "w") as f:
for audio_file in audio_files:
f.write(f"file '{audio_file}'\n")
# Concatenate with ffmpeg
result = subprocess.run([
"ffmpeg", "-y", "-f", "concat", "-safe", "0",
"-i", list_file, "-c", "copy", output_path
], capture_output=True)
# Cleanup temp files
import os
for f in audio_files:
os.unlink(f)
os.unlink(list_file)
return result.returncode == 0
#!/usr/bin/env python3
"""Create audiobook from web articles."""
import os
import re
import subprocess
import requests
# ... include all helper functions above ...
def main():
# Fetch articles
urls = [
"https://example.com/article1",
"https://example.com/article2"
]
all_text = ""
for url in urls:
print(f"Fetching: {url}")
text = fetch_article_content(url)
if not verify_content(text):
print(f"WARNING: Content from {url} may be incomplete")
all_text += f"\n\n{text}"
# Clean and convert
clean_text = clean_text_for_tts(all_text)
print(f"Total text: {len(clean_text)} characters")
# Create audiobook
success = create_audiobook(clean_text, "/root/audiobook.mp3")
if success:
print("Audiobook created successfully!")
else:
print("Failed to create audiobook")
if __name__ == "__main__":
main()
| Provider | Quality | Cost | API Key Required | Best For |
|---|---|---|---|---|
| ElevenLabs | Excellent | Paid | Yes | Professional audiobooks |
| OpenAI TTS | Very Good | Paid | Yes | General purpose |
| gTTS | Good | Free | No | Testing, budget projects |
curl directly instead of web fetch toolsecho $OPENAI_API_KEY아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Perform various data analysis on SEC 13-F and obtain some insights of fund activities such as number of holdings, AUM, and change of holdings between two quarters.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
AC branch pi-model power flow equations (P/Q and |S|) with transformer tap ratio and phase shift, matching `acopf-math-model.md` and MATPOWER branch fields. Use when computing branch flows in either direction, aggregating bus injections for nodal balance, checking MVA (rateA) limits, computing branch loading %, or debugging sign/units issues in AC power flow.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Redact text from PDF documents for blind review anonymization
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when checking simplified ADA-derived plan-view bathroom accessibility constraints such as turning space, door clear width, toilet centerline, grab bars, and lavatory knee/toe clearance.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Analyze failed GitHub Action jobs for a pull request.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when extracting plan-view architectural geometry from DXF files with semantic CAD layers, especially when outputs must normalize rooms, doors, fixtures, clearances, and grab bars into machine-checkable JSON.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.