#!/usr/bin/env python3 """실습 2 (6-7): 자연어 → SPARQL 체인. 구조: ① 용어 연결(라벨·altLabel → IRI) ② 질문 유형 분류 → 질의 틀 선택 ③ 틀 채우기 ④ 실행. 분류기는 규칙 기반 축소 구현 — 실제 체인에서는 ②를 LLM이 맡는다(프롬프트는 6-7 본문). ①③④는 실전과 동일하다.""" import rdflib, re g = rdflib.Graph().parse("psymap.owl") PRE = """PREFIX : PREFIX rdfs: PREFIX owl: PREFIX skos: """ # ---------- ① 용어 연결: 라벨과 altLabel로 IRI 사전 구축 ---------- LEX = {} for p in ("prefLabel", "altLabel"): for c, l in g.query(PRE + f'SELECT ?c ?l WHERE {{ ?c skos:{p} ?l . FILTER(lang(?l)="ko") }}'): LEX[str(l).replace(" ", "")] = c def link(question): found = [(t, iri) for t, iri in LEX.items() if t in question.replace(" ", "")] return max(found, key=lambda x: len(x[0])) if found else (None, None) # ---------- ② 질문 유형 → ③ 질의 틀 ---------- TEMPLATES = { "측정과제": ("측정하는 과제", "SELECT ?x WHERE {{ ?x rdfs:subClassOf ?r . ?r owl:onProperty :measures ; owl:someValuesFrom <{iri}> . FILTER(isIRI(?x)) }}"), "구성요소": ("구성 요소", "SELECT ?x WHERE {{ ?x rdfs:subClassOf ?r . ?r owl:onProperty :component_of ; owl:someValuesFrom <{iri}> . FILTER(isIRI(?x)) }}"), "하위유형": ("하위 유형|종류", "SELECT ?x WHERE {{ ?x rdfs:subClassOf+ <{iri}> . FILTER(isIRI(?x)) }}"), "정의": ("정의|무엇인가|뭐야", "SELECT ?x WHERE {{ <{iri}> skos:definition ?x }}"), } def classify(question): for kind, (pat, tpl) in TEMPLATES.items(): if re.search(pat, question): return kind, tpl return None, None def label_of(iri): r = list(g.query(PRE + f'SELECT ?l WHERE {{ <{iri}> skos:prefLabel ?l . FILTER(lang(?l)="ko") }}')) return str(r[0][0]) if r else str(iri).split("/")[-1] # ---------- ④ 체인 실행 ---------- def answer(question): term, iri = link(question) if iri is None: return "거절: 질문의 용어가 온톨로지에 없다 — 답을 지어내지 않는다" kind, tpl = classify(question) if kind is None: return f"거절: '{term}'은 알지만 질문 유형이 질의 틀 밖이다" rows = list(g.query(PRE + tpl.format(iri=iri))) vals = sorted(label_of(r[0]) if isinstance(r[0], rdflib.URIRef) else str(r[0]) for r in rows) return f"[{kind}·{term}] {vals}" for q in ["작업기억을 측정하는 과제는?", "작동기억의 구성 요소를 알려줘", # altLabel 경유 "서술기억의 하위 유형은?", "응고화가 뭐야?", "작업기억 용량을 늘리는 훈련법은?"]: # 범위 밖 print(f"Q: {q}\nA: {answer(q)}\n")