I am working on a static (nextjs) webapp on azure. I want to record my voice (like 5 to 10sec) and get a transcript of it using openai. I got the code working when I send a form with audio data with postman.
But in azure static web app (swa) there are some challenges. when I send a form with an audio file to the AZ function app, it cant extract the audio or even get a hold of the formData. It seems like when trying to get the formData, the function app just freezes and dont any show errors.
I did some research and think the issue is that the form being send needs to get parsed. I tried a couple of packages, like: formidable, multiparty and @anzp/azure-function-multipart.
When I use Formidable package to parse, for some reason I cant import any exported method and use any. I imported it as following : " import FormidableMeth,{parse} from "formidable". When I click on the "formidable" it leads to node_modules/formidable/dist/index.cjs. It doesnt seem like a package I can import from because it uses a different syntax like "require(), var".
The last one (package @anzp/azure-function-multipart) seems to be fit for AZ function app (obviously beacuse of the name :p), but it hasn't been updated in a couple of years and it uses a outdated "@azure/function@3.2.0" and I have "@azure/functions@.4.6.0". I tried using a forked version forked_azure_function_multipart which has been updated like a month ago but when I checked the package.json of the forked version I still see an older version being installed in the function app. And I see an error : "Type 'HttpRequest' is missing the following properties from type 'HttpRequest': get, parseFormBody"
I tried and use "patch package" and update the package.json, but this did not work with fixxing the issue.
I read some forums but I couldnt find a solution e.g. read stack overflow forum.
Does anyone has a idea how I could parse the formData and extract the audiofile and store it in a folder (for testing purpose before storing it in az storage) in azure function app using a static webapp made of NextJS.
example (SWA function) code frontend:
async function formAction(event: any) {
const NewForm = new FormData();
NewForm.append('audio', event.get('audio'), 'audio.webm');
console.log({auidFormData: event.get('audio'), event: NewForm});
const awaitTranscript = await fetch("/api/voiceTranscriptTrigger",{method:"POST", body: NewForm, headers: {
"Content-Type": "multipart/form-data"
} });
if(awaitTranscript.ok){
const response = await awaitTranscript.json();
console.log({response_awaitTranscript: response});
}
}
example code (backend) Function app (extracting the formData):
import parseMultipartFormData from "@anzp/azure-function-multipart";
export async function voiceTranscriptTrigger(request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> {
try {
console.log(`==> before checking request : <==`);
const { fields, files } = await parseMultipartFormData(request);
console.log({fields: fields});
console.log({files: files});
return new HttpResponse(test);
} catch (e) {
console.error("Error while trying to upload a file\n", e);
return new HttpResponse({body: JSON.stringify({"error": "Something went wrong."})});
}
};
app.http('voiceTranscriptTrigger', {
methods: ['POST'],
authLevel: 'anonymous',
handler: voiceTranscriptTrigger
});
In advance I want to thank you for reading this and even your thought of helping me solve this issue I appreciate.
Kind Regards
=============== UPDATE ===============
I have been trying out busboy package to parse the form data containing the audiofile.
Link to my github repository containg a demo app and the AZ function app is located in the api folder.
I am getting an error while trying to use the function app (request.body.)pipeTo method according to the following article, the error I receive is "typeError [ERR_INVALID_STATE]: Invalid state: The ReadableStream is locked"
Here is the full feedback log response when I try and parse the audiofile
=========== Update V2 =============
I have updated github repository voiceTranscriptTrigger file of my demo app. With Busboy I am able to write a file within the api folder but it does not contain the full audio file, when I try and play the created file I get an error : test.webm:1 Failed to load resource: net::ERR_REQUEST_RANGE_NOT_SATISFIABLE
@Sampath this code below works for me in azure function v4 using busboy.
currently it stores the file in the api folder of the function app.
If I helped someone with this give this answer a like :D.
async function voiceparser(request: HttpRequest, context) {
const bodyPipe = await request.body;
function readHeader(request: HttpRequest, key: string) {
return {[key] :Object.fromEntries(request.headers.entries())[key]}; // + `; boundary=${boundary}`
}
return new Promise((resolve, reject) => {
console.log({contentType: request.headers.values});
console.log({new_header: readHeader(request, 'content-type')});
const busboyHeader = readHeader(request, 'content-type');
const bb = busboy({ headers: busboyHeader });
const saveTo = join(process.cwd(), "./test.webm",);upload-${random()}`);
const downloadWriteStream = createWriteStream(saveTo);
console.log({temp_directory: saveTo});
bb.on('file', (fieldname, file, filename, encoding, mimetype) => {
const saveTo = join(process.cwd(), './audio.webm', filename);
const writeStream = createWriteStream(saveTo);
file.on("data", (chunk) => {
if(typeof chunk === 'object');
writeStream.write(chunk);
});
});
console.log({readableStream: bodyPipe});
bodyPipe.pipeTo(Writable.toWeb(bb));
})
}
voiceparser(request, context);