نکات پیاده سازی (Dialogflow)

نکات زیر را برای پیاده سازی شیوه های خوب طراحی مکالمه در Action خود مرور کنید.

انتظار تغییرات را داشته باشید

این را در ورودی «کاربر می‌گوید» در Dialogflow مدیریت کنید. همچنین، از بیش از یک هدف استفاده کنید که می‌تواند به یک عمل نگاشت شود، جایی که هر هدف می‌تواند با مجموعه‌های مختلفی از عبارات «کاربر می‌گوید» فعال شود.

پیام های مفیدی ارائه دهید و با شکوه شکست بخورید

گاهی اوقات Action شما نمی‌تواند به جلو حرکت کند زیرا ورودی (معروف به بدون ورودی) یا ورودی کاربر را درک نکرده است (معروف به no-match). وقتی این اتفاق می‌افتد، دستیار ابتدا تلاش می‌کند تا تعیین کند آیا کاربر می‌خواهد یک Action دیگر را راه‌اندازی کند یا خیر. اگر Assistant با ورودی کاربر با Action دیگری مطابقت نداشته باشد، کاربر در زمینه Action شما ادامه می‌دهد. این سناریو می‌تواند در هر زمانی اتفاق بیفتد، بنابراین بهترین تمرین این است که در هر نوبت در یک مکالمه با موقعیت‌های بدون ورودی و بدون تطابق به‌طور منحصربه‌فرد مدیریت کنید. با استفاده از جایگزینی، می توانید به کاربران کمک کنید تا به مسیر خود بازگردند.

برای انجام این کار، یک متغیر fallbackCount را در شیء conv.data خود مقداردهی اولیه کنید، و آن را روی 0 قرار دهید. آرایه ای از دو درخواست بازگشتی (با وضوح بالا) و یک اعلان بازگشتی نهایی که مکالمه را پایان می دهد، آماده کنید.

سپس، یک هدف بازگشتی ایجاد کنید (به طور ایده آل برای هر هدف قابل اجرا در عامل). در کنترل‌کننده قصد، شمارش بازگشتی را از شیء conv.data بکشید، آن را افزایش دهید و اگر کمتر از 3 باشد، درخواست را از آرایه 3 بکشید. اگر تعداد 4 یا بیشتر است، مکالمه را با استفاده از اخطار نهایی در تمام مقاصد که بازگشتی نیستند، شمارش بازگشتی را به 0 بازنشانی کنید. در حالت ایده‌آل، مقاصد بازگشتی را الگوسازی کنید تا مقاصد خاص برای آن‌ها باشد.

Node.js

const GENERAL_FALLBACK = [
   'Sorry, what was that?',
   'I didn\'t quite get that. I can help you find good local restaurants, what do you want to know about?',
];

const LIST_FALLBACK = [
   'Sorry, what was that?',
   'I didn\'t catch that. Could you tell me which one you prefer?',
];

const FINAL_FALLBACK = 'I\'m sorry I\'m having trouble here. Let\'s talk again later.';

const handleFallback = (conv, promptFetch, callback) => {
 conv.data.fallbackCount = parseInt(conv.data.fallbackCount, 10);
 conv.data.fallbackCount++;
 if (conv.data.fallbackCount > 2) {
   conv.close(promptFetch.getFinalFallbackPrompt());
 } else {
   callback();
 }
}
// Intent handlers below
const generalFallback = (conv) => {
  handleFallback = (conv, promptFetch, () => {
    conv.ask(GENERAL_FALLBACK[conv.data.fallbackCount],
      getGeneralNoInputPrompts());
 });
}

const listFallback = (conv) => {
  handleFallback = (conv, promptFetch, () => {
   conv.ask(LIST_FALLBACK[conv.data.fallbackCount],
       getGeneralNoInputPrompts());
 });
}

const nonFallback = (conv) => {
  conv.data.fallbackCount = 0;
  conv.ask('A non-fallback message here');
}

جاوا

private static final List<String> GENERAL_FALLBACK =
    Arrays.asList(
        "Sorry, what was that?",
        "I didn\'t quite get that. I can tell you all about IO, like date or location, or about the sessions. What do you want to know about?");
private static final List<String> LIST_FALLBACK =
    Arrays.asList(
        "Sorry, what was that?",
        "I didn\'t catch that. Could you tell me which one you liked?");
private static final List<String> FINAL_FALLBACK =
    Arrays.asList("I\'m sorry I\'m having trouble here. Maybe we should try this again later.");

@ForIntent("General Fallback")
public ActionResponse generalFallback(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  int fallbackCount = (Integer) request.getConversationData().get("fallbackCount");
  fallbackCount++;
  request.getConversationData().put("fallbackCount", fallbackCount);
  if (fallbackCount > 2) {
    responseBuilder.add(getRandomPromptFromList(FINAL_FALLBACK)).endConversation();
  } else {
    responseBuilder.add(getRandomPromptFromList(GENERAL_FALLBACK));
  }
  return responseBuilder.build();
}

private String getRandomPromptFromList(List<String> prompts) {
  Random rand = new Random();
  int i = rand.nextInt(prompts.size());
  return prompts.get(i);
}

@ForIntent("List Fallback")
public ActionResponse listFallback(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  int fallbackCount = (Integer) request.getConversationData().get("fallbackCount");
  fallbackCount++;
  request.getConversationData().put("fallbackCount", fallbackCount);
  if (fallbackCount > 2) {
    responseBuilder.add(getRandomPromptFromList(FINAL_FALLBACK)).endConversation();
  } else {
    responseBuilder.add(getRandomPromptFromList(LIST_FALLBACK));
  }
  return responseBuilder.build();
}

@ForIntent("Non Fallback")
public ActionResponse nonFallback(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  request.getConversationData().put("fallbackCount", 0);
  responseBuilder.add("Non Fallback message");
  return responseBuilder.build();
}

برای کمک در هر زمان آماده باشید

هدفی ایجاد کنید که به عبارات کمکی مانند "چه کاری می توانم انجام دهم؟"، "چه می توانی به من بگویی" یا "کمک" گوش می دهد. در این هدف، پاسخی (چرخشی) ارائه دهید که نمای کلی از آنچه عامل می تواند انجام دهد ارائه می دهد و کاربران را به یک اقدام احتمالی هدایت می کند. در حالت ایده‌آل، همچنین از اهداف کمکی پیگیری در Dialogflow برای ایجاد سناریوهای کمکی مختلف برای مقاصد عملی مختلف استفاده کنید.

Node.js

const HELP_PROMPTS = [
   'There\'s a lot you might want to know about the local restaurants, and I can tell you all about it, like where it is and what kind of food they have. What do you want to know?',
   'I\'m here to help, so let me know if you need any help figuring out where or what to eat. What do you want to know?',
];

// Intent handler
const help = (conv) => {
 reply(conv, promptFetch.getHelpPrompt(), // fetches random entry from HELP_PROMPTS
     promptFetch.getGeneralNoInputPrompts());
}

جاوا

private static final List<String> HELP_PROMPTS =
    Arrays.asList(
        "There's a lot you might want to know about IO, and I can tell you all about it, like where it is and what the sessions are. What do you want to know?",
        "IO can be a little overwhelming, so I\'m here to help. Let me know if you need any help figuring out the event, like when it is, or what the sessions are. What do you want to know?");

@ForIntent("Help")
public ActionResponse help(ActionRequest request) {
  return getResponseBuilder(request).add(getRandomPromptFromList(HELP_PROMPTS)).build();
}

به کاربران اجازه پخش مجدد اطلاعات را بدهید

همه متدهای app.ask(output) خود را با یک تابع پراکسی بپیچید که خروجی را به conv.data.lastPrompt اضافه می کند. یک هدف تکراری ایجاد کنید که به درخواست‌های تکراری کاربر مانند «چی؟»، «دوباره بگو» یا «می‌توانید آن را تکرار کنید؟» گوش می‌دهد. آرایه‌ای از پیشوندهای تکراری ایجاد کنید که می‌توان از آنها برای تأیید اینکه کاربر درخواست تکرار چیزی را کرده است استفاده کرد. در کنترل کننده مقصود تکرار، ask() با یک رشته پیوسته از پیشوند تکرار و مقدار conv.data.lastPrompt فراخوانی کنید. به خاطر داشته باشید که اگر در آخرین اعلان استفاده شود، باید تگ های بازکننده SSML را تغییر دهید.

Node.js

const REPEAT_PREFIX = [
    'Sorry, I said ',
    'Let me repeat that. ',
];

const reply = (conv, inputPrompt, noInputPrompts) => {
  conv.data.lastPrompt = inputPrompt;
  conv.data.lastNoInputPrompts = noInputPrompts;
  conv.ask(inputPrompt, noInputPrompts);
}
// Intent handlers
const normalIntent = (conv) => {
  reply(conv, 'Hey this is a question', SOME_NO_INPUT_PROMPTS);
}

const repeat = (conv) => {
  let repeatPrefix = promptFetch.getRepeatPrefix(); // randomly chooses from REPEAT_PREFIX
  // Move SSML start tags over
  if (conv.data.lastPrompt.startsWith(promptFetch.getSSMLPrefix())) {
    conv.data.lastPrompt =
        conv.data.lastPrompt.slice(promptFetch.getSSMLPrefix().length);
    repeatPrefix = promptFetch.getSSMLPrefix() + repeatPrefix;
  }
  conv.ask(repeatPrefix + conv.data.lastPrompt,
      conv.data.lastNoInputPrompts);
}

جاوا

private final List<String> REPEAT_PREFIX = Arrays.asList("Sorry, I said ", "Let me repeat that.");

private final String SsmlPrefix = "<speak>";

@ForIntent("Normal Intent")
public ActionResponse normalIntent(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  responseBuilder.getConversationData().put("lastPrompt", "Hey this is a question");
  return responseBuilder.build();
}

@ForIntent("repeat")
public ActionResponse repeat(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  String repeatPrefix = getRandomPromptFromList(REPEAT_PREFIX);
  // Move SSML start tags over
  String lastPrompt = (String) responseBuilder.getConversationData().get("lastPrompt");
  if (lastPrompt.startsWith(SsmlPrefix)) {
    String newLastPrompt = lastPrompt.substring(SsmlPrefix.length());
    responseBuilder.getConversationData().put("lastPrompt", newLastPrompt);
    repeatPrefix = SsmlPrefix + repeatPrefix;
  }
  responseBuilder.add(repeatPrefix + lastPrompt);
  return responseBuilder.build();
}

مکالمه را با تنظیمات برگزیده کاربر شخصی کنید

Action شما می‌تواند تنظیمات برگزیده را از کاربران بخواهد و آنها را برای استفاده بعدی به خاطر بسپارد و به شما امکان می‌دهد مکالمات آینده را با آن کاربر شخصی کنید.

این مثال Action به کاربران گزارش آب و هوا برای کد پستی می دهد. کد مثال زیر از کاربر می‌پرسد که آیا مایل است Action کد پستی خود را برای مکالمات بعدی به خاطر بسپارد یا خیر.

Node.js

app.intent('weather_report', (conv) => {
  let zip = conv.arguments.get('zipcode');
  conv.data.zip = zip;
  conv.ask(getWeatherReport(zip));
  conv.ask(new Confirmation(`Should I remember ${zip} for next time?`));
});

app.intent('remember_zip', (conv, params, confirmation) => {
  if (confirmation) {
    conv.user.storage.zip = conv.data.zip;
    conv.close('Great! See you next time.');
  } else conv.close('Ok, no problem.');
});

جاوا

@ForIntent("weather_report")
public ActionResponse weatherReport(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  String zip = (String) request.getArgument("location").getStructuredValue().get("zipCode");
  responseBuilder.getConversationData().put("zip", zip);
  responseBuilder.add(getWeatherReport(zip));
  responseBuilder.add(
      new Confirmation().setConfirmationText("Should I remember " + zip + " for next time?"));
  return responseBuilder.build();
}

@ForIntent("remember_zip")
public ActionResponse rememberZip(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  if (request.getUserConfirmation()) {
    responseBuilder.getUserStorage().put("zip", responseBuilder.getConversationData().get("zip"));
    responseBuilder.add("Great! See you next time.").endConversation();
  } else {
    responseBuilder.add("Ok, no problem.").endConversation();
  }
  return responseBuilder.build();
}

پس از پرسیدن کد پستی کاربر در اولین گفتگوی خود، می توانید از آن درخواست در هنگام فراخوانی بعدی خود صرف نظر کرده و از همان کد پستی استفاده کنید. شما هنوز هم باید یک مسیر فرار ارائه دهید (مانند یک تراشه پیشنهاد که به آنها امکان می دهد کد پستی متفاوتی را انتخاب کنند) اما با کاهش چرخش مکالمه در مورد معمول، تجربه بسیار یکپارچه تری ایجاد می کنید.

Node.js

app.intent('weather_report', (conv) => {
  let zip = conv.arguments.get('zipcode');
  if (zip) {
    conv.close(getWeatherReport(zip));
  } else if (conv.user.storage.zip) {
    conv.ask(new SimpleResponse(getWeatherReport(conv.user.storage.zip)));
    conv.ask(new Suggestions('Try another zipcode'));
  } else {
    conv.ask('What\'s your zip code?');
  }
});

app.intent('provide_zip_df', (conv) => {
  conv.user.storage.zip = conv.arguments.get('zipcode');
  conv.close(getWeatherReport(conv.user.storage.zip));
});

جاوا

public ActionResponse weatherReport2(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  String zip = (String) request.getArgument("location").getStructuredValue().get("zipCode");
  if (zip != null) {
    responseBuilder.add(getWeatherReport(zip)).endConversation();
  } else if ((zip = (String) responseBuilder.getUserStorage().get("zip")) != null) {
    responseBuilder.add(new SimpleResponse().setTextToSpeech(getWeatherReport(zip)));
    responseBuilder.add(new Suggestion().setTitle("Try another zipcode"));
  } else {
    responseBuilder.add("What's your zip code?");
  }
  return responseBuilder.build();
}

برای کاربران بازگشتی سفارشی کنید

حفظ وضعیت بین مکالمات تجربه بسیار طبیعی تری را برای کاربران بازگشتی تضمین می کند. اولین قدم در ایجاد این تجربه، استقبال متفاوت از کاربران بازگشته است. به عنوان مثال، می‌توانید احوالپرسی را باریک کنید یا اطلاعات مفیدی را بر اساس مکالمات گذشته ارائه دهید. برای انجام این کار، از ویژگی AppRequest.User lastSeen ورودی استفاده کنید تا مشخص کنید آیا کاربر قبلاً با Action شما تعامل داشته است یا خیر. اگر ویژگی lastSeen در بار درخواست گنجانده شده باشد، می توانید از یک سلام متفاوت از حالت عادی استفاده کنید.

کد زیر از کتابخانه مشتری Node.js برای واکشی مقدار last.seen استفاده می کند.

Node.js

// This function is used to handle the welcome intent
// In Dialogflow, the Default Welcome Intent ('input.welcome' action)
// In Actions SDK, the 'actions.intent.MAIN' intent
const welcome = (conv) => {
  if (conv.user.last.seen) {
    conv.ask(`Hey you're back...`);
  } else {
    conv.ask('Welcome to World Cities Trivia!...');
  }
}

جاوا

// This function is used to handle the welcome intent
// In Dialogflow, the Default Welcome Intent ('input.welcome' action)
// In Actions SDK, the 'actions.intent.MAIN' intent
public ActionResponse welcome(ActionRequest request) {
  ResponseBuilder responseBuilder = getResponseBuilder(request);
  if (request.getUser().getLastSeen() != null) {
    responseBuilder.add("Hey you're back...");
  } else {
    responseBuilder.add("Welcome to Number Genie!...");
  }
  return responseBuilder.build();
}

شما می توانید این تبریک را با تنظیم پاسخ به ارزش واقعی lastSeen بیشتر کنید. به عنوان مثال، کاربرانی که آخرین تعامل آنها چندین ماه قبل از تعامل فعلی رخ داده است، ممکن است تبریک متفاوتی نسبت به کسانی که روز قبل از Action استفاده کرده‌اند دریافت کنند.

کنترل صدا در مکالمه

در دستگاه‌های پشتیبانی‌شده، «دستیار» به کاربران امکان می‌دهد با گفتن مواردی مانند «صدا را افزایش دهید» یا «صدا را روی ۵۰ درصد تنظیم کنید» میزان صدای دستگاه را در «کنش مکالمه» شما کنترل کنند. اگر قصد دارید که عبارات آموزشی مشابهی را مدیریت کند، مقاصد شما اولویت دارند. توصیه می‌کنیم به «دستیار» اجازه دهید این درخواست‌های کاربر را رسیدگی کند، مگر اینکه Action شما دلیل خاصی برای آن داشته باشد.