Java for You AI Java 17标准HTTP调用语音转写API的超时与错误处理

Java 17标准HTTP调用语音转写API的超时与错误处理

电路板微距

把会议录音送去转文字看似是一条 HTTP 请求,真正上线后却常被大文件、慢网和重复点击拖垮。正确的入门目标不是“马上得到全文”,而是让请求有边界:只接收授权格式、密钥只来自环境变量、连接与总请求都有超时、失败能告诉前端该重传还是稍后再试。下面用 Java 17 的标准 HTTP 客户端拼一个最小 multipart 请求。

OpenAI 的语音转文字指南提供 Audio Transcriptions API。这里采用 REST,因为 Java 标准库足够完成教学示例;模型名 gpt-4o-mini-transcribe 仅作当前文档中的示例,请以目标账号实际可用模型为准。示例未在本次任务中实际调用线上 API;本机 javac 缺少 Java 运行时,故仅完成静态审阅,待 Java 17 环境编译。

mermaid diagram

准备与代码

JDK 17+即可。设置 export OPENAI_API_KEY='你的密钥';保存为 Transcribe.java;运行 javac Transcribe.java && java Transcribe meeting.mp3。只上传已取得录音授权的文件,且不要把音频或返回文本打印到生产日志。

import java.io.*;
import java.net.URI;
import java.net.http.*;
import java.nio.file.*;
import java.time.Duration;

public class Transcribe {
  static final String B = "----snail-ai-boundary";
  static void part(OutputStream out, String name, String value) throws IOException {
    out.write(("--"+B+"\r\nContent-Disposition: form-data; name=\""+name+"\"\r\n\r\n"+value+"\r\n").getBytes());
  }
  static byte[] form(Path audio) throws IOException {
    if (Files.size(audio) > 20 * 1024 * 1024) throw new IllegalArgumentException("教学示例限制20MB");
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    part(out, "model", "gpt-4o-mini-transcribe");
    out.write(("--"+B+"\r\nContent-Disposition: form-data; name=\"file\"; filename=\""
      + audio.getFileName()+"\"\r\nContent-Type: audio/mpeg\r\n\r\n").getBytes());
    out.write(Files.readAllBytes(audio)); out.write(("\r\n--"+B+"--\r\n").getBytes()); return out.toByteArray();
  }
  public static void main(String[] args) throws Exception {
    if (args.length != 1) throw new IllegalArgumentException("用法: 音频路径");
    String key = System.getenv("OPENAI_API_KEY");
    if (key == null || key.isBlank()) throw new IllegalStateException("缺少OPENAI_API_KEY");
    HttpRequest req = HttpRequest.newBuilder(URI.create("https://api.openai.com/v1/audio/transcriptions"))
      .timeout(Duration.ofSeconds(30)).header("Authorization", "Bearer "+key)
      .header("Content-Type", "multipart/form-data; boundary="+B)
      .POST(HttpRequest.BodyPublishers.ofByteArray(form(Paths.get(args[0])))).build();
    HttpResponse<String> res = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(5)).build()
      .send(req, HttpResponse.BodyHandlers.ofString());
    if (res.statusCode() / 100 != 2) throw new IOException("转写失败 HTTP="+res.statusCode());
    System.out.println("转写成功;生产环境请将JSON交给解析器并脱敏保存。");
  }
}

form 明确构造 multipart 边界和文件段,connectTimeout 控制建连,timeout 控制整次请求。真实服务不要让 HTTP 控制器同步等待30秒:接到文件后创建任务,交给队列工作者执行,前端轮询任务状态。也不要依据文件扩展名断言格式,生产中应读取 MIME、限制时长并做恶意文件扫描。

预期成功时打印“转写成功”;错误会显示缺失密钥、大小超过20MB、HTTP状态或网络异常。常见错误包括:边界与 Content-Type 不一致;音频 MIME 误标;用户刷新页面就再次上传;模型听错人名却把未经校对的文本写入合同。适合会议纪要初稿、客服质检和无障碍字幕,不适合在未告知录音参与者时秘密转写。

工程化增加任务ID、重试上限、幂等哈希、加密存储、删除策略和专名词表,并把人工修订反向用于质量抽样。5分钟实践:增加 .wav 白名单和一个“已存在音频哈希则不重复提交”的内存集合。

你的转写任务在30秒未返回时,是重试、排队还是提示用户稍后查看?

关注「蜗牛聊AI」,一起看懂技术变化背后的真正机会。


本文首发于 java4u.cn,转载请注明出处。

本文由 java4u.cn 发布,可自由转载、引用,但需署名作者且注明文章出处(作者:白色蜗牛,出处:java4u.cn)。如转载至微信公众号,请在文末添加作者公众号二维码。 https://java4u.cn/ai/3100.html

作者: 蜗牛

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

联系我们

公众号:蜗牛互联网

在线咨询: QQ交谈

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部