From 334ff647fce69a86b5414d4595180b918b586471 Mon Sep 17 00:00:00 2001 From: Zhengshou Lai Date: Wed, 3 Jun 2026 23:43:28 +0800 Subject: [PATCH] feat(api): extract pure API clients for image generation and TTS - Add bin/api/ package with generate_image() and synthesize_tts() - Refactor bin/commands/image.py to call bin.api.image.generate_image - Refactor bin/commands/voice.py to call bin.api.voice.synthesize_tts - API layer is free of Click CLI dependencies, usable by external scripts --- bin/api/__init__.py | 6 ++ bin/api/image.py | 57 +++++++++++++ bin/api/voice.py | 93 +++++++++++++++++++++ bin/commands/image.py | 46 ++-------- bin/commands/voice.py | 82 +++--------------- templates/md-to-docx/default/template.docx | Bin 26345 -> 26322 bytes 6 files changed, 174 insertions(+), 110 deletions(-) create mode 100644 bin/api/__init__.py create mode 100644 bin/api/image.py create mode 100644 bin/api/voice.py diff --git a/bin/api/__init__.py b/bin/api/__init__.py new file mode 100644 index 0000000..418d8ca --- /dev/null +++ b/bin/api/__init__.py @@ -0,0 +1,6 @@ +"""Pure API clients for external services (no CLI deps).""" + +from .image import generate_image +from .voice import synthesize_tts + +__all__ = ["generate_image", "synthesize_tts"] diff --git a/bin/api/image.py b/bin/api/image.py new file mode 100644 index 0000000..7007bab --- /dev/null +++ b/bin/api/image.py @@ -0,0 +1,57 @@ +"""Image generation API client (Doubao/Seedream).""" + +import base64 +import os +import urllib.request +from pathlib import Path + +_RATIO_MAP = { + "1:1": "1024x1024", + "4:3": "1024x768", + "3:4": "768x1024", + "16:9": "1280x720", + "9:16": "720x1280", +} + + +def generate_image( + api_key: str, + prompt: str, + size: str | None = None, + ratio: str | None = None, + output: str | None = None, + watermark: bool = True, + b64: bool = False, +) -> str: + """Generate image using Doubao/Seedream API. + + Returns absolute file path if saved, or URL string if output is None. + """ + from openai import OpenAI + + resolved_size = size or (ratio and _RATIO_MAP.get(ratio)) or "2K" + + client = OpenAI( + base_url="https://ark.cn-beijing.volces.com/api/v3", + api_key=api_key, + ) + + resp = client.images.generate( + model="doubao-seedream-5-0-260128", + prompt=prompt, + size=resolved_size, + response_format="b64_json" if b64 else "url", + extra_body={"watermark": watermark}, + ) + + if b64: + image_bytes = base64.b64decode(resp.data[0].b64_json) + save_path = output or "generated_image.png" + Path(save_path).write_bytes(image_bytes) + return os.path.abspath(save_path) + else: + url = resp.data[0].url + if output: + urllib.request.urlretrieve(url, output) + return os.path.abspath(output) + return url diff --git a/bin/api/voice.py b/bin/api/voice.py new file mode 100644 index 0000000..8be5a49 --- /dev/null +++ b/bin/api/voice.py @@ -0,0 +1,93 @@ +"""Voice / TTS API client via Volcengine (ByteDance) WebSocket API.""" + +import asyncio +import json +import uuid +from pathlib import Path + +from bin.commands.protocols import EventType, MsgType, full_client_request, receive_message + +_RESOURCE_ID = "volc.service_type.10029" +_ENDPOINT = "wss://openspeech.bytedance.com/api/v3/tts/unidirectional/stream" + +_VOICE_CHOICES = [ + "zh_female_cancan_mars_bigtts", + "zh_female_shuangkuaisisi_moon_bigtts", + "zh_male_wennuanahu_moon_bigtts", + "zh_male_sunwukong_moon_bigtts", +] + +_FORMAT_CHOICES = ["mp3", "wav", "pcm"] + + +def synthesize_tts( + appid: str, + token: str, + text: str, + speaker: str = "zh_male_wennuanahu_moon_bigtts", + fmt: str = "mp3", + speech_rate: int = 0, + output_path: str = "output.mp3", +) -> str: + """Synchronous TTS synthesis via Volcengine WebSocket API. + + Returns absolute path to the output audio file. + """ + try: + import websockets + except ImportError as e: + raise RuntimeError(f"Missing dependency: {e}. Run: pip install websockets") from e + + headers = { + "X-Api-App-Id": appid, + "X-Api-Access-Key": token, + "X-Api-Resource-Id": _RESOURCE_ID, + "X-Api-Connect-Id": str(uuid.uuid4()), + } + + async def _run() -> bytearray: + ws = await websockets.connect( + _ENDPOINT, + additional_headers=headers, + max_size=10 * 1024 * 1024, + open_timeout=30, + ) + + request = { + "user": {"uid": str(uuid.uuid4())}, + "req_params": { + "speaker": speaker, + "audio_params": { + "format": fmt, + "sample_rate": 24000, + "speech_rate": speech_rate, + }, + "text": text, + }, + } + + await full_client_request(ws, json.dumps(request).encode()) + + audio_data = bytearray() + while True: + msg = await receive_message(ws) + if msg.type == MsgType.FullServerResponse and msg.event == EventType.SessionFinished: + break + elif msg.type == MsgType.AudioOnlyServer: + audio_data.extend(msg.payload) + elif msg.type == MsgType.Error: + await ws.close() + raise RuntimeError( + f"TTS service error: {msg.payload.decode('utf-8', errors='replace')}" + ) + + await ws.close() + return audio_data + + audio_data = asyncio.run(_run()) + if not audio_data: + raise RuntimeError("No audio data received from TTS service") + + out = Path(output_path) + out.write_bytes(audio_data) + return str(out.resolve()) diff --git a/bin/commands/image.py b/bin/commands/image.py index 5cb4aa9..ba6689e 100644 --- a/bin/commands/image.py +++ b/bin/commands/image.py @@ -1,13 +1,11 @@ """Image utilities.""" -import base64 -import os import subprocess -import urllib.request from pathlib import Path import click +from bin.api.image import _RATIO_MAP, generate_image from bin.config import config from bin.utils import handle_errors, run_command @@ -187,15 +185,6 @@ def compress_images(files, target_mb, max_width, quality, suffix, dry_run): click.echo(f"Compressed: {img_file} -> {output} ({size_mb:.2f} MB)") -_RATIO_MAP = { - "1:1": "1024x1024", - "4:3": "1024x768", - "3:4": "768x1024", - "16:9": "1280x720", - "9:16": "720x1280", -} - - @image.command("generate") @click.argument("prompt", required=False) @click.option("-f", "--file", type=click.Path(exists=True), help="从文件读取 prompt") @@ -207,8 +196,6 @@ _RATIO_MAP = { @handle_errors def generate_image_cmd(prompt, file, size, ratio, output, no_watermark, b64): """使用豆包/Seedream 模型生成图片。""" - from openai import OpenAI - if file: prompt = Path(file).read_text(encoding="utf-8").strip() elif not prompt: @@ -222,30 +209,13 @@ def generate_image_cmd(prompt, file, size, ratio, output, no_watermark, b64): if size and ratio: click.echo("Warning: --size 和 --ratio 同时指定,--size 优先", err=True) - resolved_size = size or (ratio and _RATIO_MAP[ratio]) or "2K" - - client = OpenAI( - base_url="https://ark.cn-beijing.volces.com/api/v3", + result = generate_image( api_key=api_key, - ) - - resp = client.images.generate( - model="doubao-seedream-5-0-260128", prompt=prompt, - size=resolved_size, - response_format="b64_json" if b64 else "url", - extra_body={"watermark": not no_watermark}, + size=size, + ratio=ratio, + output=output, + watermark=not no_watermark, + b64=b64, ) - - if b64: - image_bytes = base64.b64decode(resp.data[0].b64_json) - save_path = output or "generated_image.png" - Path(save_path).write_bytes(image_bytes) - click.echo(os.path.abspath(save_path)) - else: - url = resp.data[0].url - if output: - urllib.request.urlretrieve(url, output) - click.echo(os.path.abspath(output)) - else: - click.echo(url) + click.echo(result) diff --git a/bin/commands/voice.py b/bin/commands/voice.py index 6e00611..b399fe9 100644 --- a/bin/commands/voice.py +++ b/bin/commands/voice.py @@ -1,19 +1,14 @@ """Voice / TTS utilities via Volcengine (ByteDance) WebSocket API.""" -import asyncio -import json import os -import uuid from pathlib import Path import click +from bin.api.voice import synthesize_tts from bin.config import config from bin.utils import handle_errors -_RESOURCE_ID = "volc.service_type.10029" -_ENDPOINT = "wss://openspeech.bytedance.com/api/v3/tts/unidirectional/stream" - _VOICE_CHOICES = [ "zh_female_cancan_mars_bigtts", "zh_female_shuangkuaisisi_moon_bigtts", @@ -41,17 +36,6 @@ def _synthesize_sync( output_path: str, ) -> str: """Synchronous wrapper around async WebSocket TTS.""" - try: - from bin.commands.protocols import ( - EventType, - MsgType, - full_client_request, - receive_message, - ) - import websockets - except ImportError as e: - raise RuntimeError(f"Missing dependency: {e}. Run: pip install websockets") - appid, access_token = _get_credentials() if not appid or not access_token: raise click.UsageError( @@ -60,61 +44,15 @@ def _synthesize_sync( " mytoolkit env set volc_access_token " ) - headers = { - "X-Api-App-Id": appid, - "X-Api-Access-Key": access_token, - "X-Api-Resource-Id": _RESOURCE_ID, - "X-Api-Connect-Id": str(uuid.uuid4()), - } - - async def _run() -> bytearray: - try: - ws = await websockets.connect( - _ENDPOINT, - additional_headers=headers, - max_size=10 * 1024 * 1024, - open_timeout=30, - ) - except Exception as e: - raise RuntimeError(f"WebSocket connection failed: {e}") from e - - request = { - "user": {"uid": str(uuid.uuid4())}, - "req_params": { - "speaker": speaker, - "audio_params": { - "format": fmt, - "sample_rate": 24000, - "speech_rate": speech_rate, - }, - "text": text, - }, - } - - await full_client_request(ws, json.dumps(request).encode()) - - audio_data = bytearray() - while True: - msg = await receive_message(ws) - if msg.type == MsgType.FullServerResponse and msg.event == EventType.SessionFinished: - break - elif msg.type == MsgType.AudioOnlyServer: - audio_data.extend(msg.payload) - elif msg.type == MsgType.Error: - await ws.close() - raise RuntimeError( - f"TTS service error: {msg.payload.decode('utf-8', errors='replace')}" - ) - - await ws.close() - return audio_data - - audio_data = asyncio.run(_run()) - if not audio_data: - raise RuntimeError("No audio data received from TTS service") - - Path(output_path).write_bytes(audio_data) - return output_path + return synthesize_tts( + appid=appid, + token=access_token, + text=text, + speaker=speaker, + fmt=fmt, + speech_rate=speech_rate, + output_path=output_path, + ) @click.group() diff --git a/templates/md-to-docx/default/template.docx b/templates/md-to-docx/default/template.docx index 7506cb88ce48fde47254cfdc4dad8df5ffc6aae5..c30e09b64bf7fa0c4ce260e180cebf91d3a9ca34 100644 GIT binary patch delta 15794 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