Lingara Lingara Ohjeet Oppaat API Kirjastot Sovellukset Rakenna Upotus Verkkosovellus
Kieli: Suomi

NPC-dialogit

Tämä sivu on käännetty englannista. Jos ne eroavat toisistaan, englanninkielinen sivu on oikea. Lue englanninkielinen sivu

Pelisi hahmo voi keskustella pelaajan kanssa kielellä, jota tämä opiskelee, pelaajan tasolle sovitettuna. Jokainen pelaajan sanoma repliikki on yksi vuoro: pelaajapaketti lähettää sen, ja hahmon vastaus virtaa takaisin paloina.

Mitä vuoro sisältää

Jokainen vuoro lähettää kaiken, mitä hahmo tarvitsee, koska Lingara ei säilytä keskustelua vuorojen välillä:

  • npc: kuka puhuu. Sen name on 1–32 merkkiä, ja sen valinnainen persona on yhden rivin kuvaus, 1–120 merkkiä, kuten “nyyttikauppias”.
  • scene: valinnainen, missä keskustelu käydään, 1–160 merkkiä.
  • source_lang ja target_lang: pelaajan oma kieli ja kieli, jota hän opiskelee. Niiden on oltava eri kielet, ja hahmo puhuu vain kieltä target_lang.
  • level: pelaajan taso, 1–9. Lingaran opas “Mitä taso tarkoittaa” kuvaa asteikon.
  • line: mitä pelaaja juuri sanoi, 1–500 merkkiä.
  • history: keskustelu tähän asti, vanhin ensin, enintään 12 riviä. Jokaisella rivillä on speaker, joko player tai npc, ja sen text, 1–500 merkkiä.

Jokainen teksti on yksi rivi. Pelisi pitää keskustelun: pelaajapaketti säilyttää ikkunan jokaiselle avaamallesi dialogille, lisää siihen jokaisen valmiin vuoron, katkaisee jokaisen vastauksen sen ensimmäiseen 500 merkkiin ja pudottaa vanhimmat rivit 12 rivin jälkeen.

Lingara käsittelee personaa ja kohtausta pelisi epäluotettavana tekstinä. Ne muokkaavat sitä, miten hahmo puhuu, eivät koskaan sitä, mitä sen sallitaan tehdä.

Miten vastaus saapuu

Vastaus virtaa tekstin paloina, jotka pelisi liittää perään sitä mukaa kuin ne saapuvat. Niiden välissä voi tulla ilmoitus, esimerkiksi sellainen, joka kertoo vastauksen katkenneen. Vuoro päättyy, kun vastaus on valmis, tilaan done, tai kun se epäonnistui, tilaan error. Vuoroa ei voi jatkaa: jos yhteys katkeaa, pelaaja sanoo repliikin uudelleen.

Sano kullekin hahmolle yksi repliikki kerrallaan. Repliikki, joka sanotaan hahmon vielä vastatessa, hylätään eikä sitä laiteta jonoon, koska jokaisesta vuorosta laskutetaan.

Kuka maksaa

Vain käyttöperusteisen asiakkaan pelaajat voivat keskustella, ja jokainen vuoro laskutetaan tältä asiakkaalta. Pelaajan tunnus tarvitsee oikeuden embed:play.

Koodiesimerkin kieli

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

Katso myös