Lingara Lingara Tài liệu Cẩm nang API Thư viện Ứng dụng Tạo Nhúng Ứng dụng web
Ngôn ngữ: Tiếng Việt

Hội thoại NPC

Trang này được dịch từ tiếng Anh. Nếu hai bản khác nhau, trang tiếng Anh là bản đúng. Đọc trang tiếng Anh

Một nhân vật trong trò chơi của bạn có thể trò chuyện với người chơi bằng ngôn ngữ họ đang học, ở đúng cấp độ của họ. Mỗi câu người chơi nói là một lượt: bộ công cụ người chơi gửi câu đó đi, và câu trả lời của nhân vật được truyền về theo từng phần.

Một lượt mang những gì

Mỗi lượt gửi toàn bộ những gì nhân vật cần, vì Lingara không giữ cuộc hội thoại nào giữa các lượt:

  • npc: ai đang nói. name của nó dài từ 1 đến 32 ký tự, và persona tùy chọn của nó là một dòng mô tả, từ 1 đến 120 ký tự, chẳng hạn “một người bán bánh bao”.
  • scene: tùy chọn, nơi cuộc hội thoại diễn ra, từ 1 đến 160 ký tự.
  • source_lang và target_lang: ngôn ngữ của chính người chơi và ngôn ngữ họ đang học. Hai ngôn ngữ phải khác nhau, và nhân vật chỉ nói target_lang.
  • level: cấp độ của người chơi, từ 1 đến 9. Hướng dẫn “Một cấp độ có nghĩa là gì” của Lingara mô tả thang đo này.
  • line: điều người chơi vừa nói, từ 1 đến 500 ký tự.
  • history: cuộc hội thoại cho đến lúc này, cũ nhất trước, tối đa 12 dòng. Mỗi dòng có một speaker, là player hoặc npc, và text của nó, từ 1 đến 500 ký tự.

Mỗi đoạn văn bản là một dòng duy nhất. Trò chơi của bạn giữ cuộc hội thoại: bộ công cụ người chơi giữ cửa sổ cho mỗi đoạn hội thoại bạn mở, thêm từng lượt đã xong vào đó, cắt mỗi câu trả lời còn 500 ký tự đầu tiên, và bỏ các dòng cũ nhất vượt quá 12.

Lingara coi persona và bối cảnh là văn bản không đáng tin cậy đến từ trò chơi của bạn. Chúng định hình cách nhân vật nói, không bao giờ định hình những gì nhân vật được phép làm.

Câu trả lời đến như thế nào

Câu trả lời được truyền về dưới dạng các phần văn bản, mà trò chơi của bạn nối vào khi chúng đến. Giữa các phần có thể có một thông báo, chẳng hạn thông báo rằng câu trả lời đã bị cắt ngắn. Lượt kết thúc bằng done khi câu trả lời hoàn tất, hoặc bằng error khi thất bại. Một lượt không thể tiếp tục lại: nếu kết nối bị ngắt, người chơi nói lại câu đó.

Hãy nói với mỗi nhân vật từng câu một. Một câu được nói khi nhân vật vẫn đang trả lời sẽ bị từ chối thay vì được xếp hàng, vì mỗi lượt đều bị tính phí.

Ai trả tiền

Chỉ người chơi của máy khách trả theo mức dùng mới có thể trò chuyện, và mỗi lượt được tính phí cho máy khách đó. Mã của người chơi cần embed:play.

Ngôn ngữ của mã mẫu

Bevy

fn spawn_seller(mut commands: Commands) {
    let mei = NpcDialogue::new("Mei", "zh", 2)
        .and_then(|npc| npc.with_persona("a dumpling seller"))
        .and_then(|npc| npc.with_scene("the night market"))
        .expect("within Lingara's bounds");
    commands.spawn(mei);
    commands.spawn(Player);
}

/// One turn at a time: a line said while the NPC is replying is a `Busy` error.
fn talk(keys: Res<ButtonInput<KeyCode>>, npcs: Query<Entity, With<NpcDialogue>>, mut say: MessageWriter<NpcSay>) {
    if keys.just_pressed(KeyCode::Digit1) {
        for entity in &npcs {
            say.write(NpcSay { entity, line: "饺子多少钱?".into() });
        }
    }
}

/// `streaming` grows as the reply arrives; `turns` holds the finished ones.
fn show_reply(transcripts: Query<&NpcTranscript, Changed<NpcTranscript>>) {
    for transcript in &transcripts {
        if let Some(partial) = &transcript.streaming {
            info!("…{partial}");
        }
    }
}

Unity

public DialogueId OpenDialogue(string npc, string sourceLang, string targetLang, byte level) =>
    Client.DialogueOpen(new DialogueConfig { Npc = new Npc { Name = npc }, SourceLang = sourceLang, TargetLang = targetLang, Level = level });

// The reply streams back as NpcTurn events: append each Fragment's text to your label.
public RequestId Say(DialogueId dialogue, string line) => Client.DialogueSay(dialogue, line);

Godot C#

public long OpenDialogue(string npc, string sourceLang, string targetLang, byte level) =>
    Client.DialogueOpen(new DialogueConfig { Npc = new Npc { Name = npc }, SourceLang = sourceLang, TargetLang = targetLang, Level = level }).Value;

// The reply streams back as NpcTurnFragment signals, then one NpcTurnFinished.
public long Say(long dialogue, string line) => Client.DialogueSay(new DialogueId(dialogue), line).Value;

GDScript

# A LingaraNpc child per character: npc_name, target_lang and level in the
# inspector. say() returns false while a turn is in flight (turns are never
# queued, because each one is billed).
func talk_to_mei(line: String) -> void:
	if mei.say(line):
		bubble.text = "…"


func _on_mei_replied(text: String) -> void:
	bubble.text = text

Unreal C++

void ALingaraEmbedSnippetActor::Say(const FString& Line)
{
	ELingaraCallResult Result;
	FLingaraEmbedError Error;
	if (Dialogue == 0)
	{
		FLingaraDialogueConfig Config;
		Config.Npc.Name = TEXT("Mei");
		Config.Npc.Persona = TEXT("a tea seller at the night market");
		Config.SourceLang = TEXT("en");
		Config.TargetLang = TEXT("zh");
		Config.Level = 2;
		Dialogue = Lingara()->DialogueOpen(Config, Result, Error);
	}
	Reply.Reset();
	Lingara()->DialogueSay(Dialogue, Line, Result, Error);
}

// The reply streams back as npc_turn events: append each fragment.
void ALingaraEmbedSnippetActor::HandleNpcTurn(const FLingaraNpcTurn& Turn)
{
	if (Turn.Dialogue == Dialogue && Turn.Update.Type == ELingaraNpcTurnUpdateType::Fragment)
	{
		Reply += Turn.Update.Text;
	}
}

Kotlin

fun talkToMei(line: String) {
    val dialogue = npc ?: lingara.dialogueOpen(DialogueConfig(Npc("Mei", "a tea seller"), "the tea house", "en", "zh", 2, emptyList()))
    npc = dialogue
    lingara.dialogueSay(dialogue, line)
}

private fun onNpcTurn(update: NpcTurnUpdate) {
    when (update) {
        is NpcTurnUpdate.Opened -> bubble = ""
        is NpcTurnUpdate.Fragment -> bubble += update.text
        is NpcTurnUpdate.Finished -> bubble = update.text
        else -> Unit
    }
}

Java

void talkToMei(String line) {
  if (npc < 0) {
    Npc mei = new Npc("Mei", "a tea seller");
    npc =
        lingara.dialogueOpen(new DialogueConfig(mei, "the tea house", "en", "zh", 2, List.of()));
  }
  lingara.dialogueSay(npc, line);
}

void onNpcTurn(EmbedEvent.NpcTurn turn) {
  if (turn.getUpdate() instanceof NpcTurnUpdate.Fragment fragment) {
    bubble.append(fragment.getText());
  } else if (turn.getUpdate() instanceof NpcTurnUpdate.Finished finished) {
    bubble.setLength(0);
    bubble.append(finished.getText());
  }
}

Xem thêm