Lingara Lingara Documentazione Guide API Librerie App Crea Incorporare App web
Lingua: Italiano

Dialoghi con gli NPC

Questa pagina è tradotta dall'inglese. Se le due versioni differiscono, fa fede la pagina in inglese. Leggi la pagina in inglese

Un personaggio del tuo gioco può sostenere una conversazione con il giocatore nella lingua che sta imparando, calibrata sul suo livello. Ogni battuta che il giocatore pronuncia è un turno: il player kit la invia e la risposta del personaggio torna indietro in streaming, a pezzi.

Cosa trasporta un turno

Ogni turno invia tutto ciò di cui il personaggio ha bisogno, perché Lingara non conserva alcuna conversazione tra un turno e l’altro:

  • npc: chi sta parlando. Il suo name è lungo da 1 a 32 caratteri, e il suo persona facoltativo è una riga di descrizione, da 1 a 120 caratteri, come “un venditore di ravioli”.
  • scene: facoltativo, dove si svolge la conversazione, da 1 a 160 caratteri.
  • source_lang e target_lang: la lingua del giocatore e quella che sta imparando. Devono essere diverse, e il personaggio parla solo target_lang.
  • level: il livello del giocatore, da 1 a 9. La guida di Lingara “Cosa significa un livello” descrive la scala.
  • line: ciò che il giocatore ha appena detto, da 1 a 500 caratteri.
  • history: la conversazione fin qui, dalla più vecchia, al massimo 12 righe. Ogni riga ha uno speaker, player oppure npc, e il suo text, da 1 a 500 caratteri.

Ogni testo è una singola riga. È il tuo gioco a conservare la conversazione: il player kit mantiene la finestra di ogni dialogo che apri, vi aggiunge ogni turno concluso, tronca ogni risposta ai suoi primi 500 caratteri ed elimina le righe più vecchie oltre le 12.

Lingara tratta il persona e la scena come testo non attendibile proveniente dal tuo gioco. Determinano come parla il personaggio, mai ciò che gli è consentito fare.

Come arriva una risposta

La risposta arriva in streaming come pezzi di testo, che il tuo gioco accoda man mano che arrivano. Tra un pezzo e l’altro può arrivare un avviso, ad esempio uno che indica che la risposta è stata troncata. Il turno termina con done quando la risposta è completa, o con error quando non è riuscita. Un turno non può essere ripreso: se la connessione cade, il giocatore ripete la battuta.

Pronuncia una battuta alla volta per ogni personaggio. Una battuta detta mentre il personaggio sta ancora rispondendo viene rifiutata anziché messa in coda, perché ogni turno viene addebitato.

Chi paga

Solo i giocatori di un client a consumo possono sostenere una conversazione, e ogni turno viene addebitato a quel client. Il token di un giocatore ha bisogno di embed:play.

Linguaggio dell'esempio di codice

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

Vedi anche