elevenlabs/elevenlabs-js

NextJS - Can't resolve 'child_process'

Closed this issue ยท 5 comments

In a very simple implementation:

"use client";

import { ElevenLabsClient, play } from "elevenlabs";

export default async function Audio(props: any) {
  const elevenlabs = new ElevenLabsClient({
    apiKey: "process.env.ELEVENLABS_API_KEY",
  });
  const audio = await elevenlabs.generate({
    voice: "Rachel",
    text: "We support two main models.",
    model_id: "eleven_multilingual_v2",
  });
  await play(audio);
  return <div>Placeholder</div>;
}

This error is persistent.

./node_modules/command-exists/lib/command-exists.js:3:0
Module not found: Can't resolve 'child_process'

https://nextjs.org/docs/messages/module-not-found

Import trace for requested module:
./node_modules/command-exists/index.js
./node_modules/elevenlabs/wrapper/play.js
./node_modules/elevenlabs/wrapper/index.js
./node_modules/elevenlabs/index.js
./components/Audio.tsx
./components/ChatMessageBubble.tsx
./components/ChatWindow.tsx

I can change the config every which way and it doesn't resolve the issue.

For example, in package.config, I can set:

  "browser": {
    "fs": false,
    "child_process": false
  },

However, then it shows the following error.

cannot destructure property 'signals' of '_os.constants' as it is undefined

These are the details of my project:

"engines": {
  "node": ">=18"
},
  "dependencies": {
   ...
   "elevenlabs": "^0.2.2",
   "next": "^14.0.1",
   "react": "18.2.0",
   "react-dom": "18.2.0",
   ...
  },

@osehmathias I see you closed this... did you figure it out? I'm hitting the same issue with nearly the same simple setup.

I closed it as I realised I ignorantly put this on the client side.

Put the ElevenLabs call in an API route then post to the route.

Ahh of course. Thanks for responding back so fast saved me some time. Cheers

// app/api/tts/route.ts

import { ElevenLabsClient } from "elevenlabs";
import { NextResponse } from "next/server";

export async function POST(req) {
  const { message } = await req.json();

  const elevenlabs = new ElevenLabsClient({
    apiKey: process.env.ELEVENLABS_API_KEY,
  });

  try {
    const audio = await elevenlabs.generate({
      voice: process.env.ELEVENLABS_VOICE_ID,
      model_id: "eleven_turbo_v2",
      voice_settings: {
        similarity_boost: 0.5,
        stability: 0.5,
        use_speaker_boost: true,
      },
      text: message,
    });

    return new Response(audio, {
      headers: { "Content-Type": "audio/mpeg" },
    });
  } catch (error) {
    console.error(error);
    return NextResponse.json(error, { status: error.statusCode });
  }
}
// in your page / component
...
const audioRef = useRef<HTMLAudioElement>(new Audio());
...
const getAudioResponse = async (text) => {
 const response = await fetch("/api/tts", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          message: text,
        }),
      });
  return await response.blob();
 }
   
  const botVoiceResponse = await getAudioResponse(text);

  const reader = new FileReader();
  reader.readAsDataURL(botVoiceResponse);
  reader.onload = () => {
        if (audioRef.current) {
          audioRef.current.src = reader.result as string;
        }
      };
....
return ( 
      <audio ref={audioRef} hidden />
  )
]

@osehmathias this is an amazing simple working example, something like this should be in their documentation, thanks so much!