Browse Source
客户端录的通话音频是双声道 WAV(左=本端麦克风、右=对端),而 DashScope 录音文件识别 不传 channel_id 时只转第 0 轨 —— 语音纪要里只有机主自己说的话,对方一句都没有。 - 提交前先探一次 WAV 头(probeWavChannels),确认是多声道才传 channel_id=[0,1]: 每多一轨按一份音频计费,单声道文件不该白花钱; - 多轨结果每轨一份 transcript,说话人直接按音轨定(0=本端 1=对端), 比让服务商去分离 speaker_id 可靠得多,再按时间轴合并成一条转写。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>main
3 changed files with 101 additions and 1 deletions
@ -0,0 +1,39 @@ |
|||||
|
package filetrans |
||||
|
|
||||
|
import ( |
||||
|
"encoding/binary" |
||||
|
"testing" |
||||
|
) |
||||
|
|
||||
|
func wavHeader(channels uint16) []byte { |
||||
|
b := make([]byte, 44) |
||||
|
copy(b[0:4], "RIFF") |
||||
|
binary.LittleEndian.PutUint32(b[4:8], 36) |
||||
|
copy(b[8:12], "WAVE") |
||||
|
copy(b[12:16], "fmt ") |
||||
|
binary.LittleEndian.PutUint32(b[16:20], 16) |
||||
|
binary.LittleEndian.PutUint16(b[20:22], 1) |
||||
|
binary.LittleEndian.PutUint16(b[22:24], channels) |
||||
|
binary.LittleEndian.PutUint32(b[24:28], 16000) |
||||
|
copy(b[36:40], "data") |
||||
|
return b |
||||
|
} |
||||
|
|
||||
|
func TestWavChannelsFromHeader(t *testing.T) { |
||||
|
if got := wavChannelsFromHeader(wavHeader(2)); got != 2 { |
||||
|
t.Fatalf("stereo: got %d", got) |
||||
|
} |
||||
|
if got := wavChannelsFromHeader(wavHeader(1)); got != 1 { |
||||
|
t.Fatalf("mono: got %d", got) |
||||
|
} |
||||
|
// 客户端 WavWriter 的头只有 44 字节,但取 64 字节的 Range 会带上 data 的前 20 字节
|
||||
|
if got := wavChannelsFromHeader(append(wavHeader(2), make([]byte, 20)...)); got != 2 { |
||||
|
t.Fatalf("stereo+data: got %d", got) |
||||
|
} |
||||
|
if got := wavChannelsFromHeader([]byte("OggS\x00\x02")); got != 0 { |
||||
|
t.Fatalf("ogg: got %d", got) |
||||
|
} |
||||
|
if got := wavChannelsFromHeader(wavHeader(2)[:20]); got != 0 { |
||||
|
t.Fatalf("truncated: got %d", got) |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue