Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions backend/langpro_annotator/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,5 @@

STATICFILES_DIRS = []
PROXY_FRONTEND = None

LANGPRO_URL = 'http://localhost:8080'
30 changes: 17 additions & 13 deletions backend/problem/views/parse.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import requests
from django.conf import settings
from dataclasses import dataclass, field, asdict

from django.http import JsonResponse
Expand Down Expand Up @@ -67,17 +69,19 @@ def send_to_parser(self, data: ParserInput) -> dict | None:

logger.info("Sending to LangPro service:", asdict(data))

# try:
# response = requests.post(
# url=f"{LANGPRO_URL}/parse",
# json=asdict(data),
# headers={"Content-Type": "application/json"},
# )
# response.raise_for_status()
# return response.json()
# except requests.RequestException as e:
# logger.exception(f"Error sending request to LangPro: {e}")
# return None
params = asdict(data)
# ask LangPro container to return results in a format suitable for
# this application
params['format'] = 'annotator'


return {"ok": "true"}
try:
response = requests.post(
url=f"{settings.LANGPRO_URL}/api/prove/",
json=params,
headers={"Content-Type": "application/json"},
)
response.raise_for_status()
return response.json()
except requests.RequestException as e:
logger.exception(f"Error sending request to LangPro: {e}")
raise
2 changes: 1 addition & 1 deletion frontend/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
],
"scripts": [],
"server": "src/main.server.ts",
"prerender": true,
"prerender": false,
"ssr": false,
"baseHref": "/"
},
Expand Down
3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"colors": "^1.4.0",
"express": "^4.18.2",
"rxjs": "~7.8.0",
"svg-pan-zoom": "bumbu/svg-pan-zoom",
"tslib": "^2.3.0",
"zone.js": "~0.15.1"
},
Expand All @@ -57,4 +58,4 @@
"ng-extract-i18n-merge": "^2.12.0",
"typescript": "~5.8.3"
}
}
}
3 changes: 2 additions & 1 deletion frontend/src/app/annotate/annotate.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<button
type="submit"
class="btn btn-success btn-lg d-flex align-items-center"
(click)="startParse()"
>
<fa-icon
[icon]="faTree"
Expand All @@ -21,4 +22,4 @@
</div>
<la-annotation-input class="col-8" />
</div>
<la-annotation-menu />
<la-annotation-menu [ccgTrees]="ccgTrees" />
43 changes: 40 additions & 3 deletions frontend/src/app/annotate/annotate.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { Component } from "@angular/core";
import { Component, DestroyRef, inject, OnInit } from "@angular/core";
import { AnnotationMenuComponent } from "./annotation-menu/annotation-menu.component";
import { NavigatorComponent } from "./navigator/navigator.component";
import { AnnotationInputComponent } from "./annotation-input/annotation-input.component";
import { AnnotationInputComponent, ParseInput } from "./annotation-input/annotation-input.component";
import { SearchComponent } from "./search/search.component";
import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
import { faTree } from "@fortawesome/free-solid-svg-icons";
import { ParseResponse, ParseService } from "@/services/parse.service";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { ProblemResponse } from "@/types";
import { ProblemService } from "@/services/problem.service";
import { Tree } from "@/tree";

@Component({
selector: "la-annotate",
Expand All @@ -19,6 +24,38 @@ import { faTree } from "@fortawesome/free-solid-svg-icons";
templateUrl: "./annotate.component.html",
styleUrl: "./annotate.component.scss",
})
export class AnnotateComponent {
export class AnnotateComponent implements OnInit {
public faTree = faTree;
private destroyRef = inject(DestroyRef);
private parseService = inject(ParseService);
private problemService = inject(ProblemService);

public ccgTrees: Tree<string>[] = [];

private problem: ProblemResponse | null = null;

ngOnInit() {
// TODO: This is wrong. It seems silly to keep a local copy of the problem,
// and it's also not connected to the form, so any edits will not affect
// the requests
this.problemService.problem$
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((problem) => {
this.problem = problem;
});
}

onParse(response: ParseResponse) {
console.log("Parse response:", response);
this.ccgTrees = response!.data.ccg_trees.map((tree: any) => new Tree(tree));
}

startParse() {
let input: ParseInput = {
premises: this.problem?.problem?.premises!,
hypothesis: this.problem?.problem?.hypothesis!,
kbItems: []
};
this.parseService.startParse(input, (r) => this.onParse(r));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { ProblemDetailsComponent } from "./problem-details/problem-details.compo
import { combineLatest, Subject } from "rxjs";
import { ActivatedRoute, Router } from "@angular/router";
import { ProblemService } from "@/services/problem.service";
import { ParseService } from "@/services/parse.service";
import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";

export type ParseInputForm = FormGroup<{
Expand Down Expand Up @@ -57,7 +56,6 @@ export class AnnotationInputComponent implements OnInit {
private router = inject(Router);
private destroyRef = inject(DestroyRef);
private problemService = inject(ProblemService);
private parseService = inject(ParseService);

public form: ParseInputForm | null = null;
public problem: ProblemResponse | null = null;
Expand All @@ -78,15 +76,6 @@ export class AnnotationInputComponent implements OnInit {
this.form = problem ? this.buildForm(problem) : null;
});

// Subscription needed to ensure a request is actually made.
// TODO: replace this with actual parse results.
this.parseService.parse$
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe((response) => {
console.log("Parse response:", response);
});

// Listen to route changes only after subscribing to ProblemService.problem$.
combineLatest([
this.route.paramMap,
this.route.queryParamMap])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
<span i18n>CCG / LLF</span>
</button>
<ng-template ngbNavContent>
<la-annotation-parse-results />
@for(tree of ccgTrees; track $index) {
<la-parse-svg [tree]="tree"></la-parse-svg>
}
</ng-template>
</li>
<li [ngbNavItem]="2">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { Component } from "@angular/core";
import { Component, Input } from "@angular/core";
import { FontAwesomeModule } from "@fortawesome/angular-fontawesome";
import { NgbNavModule } from "@ng-bootstrap/ng-bootstrap";
import {
faSquarePollHorizontal,
faTree,
faPenNib,
} from "@fortawesome/free-solid-svg-icons";
import { AnnotationParseResultsComponent } from "../annotation-parse-results/annotation-parse-results.component";
import { AnnotationTableauComponent } from "../annotation-tableau/annotation-tableau.component";
import { AnnotationCommentsComponent } from "../annotation-comments/annotation-comments.component";
import { ParseSVG } from "../parse-tree/parse-svg.component";

@Component({
selector: "la-annotation-menu",
standalone: true,
imports: [
NgbNavModule,
FontAwesomeModule,
AnnotationParseResultsComponent,
AnnotationTableauComponent,
AnnotationCommentsComponent,
ParseSVG
],
templateUrl: "./annotation-menu.component.html",
styleUrl: "./annotation-menu.component.scss",
Expand All @@ -29,4 +29,7 @@ export class AnnotationMenuComponent {
public faSquarePollHorizontal = faSquarePollHorizontal;
public faTree = faTree;
public faPenNib = faPenNib;

@Input()
public ccgTrees: any[] = [];
}
7 changes: 7 additions & 0 deletions frontend/src/app/annotate/parse-tree/parse-svg.component.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
39 changes: 39 additions & 0 deletions frontend/src/app/annotate/parse-tree/parse-svg.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Component, ChangeDetectorRef, ElementRef, Input, ViewChild, afterNextRender} from '@angular/core';
import { CommonModule } from "@angular/common";
import { Subject } from "rxjs";
import { CCGTerm, Dimensions } from '@/types';
import { ParseTree } from './parse-tree.component';
import { Tree } from "@/tree";
import svgPanZoom from 'svg-pan-zoom';

@Component({
selector: "la-parse-svg",
standalone: true,
imports: [CommonModule, ParseTree],
templateUrl: "./parse-svg.component.svg",
})
export class ParseSVG {
@ViewChild('svg')
svg?: ElementRef<SVGSVGElement>;

treeDimensions$ = new Subject<Dimensions>();
treeDimensions: Dimensions = {width:0, height: 0};

constructor(private cdref: ChangeDetectorRef) {
afterNextRender(() => {
svgPanZoom(this.svg!.nativeElement);
});
}

onTreeSize(size: Dimensions) {
this.treeDimensions = size;
}

ngAfterViewChecked() {
this.treeDimensions$.next(this.treeDimensions);
this.cdref.detectChanges();
}

@Input()
tree: Tree<CCGTerm> = Tree.empty();
}
26 changes: 26 additions & 0 deletions frontend/src/app/annotate/parse-tree/parse-term.component.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 67 additions & 0 deletions frontend/src/app/annotate/parse-tree/parse-term.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Component, ElementRef, Input, Output, ViewChild, EventEmitter } from '@angular/core';
import { CCGTerm, Dimensions } from '@/types';

@Component({
selector: "[parse-term]",
standalone: true,
imports: [],
templateUrl: "./parse-term.component.svg",
})
export class ParseTerm {
@Input()
public idx?: number;

@Input()
public label?: string;

/* background color, should probably be replaced by an enum type with the color lookup done elsewhere */
@Input()
public bg?: string;

@Input()
public term: CCGTerm = [];

@Input()
public end: boolean = false;

@Input()
public rule?: string;

@ViewChild('idxText')
idxText?: ElementRef<SVGTextElement>;

@ViewChild('termText')
termText?: ElementRef<SVGTextElement>;

@ViewChild('labelText')
labelText?: ElementRef<SVGTextElement>;

@Output()
public onSize = new EventEmitter<Dimensions>();

padding = 2;
height = 20;

idxW = 0;
termX = 0;
termW = 0;
labelX = 0;
labelW = 0;
totalW = 0;

calculateWidth() {
return this.termText!.nativeElement.getBBox().width;
}

ngAfterViewChecked() {
this.idxW = this.idxText ? this.idxText.nativeElement.getComputedTextLength() + this.padding : 0;
this.labelW = this.labelText ? this.labelText.nativeElement.getComputedTextLength() + this.padding : 0;
this.termX = this.idxW;
this.termW = this.termText ? this.calculateWidth() : 0;
this.labelX = this.termX + this.termW + this.padding;
this.totalW = this.termText ? this.labelW + this.idxW + this.calculateWidth() : 0;

this.onSize.emit({width: this.totalW, height: this.height});
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<svg
style="width: 100%; min-height: {{((treeDimensions$|async)?.height ?? 0) + 10}}px;"
>
<g tableau-tree [tree]="tree"
attr.transform="translate({{((treeDimensions$|async)?.width ?? 0)/2}}, 10)"
(onSize)="onTreeSize($event)"></g>
</svg>
Empty file.
23 changes: 23 additions & 0 deletions frontend/src/app/annotate/parse-tree/parse-tree.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ParseTree } from './parse-tree.component';

describe('ParseTree', () => {
let component: ParseTree;
let fixture: ComponentFixture<ParseTree>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ParseTree]
})
.compileComponents();

fixture = TestBed.createComponent(ParseTree);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Loading