Rename: nlg → elp (Engram Language Protocol)
This commit is contained in:
+80
-56
@@ -7,15 +7,19 @@
|
||||
// "subject" - subject referent (pronoun or noun phrase)
|
||||
// "object" - object referent (optional, "" if absent)
|
||||
// "modifiers" - semicolon-separated modifier strings (e.g. "in the park;quickly")
|
||||
// "lang" - ISO 639-1 language code (optional, defaults to "en")
|
||||
//
|
||||
// sem_to_spec converts a SemFrame into a realizer slot map ready for realize().
|
||||
// sem_realize is the end-to-end shortcut: frame -> realized English text.
|
||||
// sem_realize is the end-to-end shortcut: frame -> realized text.
|
||||
//
|
||||
// Depends on: grammar (slots_*), realizer (realize)
|
||||
// All existing function signatures are preserved; new *_lang variants add an
|
||||
// explicit lang_code parameter.
|
||||
//
|
||||
// Depends on: grammar (slots_*, realize), language-profile (lang_from_code)
|
||||
|
||||
// ── SemFrame constructors ─────────────────────────────────────────────────────
|
||||
|
||||
// Build a SemFrame slot map with all four fields.
|
||||
// Build a SemFrame with all four core fields. Language defaults to "en".
|
||||
fn sem_frame(intent: String, subject: String, obj: String, modifiers: String) -> [String] {
|
||||
let r: [String] = native_list_empty()
|
||||
let r = native_list_append(r, "intent")
|
||||
@@ -26,15 +30,33 @@ fn sem_frame(intent: String, subject: String, obj: String, modifiers: String) ->
|
||||
let r = native_list_append(r, obj)
|
||||
let r = native_list_append(r, "modifiers")
|
||||
let r = native_list_append(r, modifiers)
|
||||
let r = native_list_append(r, "lang")
|
||||
let r = native_list_append(r, "en")
|
||||
return r
|
||||
}
|
||||
|
||||
// Convenience: frame with no object and no modifiers.
|
||||
// Build a SemFrame with an explicit language code.
|
||||
fn sem_frame_lang(intent: String, subject: String, obj: String, modifiers: String, lang_code: String) -> [String] {
|
||||
let r: [String] = native_list_empty()
|
||||
let r = native_list_append(r, "intent")
|
||||
let r = native_list_append(r, intent)
|
||||
let r = native_list_append(r, "subject")
|
||||
let r = native_list_append(r, subject)
|
||||
let r = native_list_append(r, "object")
|
||||
let r = native_list_append(r, obj)
|
||||
let r = native_list_append(r, "modifiers")
|
||||
let r = native_list_append(r, modifiers)
|
||||
let r = native_list_append(r, "lang")
|
||||
let r = native_list_append(r, lang_code)
|
||||
return r
|
||||
}
|
||||
|
||||
// Convenience: no object, no modifiers, English.
|
||||
fn sem_frame_simple(intent: String, subject: String) -> [String] {
|
||||
return sem_frame(intent, subject, "", "")
|
||||
}
|
||||
|
||||
// Convenience: frame with object but no modifiers.
|
||||
// Convenience: with object, no modifiers, English.
|
||||
fn sem_frame_obj(intent: String, subject: String, obj: String) -> [String] {
|
||||
return sem_frame(intent, subject, obj, "")
|
||||
}
|
||||
@@ -57,18 +79,21 @@ fn sem_modifiers(frame: [String]) -> String {
|
||||
return slots_get(frame, "modifiers")
|
||||
}
|
||||
|
||||
fn sem_lang(frame: [String]) -> String {
|
||||
let code: String = slots_get(frame, "lang")
|
||||
if str_eq(code, "") {
|
||||
return "en"
|
||||
}
|
||||
return code
|
||||
}
|
||||
|
||||
// ── Modifier helpers ──────────────────────────────────────────────────────────
|
||||
//
|
||||
// Modifiers are stored as a semicolon-delimited string.
|
||||
// e.g. "in the park;quickly"
|
||||
// sem_first_modifier extracts the first modifier (typically a location phrase).
|
||||
|
||||
fn sem_first_modifier(mods: String) -> String {
|
||||
let n: Int = str_len(mods)
|
||||
if n == 0 {
|
||||
return ""
|
||||
}
|
||||
// Scan to first ';'
|
||||
let i: Int = 0
|
||||
let running: Bool = true
|
||||
while running {
|
||||
@@ -87,38 +112,28 @@ fn sem_first_modifier(mods: String) -> String {
|
||||
}
|
||||
|
||||
// ── Intent mapping ────────────────────────────────────────────────────────────
|
||||
//
|
||||
// Maps semantic intent names to the slot values expected by realize():
|
||||
// "assert" -> intent="assert" declarative sentence
|
||||
// "query" -> intent="question" yes/no question with do-support
|
||||
// "describe" -> intent="assert" declarative; object holds predicate phrase
|
||||
// "greet" -> handled specially "Hello, {subject}."
|
||||
|
||||
fn sem_intent_to_realize(intent: String) -> String {
|
||||
if str_eq(intent, "assert") { return "assert" }
|
||||
if str_eq(intent, "query") { return "question" }
|
||||
if str_eq(intent, "describe") { return "assert" }
|
||||
if str_eq(intent, "greet") { return "greet" }
|
||||
// Default: treat unknown as assertion
|
||||
return "assert"
|
||||
}
|
||||
|
||||
// ── sem_to_spec: SemFrame -> realizer slot map ────────────────────────────────
|
||||
//
|
||||
// Returns a [String] slot map suitable for passing directly to realize().
|
||||
// Default tense is "present", aspect is "simple". Callers that need
|
||||
// a different tense/aspect should use slots_set on the returned map.
|
||||
// The "lang" key from the SemFrame is forwarded into the GramSpec so that
|
||||
// realize() can resolve the correct language profile.
|
||||
|
||||
fn sem_to_spec(frame: [String]) -> [String] {
|
||||
let intent: String = sem_intent(frame)
|
||||
let subject: String = sem_subject(frame)
|
||||
let obj: String = sem_object(frame)
|
||||
let mods: String = sem_modifiers(frame)
|
||||
|
||||
let intent: String = sem_intent(frame)
|
||||
let subject: String = sem_subject(frame)
|
||||
let obj: String = sem_object(frame)
|
||||
let mods: String = sem_modifiers(frame)
|
||||
let lang_code: String = sem_lang(frame)
|
||||
let location: String = sem_first_modifier(mods)
|
||||
|
||||
// ── Greet: no standard grammar slot, compose directly ─────────────────
|
||||
// We still return a valid spec; sem_realize handles "greet" specially.
|
||||
if str_eq(intent, "greet") {
|
||||
let spec: [String] = native_list_empty()
|
||||
let spec = native_list_append(spec, "intent")
|
||||
@@ -135,11 +150,11 @@ fn sem_to_spec(frame: [String]) -> [String] {
|
||||
let spec = native_list_append(spec, "present")
|
||||
let spec = native_list_append(spec, "aspect")
|
||||
let spec = native_list_append(spec, "simple")
|
||||
let spec = native_list_append(spec, "lang")
|
||||
let spec = native_list_append(spec, lang_code)
|
||||
return spec
|
||||
}
|
||||
|
||||
// ── Describe: subject is topic, object is predicate noun/adj phrase ───
|
||||
// Realized as "Subject is Object." using the copula "be".
|
||||
if str_eq(intent, "describe") {
|
||||
let spec: [String] = native_list_empty()
|
||||
let spec = native_list_append(spec, "intent")
|
||||
@@ -156,10 +171,11 @@ fn sem_to_spec(frame: [String]) -> [String] {
|
||||
let spec = native_list_append(spec, "present")
|
||||
let spec = native_list_append(spec, "aspect")
|
||||
let spec = native_list_append(spec, "simple")
|
||||
let spec = native_list_append(spec, "lang")
|
||||
let spec = native_list_append(spec, lang_code)
|
||||
return spec
|
||||
}
|
||||
|
||||
// ── Assert / Query: standard subject-verb-object ───────────────────────
|
||||
let realize_intent: String = sem_intent_to_realize(intent)
|
||||
let spec: [String] = native_list_empty()
|
||||
let spec = native_list_append(spec, "intent")
|
||||
@@ -176,26 +192,20 @@ fn sem_to_spec(frame: [String]) -> [String] {
|
||||
let spec = native_list_append(spec, "present")
|
||||
let spec = native_list_append(spec, "aspect")
|
||||
let spec = native_list_append(spec, "simple")
|
||||
let spec = native_list_append(spec, "lang")
|
||||
let spec = native_list_append(spec, lang_code)
|
||||
return spec
|
||||
}
|
||||
|
||||
// ── sem_to_spec_full: SemFrame -> realizer slot map with explicit verb ────────
|
||||
//
|
||||
// For "assert" and "query" frames the object field carries the *noun phrase*
|
||||
// patient, not the verb. Callers that have a separate verb should use this
|
||||
// variant and supply it explicitly.
|
||||
//
|
||||
// verb - base form of the predicate verb
|
||||
// tense - "present" | "past" | "future"
|
||||
// aspect - "simple" | "progressive" | "perfect"
|
||||
// ── sem_to_spec_full ──────────────────────────────────────────────────────────
|
||||
|
||||
fn sem_to_spec_full(frame: [String], verb: String, tense: String, aspect: String) -> [String] {
|
||||
let intent: String = sem_intent(frame)
|
||||
let subject: String = sem_subject(frame)
|
||||
let obj: String = sem_object(frame)
|
||||
let mods: String = sem_modifiers(frame)
|
||||
|
||||
let location: String = sem_first_modifier(mods)
|
||||
let intent: String = sem_intent(frame)
|
||||
let subject: String = sem_subject(frame)
|
||||
let obj: String = sem_object(frame)
|
||||
let mods: String = sem_modifiers(frame)
|
||||
let lang_code: String = sem_lang(frame)
|
||||
let location: String = sem_first_modifier(mods)
|
||||
|
||||
if str_eq(intent, "greet") {
|
||||
return sem_to_spec(frame)
|
||||
@@ -217,6 +227,8 @@ fn sem_to_spec_full(frame: [String], verb: String, tense: String, aspect: String
|
||||
let spec = native_list_append(spec, tense)
|
||||
let spec = native_list_append(spec, "aspect")
|
||||
let spec = native_list_append(spec, aspect)
|
||||
let spec = native_list_append(spec, "lang")
|
||||
let spec = native_list_append(spec, lang_code)
|
||||
return spec
|
||||
}
|
||||
|
||||
@@ -236,6 +248,8 @@ fn sem_to_spec_full(frame: [String], verb: String, tense: String, aspect: String
|
||||
let spec = native_list_append(spec, tense)
|
||||
let spec = native_list_append(spec, "aspect")
|
||||
let spec = native_list_append(spec, aspect)
|
||||
let spec = native_list_append(spec, "lang")
|
||||
let spec = native_list_append(spec, lang_code)
|
||||
return spec
|
||||
}
|
||||
|
||||
@@ -248,12 +262,7 @@ fn sem_realize_greet(subject: String) -> String {
|
||||
return "Hello, " + subject + "."
|
||||
}
|
||||
|
||||
// ── sem_realize: SemFrame -> English text ─────────────────────────────────────
|
||||
//
|
||||
// End-to-end convenience: converts a SemFrame to a realized English string.
|
||||
// For "assert" and "query" intents, the object field is treated as the
|
||||
// predicate verb base form (intransitive use). For richer frames with both
|
||||
// a verb and an object, use sem_realize_full.
|
||||
// ── sem_realize: SemFrame -> text ─────────────────────────────────────────────
|
||||
|
||||
fn sem_realize(frame: [String]) -> String {
|
||||
let intent: String = sem_intent(frame)
|
||||
@@ -266,11 +275,7 @@ fn sem_realize(frame: [String]) -> String {
|
||||
return realize(spec)
|
||||
}
|
||||
|
||||
// ── sem_realize_full: SemFrame + explicit verb -> English text ────────────────
|
||||
//
|
||||
// Like sem_realize but accepts a separate verb, tense, and aspect.
|
||||
// Use this when the SemFrame object field carries a noun phrase patient
|
||||
// and you want to specify the predicate verb independently.
|
||||
// ── sem_realize_full ──────────────────────────────────────────────────────────
|
||||
|
||||
fn sem_realize_full(frame: [String], verb: String, tense: String, aspect: String) -> String {
|
||||
let intent: String = sem_intent(frame)
|
||||
@@ -282,3 +287,22 @@ fn sem_realize_full(frame: [String], verb: String, tense: String, aspect: String
|
||||
let spec: [String] = sem_to_spec_full(frame, verb, tense, aspect)
|
||||
return realize(spec)
|
||||
}
|
||||
|
||||
// ── sem_realize_lang: realize in an explicitly specified language ──────────────
|
||||
//
|
||||
// Convenience for callers that want to specify the output language without
|
||||
// constructing a full SemFrame. The lang_code overrides whatever "lang" is
|
||||
// set in the frame.
|
||||
|
||||
fn sem_realize_lang(frame: [String], lang_code: String) -> String {
|
||||
let intent: String = sem_intent(frame)
|
||||
|
||||
if str_eq(intent, "greet") {
|
||||
return sem_realize_greet(sem_subject(frame))
|
||||
}
|
||||
|
||||
// Inject the lang_code into the frame before converting to spec.
|
||||
let patched: [String] = slots_set(frame, "lang", lang_code)
|
||||
let spec: [String] = sem_to_spec(patched)
|
||||
return realize(spec)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user