├── src
├── assets
│ └── logo.png
├── main.js
├── components
│ ├── Result.vue
│ ├── Sidebar.vue
│ ├── Entry.vue
│ ├── SentencePart.vue
│ └── Annotator.vue
├── store
│ ├── tags.js
│ └── basic.js
└── App.vue
├── .babelrc
├── .gitignore
├── .editorconfig
├── .travis.yml
├── README.md
├── index.html
├── package.json
├── LICENSE.md
└── webpack.config.js
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aniruddha-adhikary/anitator/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", { "modules": false }],
4 | "stage-3"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 |
4 | new Vue({
5 | el: '#app',
6 | render: h => h(App)
7 | })
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 | npm-debug.log
5 | yarn-error.log
6 |
7 | # Editor directories and files
8 | .idea
9 | *.suo
10 | *.ntvs*
11 | *.njsproj
12 | *.sln
13 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "8"
4 |
5 | script:
6 | npm build
7 |
8 | cache:
9 | directories:
10 | - "node_modules"
11 |
12 | deploy:
13 | provider: pages
14 | skip-cleanup: true
15 | github-token: $GITHUB_TOKEN # Set in travis-ci.org dashboard, marked secure
16 | keep-history: true
17 | on:
18 | branch: gh-pages
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Anitator 
2 |
3 | A free tool for annotating text.
4 |
5 | As of now it can only generate training data for tagging spaCy POS Tagger. You can extend it.
6 |
7 |
8 | 
9 | 
10 |
11 |
12 | ### Running
13 |
14 | ```
15 | $ npm install dev
16 | $ npm run dev
17 | ```
18 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 |
10 | POS Tagger
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/components/Result.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
27 |
28 |
37 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pos_tag",
3 | "description": "A Vue.js project",
4 | "version": "1.0.0",
5 | "author": "Aniruddha Adhikary ",
6 | "license": "MIT",
7 | "private": true,
8 | "scripts": {
9 | "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
10 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
11 | },
12 | "dependencies": {
13 | "hoek": "^5.0.3",
14 | "vue": "^2.5.11"
15 | },
16 | "browserslist": [
17 | "> 1%",
18 | "last 2 versions",
19 | "not ie <= 8"
20 | ],
21 | "devDependencies": {
22 | "babel-core": "^6.26.0",
23 | "babel-loader": "^7.1.2",
24 | "babel-preset-env": "^1.6.0",
25 | "babel-preset-stage-3": "^6.24.1",
26 | "cross-env": "^5.0.5",
27 | "css-loader": "^0.28.7",
28 | "file-loader": "^1.1.4",
29 | "node-sass": "^4.5.3",
30 | "sass-loader": "^6.0.6",
31 | "vue-loader": "^13.0.5",
32 | "vue-template-compiler": "^2.4.4",
33 | "webpack": "^3.6.0",
34 | "webpack-dev-server": "^2.9.1"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | Copyright (c) Aniruddha Adhikary 2018
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 |
--------------------------------------------------------------------------------
/src/store/tags.js:
--------------------------------------------------------------------------------
1 | export const tagSet = [
2 | {
3 | 'ud': 'NOUN',
4 | 'tag': 'N',
5 | 'shortKey': 'n',
6 | 'display': 'Noun',
7 | 'class': 'noun'
8 | },
9 | {
10 | 'ud': 'PROPN',
11 | 'tag': 'Q',
12 | 'shortKey': 'q',
13 | 'display': 'Proper Noun',
14 | 'class': 'propn'
15 | },
16 | {
17 | 'ud': 'PRON',
18 | 'tag': 'P',
19 | 'shortKey': 'p',
20 | 'display': 'Pronoun',
21 | 'class': 'pron'
22 | },
23 | {
24 | 'ud': 'ADJ',
25 | 'tag': 'J',
26 | 'shortKey': 'j',
27 | 'display': 'Adjective',
28 | 'class': 'jj'
29 | },
30 | {
31 | 'ud': 'VERB',
32 | 'tag': 'V',
33 | 'shortKey': 'v',
34 | 'display': 'Verb',
35 | 'class': 'verb'
36 | },
37 | {
38 | 'ud': 'ADP',
39 | 'tag': 'E',
40 | 'shortKey': 'e',
41 | 'display': 'Adposition',
42 | 'class': 'adp'
43 | },
44 | {
45 | 'ud': 'CONJ',
46 | 'tag': 'C',
47 | 'shortKey': 'c',
48 | 'display': 'Conjunction',
49 | 'class': 'conj'
50 | },
51 | {
52 | 'ud': 'NUM',
53 | 'tag': '0',
54 | 'shortKey': '0',
55 | 'display': 'Numeral',
56 | 'class': 'num'
57 | },
58 | ];
59 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
31 |
32 |
47 |
--------------------------------------------------------------------------------
/src/components/Sidebar.vue:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 |
18 |
30 |
31 |
58 |
--------------------------------------------------------------------------------
/src/components/Entry.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
12 |
13 |
14 |
17 |
19 |
20 |
21 |
22 |
23 |
36 |
37 |
60 |
--------------------------------------------------------------------------------
/src/components/SentencePart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | {{content}}{{store.state.currentSentence[index].tag.display}}
8 |
9 |
10 |
11 |
12 |
33 |
34 |
64 |
--------------------------------------------------------------------------------
/src/components/Annotator.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
11 |
15 |
16 |
17 |
18 |
23 |
28 |
29 |
30 |
31 |
32 |
33 |
50 |
51 |
72 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 | var webpack = require('webpack')
3 |
4 | module.exports = {
5 | entry: './src/main.js',
6 | output: {
7 | path: path.resolve(__dirname, './dist'),
8 | publicPath: '/dist/',
9 | filename: 'build.js'
10 | },
11 | module: {
12 | rules: [
13 | {
14 | test: /\.css$/,
15 | use: [
16 | 'vue-style-loader',
17 | 'css-loader'
18 | ],
19 | },
20 | {
21 | test: /\.scss$/,
22 | use: [
23 | 'vue-style-loader',
24 | 'css-loader',
25 | 'sass-loader'
26 | ],
27 | },
28 | {
29 | test: /\.sass$/,
30 | use: [
31 | 'vue-style-loader',
32 | 'css-loader',
33 | 'sass-loader?indentedSyntax'
34 | ],
35 | },
36 | {
37 | test: /\.vue$/,
38 | loader: 'vue-loader',
39 | options: {
40 | loaders: {
41 | // Since sass-loader (weirdly) has SCSS as its default parse mode, we map
42 | // the "scss" and "sass" values for the lang attribute to the right configs here.
43 | // other preprocessors should work out of the box, no loader config like this necessary.
44 | 'scss': [
45 | 'vue-style-loader',
46 | 'css-loader',
47 | 'sass-loader'
48 | ],
49 | 'sass': [
50 | 'vue-style-loader',
51 | 'css-loader',
52 | 'sass-loader?indentedSyntax'
53 | ]
54 | }
55 | // other vue-loader options go here
56 | }
57 | },
58 | {
59 | test: /\.js$/,
60 | loader: 'babel-loader',
61 | exclude: /node_modules/
62 | },
63 | {
64 | test: /\.(png|jpg|gif|svg)$/,
65 | loader: 'file-loader',
66 | options: {
67 | name: '[name].[ext]?[hash]'
68 | }
69 | }
70 | ]
71 | },
72 | resolve: {
73 | alias: {
74 | 'vue$': 'vue/dist/vue.esm.js'
75 | },
76 | extensions: ['*', '.js', '.vue', '.json']
77 | },
78 | devServer: {
79 | historyApiFallback: true,
80 | noInfo: true,
81 | overlay: true
82 | },
83 | performance: {
84 | hints: false
85 | },
86 | devtool: '#eval-source-map'
87 | }
88 |
89 | if (process.env.NODE_ENV === 'production') {
90 | module.exports.devtool = '#source-map'
91 | // http://vue-loader.vuejs.org/en/workflow/production.html
92 | module.exports.plugins = (module.exports.plugins || []).concat([
93 | new webpack.DefinePlugin({
94 | 'process.env': {
95 | NODE_ENV: '"production"'
96 | }
97 | }),
98 | new webpack.optimize.UglifyJsPlugin({
99 | sourceMap: true,
100 | compress: {
101 | warnings: false
102 | }
103 | }),
104 | new webpack.LoaderOptionsPlugin({
105 | minimize: true
106 | })
107 | ])
108 | }
109 |
--------------------------------------------------------------------------------
/src/store/basic.js:
--------------------------------------------------------------------------------
1 | import {tagSet} from "./tags";
2 |
3 | function toObject(sentence) {
4 | const parts = sentence.replace(/[\.\,\?।\'\"\(\)\@\$৳\&\+]+/g, '').match(/\S+/g) || [];
5 |
6 | return parts.map(function (p) {
7 | return {
8 | text: p,
9 | tag: null
10 | }
11 | });
12 | }
13 |
14 | function makeTag(part) {
15 | if (part.tag !== null) {
16 | return part.tag.tag;
17 | } else {
18 | return '';
19 | }
20 | }
21 |
22 | export const store = {
23 | state: {
24 | selectedIndex: 0,
25 | currentSentence: [],
26 | sentences: [],
27 | sentenceIndex: 0,
28 | finished: false
29 | },
30 | reset: function() {
31 | this.state.sentenceIndex = 0;
32 | this.state.selectedIndex = 0;
33 | this.state.currentSentence = [];
34 | this.state.setSentences = [];
35 | this.state.finished = false;
36 | },
37 | setSentence: function (sentence) {
38 | this.state.currentSentence = sentence;
39 | this.state.selectedIndex = 0;
40 | },
41 | setSentences: function (sentences) {
42 | this.state.sentences = sentences.map(toObject);
43 | this.state.sentenceIndex = 0;
44 | this.setSentence(this.state.sentences[0]);
45 | },
46 | changeSentence(i) {
47 | this.state.sentenceIndex = i;
48 | this.setSentence(this.state.sentences[i])
49 | return this.state.currentSentence;
50 | },
51 | nextSentence() {
52 | return this.changeSentence(this.state.sentenceIndex + 1);
53 | },
54 | previousSentence() {
55 | return this.changeSentence(this.state.sentenceIndex - 1);
56 | },
57 | hasNextSentence() {
58 | return this.state.sentenceIndex + 1 < this.state.sentences.length;
59 | },
60 | hasPreviousSentence() {
61 | return this.state.sentenceIndex > 0;
62 | },
63 | setText: function (text) {
64 | const sentences = text
65 | .split(/(\.|।)/g)
66 | .map((v) => v.trim())
67 | .filter((v) => v !== "." && v !== "।" && v !== "");
68 | console.log(sentences);
69 | this.setSentences(sentences);
70 | },
71 | setSelectedIndex: function (index) {
72 | this.state.selectedIndex = index;
73 | },
74 | resetSelectedIndex: function (index) {
75 | this.state.selectedIndex = 0;
76 | },
77 | getMaxIndex: function () {
78 | return this.state.currentSentence.length - 1;
79 | },
80 | assignTag: function (tag) {
81 | if (!this.state.currentSentence.length) return;
82 | this.state.currentSentence[this.state.selectedIndex].tag = tag;
83 | this.nextSelection();
84 | },
85 | nextSelection: function () {
86 | if (this.state.selectedIndex < store.getMaxIndex())
87 | this.state.selectedIndex++;
88 | else
89 | this.state.selectedIndex = 0;
90 | },
91 | previousSelection: function () {
92 | if (store.state.selectedIndex > 0)
93 | store.state.selectedIndex--;
94 | else
95 | store.state.selectedIndex = store.getMaxIndex();
96 | },
97 | getCode() {
98 | return this.state.sentences
99 | .map((s) => [s.map((p) => p.text).join(" "),
100 | {tags: s.map(makeTag)}]);
101 | }
102 | };
103 |
104 | const KEYS = tagSet.map(function (tag) {
105 | return tag.shortKey;
106 | });
107 |
108 | document.addEventListener('keyup', function (e) {
109 | if ((e.code) === 'ArrowRight') {
110 | store.nextSelection();
111 | }
112 | else if ((e.code) === 'ArrowLeft') {
113 | store.previousSelection();
114 | }
115 | else {
116 | const index = KEYS.indexOf(e.key.toLowerCase());
117 | if (index > -1) {
118 | store.assignTag(tagSet[index]);
119 | }
120 | }
121 | });
122 |
123 | // store.setSentence('কলিমদ্দি ছেলেটার সাথেই আলাপ জমানোর চেষ্টা করলো');
124 |
--------------------------------------------------------------------------------