def makeSyntR(semR, checkSpecial=True): # checkSpecial is False when called from within specialConcept.checkSpecialConcept # to avoid infinite loop traceSyntR("makeSyntR", semR) concept = semR.concept if concept == None: # l'instance réfère à un autre AMR return instance2SyntR(semR) if checkSpecial: sConcept = specialConcept.checkSpecialConcept(semR) if sConcept != None: traceSyntR("special concept", concept) return sConcept # evaluate each role to build the environment dictInfo = getSyntR(concept) env = Env() opts = Options() roles = semR.get_roles() if isVerb(concept): #only for verbs # HACK for passive : seem to be too aggressive.... so we keep it only for top-level AMR # generate a passive sentence if concept has an :ARG0 and the actual roles does not have :ARG0 but has :ARG1 # %% do not passivate the special case of bear-02 because it is already passive if concept!="bear-02" and semR.parent==None and \ ":ARG0" in verbs[concept].args and ":ARG0" not in semR.roles and ":ARG1" in semR.roles: opts.add("typ", {"pas": True}) roleProcessing.processRoles(concept, roles, [], dictInfo, env, opts) ## patch the syntactic structures for frequent special cases if isVerb(concept): # HACK for changing nominative pronoun to accusative for :ARG1 when :ARG0 is also present if ":ARG1" in env and ":ARG0" in env and isinstance( env[":ARG1"], Pro) and env[":ARG1"].lemma == "I": env[":ARG1"].lemma = "me" elif isAdjective(concept): # adjective with :ARG0 and :ARG1 adj = dictInfo.lemma if ":ARG0" in env and ":ARG1" in env: if isinstance(env[":ARG0"], Pro) and env[":ARG0"].lemma == "me": env[":ARG0"].lemma = "I" if isinstance(env[":ARG1"], Pro) and env[":ARG1"].lemma == "I": env[":ARG0"].lemma = "me" dictInfo = LexSem( adj, "S", [":ARG0", ":ARG1"], lambda arg0, arg1: S( arg0, VP(V("be"), A(adj), pp("for", arg1)))) elif ":ARG1" in env and ":ARG2" in env: if isinstance(env[":ARG1"], Pro) and env[":ARG1"].lemma == "me": env[":ARG1"].lemma = "I" if isinstance(env[":ARG2"], Pro) and env[":ARG2"].lemma == "I": env[":ARG2"].lemma = "me" dictInfo = LexSem( adj, "S", [":ARG1", ":ARG2"], lambda arg1, arg2: S( arg1, VP(V("be"), A(adj), pp("for", arg2)))) elif ":ARG1" in env: if isinstance(env[":ARG1"], Pro) and env[":ARG1"].lemma == "me": env[":ARG1"].lemma = "I" dictInfo = LexSem(adj, "S", [":ARG1"], lambda arg1: S(arg1, VP(V("be"), A(adj)))) syntR = dictInfo.apply(env, opts) return syntR
def temp_trend(lang, trend, goalTemp, when): if lang == "en": return S( N("temperature"), VP(V(trend).t("pr"), PP(P("to"), jsrTemp(goalTemp, lang)), when)) else: return S( NP(N("température").n("p"), PP(P("à"), NP(D("le"), N(trend)))), PP(P("pour"), V("atteindre").t("b"), jsrTemp(goalTemp, lang), when))
def temperature(wInfo, period, lang): temperature_terms = wInfo.get_temperature(period) if temperature_terms == None: return None maxTemp = get_max_term(temperature_terms, 0).infos[0] minTemp = get_min_term(temperature_terms, 0).infos[0] dn = "night" if period in ["tonight", "tomorrow_night"] else "day" tempVals = wInfo.get_temperature_values(period) periodName = periodNames[period][lang](wInfo.get_issue_date()) # checking for an abnormal temperature trend, either # positive change of least 3°C during the night # negative change of last 3°C during the day (t1,t2,i1)=(maxTemp,minTemp,tempVals.index(minTemp)) if dn=="night" else\ (minTemp,maxTemp,tempVals.index(maxTemp)) # print("dn=",dn,"t1=",t1,"t2=",t2) if t1 >= t2 + 3: # abnormal change time if i1 <= 1: return realize(jsrAbnormal[dn]["a"][lang](t1, periodName), lang, False) else: if i1 < 6: # abnormality occurs during the first 6 hours of the period rest = tempVals[i1:] if all([abs(t - t1) <= 2 for t in rest]): # c) remains +/- 2 for the rest of the period return realize(jsrAbnormal[dn]["c"][lang](t1, periodName), lang, False) elif any([t - t1 > 2 for t in rest]): # d) rises more than 2 for the rest return realize(jsrAbnormal[dn]["d"][lang](t1, periodName), lang, False) elif any([t1 - t > 2 for t in rest]): # e) falls more than 2 for the rest (this should never happen!!!) return realize(jsrAbnormal[dn]["e"][lang](t1, periodName), lang, False) else: # b) low temperature after the beginning (but no special case) return realize( jsrAbnormal[dn]["b"][lang](t1, jsrTemp(t2, lang)), lang, False) # normal case res = [] if lang == "en": # output maximum temperature res.append(realize(S(Adv("high"), jsrTemp(maxTemp, "en")), "en", False)) else: res.append( realize(S(N("maximum"), jsrTemp(maxTemp, "fr")), "fr", False)) if minTemp < maxTemp - 2: # output minimum if it differs significantly from the maximum if lang == "en": res.append( realize(S(Adv("low"), jsrTemp(minTemp, "en")), "en", False)) else: res.append( realize(S(N("minimum"), jsrTemp(minTemp, "fr")), "fr", False)) return " ".join(res)
def multisentence(concept,roles,env,opts): traceSyntR("multisentence",concept) # HACK: only works for :snt[1-9] sntKeys=sorted([key for key in roles.keys() if re.fullmatch(r":snt\d",key)]) last=len(sntKeys)-1 multiS=S() for i in range(len(sntKeys)): si=S(makeSyntR(roles[sntKeys[i]])).cap("") if i<last:si.a(".") multiS.add(si) return addRoles(concept, roles, sntKeys,LexSem("multi-sentence","S",[],lambda:multiS), env, opts)
def predicate(subject, attribute): if attribute == None: return S(subject, VP(V("be"))) if isinstance(subject, S): syntR = subject.add(attribute) else: syntR = S(subject, VP(V("be"), attribute)) if isinstance(attribute, Phrase) and "typ" in attribute.props: if "neg" in attribute.props[ "typ"] and attribute.props["typ"]["neg"] != False: if "typ" not in syntR.props: syntR.props["typ"] = {} syntR.props["typ"]["neg"] = attribute.props["typ"]["neg"] return syntR
def apply(self, env=None, opts=None): if env == None: env = Env() if opts == None: opts = Options() ## process args from dictInfo building the list of arguments or None argV = [env.get(arg) if arg in env else None for arg in self.args] syntR = self.lambda_(*argV) if all([arg == None for arg in argV]) and len(env) == 0: return opts.apply(syntR) if isinstance(syntR, Terminal): if isinstance(syntR, A): if ":ARG1" in env: syntR = S(env.get(":ARG1"), VP(V("be"), syntR)) else: syntR = AP(syntR) elif isinstance(syntR, (Pro, Q, NO)): syntR = SP(syntR) elif isinstance(syntR, Adv): syntR = AdvP(syntR) elif isinstance(syntR, P): syntR = PP(syntR) else: print("** apply: strange syntR:%s:%s" % (type(syntR), syntR)) syntR = SP(syntR) ## add unprocessed args if len(env) > 0: syntR.add(env.get(":start"), 0) syntR.add(env.get(".*")) return opts.apply(syntR)
def realize(jsrExpr,lang,addS=True): if addS and not isinstance(jsrExpr,S): jsrExpr=S(jsrExpr) realization=jsRealB(jsrExpr.set_lang(lang).pp()) if savedJsrIO!=None: savedJsrIO.append((jsrExpr.show(),realization)) return realization
def amr2text(amrString, trace=False): if trace: print("*** AMR\n%s" % amrString) amrs.append(amrString) semR = SemanticRep.fromString(amrString) print("*** Semantic Representation - with inverse roles\n%s" % semR.prettyStr()) dereified = dereify(semR) if dereified != None: semR = dereified if trace: print("*** Semantic Representation - [dereified]\n%s" % semR.prettyStr()) semR.elimInv() # transform inverse roles if trace: print("*** Semantic Representation\n%s" % semR.prettyStr()) # print("*** Baseline Generation\n%s"%semR.baselineGen()) syntR = SemR2SyntR.makeSyntR(semR) if syntR is str: return syntR else: if not isinstance(syntR, (S, Q)): syntR = S( syntR) # ensure that the complete output is a full sentence if trace: print("*** Syntactic Representation") try: print(syntR.show()) except Exception as e: ## for debugging the representation... print(syntR.pp0()) raise e return jsRealB(syntR.show(-1))
def havePurpose91(concept,roles,env,opts): if ":ARG2" in roles: if roles[":ARG2"].get_concept()=="amr-unknown": env.put(":start",Q("For what ?")) return addRoles(concept, roles, [], LexSem("have-purpose","S",[":ARG1",":ARG2"], lambda arg1,arg2:S(arg1,VP(V("be"),PP(P("for"),arg2)))), env, opts) return None
def title_block(wInfo, lang): issueDate = wInfo.get_issue_date() noSecond = {"second": False} if lang == "en": s1 = S( NP(N("forecast").n("p")), VP( V("issue").t("pp"), PP( P("by"), Q("jsRealB"), DT(issueDate).dOpt(noSecond), P("for"), CP( C("and"), N("today"), DT(issueDate + datetime.timedelta(days=1)).dOpt( {"rtime": issueDate}))))) s2 = S( NP(D("the"), D("next"), V("schedule").t("pp"), N("forecast").n("p")), VP( V("be").t("f"), V("issue").t("pp"), DT(wInfo.get_next_issue_date()).dOpt(noSecond))) else: s1 = S( NP(N("prévision").n("p")), VP( V("émettre").t("pp"), PP( P("par"), Q("jsRealB"), DT(issueDate).dOpt(noSecond), P("pour"), CP( C("et"), Adv("aujourd'hui"), DT(issueDate + datetime.timedelta(days=1)).dOpt( {"rtime": issueDate}))))) s2 = S( NP(D("le"), A("prochain").pos("pre"), N("prévision").n("p")), VP( V("être").t("f"), V("émettre").t("pp"), DT(wInfo.get_next_issue_date()).dOpt(noSecond))) return "\n".join([realize(s1, lang, False), realize(s2, lang, False)])
def haveRelRole91(concept,roles,env,opts): traceSyntR("haveRelRole91",concept) # syntR_A=makeSyntR(roles[":ARG0"]) if ":ARG0" in roles else None syntR_B=makeSyntR(roles[":ARG1"]) if ":ARG1" in roles else None if ":ARG2" in roles: relation=makeSyntR(roles[":ARG2"]) if isinstance(syntR_B,Pro) and isinstance(relation,NP): relation.elements[0]=makePoss(syntR_B.lemma) return addRoles(concept, roles, [":ARG1",":ARG2"], LexSem("relation","NP",[":ARG0"],lambda arg0:S(arg0,VP(V("be"),relation))), env, opts) if syntR_B!=None: dictInfo=LexSem("have-relation","S",[":ARG0",":ARG3",":ARG4"], lambda arg0,arg3,arg4:S(arg0,VP(V("be"),relation,syntR_B,arg3,arg4))) return addRoles(concept, roles, [":ARG1",":ARG2"], dictInfo, env, opts) else: return addRoles(concept, roles, [":ARG2"],LexSem("rel-role","NP",[],lambda:relation), env, opts) else: errorSyntR("haveRelRole91 with no :ARG2:\n%s"%concept) return Q("*rel*")
jsrAbnormal = { "night": { "a": { "en": lambda t, _: temp_trend("en", "rise", t, PP(P("by"), N("morning")) ), "fr": lambda t, _: temp_trend("fr", "hausse", t, PP( P("en"), N("matinée"))) }, "b": { "en": lambda t, u: S( Adv("low"), u.a(","), P("with"), temp_trend("en", "rise", t, PP(P("by"), N("morning")))), "fr": lambda t, u: S( N("minimum"), u.a(","), temp_trend("fr", "hausse", t, PP(P("en"), N("matinée")))) }, "c": { "en": lambda t, p: temp_trend("en", "rise", t, p).add( AdvP(Adv("then"), A("steady"))), "fr": lambda t, p: temp_trend("fr", "hausse", t, p).add( PP(P("pour"), Adv("ensuite"), V("demeurer").t("b"), A("stable"))) },
# coding=utf-8 from jsRealBclass import N,A,Pro,D,Adv,V,C,P,DT,NO,Q, NP,AP,AdvP,VP,CP,PP,S,SP, jsRealB, Terminal, Phrase,Constituent from amrDicoGen import pp,optD, nouns,adjectives,verbs,adverbs,prepositions, verbalizations ,morphVerbalizations from lexicalSemantics import LexSem, nounInfo,adjInfo,pp,optD import utils import copy,re ## function to build a noun syntR dn = lambda det,arg: NP(D(det),arg) if arg!=None else None cn = lambda conj,arg:S(C(conj),arg) if arg!=None else None def addOptions(syntR,opts): for (key,val) in opts.items(): getattr(syntR, key)(val) return syntR def delCat(dct,w): if w in dct:del dct[w] ### Pronouns pronounOptions = { "I":{"pe":1}, "i":{"pe":1}, "me":{"pe":1}, "you":{"pe":2}, "he":{"pe":3,"g":"m"}, "she":{"pe":3,"g":"f"}, "it":{"pe":3,"g":"n"}, "we":{"pe":1,"n":"p"}, "they":{"pe":3,"n":"p"},
def wind(wInfo, period, lang): wind_terms = wInfo.get_wind(period) if wind_terms == None: return None lastSpeed = None lastDir = None jsrExprs = [] for wind_term in wind_terms: wSpeed = wind_term.infos[2] wDir = wind_term.infos[0] jsrExpr = S() # current expression if wSpeed >= 15 and wDir in jsrWindDirection: if lastSpeed != None and abs( wSpeed - lastSpeed) >= 20: # significant speed change lastSpeed = wSpeed if lang == "en": jsrExpr.add( VP(V("increase").t("pr"), PP(P("to"), NO(wSpeed)))) else: jsrExpr.add( VP(V("augmenter").t("pr"), PP(P("à"), NO(wSpeed)))) elif lastDir != None and dir_diff( wDir, lastDir): # significant direction change if lang == "en": jsrExpr.add( VP(V("become").t("pr"), jsrWindDirection[wDir][lang])) else: jsrExpr.add( VP( V("devenir").t("pr"), PP(P("de"), jsrWindDirection[wDir][lang]))) lastDir = wDir else: # realize wind and direction lastSpeed = wSpeed lastDir = wDir if lang == "en": jsrExpr.add( NP(N("wind"), jsrWindDirection[wDir][lang], NO(wSpeed), Q("km/h"))) else: jsrExpr.add( NP( N("vent").n("p"), PP(P("de"), jsrWindDirection[wDir][lang]), PP(P("de"), NO(wSpeed), Q("km/h")))) if len(wind_term.infos) > 3: # add gusting information gust = wind_term.infos[3] if gust.infos[0] == 'gust': if lang == "en": jsrExpr.add( VP( V("gust").t("pr"), PP(P("to"), NO(gust.infos[1])))) else: jsrExpr.add( PP( P("avec"), NP( N("rafale").n("p"), P("à"), NO(gust.infos[1])))) else: # add time information jsrExpr.add(jsrHour(wind_term.start, lang)) jsrExprs.append(jsrExpr) # add current expression to the list return " ".join(realize(jsrExpr, lang, False) for jsrExpr in jsrExprs)
## process args from dictInfo building the list of arguments or None argV = [env.get(arg) if arg in env else None for arg in self.args] syntR = self.lambda_(*argV) if len(env) > 0: ## add unprocessed args syntR.add(env.get(":start"), 0) syntR.add(env.get(".*")) return opts.apply(syntR) pp = lambda prep, arg: PP(P(prep), arg) if arg != None else None optD = lambda det: det if det != None else D("the") verbs['give-01'] = LexSem( "V", "give", [":ARG0", ":ARG1", ":ARG2"], lambda arg0, arg1, arg2: S(arg0, VP(V("give"), arg1, pp("to", arg2)))) nouns['envelope'] = LexSem("envelope", "N", [":D", ":A"], lambda d, a: NP(optD(d), a, N("envelope"))) nouns['boy'] = LexSem("boy", "N", [":D", ":A"], lambda d, a: NP(optD(d), a, N("boy"))) nouns['girl'] = LexSem("girl", "N", [":D", ":A"], lambda d, a: NP(optD(d), a, N("girl"))) adjectives["little"] = LexSem("little", "A", [], lambda: A("little")) adjectives["nice"] = LexSem("nice", "A", [], lambda: A("nice")) nounInfo = lambda lemma: LexSem(lemma, "N", [":D", ":A"], lambda d, a: NP( optD(d), a, N(lemma))) adjInfo = lambda lemma: LexSem(lemma, "A", [], lambda: A(lemma))
def pcpn(type,action,tense,moment,quantity=None,unit=None): return S(type, VP(V(action).t(tense), CP(PP(P("in"),NP(D("the"),N(moment))), None if quantity==None else NP(N("amount"),NP(NO(quantity),unit)))))