Dieses Repository erstellt einen dünnen Python-Wrapper um OpenCCG unter Verwendung der GUM-Space-Ontologie, der in einem Docker-Container ausgeführt werden kann. Eine Live-Version finden Sie unter litmus.informatik.uni-bremen.de/openccg.
Nach einem anfänglichen docker-compose up
kann der Dienst mit einer einfachen POST-Anfrage abgefragt werden, z. B. mit Curl:
$ curl --data "Take the cup." "localhost/openccg/parse?graphs"
{"version": "2.2.0", "application": "web-openccg", "uuid": "3bafdaf8-cc9c-4fdf-b455-c9687babba49", "sentence": "take the cup", "parses": ..., "http_status": 200, "json_parses": ..., "graphs": ...}
Das Feld „Graphs“ ist nur enthalten, wenn der URL-Parameter graphs
vorhanden ist.
Als Beispiel mit Python-Anfragen:
import requests
# Without graphs
print ( requests . post ( 'http://localhost/openccg/parse' , data = { 'sentence' : 'Take the cup.' }). json ())
# With graphs
print ( requests . post ( 'http://localhost/openccg/parse' ,
data = { 'sentence' : 'Take the cup.' },
params = { 'graphs' : True }). json ())
Aufgrund der Art und Weise, wie wir OpenCCG hinter Nginx bei Litmus hosten, haben die URLs für web-openccg alle das Präfix „openccg“. Für die beiden wichtigen Endpunkte ( /
für die GUI und /parse
für die API) sind jedoch Weiterleitungen vorhanden. Für Curl bedeutet das: curl -L --data "Take the cup." localhost/parse
funktioniert auch (beachten Sie das Argument -L
( --location
).
Beachten Sie, dass es noch nicht produktionsbereit ist, da es sehr langsam und nicht optimiert ist: Anstatt eine (oder mehrere) Instanzen von OpenCCG laufen zu lassen, um sie schneller abzufragen, erzeugt jede Anfrage eine einzelne OpenCCG-Instanz.
Um den Dienst visuell abzufragen, öffnen Sie einfach Ihren Browser unter http://localhost/openccg. Andernfalls verwenden Sie Curl-, Wget- oder z. B. Python-Anfragen, um web-openccg über die Befehlszeile oder Ihre Anwendung abzufragen.
Wenn Ihr Client es erlaubt, Ihren Anfragetext manuell zu erstellen, wie z. B. Curl, fügen Sie einfach den folgenden Satz ein:
curl --data "Take the cup." localhost/openccg/parse
Viele High-Level-Frameworks wie Python-Anfragen verwenden jedoch normalerweise einen Schlüsselwertmechanismus für Post-Daten. Verwenden Sie in diesem Fall den sentence
:
requests.post('http://localhost/openccg/parse', data={'sentence': 'Take the cup.'})
Ein Beispiel finden Sie unten.
Die Antwort ist ein JSON-Objekt und enthält immer diese Felder:
version
: Die JSON-Objektversion.application
: Immer „web-openccg“, dies ist nützlich, wenn Sie Parses von verschiedenen Diensten zusammenfassen.uuid
: Eine eindeutige ID für diese Antwort. Dies ist nur dann sinnvoll, wenn Sie vorhaben, das Tool irgendwie zu integrieren.http_status
: Der HTTP-Status der Anfrage.Wenn bei der Anfrage ein Satz angegeben wurde, sind diese Felder vorhanden:
sentence
: Der bereinigte Eingabesatz (alle Kleinbuchstaben, Satzzeichen entfernt, ...).Wenn mindestens eine erfolgreiche Analyse vorliegt, sind die folgenden Felder enthalten:
parses
: Ein Wörterbuch mit Parse-Identifikatoren (z. B. „np“) für tatsächliche Parses, während OpenCCG sie ausgibt.json_parses
: Eine Version von OpenCCG gibt in einem flachen JSON aus. Dies wird über eine benutzerdefinierte Grammatik für TatSu erstellt. Einzelheiten siehe unten. Jeder einzelne Wörterbuchwert ist eine Liste von Nominalen, Variablen und/oder Rollen.graphs
: Ein Wörterbuch von Parse-Identifikatoren für Punktzeichenfolgen. Sie können mit graphviz gerendert werden – die Online-GUI rendert sie automatisch. Hinweis: Die Schlüssel werden von parses
, json_parses
und graphs
gemeinsam genutzt, sodass Sie die Originalausgabe für eine JSON-Analyse problemlos nachschlagen können und umgekehrt.
Wenn ein Fehler auftritt, ist das Fehlerfeld vorhanden:
error
: Eine Fehlerbeschreibung.Aktuelle Version: 2.3.0
Das JSON-Format für die OpenCCG-Analysen kann anhand des obigen Beispiels oder durch sorgfältige Prüfung der vollständig typisierten OpenCCG.ebnf ermittelt werden.
Es gibt drei verschiedene Arten von Objekten: Nominal, Variable und Rolle. Die vollständige semantische Spezifikation (die JSON-Datei) kann entweder eine einzelne Entität eines der drei Typen oder eine Liste von Nominalen sein. Wenn wir Parses finden, die Listen von Variablen oder Rollen sind, wird die Grammatik erweitert. Bitte öffnen Sie ein Problem, wenn Sie Sätze finden, die nicht korrekt analysiert werden können.
Ein Nominal ist wie eine spezielle Variable, es beschreibt das „Hauptthema“ des Satzes. Da sie praktisch gleich sind (sie haben tatsächlich sehr ähnliche Parsing-Regeln), stellt das JSON-Format sie mit einer identischen Struktur dar:
{
"__class__" : " Variable " ,
"name" : " x1 " ,
"type" : " gum-OrientationChange " ,
"roles" : []
}
__class__
ist entweder Variable
oder Nominal
.name
ist die von OpenCCG verwendete Variable name, ein Buchstabe gefolgt von einer Zahl, zum Beispiel x1
oder w12
.type
ist ein GUM-Bezeichner, der den Typ der Variablen angibt. Es kann auch null
sein, wenn der Typ nicht angegeben ist.roles
ist eine Liste von Rollen, wie unten beschrieben. Eine Rolle definiert alle Eigenschaften, die eine Variable oder ein Nominalwert haben kann. Es folgt einer sehr ähnlichen Struktur:
{
"__class__" : " Role " ,
"type" : " quant " ,
"target" : ...
}
__class__
: Role
.type
: Der Rollentyp. Dadurch werden die target
bestimmt.target
: Der Wert der Rolle. Dies kann mehrere verschiedene Dinge sein, siehe unten. Wenn der Typ „ entity
ist, ist das Ziel eine Instanz wie „cup“ oder „slm-Taking“. Wenn der Typ ein Präfix gefolgt von einem Bindestrich hat, z. B. gs-hasSpatialModality
oder gs-direction
, dann ist das Ziel eine Variable
; In Owl wäre dies eine ObjectProperty. Wenn der Typ eine andere Zeichenfolge ist, ist das Ziel eine atomare Zeichenfolge, z. B. kann der Typ det
das Ziel the
haben, während der Typ quant
das Ziel singular
haben kann.
Die meisten Webdienste verwenden Port 80 als Standardport, ebenso wie web-openccg.
Um den Port zu ändern, passen Sie die Docker-Compose-Datei an und ändern Sie die Portzeile von "80:80"
auf Ihren Port auf der linken Seite (aber behalten Sie die 80 auf der rechten Seite), um beispielsweise den Dienst auf Port 9043 einzurichten , würden Sie es in "9043:80"
ändern.
Bevor Sie mit der Entwicklung beginnen, müssen Sie den Docker-Container erstellen mit:
make build
Dieser Schritt umfasst auch einige Dateien, die während des Erstellungsprozesses in Ihr lokales Verzeichnis ./webopenccg/static heruntergeladen wurden. Die Kopien werden erstellt, weil der Entwicklungsserver das Verzeichnis bereitstellt, wodurch die Dateien überschrieben werden, die nur im Container, aber nicht auf dem Hostsystem verfügbar sind.
Um den Entwicklungs-Docker-Container zu starten, verwenden Sie das Makefile:
make run
Der Entwicklungsserver bindet an Port 5000 und verwendet die Flask-Debug-Umgebung. Darüber hinaus bindet der mit make run
gestartete Docker-Container das App-Verzeichnis, sodass das Neuladen von Flask ordnungsgemäß funktioniert.
Führen Sie Folgendes aus, um die OpenCCG.ebnf-Grammatik zu kompilieren:
make
Eine Beispielantwort für den Satz „Nimm den Becher.“ Ist:
{
"version" : " 2.2.0 " ,
"application" : " web-openccg " ,
"uuid" : " ecae8222-af9b-4185-a508-efa8be33c7e6 " ,
"sentence" : " take the cup " ,
"parses" : {
"smain" : " @x1:gum-OrientationChange( <mood>imp ^ <gs-direction>(x2:gs-GeneralizedLocation ^ <gs-hasSpatialModality>(w2:slm-Cup ^ cup ^ <det>the ^ <ident>specific ^ <quant>singular)) ^ <gum-processInConfiguration>(w0:slm-Moving ^ slm-Taking)) " ,
"smain/0" : " @x1:gum-OrientationChange( <mood>imp ^ <gs-direction>(x2:gs-GeneralizedLocation ^ <gs-hasSpatialModality>(w2:slm-Cup ^ cup ^ <det>the ^ <ident>specific ^ <quant>singular)) ^ <gum-processInConfiguration>(w0:slm-Taking ^ slm-Taking)) " ,
"smain/.r" : " @x1:gs-AffectingDirectedMotion( <mood>imperative ^ <gs-route>x2 ^ <gum-actee>(w2:slm-Cup ^ cup ^ <det>the ^ <ident>specific ^ <quant>singular) ^ <gum-processInConfiguration>(w0:slm-Moving ^ slm-Taking)) " ,
"smain/.r/0" : " @x1:gs-AffectingDirectedMotion( <mood>imperative ^ <gs-route>x2 ^ <gum-actee>(w2:slm-Cup ^ cup ^ <det>the ^ <ident>specific ^ <quant>singular) ^ <gum-processInConfiguration>(w0:slm-Taking ^ slm-Taking)) "
},
"http_status" : 200 ,
"json_parses" : {
"smain" : {
"__class__" : " Nominal " ,
"type" : " gum-OrientationChange " ,
"name" : " x1 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " mood " ,
"target" : " imp "
},
{
"__class__" : " Role " ,
"type" : " gs-direction " ,
"target" : {
"__class__" : " Variable " ,
"type" : " gs-GeneralizedLocation " ,
"name" : " x2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " gs-hasSpatialModality " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Cup " ,
"name" : " w2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " cup "
},
{
"__class__" : " Role " ,
"type" : " det " ,
"target" : " the "
},
{
"__class__" : " Role " ,
"type" : " ident " ,
"target" : " specific "
},
{
"__class__" : " Role " ,
"type" : " quant " ,
"target" : " singular "
}
]
}
}
]
}
},
{
"__class__" : " Role " ,
"type" : " gum-processInConfiguration " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Moving " ,
"name" : " w0 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " slm-Taking "
}
]
}
}
]
},
"smain/0" : {
"__class__" : " Nominal " ,
"type" : " gum-OrientationChange " ,
"name" : " x1 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " mood " ,
"target" : " imp "
},
{
"__class__" : " Role " ,
"type" : " gs-direction " ,
"target" : {
"__class__" : " Variable " ,
"type" : " gs-GeneralizedLocation " ,
"name" : " x2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " gs-hasSpatialModality " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Cup " ,
"name" : " w2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " cup "
},
{
"__class__" : " Role " ,
"type" : " det " ,
"target" : " the "
},
{
"__class__" : " Role " ,
"type" : " ident " ,
"target" : " specific "
},
{
"__class__" : " Role " ,
"type" : " quant " ,
"target" : " singular "
}
]
}
}
]
}
},
{
"__class__" : " Role " ,
"type" : " gum-processInConfiguration " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Taking " ,
"name" : " w0 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " slm-Taking "
}
]
}
}
]
},
"smain/.r" : {
"__class__" : " Nominal " ,
"type" : " gs-AffectingDirectedMotion " ,
"name" : " x1 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " mood " ,
"target" : " imperative "
},
{
"__class__" : " Role " ,
"type" : " gs-route " ,
"target" : {
"__class__" : " Variable " ,
"type" : null ,
"name" : " x2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " gum-actee " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Cup " ,
"name" : " w2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " cup "
},
{
"__class__" : " Role " ,
"type" : " det " ,
"target" : " the "
},
{
"__class__" : " Role " ,
"type" : " ident " ,
"target" : " specific "
},
{
"__class__" : " Role " ,
"type" : " quant " ,
"target" : " singular "
}
]
}
},
{
"__class__" : " Role " ,
"type" : " gum-processInConfiguration " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Moving " ,
"name" : " w0 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " slm-Taking "
}
]
}
}
]
}
}
]
},
"smain/.r/0" : {
"__class__" : " Nominal " ,
"type" : " gs-AffectingDirectedMotion " ,
"name" : " x1 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " mood " ,
"target" : " imperative "
},
{
"__class__" : " Role " ,
"type" : " gs-route " ,
"target" : {
"__class__" : " Variable " ,
"type" : null ,
"name" : " x2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " gum-actee " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Cup " ,
"name" : " w2 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " cup "
},
{
"__class__" : " Role " ,
"type" : " det " ,
"target" : " the "
},
{
"__class__" : " Role " ,
"type" : " ident " ,
"target" : " specific "
},
{
"__class__" : " Role " ,
"type" : " quant " ,
"target" : " singular "
}
]
}
},
{
"__class__" : " Role " ,
"type" : " gum-processInConfiguration " ,
"target" : {
"__class__" : " Variable " ,
"type" : " slm-Taking " ,
"name" : " w0 " ,
"roles" : [
{
"__class__" : " Role " ,
"type" : " entity " ,
"target" : " slm-Taking "
}
]
}
}
]
}
}
]
}
},
"graphs" : {
"smain": "strict graph "" {ntnode [label="\N"];ntsubgraph cluster_x1 {nttgraph [fillcolor=lightskyblue,ntttlabel="x1: gum-OrientationChange",ntttstyle=filledntt];nttsubgraph "cluster_gs-direction" {ntttgraph [fillcolor=honeydew,nttttlabel="gs-direction",nttttstyle=fillednttt];ntttsubgraph cluster_x2 {nttttgraph [fillcolor=lightblue,ntttttlabel="x2: gs-GeneralizedLocation",ntttttstyle=filledntttt];nttttsubgraph "cluster_gs-hasSpatialModality" {ntttttgraph [fillcolor=honeydew,nttttttlabel="gs-hasSpatialModality",nttttttstyle=fillednttttt];ntttttsubgraph cluster_w2 {nttttttgraph [fillcolor=lightblue,ntttttttlabel="w2: slm-Cup",ntttttttstyle=filledntttttt];nttttttw2tttttt [fillcolor=aliceblue,ntttttttlabel="{<entity> cup|<det> the|<ident> specific|<quant> singular}",ntttttttshape=Mrecord,ntttttttstyle=filled];nttttt}ntttt}nttt}ntt}nttsubgraph "cluster_gum-processInConfiguration" {ntttgraph [fillcolor=honeydew,nttttlabel="gum-processInConfiguration",nttttstyle=fillednttt];ntttsubgraph cluster_w0 {nttttgraph [fillcolor=lightblue,ntttttlabel="w0: slm-Moving",ntttttstyle=filledntttt];nttttw0tttt [fillcolor=aliceblue,ntttttlabel="{<entity> slm-Taking}",ntttttshape=Mrecord,ntttttstyle=filled];nttt}ntt}nttx1tt [fillcolor=aliceblue,ntttlabel="{<mood> imp}",ntttshape=Mrecord,ntttstyle=filled];nt}n}n",
"smain/0": "strict graph "" {ntnode [label="\N"];ntsubgraph cluster_x1 {nttgraph [fillcolor=lightskyblue,ntttlabel="x1: gum-OrientationChange",ntttstyle=filledntt];nttsubgraph "cluster_gs-direction" {ntttgraph [fillcolor=honeydew,nttttlabel="gs-direction",nttttstyle=fillednttt];ntttsubgraph cluster_x2 {nttttgraph [fillcolor=lightblue,ntttttlabel="x2: gs-GeneralizedLocation",ntttttstyle=filledntttt];nttttsubgraph "cluster_gs-hasSpatialModality" {ntttttgraph [fillcolor=honeydew,nttttttlabel="gs-hasSpatialModality",nttttttstyle=fillednttttt];ntttttsubgraph cluster_w2 {nttttttgraph [fillcolor=lightblue,ntttttttlabel="w2: slm-Cup",ntttttttstyle=filledntttttt];nttttttw2tttttt [fillcolor=aliceblue,ntttttttlabel="{<entity> cup|<det> the|<ident> specific|<quant> singular}",ntttttttshape=Mrecord,ntttttttstyle=filled];nttttt}ntttt}nttt}ntt}nttsubgraph "cluster_gum-processInConfiguration" {ntttgraph [fillcolor=honeydew,nttttlabel="gum-processInConfiguration",nttttstyle=fillednttt];ntttsubgraph cluster_w0 {nttttgraph [fillcolor=lightblue,ntttttlabel="w0: slm-Taking",ntttttstyle=filledntttt];nttttw0tttt [fillcolor=aliceblue,ntttttlabel="{<entity> slm-Taking}",ntttttshape=Mrecord,ntttttstyle=filled];nttt}ntt}nttx1tt [fillcolor=aliceblue,ntttlabel="{<mood> imp}",ntttshape=Mrecord,ntttstyle=filled];nt}n}n",
"smain/.r": "strict graph "" {ntnode [label="\N"];ntsubgraph cluster_x1 {nttgraph [fillcolor=lightskyblue,ntttlabel="x1: gs-AffectingDirectedMotion",ntttstyle=filledntt];nttsubgraph "cluster_gs-route" {ntttgraph [fillcolor=honeydew,nttttlabel="gs-route",nttttstyle=fillednttt];ntttsubgraph cluster_x2 {nttttgraph [fillcolor=lightblue,ntttttlabel=None,ntttttstyle=filledntttt];nttttsubgraph "cluster_gum-actee" {ntttttgraph [fillcolor=honeydew,nttttttlabel="gum-actee",nttttttstyle=fillednttttt];ntttttsubgraph cluster_w2 {nttttttgraph [fillcolor=lightblue,ntttttttlabel="w2: slm-Cup",ntttttttstyle=filledntttttt];nttttttw2tttttt [fillcolor=aliceblue,ntttttttlabel="{<entity> cup|<det> the|<ident> specific|<quant> singular}",ntttttttshape=Mrecord,ntttttttstyle=filled];nttttt}ntttt}nttttsubgraph "cluster_gum-processInConfiguration" {ntttttgraph [fillcolor=honeydew,nttttttlabel="gum-processInConfiguration",nttttttstyle=fillednttttt];ntttttsubgraph cluster_w0 {nttttttgraph [fillcolor=lightblue,ntttttttlabel="w0: slm-Moving",ntttttttstyle=filledntttttt];nttttttw0tttttt [fillcolor=aliceblue,ntttttttlabel="{<entity> slm-Taking}",ntttttttshape=Mrecord,ntttttttstyle=filled];nttttt}ntttt}nttt}ntt}nttx1tt [fillcolor=aliceblue,ntttlabel="{<mood> imperative}",ntttshape=Mrecord,ntttstyle=filled];nt}n}n",
"smain/.r/0": "strict graph "" {ntnode [label="\N"];ntsubgraph cluster_x1 {nttgraph [fillcolor=lightskyblue,ntttlabel="x1: gs-AffectingDirectedMotion",ntttstyle=filledntt];nttsubgraph "cluster_gs-route" {ntttgraph [fillcolor=honeydew,nttttlabel="gs-route",nttttstyle=fillednttt];ntttsubgraph cluster_x2 {nttttgraph [fillcolor=lightblue,ntttttlabel=None,ntttttstyle=filledntttt];nttttsubgraph "cluster_gum-actee" {ntttttgraph [fillcolor=honeydew,nttttttlabel="gum-actee",nttttttstyle=fillednttttt];ntttttsubgraph cluster_w2 {nttttttgraph [fillcolor=lightblue,ntttttttlabel="w2: slm-Cup",ntttttttstyle=filledntttttt];nttttttw2tttttt [fillcolor=aliceblue,ntttttttlabel="{<entity> cup|<det> the|<ident> specific|<quant> singular}",ntttttttshape=Mrecord,ntttttttstyle=filled];nttttt}ntttt}nttttsubgraph "cluster_gum-processInConfiguration" {ntttttgraph [fillcolor=honeydew,nttttttlabel="gum-processInConfiguration",nttttttstyle=fillednttttt];ntttttsubgraph cluster_w0 {nttttttgraph [fillcolor=lightblue,ntttttttlabel="w0: slm-Taking",ntttttttstyle=filledntttttt];nttttttw0tttttt [fillcolor=aliceblue,ntttttttlabel="{<entity> slm-Taking}",ntttttttshape=Mrecord,ntttttttstyle=filled];nttttt}ntttt}nttt}ntt}nttx1tt [fillcolor=aliceblue,ntttlabel="{<mood> imperative}",ntttshape=Mrecord,ntttstyle=filled];nt}n}n"
}
}
Beispielvisualisierung (nur Ausschnitte dargestellt):