├── .gitignore
├── LICENSE
├── client
├── index.html
└── js
│ ├── alignment.js
│ ├── translate.js
│ └── vcomponent.js
└── server.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Lua sources
2 | luac.out
3 |
4 | # luarocks build files
5 | *.src.rock
6 | *.zip
7 | *.tar.gz
8 |
9 | # Object files
10 | *.o
11 | *.os
12 | *.ko
13 | *.obj
14 | *.elf
15 |
16 | # Precompiled Headers
17 | *.gch
18 | *.pch
19 |
20 | # Libraries
21 | *.lib
22 | *.a
23 | *.la
24 | *.lo
25 | *.def
26 | *.exp
27 |
28 | # Shared objects (inc. Windows DLLs)
29 | *.dll
30 | *.so
31 | *.so.*
32 | *.dylib
33 |
34 | # Executables
35 | *.exe
36 | *.out
37 | *.app
38 | *.i*86
39 | *.x86_64
40 | *.hex
41 |
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 OpenNMT
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/client/js/alignment.js:
--------------------------------------------------------------------------------
1 | class AlignmentComponent extends VComponent {
2 |
3 | get events() {
4 | return {
5 | }
6 | }
7 |
8 | get defaultOptions() {
9 | return {
10 | }
11 | }
12 |
13 | // Data Style
14 | get _dataStyle() {
15 | return {
16 | }
17 | }
18 |
19 |
20 | // INIT METHODS
21 | _init() {
22 | this.base = this.parent.append("g")
23 | }
24 |
25 | _wrangle(data) {
26 | let attn = [];
27 | _.map(data.attn, (d, i) => _.map(d, (v, j) => attn.push({src: j, tgt: i, val: v})));
28 | data.attnGroup = attn;
29 | return data;
30 | }
31 |
32 |
33 | _render(renderData) {
34 | let xWord = d3.scaleLinear().domain([0,25]).range([0, 1500]);
35 | console.log(renderData.src);
36 | this.src = this.base.append("g");
37 |
38 |
39 | const src_words = this.src.selectAll("g")
40 | .data(renderData.src)
41 | .enter();
42 | src_words
43 | .append("g")
44 | .attr("transform", (d, i) => "translate(" + xWord(i) + ", 0)")
45 | .append("text")
46 | .text(d => d);
47 |
48 | this.tgt = this.base.append("g").attr("transform", "translate(0, 100)")
49 |
50 | const tgt_words = this.tgt.selectAll("g")
51 | .data(renderData.message)
52 | .enter();
53 | tgt_words
54 | .append("g")
55 | .attr("transform", (d, i) => "translate(" + xWord(i) + ", 0)")
56 | .append("text")
57 | .text(d => d);
58 |
59 | console.log(renderData.attnGroup);
60 | this.base.selectAll(".attn")
61 | .data(renderData.attnGroup)
62 | .enter()
63 | .append("line")
64 | .classed("attn", true)
65 | .attr("x1", d => xWord(d.src) + (xWord(0.5) -xWord(0)))
66 | .attr("x2", d => xWord(d.tgt) + (xWord(0.5) -xWord(0)))
67 | .attr("y1", 10)
68 | .attr("y2", 90)
69 | .style("stroke", "black")
70 | .style("opacity", d => d.val);
71 |
72 |
73 | }
74 | }
75 |
76 | AlignmentComponent;
77 |
--------------------------------------------------------------------------------
/client/js/translate.js:
--------------------------------------------------------------------------------
1 | class TranslateComponent extends VComponent {
2 |
3 | get events() {
4 | return {
5 | }
6 | }
7 |
8 | get defaultOptions() {
9 | return {
10 | }
11 | }
12 |
13 | // Data Style
14 | get _dataStyle() {
15 | return {
16 | }
17 | }
18 |
19 |
20 | // INIT METHODS
21 | _init() {
22 | let form = this.parent.append("form");
23 | this.input = form
24 | .append("input")
25 | .attr("type","input");
26 | this.buttom = form
27 | .append("input")
28 | .attr("value", "Translate")
29 | .attr("type", "button")
30 | .on("click",() => this.translate());
31 | this.output = form
32 | .append("input")
33 | .attr("type","input");
34 | this.svg = this.parent.append("svg").attr("width",2000).attr("height", 1000);
35 | let alignments = SVG.group(this.svg, "", {x: 0, y: 100});
36 | this.alignment = [new AlignmentComponent({parent: alignments})];
37 | }
38 |
39 | translate() {
40 | console.log(this.input.property("value"));
41 | $.ajax("/api/translate?src="+this.input.property("value"), {
42 | dataType : 'json',
43 | success: translation => {
44 | console.log(translation);
45 | // this.output.property("value", translation.message);
46 | this.alignment[0].update(translation[1]);
47 | }
48 | })
49 | }
50 |
51 | // RENDER/WRANGLE METHODS
52 | _wrangle(data) {
53 | }
54 |
55 | _render(renderData) {
56 |
57 | }
58 |
59 | // ACTION METHODS
60 | actionHoverCell(x, y, select) {
61 | const hovered = this.hm.selectAll(".x" + x + ".y" + y);
62 | hovered.classed('hovered', select);
63 | if (select) {
64 | const datum = hovered.datum();
65 | this.tooltip.attrs({
66 | opacity: 1,
67 | "transform": SVG.translate({
68 | x: this.scaleX(datum.col),
69 | y: this.scaleY(datum.row + 1) + 5
70 | })
71 | }).select('text').text(datum.label);
72 | } else {
73 | this.tooltip.attrs({opacity: 0});
74 | }
75 | }
76 |
77 | bindEvents(handler) {
78 | this.eventHandler = handler;
79 | handler.bind(this.events.cellHovered, (e, data) =>
80 | this.actionHoverCell(data.col, data.row, data.active));
81 |
82 | handler.bind(this.events.rectSelected, (e, hm_id) =>
83 | this.hm.selectAll('.mapping-rect-button').classed('selected', this.id == hm_id));
84 |
85 | handler.bind(this.events.circleSelected, (e, hm_id) =>
86 | this.hm.selectAll('.mapping-circle-button').classed('selected', this.id == hm_id));
87 | }
88 | }
89 |
90 | TranslateComponent;
91 |
--------------------------------------------------------------------------------
/client/js/vcomponent.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Hendrik Strobelt (hendrik.strobelt.com) on 12/3/16.
3 | */
4 |
5 | class VComponent {
6 |
7 | /**
8 | * The static property that contains all class related events.
9 | * Should be overwritten and event strings have to be unique!!
10 | * @returns {{}} an key-value object for object to string
11 | */
12 | static get events() {
13 | console.error('static get events() -- not implemented');
14 |
15 | return {noEvent: 'VComponent_noEvent'}
16 | }
17 |
18 | /**
19 | * Should be overwritten to define the set of ALL options and their defaults
20 | * @returns {{}} an key-value object for default options
21 | */
22 | static get defaultOptions() {
23 | console.error('static get defaultOptions() not implemented');
24 |
25 | return {};
26 | }
27 |
28 | /**
29 | * Inits the class and creates static DOM elements
30 | * @param {Element} parent SVG DOM Element
31 | * @param {Object} options initial options
32 | */
33 | constructor({parent, options}) {
34 | this.parent = parent;
35 |
36 | const defaults = this.defaultOptions;
37 | this.options = {};
38 | this.id = Util.simpleUId({});
39 | Object.keys(defaults).forEach(key => this.options[key] = options[key] || defaults[key]);
40 |
41 | this._init()
42 | }
43 |
44 | /**
45 | * Should be overwritten to create the static DOM elements
46 | * @private
47 | * @return {*} ---
48 | */
49 | _init() {
50 | console.error(this.constructor.name + '._init() not implemented')
51 | }
52 |
53 | /**
54 | * Every time data has changed, update is called and
55 | * triggers wrangling and re-rendering
56 | * @param {Object} data data object
57 | * @return {*} ---
58 | */
59 | update(data) {
60 | this.data = data;
61 | this.renderData = this._wrangle(data);
62 | this._render(this.renderData);
63 | }
64 |
65 |
66 | /**
67 | * Data wrangling method -- implement in subclass
68 | * @param {Object} data data
69 | * @returns {*} ---
70 | * @private
71 | */
72 | _wrangle(data) {
73 |
74 | return data;
75 | }
76 |
77 | /**
78 | * Is responsible for mapping data to DOM elements
79 | * @param {Object} renderData pre-processed (wrangled) data
80 | * @private
81 | * @returns {*} ---
82 | */
83 | _render(renderData) {
84 | console.error(this.constructor.name + '._render() not implemented', renderData)
85 | }
86 |
87 |
88 | /**
89 | * Updates instance options
90 | * @param {Object} options only the options that should be updated
91 | * @returns {*} ---
92 | */
93 | updateOptions({options}) {
94 | Object.keys(options).forEach(k => this.options[k] = options[k]);
95 | }
96 |
97 | }
98 |
99 | VComponent;
100 |
101 | /**
102 | * Created by Hendrik Strobelt (hendrik.strobelt.com) on 11/30/16.
103 | */
104 |
105 | class SVG {
106 | static translate({x, y}) {return "translate(" + x + "," + y + ")"}
107 |
108 | static group(parent, classes, pos) {
109 | return parent.append('g')
110 | .attr("class", classes)
111 | .attr("transform", SVG.translate(pos));
112 |
113 | }
114 |
115 | }
116 |
117 | let the_unique_id_counter = 0;
118 | class Util {
119 | static simpleUId({prefix = ''}) {
120 | the_unique_id_counter += 1;
121 |
122 | return prefix + the_unique_id_counter;
123 | }
124 | }
125 |
126 | SVG, Util;
127 |
--------------------------------------------------------------------------------
/server.py:
--------------------------------------------------------------------------------
1 | import zmq
2 | import argparse
3 | import json
4 |
5 | import os
6 |
7 | import numpy as np
8 | import yaml
9 | from flask import Flask, send_from_directory, jsonify, Response, redirect
10 | from flask import request
11 | from flask_cors import CORS
12 |
13 | app = Flask(__name__)
14 | CORS(app)
15 |
16 | data_handlers = {}
17 | index_map = {}
18 |
19 |
20 | @app.route('/api/translate/')
21 | def transate():
22 | options = request.args
23 | src = options.get('src')
24 | print("src", src)
25 | sock.send(json.dumps({"src" : src}))
26 | result = sock.recv()
27 | return result
28 |
29 | # send everything from client as static content
30 | @app.route('/client/')
31 | def send_static(path):
32 | """ serves all files from ./client/ to ``/client/``
33 |
34 | :param path: path from api call
35 | """
36 | return send_from_directory('client/', path)
37 |
38 |
39 |
40 | @app.route('/')
41 | def hello_world():
42 | """
43 | :return: "hello world"
44 | """
45 | return redirect('client/index.html')
46 |
47 | parser = argparse.ArgumentParser()
48 | parser.add_argument("--nodebug", default=False)
49 | parser.add_argument("--port", default="8888")
50 | parser.add_argument("--nocache", default=False)
51 | parser.add_argument("-dir", type=str, default=os.path.abspath('data'))
52 |
53 | if __name__ == '__main__':
54 | args = parser.parse_args()
55 | # create_data_handlers(args.dir)
56 |
57 | # print args
58 |
59 | # ZeroMQ Context
60 | context = zmq.Context()
61 |
62 | # Define the socket using the "Context"
63 | sock = context.socket(zmq.REQ)
64 | sock.connect("tcp://127.0.0.1:5556")
65 |
66 | app.run(port=int(args.port), debug=not args.nodebug, host="0.0.0.0")
67 |
--------------------------------------------------------------------------------