V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
lyxxxh2
V2EX  ›  微信

小程序语音上传到 dify 415 的解决办法

  •  
  •   lyxxxh2 · 29 天前 · 606 次点击

    问题

    用 curl 正常

    curl -X POST 'https://xxx/audio-to-text' --header 'Authorization: xxx' --form 'file=@xxx/1.mp3;type=audio/mp3'

    小程序: 一直 415

    对了半天: mine-type不一样。

    wx.uploadFile 不支持 mine-type,让 ai 重新写了,终于解决了。

    解决代码

    cv 给 ai,让 ai 参考就行

    // 修复的方案 2:正确处理二进制文件数据
    (async function testAudioAPIFixed() {
        console.log('=== 修复的手动构造 multipart 测试 ===')
        
        const audioUrl = 'xxx/1.mp3'
        const apiConfig = {
            baseUrl: 'https://xxx/v1',
            apiKey: 'xxxx'
        }
        
        try {
            // 下载文件
            const downloadResult = await new Promise((resolve, reject) => {
                wx.downloadFile({
                    url: audioUrl,
                    success: resolve,
                    fail: reject
                })
            })
            
            // 读取文件数据为 ArrayBuffer
            const fileData = await new Promise((resolve, reject) => {
                wx.getFileSystemManager().readFile({
                    filePath: downloadResult.tempFilePath,
                    success: resolve,
                    fail: reject
                })
            })
            
            console.log('文件读取成功,大小:', fileData.data.byteLength)
            
            // 手动构造 multipart/form-data - 正确处理二进制数据
            const boundary = '----formdata-' + Date.now()
            const encoder = new TextEncoder()
            
            // 构造表单头部(文本部分)
            let formHeader = ''
            formHeader += `--${boundary}\r\n`
            formHeader += `Content-Disposition: form-data; name="file"; filename="1.mp3"\r\n`
            formHeader += `Content-Type: audio/mp3\r\n\r\n` // ✅ 关键:设置正确的 MIME 类型
            
            // 构造表单尾部(文本部分)
            const formFooter = `\r\n--${boundary}--\r\n`
            
            // 转换文本部分为 ArrayBuffer
            const headerBuffer = encoder.encode(formHeader)
            const footerBuffer = encoder.encode(formFooter)
            
            // 组合所有数据:头部 + 文件数据 + 尾部
            const totalLength = headerBuffer.byteLength + fileData.data.byteLength + footerBuffer.byteLength
            const finalBuffer = new ArrayBuffer(totalLength)
            const finalView = new Uint8Array(finalBuffer)
            
            let offset = 0
            // 复制头部
            finalView.set(new Uint8Array(headerBuffer), offset)
            offset += headerBuffer.byteLength
            
            // 复制文件数据(保持原始二进制格式)
            finalView.set(new Uint8Array(fileData.data), offset)
            offset += fileData.data.byteLength
            
            // 复制尾部
            finalView.set(new Uint8Array(footerBuffer), offset)
            
            console.log('multipart 数据组装完成,总大小:', finalBuffer.byteLength)
            
            // 发送请求
            const result = await new Promise((resolve, reject) => {
                wx.request({
                    url: `${apiConfig.baseUrl}/audio-to-text`,
                    method: 'POST',
                    header: {
                        'Authorization': `Bearer ${apiConfig.apiKey}`,
                        'Content-Type': `multipart/form-data; boundary=${boundary}`
                    },
                    data: finalBuffer, // ✅ 发送完整的 ArrayBuffer
                    success: resolve,
                    fail: reject
                })
            })
            
            console.log('修复版 multipart 结果:', result)
            
            if (result.statusCode === 200) {
                const responseData = typeof result.data === 'string' ? JSON.parse(result.data) : result.data
                console.log('✅ 成功!', responseData)
                wx.showModal({
                    title: '修复版 multipart 成功',
                    content: `识别结果: ${responseData.text}`,
                    showCancel: false
                })
            } else {
                console.error('❌ 失败:', result.statusCode, result.data)
                wx.showModal({
                    title: '修复版 multipart 失败',
                    content: `状态码: ${result.statusCode}\n 错误: ${result.data}`,
                    showCancel: false
                })
            }
            
        } catch (error) {
            console.error('❌ 修复版 multipart 错误:', error)
            wx.showModal({
                title: '修复版 multipart 异常',
                content: error.message,
                showCancel: false
            })
        }
    })()
    

    https://i.imgur.com/20P1OdM.png

    第 1 条附言  ·  29 天前
    手机没有 new TextEncoder()
    代码不可用
    目前尚无回复
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   898 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 20:40 · PVG 04:40 · LAX 13:40 · JFK 16:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.