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

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

انتظار تفاوت‌هایی را داشته باشید

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

بازدرخواست‌های مفید ارائه دهید و به‌خوبی از عهده خطاها برآیید

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

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

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

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();
}

شخصی‌سازی مکالمه با اولویت‌های کاربر

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

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

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 استفاده کنید تا مشخص شود آیا کاربر قبلاً با «کنش» شما تعامل داشته است یا نه. اگر ویژگی 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، این خوشامدگویی را بیشتر بهبود دهید. برای مثال، کاربرانی که آخرین تعاملشان ماه‌ها قبل‌از تعامل فعلی بوده است ممکن است خوشامدگویی متفاوتی نسبت به کسانی که روز قبل از «کنش» استفاده کرده‌اند دریافت کنند.

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

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