def jsrTemp(val, lang): if val == 0: return N("zero") if lang == "en" else N("zéro") if val < 0: return AdvP(A("minus") if lang == "en" else Adv("moins"), NO(abs(val))) if val <= 5: return AP(A("plus"), NO(val)) if lang == "en" else AdvP( Adv("plus"), NO(val)) return NO(val)
def havePolarity91(concept,roles,env,opts): if ":ARG2" in roles: pol=unquote(roles[":ARG2"].get_instance()) if pol=='-': env.push(AdvP(Adv("not"))) elif pol =='+': env.push(AdvP(Adv("yes"))) return addRoles(concept, roles, [":ARG2"], LexSem("polarity","SP",[],lambda:SP()), env, opts) return None
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 liRole(semR, env, opts): traceSyntR("liRole", semR) semR_i = unquote(semR.get_instance()) if semR_i == "-1": env.unshift(Adv("lastly")) elif semR_i == "1": env.unshift(Adv("first")) elif is_number(semR_i): env.unshift(Q("(" + str(semR_i) + ")")) elif semR_i[0] == '"': env.unshift(Q("(" + semR_i + ")"))
def polarityRole(semR, env, opts): traceSyntR("polarityRole", semR) if unquote(semR.get_instance()) == "-": parent_concept = semR.get_parent_concept() if isVerb(parent_concept): opts.add("typ", {"neg": True}) elif isNoun(parent_concept): env.put(":D", Adv("no")) else: env.unshift(Adv("not")) elif semR.get_concept() == "amr-unknown": opts.add("typ", {"int": "yon"})
def mannerRole(semR, env, opts): traceSyntR("mannerRole", semR) cManner = semR.get_concept() if cManner == "amr-unknown": opts.add("typ", {"int": "how"}) else: syntR = makeSyntR(semR) if isinstance(syntR, Q): env.push(syntR) elif isinstance(syntR, A): adv = Adv(adverbFromAdjective(syntR.lemma)) adv.props = syntR.props env.push(adv) elif isinstance(syntR, (S, V, VP)): env.push(PP(P("by"), syntR.typ({"prog": True}))) else: addPrep("with", semR, env)
def processTime(concept, syntR): if concept == "amr-unknown": opts.add("typ", {"int": "whn"}) env.push(syntR) elif syntR == A("former"): env.unshift(Adv("formerly")) elif syntR == Q("ex"): env.unshift(syntR) elif syntR == Q("about to"): env.push(Adv("about")) env.push(P("to")) elif isVerb(concept): env.push(SP(C("when"), syntR)) elif isinstance(syntR, A): env.push(Adv(adverbFromAdjective(syntR.lemma))) else: env.push(syntR)
def ensurePhrase(syntR): if isinstance(syntR, Phrase): return syntR if isinstance(syntR, Terminal): if isinstance(syntR, N): return NP(syntR) if isinstance(syntR, A): return AP(syntR) if isinstance(syntR, V): return VP(syntR) if isinstance(syntR, Adv): return Adv(syntR) return SP(syntR) print("ensurePhrase: type inattendu:%s" % type(syntR))
def makeAdv(lemma): adv=adverbs[lemma] if isinstance(adv,AdvP): return LexSem(lemma,"Adv",[":op1"],lambda op1:copy.deepcopy(adv).add(accPron(op1))) if isinstance(adv,Adv): return LexSem(lemma,"Adv",[":op1"],lambda op1:AdvP(copy.deepcopy(adv),accPron(op1))) if isinstance(adv,str): return LexSem(lemma,"Adv",[":op1"],lambda op1:Adv(adv) if op1==None else AdvP(Adv(adv),accPron(op1))) print("### strange adverb:"+str(adv)) return adverbs[lemma]
def frequencyRole(semR, env, opts): traceSyntR("frequencyRole", semR) concept = semR.get_concept() instance = semR.get_instance() if concept == None and is_number(instance): if instance == 1: env.push(Adv("once")) elif instance == 2: env.push(D("twice")) else: env.push(NP(NO(instance), N("time"))) else: env.push(makeSyntR(semR))
def pathRole(semR, env, opts): traceSyntR("pathRole", semR) concept = semR.get_concept() if concept == "past" and ":op1" in semR.roles: env.push(AdvP(Adv("past"), makeSyntR(semR.roles[":op1"]))) else: syntR = makeSyntR(semR) if isinstance(syntR, Pro): syntR.lemma = "me" else: if isinstance(syntR, (Adv, P, PP)): env.push(syntR) else: env.push(PP(P("via"), syntR))
def degreeRole(semR, env, opts): traceSyntR("degreeRole", semR) global comp comp = "" deg = semR.get_concept() if deg == "amr-unknown": opts.add("b", "how ") elif deg == "more": opts.add("f", "co") comp = "co" elif deg == "most": opts.add("f", "su") comp = "su" elif deg == "part": env.unshift(Adv("partially")) elif deg in ["too", "so", "very", "all", "quite"]: env.unshift(Adv(deg)) elif isAdverb(deg): env.push(Adv(deg)) elif isAdjective(deg): env.push(A(deg)) else: env.push(makeSyntR(semR))
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 simpleModNoun(concept, neg): ## check for "simple" cases if concept in [ "all", "many", "both", "no", "too", "any", "other", "some", "one", "kind-yy", "then", "such" ]: env.put(":D", Q("kind of" if concept == "kind-yy" else concept)) if neg: env.unshift(Q("not")) if concept in ["all", "many", "both"]: opts.add("n", "p") elif concept in determiners: env.put(":D", D(concept)) elif is_number(concept): env.push(NO(concept)) elif isNoun(concept): ## prefix the :mod for nouns newNoun = N(nouns[concept].lemma) # keep only noun from NP if ":A" in env: env.insertAfter(":A", ":A", newNoun) else: env.put(":A", newNoun) if neg: env.insertBefore(":A", ":A", Q("non")) elif isAdjective(concept): ## postfix the :mod for adjectives newAdj = A(adjectives[concept].lemma) if ":A" in env: env.insertAfter(":A", ":A", newAdj) else: env.put(":A", newAdj) if neg: env.insertBefore(":A", ":A", Q("non")) elif isAdverb(concept): env.put(":D", Adv(concept)) elif isVerb(concept): env.push(V(re.sub(r"-\d+$", '', concept)).t("pr")) elif semR.roles.areEmpty(): ## equivalent to processSimpleModOther env.push(Q(generateConceptWord(concept))) else: return False return True
from jsRealBclass import N,A,Adv,V,D,P,C,DT,NO,Q, NP,AP,AdvP,VP,S,PP,CP from Realization.common import realize, jsrDayPeriod sky_condition_terminology = { ## types of sky conditions "c1":{"en":(AP(A("sunny")),AP(A("clear"))), "fr":(AP(A("ensoleillé")),AP(A("dégagé")))}, "c2":{"en":(AP(Adv("mainly"),A("sunny")),NP(Q("a"),D("few"),N("cloud").n("p"))), "fr":(AP(Adv("généralement"),A("ensoleillé")),NP(D("quelque"),N("nuage").n("p")))}, "c3":{"en":(NP(D("a"),N("mix"),PP(P("of"),CP(C("and"),N("sun"),N("cloud").n("p")))), AP(Adv("partly"),A("cloudy"))), "fr":(NP(N("alternance"),CP(C("et"),PP(P("de"),N("soleil")),PP(P("de"),N("nuage").n("p")))), AP(Adv("partiellement"),A("couvert")))}, "c4":{"en":(AP(Adv("mainly"),A("cloudy")),), "fr":(AP(Adv("généralement"),A("nuageux")),)}, "c5":{"en":(AP(A("cloudy")),), "fr":(AP(A("nuageux")),)}, "c6":{"en":(AP(A("overcast")),), "fr":(AP(A("couvert")),)}, "c7":{"en":(NP(V("increase").t("pr"),N("cloudiness")),), "fr":(NP(N("ennuagement")),)}, "c8":{"en":(NP(N("clearing")),), "fr":(NP(N("dégagement")),)}, } def sky_condition(mc,period,lang): previous_conditions=[] jsrExprs=[] def addNoRepeat(c,dn,period=None): # avoid generating same sentence twice if c not in previous_conditions: if len(sky_condition_terminology[c][lang])==1:dn=0
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"))) },
def clearSavedJsrIO(): savedJsrIO=[] def getSavedJsrIO(): return savedJsrIO 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 dayPeriods=[(0,5,{"en":lambda:NP(N("night")),"fr":lambda:NP(N("nuit"))}), (5,9,{"en":lambda:NP(Adv("early"),N("morning")),"fr":lambda:NP(N("début"),PP(P("de"),N("matinée")))}), (9,12,{"en":lambda:NP(N("morning")),"fr":lambda:NP(N("matin"))}), (12,18,{"en":lambda:NP(N("afternoon")),"fr":lambda:NP(N("après-midi"))}), (18,24,{"en":lambda:NP(N("tonight")),"fr":lambda:NP(N("soir"))}), ] def jsrDayPeriod(hour,lang): isTomorrow=hour>23 hour=hour%24 for (s,e,jsrExp) in dayPeriods: if hour in range(s,e): exp=jsrExp[lang]() if isTomorrow: return exp.add(N("tomorrow" if lang=="en" else "demain"),0) elif s!=18: return exp.add(D("this" if lang=="en" else "ce"),0)
from jsRealBclass import jsRealB, N,A,Adv,V,D,P,C,DT,NO,Q, NP,AP,AdvP,VP,S,PP,CP from Realization.common import realize, jsrDayPeriod, jsrHour, get_max_term, get_min_term, get_term_at #### UV_index values: info taken from # https://www.canada.ca/en/environment-climate-change/services/weather-health/uv-index-sun-safety/about.html # Low (0-2), Moderate (3-5), High (6-7), Very High (8-10), and Extreme (11+) uv_ranges= [(2, {"en":A("low"), "fr":A("bas")}), (5, {"en":A("moderate"), "fr":A("modéré")}), (7, {"en":A("high"), "fr":A("élevé")}), (10, {"en":AP(Adv("very"), A("high")), "fr":AP(Adv("très"),A("élevé"))}), (1000,{"en":A("extreme"), "fr":A("extrême")})] def uv_index(wInfo,period,lang): if period in ["tonight","tomorrow_night"]: # no UV index during the night return None uvi_terms=wInfo.get_uv_index(period) if uvi_terms==None:return None uvVal=uvi_terms[0].infos[0] # consider only the first uvi_term if uvVal<1: return None # too low uvVal=round(uvVal) if uvVal==0:return None for high,expr in uv_ranges: if uvVal<=high: return realize(NP(Q("UV index" if lang=="en" else "indice UV"), NO(uvVal),C("or" if lang=="en" else "ou"),expr[lang]), lang) return None if __name__ == '__main__': def showEnFr(jsrExprEN,jsrExprFR):
conjunctions["sum-of"]=op16("and") conjunctions["ratio-of"]=op12("ratio-of",NP(N("ratio"),P("of")),"to") conjunctions["difference-of"]=op16("minus") conjunctions["quotient-of"]=op16("divided by") conjunctions["power-of"]=op16("to the power of") conjunctions["root-of"]= LexSem("root-of","P",[":op1",":op2"], lambda op1,op2:NP(NO(op2[0].lemma).dOpt({"ord":True}),N("root"),PP(P("of"),op1))) conjunctions["logarithm-of"]= LexSem("log-of","P",[":op1",":op2"], lambda op1,op2:NP(N("logarithm"),PP(P("of"),op1,N("base").a(":"),op2))) def isConjunction(lemma):return lemma in conjunctions def makeCP(lemma): return conjunctions[lemma] ### Adverbs adverbs["et-cetera"]=AdvP(Adv("etc")) adverbs["at-least"]=AdvP(P("at"),Adv("least")) adverbs["next-to"]=AdvP(Adv("next"),P("to")) adverbs["kind-of"]=AdvP(Q("kind of")) adverbs["away"]=AdvP(Adv("away"),P("from")) delCat(adverbs,"between") delCat(adverbs,"near") delCat(adverbs,"this") delCat(adverbs,"that") delCat(adverbs,"after") # keep only prep delCat(adverbs,"this") def isAdverb(lemma):return lemma in adverbs def makeAdv(lemma): adv=adverbs[lemma] if isinstance(adv,AdvP):
from jsRealBclass import jsRealB, N, A, Adv, V, D, P, C, DT, NO, Q, NP, AP, AdvP, VP, S, PP, CP from Realization.common import realize, jsrDayPeriod, jsrHour, get_max_term, get_min_term, get_term_at ### Pubpro sec 2.3.4 ## vents : start end direction modif? speed value exception? # e | nil | n | ne | nw | w | ely | nly | nely | nwly | wly | sly| sely | swly | sly | sely | sw | vrbl jsrWindDirection = { "e": { "en": Adv("east"), "fr": NP(D("le"), N("est")), "deg": 90 }, "n": { "en": Adv("north"), "fr": NP(D("le"), N("nord")), "deg": 0 }, "ne": { "en": Adv("northeast"), "fr": NP(D("le"), N("nord-est")), "deg": 45 }, "nw": { "en": Adv("northwest"), "fr": NP(D("le"), N("nord-ouest")), "deg": 315 }, "w": { "en": Adv("west"), "fr": NP(D("le"), N("ouest")), "deg": 290
def haveDegree91(concept,roles,env,opts): traceSyntR("haveDegree91",concept) subject=None attribute=None comp="" quant=None if ":ARG1" in roles: arg1=roles[":ARG1"] # print("haveDegree1:",arg1.instanceIsRef()) if not arg1.instanceIsRef(): # do not follow link for subject subject=makeSyntR(arg1) if ":ARG2" in roles: concept=roles[":ARG2"].concept attribute=makeSyntR(roles[":ARG2"]) # HACK: remove spurious pronouns created by starrole if isinstance(attribute, AP) and len(attribute.elements)>1 and isinstance(attribute.elements[1],Pro): del attribute.elements[1] if len(attribute.elements)==1: attribute=attribute.elements[0] else: errorSyntR("have-degree-91 without :ARG2:%s"%concept) return Q("degree-91") if ":mod" in roles: if isinstance(attribute,Terminal): attribute=AP(attribute) attribute.add(makeSyntR(roles[":mod"])) if ":ARG3" in roles: rolesARG3=roles[":ARG3"] deg=rolesARG3.get_concept() moreRoles=rolesARG3.get_roles() if moreRoles!=None and len(moreRoles)>0: if ":quant" in moreRoles: quant=makeSyntR(moreRoles[":quant"]) else: attribute.add(makeSyntR(moreRoles[0][1])) if deg=="more": attribute=attribute.f("co") if quant!=None: attribute=NP(quant,attribute) quant=None comp="co" elif deg=="most": if isinstance(attribute,A): attribute=AP(D("the"),attribute.f("su")) else: attribute=AP(attribute,D("the"),Adv("most")) comp="su" elif deg in ["too","so","less"]: attribute=AdvP(Adv(deg),attribute) if deg=="less": comp="co" elif quant!=None: attribute=AP(attribute,quant) quant=None elif deg=="equal": attribute=AdvP(Adv("as"),attribute,Adv("as")) elif deg=="times": if quant!=None: quant=NP(quant,N("time")) attribute=attribute.f("co") comp="co" else: attribute=AdvP(attribute,Adv(deg)) if ":ARG4" in roles: syntR4=makeSyntR(roles[":ARG4"]) if comp=="co": attribute=PP(attribute,P("than"),syntR4) if quant!=None: attribute.add(quant,0) elif comp=="su": attribute=AP(attribute,Adv("in"),syntR4) else: attribute.add(syntR4) if ":ARG5" in roles: attribute.add(makeSyntR(roles[":ARG5"])) if ":ARG6" in roles: attribute=NP(attribute,makeSyntR(roles[":ARG6"])) # print("have-degree-91:subject:",subject) while ":li" in roles: semR=roles[":li"] del roles[":li"] ## analogous to roleProcessing.lirole semR_i=unquote(semR.get_instance()) if semR_i=="-1": attribute.add(Adv("lastly"),0) elif semR_i=="1": attribute.add(Adv("first"),0) elif is_number(semR_i): attribute.add(Q("("+str(semR_i)+")"),0) elif semR_i[0]=='"': attribute.add(Q("("+semR_i+")"),0) restRoles=addRoles(concept, roles, [":ARG1",":ARG2",":ARG3",":ARG4",":ARG5",":ARG6",":li",":mod",":polarity"], LexSem("degree","SP",[],lambda:SP()),env, opts) if len(restRoles.elements)>0: attribute=ensurePhrase(attribute).add(restRoles) if subject!=None: attribute=predicate(subject,attribute) if hasNegPolarity(roles): return attribute.typ({"neg":True}) else: if hasNegPolarity(roles): return AdvP(Adv("not"),attribute) return attribute
def quantRole(semR, env, opts): def processSimpleQuant(concept): simpleQuants = { # concept: string to add to the start, boolean to indicate if plural "most": ["most of", True], "more": ["more", True], "numerous": ["numerous", True], "many": ["many", True], "multiple": ["multiple", True], "few": ["few", True], "some": ["some", False], "such": ["a sack of", False], "last": ["last", False], "one": ["one", False], "entire": ["entire", False], "lot": ["a lot", False], "sack": ["a sack of", False] } if concept in simpleQuants: if concept == "lot": env.push(Q(simpleQuants[concept][0])) else: env.unshift(Q(simpleQuants[concept][0])) if simpleQuants[concept][1]: opts.add("n", "p") return True return False # fuzzy operators from https://www.isi.edu/~ulf/amr/lib/popup/quantities.html#non-exact-quantities # role :op1 # about, above, almost, approximately, around, at-least, at-most, below, close-to, couple, few, less-than, # lot, many, more-than, multiple, nearly, no-more-than, over, roughly, several, some, under, up-to # number is dealt separately def fuzzyQuant1(concept): fuzzyQuants = [ 'about', 'above', 'almost', 'approximately', 'around', 'at-least', 'at-most', 'below', 'close-to', 'couple', 'few', 'less-than', 'lot', 'many', 'more-than', 'nearly', 'no-more-than', 'over', 'roughly', 'several', 'some', 'under', 'up-to' ] if concept == "multiple": env.unshift(Q("multiple")) env.push(Q("of")) if ":op1" in semR.roles: env.push(makeSyntR(semR.roles[":op1"])) return True if concept in fuzzyQuants and ":op1" in semR.roles: env.put( ":D", AP(Q(generateConceptWord(concept)), makeSyntR(semR.roles[":op1"]))) opts.add("n", "p") return True return False def fuzzyQuant2(concept): roles = semR.get_roles() if ":op1" in roles and ":op2" in roles: env.put( ":D", PP(P("between"), makeSyntR(roles[":op1"]), C("and"), makeSyntR(roles[":op2"]))) return True return False traceSyntR("quantRole", semR) concept = semR.get_concept() roles = semR.roles if len(roles) == 0 and processSimpleQuant(concept): return if fuzzyQuant1(concept): return if fuzzyQuant2(concept): return if isinstance(concept, str) and re.match(r'.+-quantity$', concept): env.unshift( PP(specialConcept.quantity(concept, roles, Env(), Options()), P("of"))) return if concept == "amr-unknown": env.unshift(AdvP(Adv("how"), Adv("much"))) opts.add("a", "?") else: syntR = makeSyntR(semR, False) if isinstance(syntR, NO): env.put(":D", syntR) else: env.unshift(PP(syntR, P("of")))