זיהוי כוונות באמצעות קלט אודיו

בדף הזה מוסבר איך להשתמש ב-API כדי להעביר קלט אודיו בסטרימינג לבקשה לזיהוי כוונה. ‫Dialogflow מעבד את האודיו וממיר אותו לטקסט לפני שהוא מנסה להתאים אותו ל-Intent. התהליך הזה נקרא קלט אודיו, זיהוי דיבור, המרת דיבור לטקסט או STT.

לפני שמתחילים

התכונה הזו רלוונטית רק כשמשתמשים ב-API לאינטראקציות עם משתמשי קצה. אם אתם משתמשים בשילוב, אתם יכולים לדלג על המדריך הזה.

לפני שתקראו את המדריך הזה, אתם צריכים:

יצירת סוכן

  1. נכנסים למסוף Dialogflow ES.
  2. אם מופיעה בקשה, נכנסים למסוף. מידע נוסף זמין בסקירה הכללית על מסוף Dialogflow.
  3. בתפריט הצד, מרחיבים את הקטע סוכני טעינה.
  4. לוחצים על יצירת נציג חדש.
  5. מזינים את שם הנציג, שפת ברירת המחדל ואזור הזמן שמוגדר כברירת מחדל.
  6. נכנסים לפרויקט קיים. כדי ליצור פרויקט במסוף Dialogflow, בוחרים באפשרות Create a new Google project.
  7. לוחצים על יצירה.

היסודות של סטרימינג

השיטה streamingDetectIntent של הסוג Session מחזירה אובייקט סטרימינג דו-כיווני של gRPC. השיטות שזמינות לאובייקט הזה משתנות בהתאם לשפה, לכן כדאי לעיין במאמרי העזרה של ספריית הלקוח שלכם כדי לקבל פרטים.

אובייקט הסטרימינג משמש לשליחה ולקבלה של נתונים בו-זמנית. באמצעות האובייקט הזה, הלקוח מעביר בסטרימינג תוכן אודיו ל-Dialogflow, ובמקביל מאזין ל-StreamingDetectIntentResponse.

לשיטה streamingDetectIntent יש פרמטר query_input.audio_config.single_utterance שמשפיע על זיהוי הדיבור:

  • אם הערך הוא false (ברירת המחדל), זיהוי הדיבור לא מפסיק עד שהלקוח סוגר את הסטרימינג.
  • אם הערך הוא true, ‏Dialogflow יזהה ביטוי אחד שנאמר באודיו של הקלט. כש-Dialogflow מזהה שהקול באודיו נפסק או הושהה, הוא מפסיק את זיהוי הדיבור ושולח ללקוח StreamingDetectIntentResponse עם תוצאת זיהוי של END_OF_SINGLE_UTTERANCE. כל אודיו שנשלח ל-Dialogflow בסטרימינג אחרי קבלת END_OF_SINGLE_UTTERANCE לא יטופל על ידי Dialogflow.

בסטרימינג דו-כיווני, הלקוח יכול לסגור חלקית את אובייקט הסטרימינג כדי לאותת לשרת שהוא לא ישלח יותר נתונים. לדוגמה, ב-Java וב-Go, השיטה הזו נקראת closeSend.

חשוב לסגור חלקית (אבל לא לבטל) את הסטרימינג במצבים הבאים:

  • הלקוח סיים לשלוח נתונים.
  • הלקוח מוגדר עם single_utterance שמוגדר ל-true, והוא מקבל StreamingDetectIntentResponse עם תוצאת זיהוי של END_OF_SINGLE_UTTERANCE.

אחרי סגירת הסטרימינג, הלקוח צריך להתחיל בקשה חדשה עם סטרימינג חדש לפי הצורך.

זיהוי כוונה בסטרימינג

בדוגמאות הבאות נעשה שימוש ב-method‏ streamingDetectIntent של הסוג Session כדי להעביר אודיו בסטרימינג.

Go

כדי לבצע אימות ב-Dialogflow CX, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.

func DetectIntentStream(projectID, sessionID, audioFile, languageCode string) (string, error) {
	ctx := context.Background()

	sessionClient, err := dialogflow.NewSessionsClient(ctx)
	if err != nil {
		return "", err
	}
	defer sessionClient.Close()

	if projectID == "" || sessionID == "" {
		return "", fmt.Errorf("detect.DetectIntentStream empty project (%s) or session (%s)", projectID, sessionID)
	}

	sessionPath := fmt.Sprintf("projects/%s/agent/sessions/%s", projectID, sessionID)

	// In this example, we hard code the encoding and sample rate for simplicity.
	audioConfig := dialogflowpb.InputAudioConfig{AudioEncoding: dialogflowpb.AudioEncoding_AUDIO_ENCODING_LINEAR_16, SampleRateHertz: 16000, LanguageCode: languageCode}

	queryAudioInput := dialogflowpb.QueryInput_AudioConfig{AudioConfig: &audioConfig}

	queryInput := dialogflowpb.QueryInput{Input: &queryAudioInput}

	streamer, err := sessionClient.StreamingDetectIntent(ctx)
	if err != nil {
		return "", err
	}

	f, err := os.Open(audioFile)
	if err != nil {
		return "", err
	}

	defer f.Close()

	go func() {
		audioBytes := make([]byte, 1024)

		request := dialogflowpb.StreamingDetectIntentRequest{Session: sessionPath, QueryInput: &queryInput}
		err = streamer.Send(&request)
		if err != nil {
			log.Fatal(err)
		}

		for {
			_, err := f.Read(audioBytes)
			if err == io.EOF {
				streamer.CloseSend()
				break
			}
			if err != nil {
				log.Fatal(err)
			}

			request = dialogflowpb.StreamingDetectIntentRequest{InputAudio: audioBytes}
			err = streamer.Send(&request)
			if err != nil {
				log.Fatal(err)
			}
		}
	}()

	var queryResult *dialogflowpb.QueryResult

	for {
		response, err := streamer.Recv()
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatal(err)
		}

		recognitionResult := response.GetRecognitionResult()
		transcript := recognitionResult.GetTranscript()
		log.Printf("Recognition transcript: %s\n", transcript)

		queryResult = response.GetQueryResult()
	}

	fulfillmentText := queryResult.GetFulfillmentText()
	return fulfillmentText, nil
}

Java

כדי לבצע אימות ב-Dialogflow CX, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.


import com.google.api.gax.rpc.ApiException;
import com.google.api.gax.rpc.BidiStream;
import com.google.cloud.dialogflow.v2.AudioEncoding;
import com.google.cloud.dialogflow.v2.InputAudioConfig;
import com.google.cloud.dialogflow.v2.QueryInput;
import com.google.cloud.dialogflow.v2.QueryResult;
import com.google.cloud.dialogflow.v2.SessionName;
import com.google.cloud.dialogflow.v2.SessionsClient;
import com.google.cloud.dialogflow.v2.StreamingDetectIntentRequest;
import com.google.cloud.dialogflow.v2.StreamingDetectIntentResponse;
import com.google.protobuf.ByteString;
import java.io.FileInputStream;
import java.io.IOException;

class DetectIntentStream {

  // DialogFlow API Detect Intent sample with audio files processes as an audio stream.
  static void detectIntentStream(String projectId, String audioFilePath, String sessionId)
      throws IOException, ApiException {
    // String projectId = "YOUR_PROJECT_ID";
    // String audioFilePath = "path_to_your_audio_file";
    // Using the same `sessionId` between requests allows continuation of the conversation.
    // String sessionId = "Identifier of the DetectIntent session";

    // Instantiates a client
    try (SessionsClient sessionsClient = SessionsClient.create()) {
      // Set the session name using the sessionId (UUID) and projectID (my-project-id)
      SessionName session = SessionName.of(projectId, sessionId);

      // Instructs the speech recognizer how to process the audio content.
      // Note: hard coding audioEncoding and sampleRateHertz for simplicity.
      // Audio encoding of the audio content sent in the query request.
      InputAudioConfig inputAudioConfig =
          InputAudioConfig.newBuilder()
              .setAudioEncoding(AudioEncoding.AUDIO_ENCODING_LINEAR_16)
              .setLanguageCode("en-US") // languageCode = "en-US"
              .setSampleRateHertz(16000) // sampleRateHertz = 16000
              .build();

      // Build the query with the InputAudioConfig
      QueryInput queryInput = QueryInput.newBuilder().setAudioConfig(inputAudioConfig).build();

      // Create the Bidirectional stream
      BidiStream<StreamingDetectIntentRequest, StreamingDetectIntentResponse> bidiStream =
          sessionsClient.streamingDetectIntentCallable().call();

      // The first request must **only** contain the audio configuration:
      bidiStream.send(
          StreamingDetectIntentRequest.newBuilder()
              .setSession(session.toString())
              .setQueryInput(queryInput)
              .build());

      try (FileInputStream audioStream = new FileInputStream(audioFilePath)) {
        // Subsequent requests must **only** contain the audio data.
        // Following messages: audio chunks. We just read the file in fixed-size chunks. In reality
        // you would split the user input by time.
        byte[] buffer = new byte[4096];
        int bytes;
        while ((bytes = audioStream.read(buffer)) != -1) {
          bidiStream.send(
              StreamingDetectIntentRequest.newBuilder()
                  .setInputAudio(ByteString.copyFrom(buffer, 0, bytes))
                  .build());
        }
      }

      // Tell the service you are done sending data
      bidiStream.closeSend();

      for (StreamingDetectIntentResponse response : bidiStream) {
        QueryResult queryResult = response.getQueryResult();
        System.out.println("====================");
        System.out.format("Intent Display Name: %s\n", queryResult.getIntent().getDisplayName());
        System.out.format("Query Text: '%s'\n", queryResult.getQueryText());
        System.out.format(
            "Detected Intent: %s (confidence: %f)\n",
            queryResult.getIntent().getDisplayName(), queryResult.getIntentDetectionConfidence());
        System.out.format(
            "Fulfillment Text: '%s'\n",
            queryResult.getFulfillmentMessagesCount() > 0
                ? queryResult.getFulfillmentMessages(0).getText()
                : "Triggered Default Fallback Intent");
      }
    }
  }
}

Node.js

כדי לבצע אימות ב-Dialogflow CX, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.

const fs = require('fs');
const util = require('util');
const {Transform, pipeline} = require('stream');
const {struct} = require('pb-util');

const pump = util.promisify(pipeline);
// Imports the Dialogflow library
const dialogflow = require('@google-cloud/dialogflow');

// Instantiates a session client
const sessionClient = new dialogflow.SessionsClient();

// The path to the local file on which to perform speech recognition, e.g.
// /path/to/audio.raw const filename = '/path/to/audio.raw';

// The encoding of the audio file, e.g. 'AUDIO_ENCODING_LINEAR_16'
// const encoding = 'AUDIO_ENCODING_LINEAR_16';

// The sample rate of the audio file in hertz, e.g. 16000
// const sampleRateHertz = 16000;

// The BCP-47 language code to use, e.g. 'en-US'
// const languageCode = 'en-US';
const sessionPath = sessionClient.projectAgentSessionPath(
  projectId,
  sessionId
);

const initialStreamRequest = {
  session: sessionPath,
  queryInput: {
    audioConfig: {
      audioEncoding: encoding,
      sampleRateHertz: sampleRateHertz,
      languageCode: languageCode,
    },
  },
};

// Create a stream for the streaming request.
const detectStream = sessionClient
  .streamingDetectIntent()
  .on('error', console.error)
  .on('data', data => {
    if (data.recognitionResult) {
      console.log(
        `Intermediate transcript: ${data.recognitionResult.transcript}`
      );
    } else {
      console.log('Detected intent:');

      const result = data.queryResult;
      // Instantiates a context client
      const contextClient = new dialogflow.ContextsClient();

      console.log(`  Query: ${result.queryText}`);
      console.log(`  Response: ${result.fulfillmentText}`);
      if (result.intent) {
        console.log(`  Intent: ${result.intent.displayName}`);
      } else {
        console.log('  No intent matched.');
      }
      const parameters = JSON.stringify(struct.decode(result.parameters));
      console.log(`  Parameters: ${parameters}`);
      if (result.outputContexts && result.outputContexts.length) {
        console.log('  Output contexts:');
        result.outputContexts.forEach(context => {
          const contextId =
            contextClient.matchContextFromProjectAgentSessionContextName(
              context.name
            );
          const contextParameters = JSON.stringify(
            struct.decode(context.parameters)
          );
          console.log(`    ${contextId}`);
          console.log(`      lifespan: ${context.lifespanCount}`);
          console.log(`      parameters: ${contextParameters}`);
        });
      }
    }
  });

// Write the initial stream request to config for audio input.
detectStream.write(initialStreamRequest);

// Stream an audio file from disk to the Conversation API, e.g.
// "./resources/audio.raw"
await pump(
  fs.createReadStream(filename),
  // Format the audio stream into the request format.
  new Transform({
    objectMode: true,
    transform: (obj, _, next) => {
      next(null, {inputAudio: obj});
    },
  }),
  detectStream
);

Python

כדי לבצע אימות ב-Dialogflow CX, צריך להגדיר את Application Default Credentials. למידע נוסף, ראו הגדרת אימות לסביבת פיתוח מקומית.

def detect_intent_stream(project_id, session_id, audio_file_path, language_code):
    """Returns the result of detect intent with streaming audio as input.

    Using the same `session_id` between requests allows continuation
    of the conversation."""
    from google.cloud import dialogflow

    session_client = dialogflow.SessionsClient()

    # Note: hard coding audio_encoding and sample_rate_hertz for simplicity.
    audio_encoding = dialogflow.AudioEncoding.AUDIO_ENCODING_LINEAR_16
    sample_rate_hertz = 16000

    session_path = session_client.session_path(project_id, session_id)
    print("Session path: {}\n".format(session_path))

    def request_generator(audio_config, audio_file_path):
        query_input = dialogflow.QueryInput(audio_config=audio_config)

        # The first request contains the configuration.
        yield dialogflow.StreamingDetectIntentRequest(
            session=session_path, query_input=query_input
        )

        # Here we are reading small chunks of audio data from a local
        # audio file.  In practice these chunks should come from
        # an audio input device.
        with open(audio_file_path, "rb") as audio_file:
            while True:
                chunk = audio_file.read(4096)
                if not chunk:
                    break
                # The later requests contains audio data.
                yield dialogflow.StreamingDetectIntentRequest(input_audio=chunk)

    audio_config = dialogflow.InputAudioConfig(
        audio_encoding=audio_encoding,
        language_code=language_code,
        sample_rate_hertz=sample_rate_hertz,
    )

    requests = request_generator(audio_config, audio_file_path)
    responses = session_client.streaming_detect_intent(requests=requests)

    print("=" * 20)
    for response in responses:
        print(
            'Intermediate transcript: "{}".'.format(
                response.recognition_result.transcript
            )
        )
        # Note: Since Python gRPC doesn't have closeSend method, to stop processing the audio after result is recognized,
        # you may close the channel manually to prevent further iteration.
        # Keep in mind that if there is a silence chunk in the audio, part after it might be missed because of early teardown.
        # https://cloud.google.com/dialogflow/es/docs/how/detect-intent-stream#streaming_basics
        if response.recognition_result.is_final:
            session_client.transport.close()
            break

    # Note: The result from the last response is the final transcript along
    # with the detected content.
    query_result = response.query_result

    print("=" * 20)
    print("Query text: {}".format(query_result.query_text))
    print(
        "Detected intent: {} (confidence: {})\n".format(
            query_result.intent.display_name, query_result.intent_detection_confidence
        )
    )
    print("Fulfillment text: {}\n".format(query_result.fulfillment_text))

שפות נוספות

‫C#‎: פעלו לפי הוראות ההגדרה של C# ‎ בדף ספריות הלקוח, ואז עיינו במאמרי העזרה של Dialogflow CX ל-‎ .NET.

‫PHP: פועלים לפי הוראות ההגדרה של PHP בדף ספריות הלקוח, ואז נכנסים למאמרי העזרה של Dialogflow CX ל-PHP.

‫Ruby: פועלים לפי הוראות ההגדרה של Ruby בדף ספריות הלקוח, ואז נכנסים למאמרי העזרה של Dialogflow CX ל-Ruby.

דוגמאות

בדף הדוגמאות מפורטות שיטות מומלצות להעברת סטרימינג ממיקרופון של דפדפן ל-Dialogflow.