Replace MinIO with S3-compatible storage and reorganize project structure

- Switch from MinIO to boto3 for S3-compatible object storage (Cloudflare R2)
- Rename storage config vars from R2_* to generic S3_*
- Organize root directory: docs/, tools/, output/, Archive/{audio,results}/
- Output transcriptions to output/ directory
- Add transcribe_legacy.py, transcribe_all.py, and docs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Misaka_Company
2026-05-27 16:08:33 +08:00
parent 060ee7012e
commit 85dc3c77b3
6 changed files with 992 additions and 0 deletions

161
transcribe_legacy.py Normal file
View File

@@ -0,0 +1,161 @@
import json
import os
import sys
import time
import uuid
import requests
from boto3 import client as s3_client
from botocore.config import Config
from dotenv import load_dotenv
load_dotenv()
APP_ID = os.getenv("X_API_APP_KEY")
ACCESS_TOKEN = os.getenv("X_API_ACCESS_KEY")
RESOURCE_ID = os.getenv("X_API_RESOURCE_ID")
S3_ENDPOINT = os.getenv("S3_ENDPOINT")
S3_ACCESS_KEY_ID = os.getenv("S3_ACCESS_KEY_ID")
S3_SECRET_ACCESS_KEY = os.getenv("S3_SECRET_ACCESS_KEY")
S3_BUCKET = os.getenv("S3_BUCKET")
SUBMIT_URL = "https://openspeech.bytedance.com/api/v3/auc/bigmodel/submit"
QUERY_URL = "https://openspeech.bytedance.com/api/v3/auc/bigmodel/query"
s3 = s3_client(
"s3",
endpoint_url=S3_ENDPOINT,
aws_access_key_id=S3_ACCESS_KEY_ID,
aws_secret_access_key=S3_SECRET_ACCESS_KEY,
config=Config(signature_version="s3v4"),
region_name="auto",
)
def fmt_time(ms):
s = ms / 1000
m = int(s // 60)
sec = s % 60
return f"{m:02d}:{sec:05.2f}"
def build_markdown(data, audio_file):
result = data.get("result", {})
utterances = result.get("utterances", [])
duration = data.get("audio_info", {}).get("duration", 0)
speaker_order = []
for u in utterances:
sp = u.get("additions", {}).get("speaker", "unknown")
if sp not in speaker_order:
speaker_order.append(sp)
lines = [
"# 转写结果",
"",
f"**源文件**: {audio_file} ",
f"**音频时长**: {fmt_time(duration)} ",
f"**说话人数量**: {len(speaker_order)}",
f"**分句数量**: {len(utterances)}",
"",
"---",
"",
"## 按时间线",
"",
]
for u in utterances:
sp = u.get("additions", {}).get("speaker", "?")
start = u.get("start_time", 0)
end = u.get("end_time", 0)
t = u.get("text", "").strip()
if not t:
continue
lines.append(f"- **{fmt_time(start)} - {fmt_time(end)}** **说话人{sp}** {t}")
lines.append("")
return "\n".join(lines)
def make_headers(task_id, with_sequence=False):
headers = {
"X-Api-App-Key": APP_ID,
"X-Api-Access-Key": ACCESS_TOKEN,
"X-Api-Resource-Id": RESOURCE_ID,
"X-Api-Request-Id": task_id,
}
if with_sequence:
headers["X-Api-Sequence"] = "-1"
return headers
audio_file = sys.argv[1] if len(sys.argv) > 1 else "2026年05月26日 17点53分.mp3"
audio_ext = os.path.splitext(audio_file)[1].lstrip(".")
audio_name = os.path.splitext(os.path.basename(audio_file))[0]
obj_name = f"audio/{uuid.uuid4().hex[:8]}_{os.path.basename(audio_file)}"
print(f"Uploading {audio_file} ...")
s3.upload_file(audio_file, S3_BUCKET, obj_name)
url = s3.generate_presigned_url(
"get_object",
Params={"Bucket": S3_BUCKET, "Key": obj_name},
ExpiresIn=3600,
)
task_id = str(uuid.uuid4())
headers = make_headers(task_id, with_sequence=True)
body = {
"user": {"uid": "audioscribe"},
"audio": {"url": url, "format": audio_ext},
"request": {
"model_name": "bigmodel",
"enable_itn": True,
"enable_punc": True,
"enable_ddc": True,
"enable_speaker_info": True,
"show_utterances": True,
},
}
resp = requests.post(SUBMIT_URL, json=body, headers=headers)
logid = resp.headers.get("X-Tt-Logid", "")
status = resp.headers.get("X-Api-Status-Code", "")
print(f"Submit: {status}")
if status != "20000000":
print(f"FAILED: {resp.headers.get('X-Api-Message', '')}")
else:
while True:
resp = requests.post(
QUERY_URL,
json={},
headers={
**make_headers(task_id),
"X-Tt-Logid": logid,
},
)
code = resp.headers.get("X-Api-Status-Code", "")
if code == "20000000":
data = resp.json()
text = data.get("result", {}).get("text", "")
utterances = data.get("result", {}).get("utterances", [])
os.makedirs("output", exist_ok=True)
json_path = f"output/{audio_name}_转写结果.json"
with open(json_path, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
md_path = f"output/{audio_name}_转写结果.md"
with open(md_path, "w", encoding="utf-8") as f:
f.write(build_markdown(data, audio_file))
print(f"Done ({len(text)} chars, {len(utterances)} utterances)")
print(f"Saved: {json_path}, {md_path}")
break
elif code in ("20000001", "20000002"):
print(f" Processing... ({code})")
time.sleep(5)
else:
print(f"FAILED: {code} {resp.headers.get('X-Api-Message', '')}")
break
print("\nAll done.")