├── .eslintignore
├── .eslintrc
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── dependabot.yml
└── workflows
│ ├── codecov.yml
│ ├── codeql-analysis.yml
│ ├── lib-test.yml
│ ├── njsscan-analysis.yml
│ ├── node.js.yml
│ └── playground-tests.yml
├── .gitignore
├── .npmignore
├── .replit
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── babel.config.js
├── deploy.sh
├── example.ts
├── index.ts
├── jest.config.js
├── lib
├── build.sh
├── download_models.py
├── download_models.sh
├── install.sh
├── requirements.txt
└── tfjs
│ └── web_model
│ ├── group1-shard1of6.bin
│ ├── group1-shard2of6.bin
│ ├── group1-shard3of6.bin
│ ├── group1-shard4of6.bin
│ ├── group1-shard5of6.bin
│ ├── group1-shard6of6.bin
│ └── model.json
├── media
└── sample.gif
├── package-lock.json
├── package.json
├── playground
├── classifications
│ └── hotdog.png
├── docker-compose.yml
├── server
│ ├── .babelrc
│ ├── Dockerfile
│ ├── __tests__
│ │ ├── fish.jpg
│ │ └── server.test.js
│ ├── index.js
│ ├── package-lock.json
│ ├── package.json
│ └── server.js
└── ui
│ ├── .browserslistrc
│ ├── .editorconfig
│ ├── .gitignore
│ ├── Dockerfile
│ ├── README.md
│ ├── angular.json
│ ├── e2e
│ ├── protractor.conf.js
│ ├── src
│ │ ├── app.e2e-spec.ts
│ │ └── app.po.ts
│ └── tsconfig.json
│ ├── karma.conf.js
│ ├── nginx.conf
│ ├── package.json
│ ├── src
│ ├── app
│ │ ├── app-routing.module.ts
│ │ ├── app.component.html
│ │ ├── app.component.scss
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── header
│ │ │ ├── header.component.html
│ │ │ ├── header.component.scss
│ │ │ ├── header.component.spec.ts
│ │ │ └── header.component.ts
│ │ ├── imageuploader
│ │ │ ├── imageuploader.component.html
│ │ │ ├── imageuploader.component.scss
│ │ │ ├── imageuploader.component.spec.ts
│ │ │ └── imageuploader.component.ts
│ │ ├── interfces
│ │ │ └── index.ts
│ │ ├── languages-api.service.spec.ts
│ │ ├── languages-api.service.ts
│ │ ├── note
│ │ │ ├── note.component.html
│ │ │ ├── note.component.scss
│ │ │ ├── note.component.spec.ts
│ │ │ └── note.component.ts
│ │ ├── primeng-imports.ts
│ │ ├── results
│ │ │ ├── results.component.html
│ │ │ ├── results.component.scss
│ │ │ ├── results.component.spec.ts
│ │ │ └── results.component.ts
│ │ ├── single-result
│ │ │ ├── single-result.component.html
│ │ │ ├── single-result.component.scss
│ │ │ ├── single-result.component.spec.ts
│ │ │ └── single-result.component.ts
│ │ └── uploader
│ │ │ ├── uploader.component.html
│ │ │ ├── uploader.component.scss
│ │ │ ├── uploader.component.spec.ts
│ │ │ └── uploader.component.ts
│ ├── assets
│ │ └── .gitkeep
│ ├── environments
│ │ ├── environment.prod.ts
│ │ └── environment.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ ├── polyfills.ts
│ ├── proxy.conf.json
│ ├── styles.scss
│ └── test.ts
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.spec.json
│ └── tslint.json
├── samples
├── car.jpg
├── fish.jpg
├── gun.jpg
└── panda.jpg
├── src
├── EfficientNetCheckPoint.ts
├── EfficientNetCheckPointFactory.ts
├── EfficientNetLanguageProvider.ts
├── EfficientNetResult.ts
├── EfficientnetModel.ts
├── ModelResourcesProvider.ts
└── misc
│ ├── ar.json
│ ├── en.json
│ ├── es.json
│ ├── fr.json
│ ├── he.json
│ ├── ru.json
│ └── zh.json
├── tester
├── package.json
├── samples
│ ├── car.jpg
│ ├── fish.jpg
│ ├── gun.jpg
│ └── panda.jpg
└── tests
│ ├── language-provider.test.js
│ └── model.test.js
├── tests
├── examples
│ ├── fish.gif
│ ├── fish.heic
│ ├── fish.png
│ ├── fish.svg
│ └── fish.webp
├── language-provider.test.js
└── model.test.js
└── tsconfig.json
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | web
4 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "parser": "@typescript-eslint/parser",
4 | "plugins": ["@typescript-eslint", "import", "jest", "prettier"],
5 | "extends": [
6 | "eslint:recommended",
7 | "plugin:@typescript-eslint/eslint-recommended",
8 | "plugin:@typescript-eslint/recommended",
9 | "plugin:prettier/recommended"
10 | ],
11 | "rules": {
12 | "prettier/prettier": "error",
13 | "import/no-unresolved": "error",
14 | "@typescript-eslint/no-non-null-assertion": "off"
15 | },
16 | "env": {
17 | "jest/globals": true,
18 | "node": true,
19 | "browser": true
20 | },
21 | "settings": {
22 | "import/parsers": {
23 | "@typescript-eslint/parser": [".ts", ".tsx"]
24 | },
25 | "import/resolver": {
26 | "typescript": {
27 | "alwaysTryTypes": true
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 | custom: ['https://paypal.me/tedgi']
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # To get started with Dependabot version updates, you'll need to specify which
2 | # package ecosystems to update and where the package manifests are located.
3 | # Please see the documentation for all configuration options:
4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5 |
6 | version: 2
7 | updates:
8 | - package-ecosystem: "npm" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "weekly"
12 |
--------------------------------------------------------------------------------
/.github/workflows/codecov.yml:
--------------------------------------------------------------------------------
1 | name: CodeCov - Running Code Coverage
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 |
8 | runs-on: ubuntu-latest
9 |
10 | strategy:
11 | matrix:
12 | node-version: [16.x]
13 |
14 | steps:
15 | - name: Checkout repository
16 | uses: actions/checkout@v2
17 | with:
18 | fetch-depth: 2
19 |
20 | - name: Set up Node.js ${{ matrix.node-version }}
21 | uses: actions/setup-node@v1
22 | with:
23 | node-version: ${{ matrix.node-version }}
24 |
25 | - name: Install dependencies
26 | run: npm install
27 |
28 | - name: Run the tests
29 | run: npm test
30 |
31 | - name: Upload coverage to Codecov
32 | uses: codecov/codecov-action@v3
33 | with:
34 | token: ${{ secrets.CODECOV_TOKEN }}
35 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL - Analysis"
13 |
14 | on:
15 | push:
16 | branches: [ main, pr ]
17 | pull_request:
18 | branches: [ main ]
19 |
20 | jobs:
21 | analyze:
22 | name: Analyze
23 | runs-on: ubuntu-latest
24 |
25 | strategy:
26 | fail-fast: false
27 | matrix:
28 | language: [ 'javascript', 'python' ]
29 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
30 | # Learn more:
31 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
32 |
33 | steps:
34 | - name: Checkout repository
35 | uses: actions/checkout@v2
36 |
37 | # Initializes the CodeQL tools for scanning.
38 | - name: Initialize CodeQL
39 | uses: github/codeql-action/init@v1
40 | with:
41 | languages: ${{ matrix.language }}
42 | # If you wish to specify custom queries, you can do so here or in a config file.
43 | # By default, queries listed here will override any specified in a config file.
44 | # Prefix the list here with "+" to use these queries and those in the config file.
45 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
46 |
47 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
48 | # If this step fails, then you should remove it and run the build manually (see below)
49 | - name: Autobuild
50 | uses: github/codeql-action/autobuild@v1
51 |
52 | # ℹ️ Command-line programs to run using the OS shell.
53 | # 📚 https://git.io/JvXDl
54 |
55 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
56 | # and modify them (or add more) to build your code if your project
57 | # uses a compiled language
58 |
59 | #- run: |
60 | # make bootstrap
61 | # make release
62 |
63 | - name: Perform CodeQL Analysis
64 | uses: github/codeql-action/analyze@v1
65 |
--------------------------------------------------------------------------------
/.github/workflows/lib-test.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: LIB Tests
5 |
6 | on:
7 | push:
8 | branches: [main]
9 | pull_request:
10 | branches: [main]
11 |
12 | jobs:
13 | build:
14 | runs-on: ubuntu-latest
15 | strategy:
16 | matrix:
17 | node-version: [14.x, 16.x, 18.x]
18 | steps:
19 | - uses: actions/checkout@v2
20 | - name: Use Node.js ${{ matrix.node-version }}
21 | uses: actions/setup-node@v1
22 | with:
23 | node-version: ${{ matrix.node-version }}
24 | - run: npm install
25 | - run: npm run build --if-present
26 | - run: npm run test
27 |
--------------------------------------------------------------------------------
/.github/workflows/njsscan-analysis.yml:
--------------------------------------------------------------------------------
1 | # This workflow integrates njsscan with GitHub's Code Scanning feature
2 | # nodejsscan is a static security code scanner that finds insecure code patterns in your Node.js applications
3 |
4 | name: NodeJS Scan - Static Application Testing
5 |
6 | on:
7 | push:
8 | branches: [ main ]
9 | pull_request:
10 | branches: [ main ]
11 |
12 | jobs:
13 | njsscan:
14 | runs-on: ubuntu-latest
15 | name: njsscan code scanning
16 | steps:
17 | - name: Checkout the code
18 | uses: actions/checkout@v2
19 | - name: nodejsscan scan
20 | id: njsscan
21 | uses: ajinabraham/njsscan-action@master
22 | with:
23 | args: '. --sarif --output results.sarif || true'
24 | - name: Upload njsscan report
25 | uses: github/codeql-action/upload-sarif@v1
26 | with:
27 | sarif_file: results.sarif
28 |
--------------------------------------------------------------------------------
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: Package Tests
5 |
6 | on:
7 | push:
8 | branches: [ main ]
9 | pull_request:
10 | branches: [ main ]
11 |
12 | jobs:
13 | build:
14 | runs-on: ubuntu-latest
15 |
16 | strategy:
17 | matrix:
18 | node-version: [10.x, 12.x, 14.x, 16.x, 18.x]
19 |
20 | steps:
21 | - uses: actions/checkout@v2
22 | - name: Use Node.js ${{ matrix.node-version }}
23 | uses: actions/setup-node@v1
24 | with:
25 | node-version: ${{ matrix.node-version }}
26 | - run: npm install
27 | - run: npm run build --if-present
28 |
--------------------------------------------------------------------------------
/.github/workflows/playground-tests.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3 |
4 | name: Playground Tests
5 |
6 | on:
7 | push:
8 | branches: [main]
9 | pull_request:
10 | branches: [main]
11 |
12 | jobs:
13 | build:
14 | runs-on: ubuntu-latest
15 |
16 | strategy:
17 | matrix:
18 | node-version: [14.x, 16.x, 18.x]
19 |
20 | steps:
21 | - uses: actions/checkout@v2
22 | - name: Use Node.js ${{ matrix.node-version }}
23 | uses: actions/setup-node@v1
24 | with:
25 | node-version: ${{ matrix.node-version }}
26 | - run: npm run test:playground
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | lib/model
3 | # Logs
4 | logs
5 | *.log
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 | lerna-debug.log*
10 | .idea
11 | # Diagnostic reports (https://nodejs.org/api/report.html)
12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
13 |
14 | # Runtime data
15 | pids
16 | *.pid
17 | *.seed
18 | *.pid.lock
19 |
20 | # Directory for instrumented libs generated by jscoverage/JSCover
21 | lib-cov
22 |
23 | # Coverage directory used by tools like istanbul
24 | coverage
25 | *.lcov
26 |
27 | # nyc test coverage
28 | .nyc_output
29 |
30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
31 | .grunt
32 |
33 | # Bower dependency directory (https://bower.io/)
34 | bower_components
35 |
36 | # node-waf configuration
37 | .lock-wscript
38 |
39 | # Compiled binary addons (https://nodejs.org/api/addons.html)
40 | build/Release
41 |
42 | # Dependency directories
43 | node_modules/
44 | jspm_packages/
45 |
46 | # Snowpack dependency directory (https://snowpack.dev/)
47 | web_modules/
48 |
49 | # TypeScript cache
50 | *.tsbuildinfo
51 |
52 | # Optional npm cache directory
53 | .npm
54 |
55 | # Optional eslint cache
56 | .eslintcache
57 |
58 | # Microbundle cache
59 | .rpt2_cache/
60 | .rts2_cache_cjs/
61 | .rts2_cache_es/
62 | .rts2_cache_umd/
63 |
64 | # Optional REPL history
65 | .node_repl_history
66 |
67 | # Output of 'npm pack'
68 | *.tgz
69 |
70 | # Yarn Integrity file
71 | .yarn-integrity
72 |
73 | # dotenv environment variables file
74 | .env
75 | .env.test
76 |
77 | # parcel-bundler cache (https://parceljs.org/)
78 | .cache
79 | .parcel-cache
80 |
81 | # Next.js build output
82 | .next
83 | out
84 |
85 | # Nuxt.js build / generate output
86 | .nuxt
87 | dist
88 |
89 | # Gatsby files
90 | .cache/
91 | # Comment in the public line in if your project uses Gatsby and not Next.js
92 | # https://nextjs.org/blog/next-9-1#public-directory-support
93 | # public
94 |
95 | # vuepress build output
96 | .vuepress/dist
97 |
98 | # Serverless directories
99 | .serverless/
100 |
101 | # FuseBox cache
102 | .fusebox/
103 |
104 | # DynamoDB Local files
105 | .dynamodb/
106 |
107 | # TernJS port file
108 | .tern-port
109 |
110 | # Stores VSCode versions used for testing VSCode extensions
111 | .vscode-test
112 |
113 | # yarn v2
114 | .yarn/cache
115 | .yarn/unplugged
116 | .yarn/build-state.yml
117 | .yarn/install-state.gz
118 | .pnp.*
119 | .vscode
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | lib/
2 | .idea
3 | example.ts
4 | samples
5 | tests
6 | coverage/*
7 | .coveralls.yml
8 | .travis.yml
9 | .github/*
10 | .replit
11 | *.config.*
12 | playground
13 | misc/s*
14 | web
15 | .eslintrc
16 | .eslintignore
17 | LICENSE
18 | CODE_OF_CONDUCT.md
19 | tester
20 | .vscode
21 | media
22 | *.tar
--------------------------------------------------------------------------------
/.replit:
--------------------------------------------------------------------------------
1 | language = "nodejs"
2 | run = "npm run example"
3 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at naor.tedgi@gmail.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | When contributing to this repository, please first discuss the change you wish to make via issue,
4 | email, or any other method with the owners of this repository before making a change.
5 |
6 | Please note we have a code of conduct, please follow it in all your interactions with the project.
7 |
8 | ## Pull Request Process
9 |
10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a
11 | build.
12 | 2. Update the README.md with details of changes to the interface, this includes new environment
13 | variables, exposed ports, useful file locations and container parameters.
14 | 3. Increase the version numbers in any examples files and the README.md to the new version that this
15 | Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
16 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
17 | do not have permission to do that, you may request the second reviewer to merge it for you.
18 |
19 | ## Code of Conduct
20 |
21 | ### Our Pledge
22 |
23 | In the interest of fostering an open and welcoming environment, we as
24 | contributors and maintainers pledge to making participation in our project and
25 | our community a harassment-free experience for everyone, regardless of age, body
26 | size, disability, ethnicity, gender identity and expression, level of experience,
27 | nationality, personal appearance, race, religion, or sexual identity and
28 | orientation.
29 |
30 | ### Our Standards
31 |
32 | Examples of behavior that contributes to creating a positive environment
33 | include:
34 |
35 | * Using welcoming and inclusive language
36 | * Being respectful of differing viewpoints and experiences
37 | * Gracefully accepting constructive criticism
38 | * Focusing on what is best for the community
39 | * Showing empathy towards other community members
40 |
41 | Examples of unacceptable behavior by participants include:
42 |
43 | * The use of sexualized language or imagery and unwelcome sexual attention or
44 | advances
45 | * Trolling, insulting/derogatory comments, and personal or political attacks
46 | * Public or private harassment
47 | * Publishing others' private information, such as a physical or electronic
48 | address, without explicit permission
49 | * Other conduct which could reasonably be considered inappropriate in a
50 | professional setting
51 |
52 | ### Our Responsibilities
53 |
54 | Project maintainers are responsible for clarifying the standards of acceptable
55 | behavior and are expected to take appropriate and fair corrective action in
56 | response to any instances of unacceptable behavior.
57 |
58 | Project maintainers have the right and responsibility to remove, edit, or
59 | reject comments, commits, code, wiki edits, issues, and other contributions
60 | that are not aligned to this Code of Conduct, or to ban temporarily or
61 | permanently any contributor for other behaviors that they deem inappropriate,
62 | threatening, offensive, or harmful.
63 |
64 | ### Scope
65 |
66 | This Code of Conduct applies both within project spaces and in public spaces
67 | when an individual is representing the project or its community. Examples of
68 | representing a project or community include using an official project e-mail
69 | address, posting via an official social media account, or acting as an appointed
70 | representative at an online or offline event. Representation of a project may be
71 | further defined and clarified by project maintainers.
72 |
73 | ### Enforcement
74 |
75 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
76 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
77 | complaints will be reviewed and investigated and will result in a response that
78 | is deemed necessary and appropriate to the circumstances. The project team is
79 | obligated to maintain confidentiality with regard to the reporter of an incident.
80 | Further details of specific enforcement policies may be posted separately.
81 |
82 | Project maintainers who do not follow or enforce the Code of Conduct in good
83 | faith may face temporary or permanent repercussions as determined by other
84 | members of the project's leadership.
85 |
86 | ### Attribution
87 |
88 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
89 | available at [http://contributor-covenant.org/version/1/4][version]
90 |
91 | [homepage]: http://contributor-covenant.org
92 | [version]: http://contributor-covenant.org/version/1/4/
93 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2010-2020 Google LLC. http://angularjs.org
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TensorflowJS EfficientNet
2 |
3 |   [](https://codecov.io/gh/ntedgi/node-efficientnet)
4 | [](https://www.codacy.com/gh/ntedgi/node-efficientnet/dashboard?utm_source=github.com&utm_medium=referral&utm_content=ntedgi/node-efficientnet&utm_campaign=Badge_Grade)
5 | [](https://repl.it/github/ntedgi/node-efficientnet)
6 |
7 |
8 |
9 | [](https://gitter.im/node-efficientnet/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
10 |
11 |
12 |
13 | This repository contains a tensorflowJs implementation of **EfficientNet**,
14 | an object detection model trained on [ImageNet](http://www.image-net.org/) and can detect [1000 different objects](https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt).
15 |
16 | EfficientNet a lightweight convolutional neural network architecture achieving the [state-of-the-art accuracy with an order of magnitude fewer parameters and FLOPS](https://arxiv.org/abs/1905.11946), on both ImageNet and
17 | five other commonly used transfer learning datasets.
18 |
19 | The codebase is heavily inspired by the [TensorFlow implementation](https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet).
20 |
21 | 
22 |
23 | #
24 |
25 | ## 👏 Supporters
26 |
27 | ### ↳ Stargazers
28 |
29 | [](https://github.com/ntedgi/node-efficientnet/stargazers)
30 |
31 | ### ↳ Forkers
32 |
33 | [](https://github.com/ntedgi/node-efficientnet/network/members)
34 |
35 | ## Multilingual status
36 |
37 | | locale | status | translate by 👑 |
38 | |:-------:|:--------------------------:|:------------------------------------------:|
39 | | `en` | ✅ | |
40 | | `zh` | ✅ | [@luoye-fe](https://github.com/luoye-fe) |
41 | | `es` | ✅ | [@h383r](https://github.com/h383r) |
42 | | `ar` | ✅ | [@lamamyf](https://github.com/lamamyf) |
43 | | `ru` | ✅ | [@Abhighyaa](https://github.com/Abhighyaa) |
44 | | `he` | ✅ | [@jhonDoe15](https://github.com/jhonDoe15) |
45 | | `fr` | ✅ | [@burmanp](https://github.com/burmanp) |
46 | | `other` | ⏩ (need help, PR welcome ) | |
47 |
48 | ## Table of Contents
49 |
50 | 1. [Just Want to Play With The Model](#how-i-run-this-project-locally-)
51 | 2. [Installation](#installation)
52 | 3. [API](#api)
53 | 4. [Examples](#examples)
54 | 5. [Usage](#usgae)
55 | 6. [About EfficientNet Models](#about-efficientnet-models)
56 | 7. [Models](#models)
57 | 8. [Multilingual status](#multilingual-status)
58 |
59 | ## How I Run This Project Locally ?
60 |
61 | - clone this repository
62 | - Just Want to Play ?
63 | - At the root project go to playground directory, Run: `docker-compose up`
64 | - Navigate to http://localhost:8080
65 |
66 | ## Usage:
67 |
68 | EfficientNet has 8 different model checkpoints each checkpoint as different input layer resolution
69 | for larger input layer resolution, the greater the accuracy and the running time is slower.
70 |
71 | for example lets take this images:
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | Model
82 | Prediction
83 |
84 |
85 | EfficientNetB0
86 | ('Giant panda',83.607) , ( 'Skunk',11.61) , ('hog',4.772)
87 |
88 |
89 | EfficientNetB7
90 | ('Giant panda',90.406) , ( 'American black bear',7.07) , ('Badger',2.5192)
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | Model
103 | Prediction
104 |
105 |
106 | EfficientNetB3
107 | ('goldfish, Carassius auratus',82.5) , ( 'starfish, sea star',9.26) , ('corn'',7.33)
108 |
109 |
110 | EfficientNetB7
111 | ('goldfish, Carassius auratus',97.5) , ( 'starfish, sea star',1.46) , ('corn'',0.93)
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 | Model
124 | Prediction
125 |
126 |
127 | EfficientNetB0
128 | ('Sports Car',88.02) , ( 'racing car',6.647) , ('car wheel',5.32)
129 |
130 |
131 | EfficientNetB7
132 | ('Sports Car',87.68) , ( 'convertible'',7.831) , ('car wheel',4.485)
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 | Model
145 | Prediction
146 |
147 |
148 | EfficientNetB0
149 | ('revolver',85.52) , ( 'assault rifle',9.85) , ('rifle',4.6197)
150 |
151 |
152 | EfficientNetB7
153 | ('revolver',88.13) , ( 'rifle',8.29) , ('assault rifle',3.56)
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 | #
163 |
164 | ## Installation
165 |
166 | ```node
167 | npm i --save node-efficientnet
168 | ```
169 |
170 | ## API
171 |
172 | ### `EfficientNetCheckPointFactory.create(checkPoint: EfficientNetCheckPoint, options?: EfficientNetCheckPointFactoryOptions): Promise`
173 |
174 | Example: to create an efficientnet model you need to pass `EfficientNetCheckPoint`
175 | (available checkpoint [B0..B7]) each one of them represent different model
176 |
177 | ```javascript
178 | const {
179 | EfficientNetCheckPointFactory,
180 | EfficientNetCheckPoint,
181 | } = require("node-efficientnet");
182 |
183 | const model = await EfficientNetCheckPointFactory.create(
184 | EfficientNetCheckPoint.B7
185 | );
186 |
187 | const path2image = "...";
188 |
189 | const topResults = 5;
190 |
191 | const result = await model.inference(path2image, {
192 | topK: topResults,
193 | locale: "zh",
194 | });
195 | ```
196 |
197 | Of course, you can use local model file to speed up loading
198 |
199 | You can download model file from [efficientnet-tensorflowjs-binaries](https://github.com/ntedgi/efficientnet-tensorflowjs-binaries), please keep the directory structure consistent, just like:
200 |
201 | ```
202 | local_model
203 | └── B0
204 | ├── group1-shard1of6.bin
205 | ├── group1-shard2of6.bin
206 | ├── group1-shard3of6.bin
207 | ├── group1-shard4of6.bin
208 | ├── group1-shard5of6.bin
209 | ├── group1-shard6of6.bin
210 | └── model.json
211 | ```
212 |
213 | ```javascript
214 | const path = require("path");
215 | const {
216 | EfficientNetCheckPointFactory,
217 | EfficientNetCheckPoint,
218 | } = require("node-efficientnet");
219 |
220 | const model = await EfficientNetCheckPointFactory.create(
221 | EfficientNetCheckPoint.B7,
222 | {
223 | localModelRootDirectory: path.join(__dirname, "local_model"),
224 | }
225 | );
226 |
227 | const path2image = "...";
228 |
229 | const topResults = 5;
230 |
231 | const result = await model.inference(path2image, {
232 | topK: topResults,
233 | locale: "zh",
234 | });
235 | ```
236 |
237 | #
238 |
239 | ## Examples
240 |
241 | download files from remote and predict using model
242 |
243 | ```js
244 | const fs = require("fs");
245 | const nodeFetch = require("node-fetch");
246 |
247 | const {
248 | EfficientNetCheckPointFactory,
249 | EfficientNetCheckPoint,
250 | } = require("node-efficientnet");
251 |
252 | const images = ["car.jpg", "panda.jpg"];
253 | const imageDir = "./samples";
254 | const imageDirRemoteUri =
255 | "https://raw.githubusercontent.com/ntedgi/node-EfficientNet/main/samples";
256 |
257 | if (!fs.existsSync(imageDir)) {
258 | fs.mkdirSync(imageDir);
259 | }
260 |
261 | async function download(image, cb) {
262 | const response = await nodeFetch.default(`${imageDirRemoteUri}/${image}`);
263 | const buffer = await response.buffer();
264 | fs.writeFile(`${imageDir}/${image}`, buffer, cb);
265 | }
266 |
267 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B2)
268 | .then((model) => {
269 | images.forEach(async (image) => {
270 | await download(image, () => {
271 | model.inference(`${imageDir}/${image}`).then((result) => {
272 | console.log(result.result);
273 | });
274 | });
275 | });
276 | })
277 | .catch((e) => {
278 | console.error(e);
279 | });
280 | ```
281 |
282 | output :
283 |
284 | ```js
285 | [
286 | { label: "sports car, sport car", precision: 88.02440940394301 },
287 | {
288 | label: "racer, race car, racing car",
289 | precision: 6.647441678387659,
290 | },
291 | { label: "car wheel", precision: 5.3281489176693295 },
292 | ][
293 | ({
294 | label: "giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca",
295 | precision: 83.60747593436018,
296 | },
297 | { label: "skunk, poleca", precision: 11.61300759424677 },
298 | {
299 | label: "hog, pig, grunter, squealer, Sus scrofa",
300 | precision: 4.779516471393051,
301 | })
302 | ];
303 | ```
304 |
305 | #
306 |
307 | ## About EfficientNet Models
308 |
309 | EfficientNets rely on AutoML and compound scaling to achieve superior performance without compromising resource efficiency. The [AutoML Mobile framework](https://ai.googleblog.com/2018/08/mnasnet-towards-automating-design-of.html) has helped develop a mobile-size baseline network, **EfficientNet-B0**, which is then improved by the compound scaling method to obtain EfficientNet-B1 to B7.
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 | #
323 |
324 | EfficientNets achieve state-of-the-art accuracy on ImageNet with an order of magnitude better efficiency:
325 |
326 | - In high-accuracy regime, EfficientNet-B7 achieves the state-of-the-art 84.4% top-1 / 97.1% top-5 accuracy on ImageNet with 66M parameters and 37B FLOPS. At the same time, the model is 8.4x smaller and 6.1x faster on CPU inference than the former leader, [Gpipe](https://arxiv.org/abs/1811.06965).
327 |
328 | - In middle-accuracy regime, EfficientNet-B1 is 7.6x smaller and 5.7x faster on CPU inference than [ResNet-152](https://arxiv.org/abs/1512.03385), with similar ImageNet accuracy.
329 |
330 | - Compared to the widely used [ResNet-50](https://arxiv.org/abs/1512.03385), EfficientNet-B4 improves the top-1 accuracy from 76.3% of ResNet-50 to 82.6% (+6.3%), under similar FLOPS constraints.
331 |
332 | #
333 |
334 | ## Models
335 |
336 | The performance of each model variant using the pre-trained weights converted from checkpoints provided by the authors is as follows:
337 |
338 | | Architecture | @top1\* Imagenet | @top1\* Noisy-Student |
339 | | -------------- | :--------------: | :-------------------: |
340 | | EfficientNetB0 | 0.772 | 0.788 |
341 | | EfficientNetB1 | 0.791 | 0.815 |
342 | | EfficientNetB2 | 0.802 | 0.824 |
343 | | EfficientNetB3 | 0.816 | 0.841 |
344 | | EfficientNetB4 | 0.830 | 0.853 |
345 | | EfficientNetB5 | 0.837 | 0.861 |
346 | | EfficientNetB6 | 0.841 | 0.864 |
347 | | EfficientNetB7 | 0.844 | 0.869 |
348 |
349 | **\*** - topK accuracy score for converted models (imagenet `val` set)
350 |
351 | ---
352 |
353 | ```ts
354 | if (this.repo.isAwesome || this.repo.isHelpful) {
355 | Star(this.repo);
356 | }
357 | ```
358 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | // babel.config.js
2 | module.exports = {
3 | presets: [
4 | ['@babel/preset-env', {targets: {node: 'current'}}],
5 | '@babel/preset-typescript',
6 | ],
7 | "env": {
8 | "test": {
9 | "presets": [["@babel/preset-env"], '@babel/preset-typescript']
10 | }
11 | },
12 | "plugins": ["@babel/proposal-class-properties"]
13 | };
14 |
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | set -x
4 | cd playground
5 | docker-compose up --build -d
--------------------------------------------------------------------------------
/example.ts:
--------------------------------------------------------------------------------
1 | import * as fs from "fs";
2 | import * as nodeFetch from "node-fetch";
3 |
4 | import {
5 | EfficientNetCheckPointFactory,
6 | EfficientNetCheckPoint,
7 | EfficientNetModel,
8 | EfficientNetResult,
9 | EfficientNetLableLanguage,
10 | EfficientNetLanguageProvider
11 | } from "./index";
12 |
13 | const images = ["car.jpg", "panda.jpg", "fish.jpg"];
14 | const imageDir = "./samples";
15 | const imageDirRemoteUri =
16 | "https://raw.githubusercontent.com/ntedgi/node-EfficientNet/main/samples";
17 |
18 | if (!fs.existsSync(imageDir)) fs.mkdirSync(imageDir);
19 |
20 | async function download(image: string, cb: fs.NoParamCallback) {
21 | const response = await nodeFetch.default(`${imageDirRemoteUri}/${image}`);
22 | const buffer = await response.buffer();
23 | fs.writeFile(`${imageDir}/${image}`, buffer, cb);
24 | }
25 |
26 | //Default language results (English)
27 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0)
28 | .then((model: EfficientNetModel) => {
29 | images.forEach(async (image) => {
30 | await download(image, () => {
31 | model
32 | .inference(`${imageDir}/${image}`, { topK: 3 })
33 | .then((result: EfficientNetResult) => {
34 | console.log("Result in English : \n -------------------");
35 | console.log(result.result);
36 | });
37 | });
38 | });
39 | })
40 | .catch((e: Error) => {
41 | console.error(e);
42 | });
43 |
44 | //Not default language results (Spanish)
45 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0)
46 | .then(async (model: EfficientNetModel) => {
47 |
48 | const labelLanguage = EfficientNetLableLanguage.SPANISH;
49 | const languageProvider = new EfficientNetLanguageProvider(labelLanguage);
50 | await languageProvider.load();
51 |
52 | images.forEach(async (image) => {
53 | await download(image, () => {
54 | model
55 | .inference(`${imageDir}/${image}`, { topK: 3 }, languageProvider)
56 | .then((result: EfficientNetResult) => {
57 | console.log("Result in Spanish : \n -------------------");
58 | console.log(result.result);
59 | });
60 | });
61 | });
62 | })
63 | .catch((e: Error) => {
64 | console.error(e);
65 | });
66 |
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 | import EfficientNetCheckPointFactory from "./src/EfficientNetCheckPointFactory";
2 | import EfficientNetModel from "./src/EfficientnetModel";
3 | import EfficientNetResult from "./src/EfficientNetResult";
4 | import { EfficientNetCheckPoint } from "./src/EfficientNetCheckPoint";
5 | import {
6 | EfficientNetLabelLanguage,
7 | EfficientNetLanguageProvider,
8 | } from "./src/EfficientNetLanguageProvider";
9 | export {
10 | EfficientNetModel,
11 | EfficientNetResult,
12 | EfficientNetCheckPoint,
13 | EfficientNetLabelLanguage,
14 | EfficientNetLanguageProvider,
15 | EfficientNetCheckPointFactory,
16 | };
17 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | verbose: true,
3 | testTimeout: 1000000,
4 | transform: {
5 | "^.+\\.ts$": "babel-jest",
6 | },
7 | modulePathIgnorePatterns: ["/playground/"],
8 | coverageReporters: ["text", "cobertura"],
9 | };
10 |
--------------------------------------------------------------------------------
/lib/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | set -x
4 | tensorflowjs_converter --input_format=tf_saved_model --output_format=tfjs_graph_model --signature_name=serving_default --saved_model_tags=serve efficientnet_b7_classification_1 ./models/B7
5 |
--------------------------------------------------------------------------------
/lib/download_models.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import numpy as np
3 | from skimage.io import imread
4 | sys.path.append('..')
5 |
6 | from keras.applications.imagenet_utils import decode_predictions
7 | from efficientnet.keras import EfficientNetB0
8 | from efficientnet.keras import center_crop_and_resize, preprocess_input
9 | model = EfficientNetB0(weights='imagenet')
10 |
11 | image = imread('../misc/panda.jpg')
12 | image_size = model.input_shape[1]
13 | x = center_crop_and_resize(image, image_size=image_size)
14 | # x = preprocess_input(x)
15 | x = np.expand_dims(x, 0)
16 |
17 | y = model.predict(x)
18 | print(decode_predictions(y))
19 |
20 | #https://storage.googleapis.com/keras-applications/efficientnetb0.h5
21 |
--------------------------------------------------------------------------------
/lib/download_models.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | set -x
4 | curl https://tfhub.dev/tensorflow/efficientnet/b0/classification/1?tf-hub-format=compressed --output b0.tgz
5 | curl https://tfhub.dev/tensorflow/efficientnet/b1/classification/1?tf-hub-format=compressed --output b1.tgz
6 | curl https://tfhub.dev/tensorflow/efficientnet/b2/classification/1?tf-hub-format=compressed --output b2.tgz
7 | curl https://tfhub.dev/tensorflow/efficientnet/b3/classification/1?tf-hub-format=compressed --output b3.tgz
8 | curl https://tfhub.dev/tensorflow/efficientnet/b4/classification/1?tf-hub-format=compressed --output b4.tgz
9 | curl https://tfhub.dev/tensorflow/efficientnet/b5/classification/1?tf-hub-format=compressed --output b5.tgz
10 | curl https://tfhub.dev/tensorflow/efficientnet/b6/classification/1?tf-hub-format=compressed --output b6.tgz
11 | curl https://tfhub.dev/tensorfl ow/efficientnet/b7/classification/1?tf-hub-format=compressed --output b1.tgz
12 |
13 |
--------------------------------------------------------------------------------
/lib/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 | set -x
4 | pip3 install virtualenv
5 | virtualenv -p python3 model
6 | model/bin/pip3 install -r requirements.txt
--------------------------------------------------------------------------------
/lib/requirements.txt:
--------------------------------------------------------------------------------
1 | tensorflowjs==2.8.1
2 | keras==2.4.3
3 | efficientnet==1.1.1
4 |
--------------------------------------------------------------------------------
/lib/tfjs/web_model/group1-shard1of6.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/lib/tfjs/web_model/group1-shard1of6.bin
--------------------------------------------------------------------------------
/lib/tfjs/web_model/group1-shard2of6.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/lib/tfjs/web_model/group1-shard2of6.bin
--------------------------------------------------------------------------------
/lib/tfjs/web_model/group1-shard3of6.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/lib/tfjs/web_model/group1-shard3of6.bin
--------------------------------------------------------------------------------
/lib/tfjs/web_model/group1-shard4of6.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/lib/tfjs/web_model/group1-shard4of6.bin
--------------------------------------------------------------------------------
/lib/tfjs/web_model/group1-shard5of6.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/lib/tfjs/web_model/group1-shard5of6.bin
--------------------------------------------------------------------------------
/lib/tfjs/web_model/group1-shard6of6.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/lib/tfjs/web_model/group1-shard6of6.bin
--------------------------------------------------------------------------------
/media/sample.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/media/sample.gif
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-efficientnet",
3 | "version": "2.1.0",
4 | "description": "Implementation of efficientNet model in nodejs",
5 | "main": "dist/index.js",
6 | "types": "dist/index.d.ts",
7 | "scripts": {
8 | "prepublish": "npm run build",
9 | "build": "rm -rf ./dist && tsc && cp -r src/misc ./dist/src/misc",
10 | "example": "ts-node example.ts",
11 | "coveralls": "cat ./coverage/lcov.info | coveralls",
12 | "test": "npm run test:prapare && npm run test:unit",
13 | "lint": "eslint . --fix --ext .ts && npm run lint:md",
14 | "lint:md": "remark .",
15 | "test:unit": "jest --clearCache && jest --coverage",
16 | "test:prapare": "npm link && cd tester && npm link ${npm_package_name}",
17 | "test:playground": "npm i && npm run pack && cd playground/server && npm i && npm test && cd ../../ && npm run remove:pack",
18 | "prepare:pack": "npm run build && npm pack",
19 | "apply:pack": "cd playground/server && npm i file:../../${npm_package_name}-${npm_package_version}.tgz",
20 | "pack": "npm run prepare:pack && npm run apply:pack",
21 | "remove:pack": "rm ${npm_package_name}-${npm_package_version}.tgz && cd playground/server && npm uninstall ${npm_package_name} && npm i ${npm_package_name}",
22 | "deploy:playground": "sh deploy.sh"
23 | },
24 | "repository": {
25 | "type": "git",
26 | "url": "git+https://github.com/ntedgi/node-efficientnet.git"
27 | },
28 | "author": "Naor Tedgi (Naor.tedgi@gmail.com)",
29 | "license": "MIT",
30 | "bugs": {
31 | "url": "https://github.com/ntedgi/node-efficientnet/issues"
32 | },
33 | "homepage": "https://github.com/ntedgi/node-efficientnet#readme",
34 | "dependencies": {
35 | "@tensorflow/tfjs-core": "^3.3.0",
36 | "@tensorflow/tfjs-node-gpu": "^3.3.0",
37 | "@types/cli-progress": "^3.8.0",
38 | "cli-progress": "^3.8.2",
39 | "jimp": "^0.16.1",
40 | "node-fetch": "^3.2.10",
41 | "ts-node": "^9.1.1"
42 | },
43 | "devDependencies": {
44 | "@babel/core": "^7.12.10",
45 | "@babel/preset-env": "^7.12.11",
46 | "@babel/preset-typescript": "^7.12.7",
47 | "@types/jest": "^26.0.19",
48 | "@typescript-eslint/eslint-plugin": "^4.11.1",
49 | "@typescript-eslint/parser": "^4.11.1",
50 | "babel-jest": "^29.1.2",
51 | "babel-plugin-transform-class-properties": "^6.24.1",
52 | "coveralls": "^3.1.0",
53 | "eslint": "^7.16.0",
54 | "eslint-config-prettier": "^8.5.0",
55 | "eslint-import-resolver-typescript": "^3.5.2",
56 | "eslint-plugin-import": "^2.22.1",
57 | "eslint-plugin-jest": "^24.1.3",
58 | "eslint-plugin-prettier": "^3.3.0",
59 | "jest": "^26.6.3",
60 | "prettier": "^2.2.1",
61 | "regenerator-runtime": "^0.13.7",
62 | "remark-cli": "^9.0.0",
63 | "remark-lint": "^8.0.0",
64 | "remark-lint-emphasis-marker": "^3.1.1",
65 | "remark-lint-strong-marker": "^2.0.1",
66 | "remark-preset-lint-recommended": "^6.1.2",
67 | "shelljs": "^0.8.4",
68 | "typescript": "^4.1.3"
69 | },
70 | "jest": {
71 | "transform": {}
72 | },
73 | "remarkConfig": {
74 | "settings": {
75 | "emphasis": "*",
76 | "strong": "*"
77 | },
78 | "plugins": [
79 | "remark-preset-lint-recommended",
80 | "remark-lint-emphasis-marker",
81 | "remark-lint-strong-marker",
82 | "remark-stringify"
83 | ]
84 | },
85 | "keywords": [
86 | "tensorflow",
87 | "tfjs",
88 | "efficientnet",
89 | "imagenet",
90 | "object detection",
91 | "dnn"
92 | ]
93 | }
94 |
--------------------------------------------------------------------------------
/playground/classifications/hotdog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/playground/classifications/hotdog.png
--------------------------------------------------------------------------------
/playground/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.2'
2 | services:
3 | node-server:
4 | build:
5 | context: ./server
6 | dockerfile: Dockerfile
7 | ports:
8 | - "3000:3000"
9 | environment:
10 | - INSTANCE=node-server
11 | volumes:
12 | - ./:/server
13 | nginx:
14 | build:
15 | context: ./ui
16 | dockerfile: Dockerfile
17 | depends_on:
18 | - node-server
19 | ports:
20 | - "8080:80"
21 | links:
22 | - node-server:node-server
23 | restart: always
24 |
--------------------------------------------------------------------------------
/playground/server/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-env"
4 | ]
5 | }
--------------------------------------------------------------------------------
/playground/server/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:14.16.1-buster
2 | EXPOSE 3000
3 | WORKDIR /home/app
4 | COPY . .
5 |
6 | RUN rm -rf node_modules \
7 | && npm ci --quiet --no-progress
8 |
9 | CMD ["npm","start"]
10 |
--------------------------------------------------------------------------------
/playground/server/__tests__/fish.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/playground/server/__tests__/fish.jpg
--------------------------------------------------------------------------------
/playground/server/__tests__/server.test.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-undef */
2 | import request from "supertest";
3 | import { createServer } from "../server.js";
4 | import { join } from "path";
5 | import { EfficientNetLabelLanguage } from "node-efficientnet";
6 |
7 | let app = null;
8 | beforeAll(async (done) => {
9 | app = await createServer();
10 | done();
11 | }, 60000);
12 |
13 | describe("Get Endpoints", () => {
14 | it("/api/languages should return all existing languages", async (done) => {
15 | jest.setTimeout(1000000);
16 | const res = await request(app)
17 | .get("/api/languages")
18 | .expect(200)
19 | .then((output, err) => {
20 | if (output) {
21 | //Expected languages
22 | const languagesEnumKeys = Object.keys(EfficientNetLabelLanguage);
23 | const languagesAmount = languagesEnumKeys.length / 2;
24 | const languagesArr = languagesEnumKeys.slice(languagesAmount);
25 |
26 | const expectedLanguagesArr = languagesArr
27 | .map((language) => language.toLowerCase())
28 | .map((item) => item.charAt(0).toUpperCase() + item.slice(1));
29 |
30 | //Actual languages
31 | const { _body: actualLanguagesArr } = output;
32 |
33 | expect(expectedLanguagesArr).toEqual(actualLanguagesArr);
34 | done();
35 | } else {
36 | done(err);
37 | }
38 | })
39 | .catch((err) => {
40 | done(err);
41 | });
42 | });
43 | });
44 |
45 | describe("Post Endpoints", () => {
46 | it("should predict simple gold fish", (done) => {
47 | jest.setTimeout(100000);
48 | const filePath = join(__dirname, "fish.jpg");
49 | request(app)
50 | .post("/api/upload/english")
51 | .attach("file", filePath)
52 | .expect(200)
53 | .then((output, err) => {
54 | const expectedLabel = "goldfish, Carassius auratus";
55 | if (output) {
56 | const { result } = output.body;
57 | expect(result[0].label).toEqual(expectedLabel);
58 | done();
59 | } else {
60 | done(err);
61 | }
62 | })
63 | .catch((err) => {
64 | done(err);
65 | });
66 | });
67 | it("should predict simple gold fish in spanish", (done) => {
68 | jest.setTimeout(100000);
69 | const filePath = join(__dirname, "fish.jpg");
70 | request(app)
71 | .post("/api/upload/spanish")
72 | .attach("file", filePath)
73 | .expect(200)
74 | .then((output, err) => {
75 | const expectedLabel = "pez dorado, Carassius auratus";
76 | if (output) {
77 | const { result } = output.body;
78 | expect(result[0].label).toEqual(expectedLabel);
79 | done();
80 | } else {
81 | done(err);
82 | }
83 | })
84 | .catch((err) => {
85 | done(err);
86 | });
87 | });
88 | it("sanity test server/version", (done) => {
89 | request(app)
90 | .get("/api/version/")
91 | .expect(200)
92 | .then((response) => {
93 | const version = response.body;
94 | done();
95 | })
96 | .catch((err) => {
97 | done(err);
98 | });
99 | });
100 | });
101 |
102 |
--------------------------------------------------------------------------------
/playground/server/index.js:
--------------------------------------------------------------------------------
1 | import { createServer } from "./server.js";
2 | const port = 3000;
3 | createServer()
4 | .then((app) => {
5 | app.listen(port, () => {
6 | console.log("Server is running on PORT", port);
7 | });
8 | })
9 | .catch((err) => {
10 | console.log(err);
11 | });
12 |
--------------------------------------------------------------------------------
/playground/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "nodemon index.js",
8 | "test": "jest --clearCache && jest --detectOpenHandles "
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "express": "^4.17.1",
14 | "express-body-parser-error-handler": "^1.0.3",
15 | "express-formidable": "^1.2.0",
16 | "multer": "^1.4.2",
17 | "node-efficientnet": "file:../../node-efficientnet-2.0.4.tgz",
18 | "node-fetch": "^2.6.1"
19 | },
20 | "devDependencies": {
21 | "@babel/plugin-transform-modules-commonjs": "^7.13.8",
22 | "@babel/preset-env": "^7.13.12",
23 | "babel-jest": "^26.6.3",
24 | "jest": "^26.6.3",
25 | "nodemon": "^2.0.7",
26 | "supertest": "^6.3.0"
27 | },
28 | "type": "module",
29 | "jest": {
30 | "testEnvironment": "node",
31 | "coveragePathIgnorePatterns": [
32 | "/node_modules/"
33 | ],
34 | "transform": {
35 | "^.+\\.jsx?$": "babel-jest"
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/playground/server/server.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2 | /* eslint-disable no-undef */
3 | import express, { Router } from "express";
4 | import formidable from "express-formidable";
5 | import bodyParserErrorHandler from "express-body-parser-error-handler";
6 |
7 | const { urlencoded, json } = express;
8 |
9 | import {
10 | EfficientNetCheckPointFactory,
11 | EfficientNetCheckPoint,
12 | EfficientNetLabelLanguage,
13 | EfficientNetLanguageProvider,
14 | } from "node-efficientnet";
15 |
16 | const safeGet = (fn, fallBack) => {
17 | try {
18 | return fn();
19 | } catch (e) {
20 | return fallBack;
21 | }
22 | };
23 |
24 | const loggerMiddleware = (serverName) => (req, _res, next) => {
25 | console.info(`${serverName} | ${req.url} ${req.method} -- ${new Date()}`);
26 | next();
27 | };
28 |
29 | const initServer = (model, serverName = "back-end") => {
30 | const app = express();
31 | const router = Router();
32 | app.use(loggerMiddleware(serverName));
33 |
34 | router.post("/api/upload/:language", async (req, res) => {
35 | try {
36 | console.log(`/api/upload/ ^ language=>${req.params.language}`);
37 | const filePath = safeGet(() => req.files.file.path, null);
38 | if (!filePath) {
39 | res.status(400);
40 | res.send({ error: "should pass file to inference" });
41 | } else {
42 | const language = safeGet(() => req.params.language, null);
43 | if (!language) {
44 | res.status(400);
45 | res.send({ error: "should pass file to inference" });
46 | } else {
47 | const formattedLanguage = language.toUpperCase();
48 | const labelLanguage = EfficientNetLabelLanguage[formattedLanguage];
49 | const languageProvider = new EfficientNetLanguageProvider(
50 | labelLanguage
51 | );
52 | await languageProvider.load();
53 | const result = await model.inference(
54 | filePath,
55 | null,
56 | languageProvider
57 | );
58 | res.send(result);
59 | }
60 | }
61 | } catch (err) {
62 | console.error(err);
63 | res.status(500).send("Something went wrong");
64 | }
65 | });
66 |
67 | router.get("/api/languages", async (req, res) => {
68 | try {
69 | const languagesEnumKeys = Object.keys(EfficientNetLabelLanguage);
70 | const languagesAmount = languagesEnumKeys.length / 2;
71 | const languagesArr = languagesEnumKeys.slice(languagesAmount);
72 |
73 | const formattedLanguagesArr = languagesArr
74 | .map((language) => language.toLowerCase())
75 | .map((item) => item.charAt(0).toUpperCase() + item.slice(1));
76 |
77 | res.send(formattedLanguagesArr);
78 | } catch (err) {
79 | console.error(err);
80 | res.status(500).send("Something went wrong");
81 | }
82 | });
83 |
84 | router.get("/api/version", async (req, res) => {
85 | res.send({ version: "1.0" });
86 | });
87 |
88 | app.use(urlencoded({ extended: true }));
89 | app.use(json());
90 | app.use(formidable());
91 | app.use(bodyParserErrorHandler());
92 | app.use(router);
93 | return app;
94 | };
95 |
96 | const createServer = async () => {
97 | const model = await EfficientNetCheckPointFactory.create(
98 | EfficientNetCheckPoint.B7
99 | );
100 | console.log("model loaded starting server.");
101 | return initServer(model);
102 | };
103 |
104 | export { createServer };
105 |
--------------------------------------------------------------------------------
/playground/ui/.browserslistrc:
--------------------------------------------------------------------------------
1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
2 | # For additional information regarding the format and rule options, please see:
3 | # https://github.com/browserslist/browserslist#queries
4 |
5 | # For the full list of supported browsers by the Angular framework, please see:
6 | # https://angular.io/guide/browser-support
7 |
8 | # You can see what browsers were selected by your queries by running:
9 | # npx browserslist
10 |
11 | last 1 Chrome version
12 | last 1 Firefox version
13 | last 2 Edge major versions
14 | last 2 Safari major versions
15 | last 2 iOS major versions
16 | Firefox ESR
17 | not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
18 |
--------------------------------------------------------------------------------
/playground/ui/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.ts]
12 | quote_type = single
13 |
14 | [*.md]
15 | max_line_length = off
16 | trim_trailing_whitespace = false
17 |
--------------------------------------------------------------------------------
/playground/ui/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /tmp
6 | /out-tsc
7 | # Only exists if Bazel was run
8 | /bazel-out
9 |
10 | # dependencies
11 | /node_modules
12 |
13 | # profiling files
14 | chrome-profiler-events*.json
15 | speed-measure-plugin*.json
16 |
17 | # IDEs and editors
18 | /.idea
19 | .project
20 | .classpath
21 | .c9/
22 | *.launch
23 | .settings/
24 | *.sublime-workspace
25 |
26 | # IDE - VSCode
27 | .vscode/*
28 | !.vscode/settings.json
29 | !.vscode/tasks.json
30 | !.vscode/launch.json
31 | !.vscode/extensions.json
32 | .history/*
33 |
34 | # misc
35 | /.angular/cache
36 | /.sass-cache
37 | /connect.lock
38 | /coverage
39 | /libpeerconnection.log
40 | npm-debug.log
41 | yarn-error.log
42 | testem.log
43 | /typings
44 |
45 | # System Files
46 | .DS_Store
47 | Thumbs.db
48 |
--------------------------------------------------------------------------------
/playground/ui/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:14.16.1-buster as node-efficientnet-client
2 | WORKDIR /app
3 | COPY package*.json ./
4 | RUN npm install
5 | COPY . .
6 | RUN npm run build
7 |
8 | FROM nginx
9 | RUN rm -rf /usr/share/nginx/html/*
10 | COPY ./nginx.conf /etc/nginx/nginx.conf
11 | COPY --from=node-efficientnet-client /app/dist/playground /usr/share/nginx/html
12 | EXPOSE 80
13 |
--------------------------------------------------------------------------------
/playground/ui/README.md:
--------------------------------------------------------------------------------
1 | # Playground
2 |
3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 11.0.6.
4 |
5 | ## Development server
6 |
7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
8 |
9 | ## Code scaffolding
10 |
11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
12 |
13 | ## Build
14 |
15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
16 |
17 | ## Running unit tests
18 |
19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
20 |
21 | ## Running end-to-end tests
22 |
23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
24 |
25 | ## Further help
26 |
27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
28 |
--------------------------------------------------------------------------------
/playground/ui/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "playground": {
7 | "projectType": "application",
8 | "schematics": {
9 | "@schematics/angular:component": {
10 | "style": "scss"
11 | }
12 | },
13 | "root": "",
14 | "sourceRoot": "src",
15 | "prefix": "app",
16 | "architect": {
17 | "build": {
18 | "builder": "@angular-devkit/build-angular:browser",
19 | "options": {
20 | "outputPath": "dist/playground",
21 | "index": "src/index.html",
22 | "main": "src/main.ts",
23 | "polyfills": "src/polyfills.ts",
24 | "tsConfig": "tsconfig.app.json",
25 | "assets": [
26 | "src/favicon.ico",
27 | "src/assets"
28 | ],
29 | "styles": [
30 | "src/styles.scss",
31 | "node_modules/primeng/resources/themes/bootstrap4-light-blue/theme.css",
32 | "node_modules/primeng/resources/primeng.min.css",
33 | "node_modules/primeicons/primeicons.css"
34 | ],
35 | "scripts": [],
36 | "vendorChunk": true,
37 | "extractLicenses": false,
38 | "buildOptimizer": false,
39 | "sourceMap": true,
40 | "optimization": false,
41 | "namedChunks": true
42 | },
43 | "configurations": {
44 | "production": {
45 | "fileReplacements": [
46 | {
47 | "replace": "src/environments/environment.ts",
48 | "with": "src/environments/environment.prod.ts"
49 | }
50 | ],
51 | "optimization": true,
52 | "outputHashing": "all",
53 | "sourceMap": false,
54 | "namedChunks": false,
55 | "extractLicenses": true,
56 | "vendorChunk": false,
57 | "buildOptimizer": true,
58 | "budgets": [
59 | {
60 | "type": "initial",
61 | "maximumWarning": "2mb",
62 | "maximumError": "5mb"
63 | },
64 | {
65 | "type": "anyComponentStyle",
66 | "maximumWarning": "6kb",
67 | "maximumError": "10kb"
68 | }
69 | ]
70 | }
71 | },
72 | "defaultConfiguration": ""
73 | },
74 | "serve": {
75 | "builder": "@angular-devkit/build-angular:dev-server",
76 | "options": {
77 | "browserTarget": "playground:build",
78 | "proxyConfig": "src/proxy.conf.json"
79 | },
80 | "configurations": {
81 | "production": {
82 | "browserTarget": "playground:build:production"
83 | }
84 | }
85 | },
86 | "extract-i18n": {
87 | "builder": "@angular-devkit/build-angular:extract-i18n",
88 | "options": {
89 | "browserTarget": "playground:build"
90 | }
91 | },
92 | "test": {
93 | "builder": "@angular-devkit/build-angular:karma",
94 | "options": {
95 | "main": "src/test.ts",
96 | "polyfills": "src/polyfills.ts",
97 | "tsConfig": "tsconfig.spec.json",
98 | "karmaConfig": "karma.conf.js",
99 | "assets": [
100 | "src/favicon.ico",
101 | "src/assets"
102 | ],
103 | "styles": [
104 | "src/styles.scss",
105 | "node_modules/primeng/resources/themes/bootstrap4-light-blue/theme.css",
106 | "node_modules/primeng/resources/primeng.min.css",
107 | "node_modules/primeicons/primeicons.css"
108 | ],
109 | "scripts": []
110 | }
111 | },
112 | "e2e": {
113 | "builder": "@angular-devkit/build-angular:protractor",
114 | "options": {
115 | "protractorConfig": "e2e/protractor.conf.js",
116 | "devServerTarget": "playground:serve"
117 | },
118 | "configurations": {
119 | "production": {
120 | "devServerTarget": "playground:serve:production"
121 | }
122 | }
123 | }
124 | }
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/playground/ui/e2e/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | // Protractor configuration file, see link for more information
3 | // https://github.com/angular/protractor/blob/master/lib/config.ts
4 |
5 | const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
6 |
7 | /**
8 | * @type { import("protractor").Config }
9 | */
10 | exports.config = {
11 | allScriptsTimeout: 11000,
12 | specs: [
13 | './src/**/*.e2e-spec.ts'
14 | ],
15 | capabilities: {
16 | browserName: 'chrome'
17 | },
18 | directConnect: true,
19 | SELENIUM_PROMISE_MANAGER: false,
20 | baseUrl: 'http://localhost:4200/',
21 | framework: 'jasmine',
22 | jasmineNodeOpts: {
23 | showColors: true,
24 | defaultTimeoutInterval: 30000,
25 | print: function() {}
26 | },
27 | onPrepare() {
28 | require('ts-node').register({
29 | project: require('path').join(__dirname, './tsconfig.json')
30 | });
31 | jasmine.getEnv().addReporter(new SpecReporter({
32 | spec: {
33 | displayStacktrace: StacktraceOption.PRETTY
34 | }
35 | }));
36 | }
37 | };
--------------------------------------------------------------------------------
/playground/ui/e2e/src/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { AppPage } from './app.po';
2 | import { browser, logging } from 'protractor';
3 |
4 | describe('workspace-project App', () => {
5 | let page: AppPage;
6 |
7 | beforeEach(() => {
8 | page = new AppPage();
9 | });
10 |
11 | it('should display welcome message', async () => {
12 | await page.navigateTo();
13 | expect(await page.getTitleText()).toEqual('playground app is running!');
14 | });
15 |
16 | afterEach(async () => {
17 | // Assert that there are no errors emitted from the browser
18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER);
19 | expect(logs).not.toContain(
20 | jasmine.objectContaining({
21 | level: logging.Level.SEVERE,
22 | } as logging.Entry)
23 | );
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/playground/ui/e2e/src/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, by, element } from 'protractor';
2 |
3 | export class AppPage {
4 | async navigateTo(): Promise {
5 | return browser.get(browser.baseUrl);
6 | }
7 |
8 | async getTitleText(): Promise {
9 | return element(by.css('app-root .content span')).getText();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/playground/ui/e2e/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "../tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "../out-tsc/e2e",
6 | "module": "commonjs",
7 | "target": "es2018",
8 | "types": [
9 | "jasmine",
10 | "node"
11 | ]
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/playground/ui/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | jasmine: {
17 | // you can add configuration options for Jasmine here
18 | // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html
19 | // for example, you can disable the random execution with `random: false`
20 | // or set a specific seed with `seed: 4321`
21 | },
22 | clearContext: false // leave Jasmine Spec Runner output visible in browser
23 | },
24 | jasmineHtmlReporter: {
25 | suppressAll: true // removes the duplicated traces
26 | },
27 | coverageReporter: {
28 | dir: require('path').join(__dirname, './coverage/playground'),
29 | subdir: '.',
30 | reporters: [
31 | { type: 'html' },
32 | { type: 'text-summary' }
33 | ]
34 | },
35 | reporters: ['progress', 'kjhtml'],
36 | port: 9876,
37 | colors: true,
38 | logLevel: config.LOG_INFO,
39 | autoWatch: true,
40 | browsers: ['Chrome'],
41 | singleRun: false,
42 | restartOnFileChange: true
43 | });
44 | };
45 |
--------------------------------------------------------------------------------
/playground/ui/nginx.conf:
--------------------------------------------------------------------------------
1 | worker_processes 1;
2 |
3 | events { worker_connections 1024; }
4 |
5 | http {
6 | include /etc/nginx/mime.types;
7 |
8 | upstream node-app {
9 | server node-server:3000 weight=1 max_fails=3 fail_timeout=30s;
10 | }
11 |
12 | server {
13 | listen 80;
14 | root /usr/share/nginx/html;
15 |
16 | location /api/upload {
17 | proxy_pass http://node-app;
18 | }
19 |
20 | location / {
21 | root /usr/share/nginx/html;
22 | index index.html index.htm;
23 | try_files $uri $uri/ /index.html;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/playground/ui/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "playground",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "ng": "ng",
6 | "start": "ng serve",
7 | "build": "ng build",
8 | "test": "ng test",
9 | "lint": "ng lint",
10 | "e2e": "ng e2e"
11 | },
12 | "private": true,
13 | "dependencies": {
14 | "@angular/animations": "^14.2.3",
15 | "@angular/cdk": "^14.2.2",
16 | "@angular/common": "^14.2.3",
17 | "@angular/compiler": "^14.2.3",
18 | "@angular/core": "^14.2.3",
19 | "@angular/forms": "^14.2.3",
20 | "@angular/platform-browser": "^14.2.3",
21 | "@angular/platform-browser-dynamic": "^14.2.3",
22 | "@angular/router": "^14.2.3",
23 | "github-fork-ribbon-css": "^0.2.3",
24 | "primeicons": "^4.1.0",
25 | "primeng": "^11.1.0-rc.1",
26 | "rxjs": "~6.6.0",
27 | "tslib": "^2.0.0",
28 | "zone.js": "~0.11.4"
29 | },
30 | "devDependencies": {
31 | "@angular-devkit/build-angular": "^14.2.3",
32 | "@angular/cli": "^14.2.3",
33 | "@angular/compiler-cli": "^14.2.3",
34 | "@types/jasmine": "~3.6.0",
35 | "@types/node": "^12.11.1",
36 | "codelyzer": "^6.0.0",
37 | "jasmine-core": "~3.6.0",
38 | "jasmine-spec-reporter": "~5.0.0",
39 | "karma": "~6.4.1",
40 | "karma-chrome-launcher": "~3.1.0",
41 | "karma-coverage": "~2.0.3",
42 | "karma-jasmine": "~4.0.0",
43 | "karma-jasmine-html-reporter": "^1.5.0",
44 | "protractor": "~7.0.0",
45 | "ts-node": "~8.3.0",
46 | "tslint": "~6.1.0",
47 | "typescript": "~4.6.4"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/playground/ui/src/app/app-routing.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { Routes, RouterModule } from '@angular/router';
3 | import { UploaderComponent } from './uploader/uploader.component';
4 |
5 | const routes: Routes = [{ path: '', component: UploaderComponent }];
6 |
7 | @NgModule({
8 | imports: [RouterModule.forRoot(routes)],
9 | exports: [RouterModule],
10 | })
11 | export class AppRoutingModule {}
12 |
--------------------------------------------------------------------------------
/playground/ui/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/playground/ui/src/app/app.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/playground/ui/src/app/app.component.scss
--------------------------------------------------------------------------------
/playground/ui/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 | import { RouterTestingModule } from '@angular/router/testing';
3 | import { AppComponent } from './app.component';
4 |
5 | describe('AppComponent', () => {
6 | beforeEach(async () => {
7 | await TestBed.configureTestingModule({
8 | imports: [RouterTestingModule],
9 | declarations: [AppComponent],
10 | }).compileComponents();
11 | });
12 |
13 | it('should create the app', () => {
14 | const fixture = TestBed.createComponent(AppComponent);
15 | const app = fixture.componentInstance;
16 | expect(app).toBeTruthy();
17 | });
18 |
19 | it(`should have as title 'playground'`, () => {
20 | const fixture = TestBed.createComponent(AppComponent);
21 | const app = fixture.componentInstance;
22 | expect(app.title).toEqual('node-efficientnet playground');
23 | });
24 |
25 | it('should render title', () => {
26 | const fixture = TestBed.createComponent(AppComponent);
27 | fixture.detectChanges();
28 | const compiled = fixture.nativeElement;
29 | expect(compiled.querySelector('.github-fork-ribbon').textContent).toContain(
30 | 'Fork me on GitHub'
31 | );
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/playground/ui/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { PrimeNGConfig } from 'primeng/api';
3 |
4 | @Component({
5 | selector: 'app-root',
6 | templateUrl: './app.component.html',
7 | styleUrls: ['./app.component.scss'],
8 | })
9 | export class AppComponent {
10 | title = 'node-efficientnet playground';
11 | constructor(private primengConfig: PrimeNGConfig) {}
12 | ngOnInit() {
13 | this.primengConfig.ripple = true;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/playground/ui/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { BrowserModule } from '@angular/platform-browser';
2 | import { NgModule , CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
3 | import { PrimeNgModuleLoaders } from './primeng-imports';
4 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
5 | import { AppRoutingModule } from './app-routing.module';
6 | import { AppComponent } from './app.component';
7 | import { UploaderComponent } from './uploader/uploader.component';
8 | import { HeaderComponent } from './header/header.component';
9 | import { ImageuploaderComponent } from './imageuploader/imageuploader.component';
10 | import { HttpClientModule } from '@angular/common/http';
11 | import { NoteComponent } from './note/note.component';
12 | import { ResultsComponent } from './results/results.component';
13 | import { SingleResultComponent } from './single-result/single-result.component';
14 | import { FormsModule } from '@angular/forms';
15 |
16 |
17 | @NgModule({
18 | declarations: [
19 | AppComponent,
20 | UploaderComponent,
21 | HeaderComponent,
22 | ImageuploaderComponent,
23 | NoteComponent,
24 | ResultsComponent,
25 | SingleResultComponent,
26 | ],
27 | schemas: [CUSTOM_ELEMENTS_SCHEMA],
28 | imports: [
29 | HttpClientModule,
30 | BrowserModule,
31 | AppRoutingModule,
32 | PrimeNgModuleLoaders,
33 | BrowserAnimationsModule,
34 | FormsModule
35 | ],
36 | providers: [],
37 | bootstrap: [AppComponent],
38 | })
39 | export class AppModule {}
40 |
--------------------------------------------------------------------------------
/playground/ui/src/app/header/header.component.html:
--------------------------------------------------------------------------------
1 |
2 |
Try node-efficientnet
3 |
Use the application below to return image annotations for your image file. Click the Choose button to upload image.
4 |
5 | Maximum file size is 4MB.
6 | Your browser must have JavaScript enabled.
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/playground/ui/src/app/header/header.component.scss:
--------------------------------------------------------------------------------
1 | [header-container]{
2 | width:80vh;
3 | padding-left:40px;
4 | padding-right:40px;
5 | }
6 |
7 | [header]{
8 | font-size: 28px;
9 | }
10 |
--------------------------------------------------------------------------------
/playground/ui/src/app/header/header.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { HeaderComponent } from './header.component';
4 |
5 | describe('HeaderComponent', () => {
6 | let component: HeaderComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async () => {
10 | await TestBed.configureTestingModule({
11 | declarations: [HeaderComponent],
12 | }).compileComponents();
13 | });
14 |
15 | beforeEach(() => {
16 | fixture = TestBed.createComponent(HeaderComponent);
17 | component = fixture.componentInstance;
18 | fixture.detectChanges();
19 | });
20 |
21 | it('should create', () => {
22 | expect(component).toBeTruthy();
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/playground/ui/src/app/header/header.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-header',
5 | templateUrl: './header.component.html',
6 | styleUrls: ['./header.component.scss'],
7 | })
8 | export class HeaderComponent implements OnInit {
9 | constructor() {}
10 |
11 | ngOnInit(): void {}
12 | }
13 |
--------------------------------------------------------------------------------
/playground/ui/src/app/imageuploader/imageuploader.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Results language :
4 |
5 |
6 |
7 |
9 |
10 |
11 | {{file.name}} - {{file.size}} bytes
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/playground/ui/src/app/imageuploader/imageuploader.component.scss:
--------------------------------------------------------------------------------
1 | [languages-container]{
2 | width:80vh;
3 | padding-left:40px;
4 | padding-right:40px;
5 | padding-top:40px;
6 | font-family: 'Roboto', sans-serif;
7 | }
8 | [upload-image-wrapper]{
9 | padding: 40px;
10 | }
11 |
--------------------------------------------------------------------------------
/playground/ui/src/app/imageuploader/imageuploader.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { ImageuploaderComponent } from './imageuploader.component';
4 |
5 | describe('ImageuploaderComponent', () => {
6 | let component: ImageuploaderComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async () => {
10 | await TestBed.configureTestingModule({
11 | declarations: [ImageuploaderComponent],
12 | }).compileComponents();
13 | });
14 |
15 | beforeEach(() => {
16 | fixture = TestBed.createComponent(ImageuploaderComponent);
17 | component = fixture.componentInstance;
18 | fixture.detectChanges();
19 | });
20 |
21 | it('should create', () => {
22 | expect(component).toBeTruthy();
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/playground/ui/src/app/imageuploader/imageuploader.component.ts:
--------------------------------------------------------------------------------
1 | import {Component, OnInit, Output, EventEmitter, ViewChild} from '@angular/core';
2 | import {MessageService, SelectItem} from 'primeng/api';
3 | import {HttpClient} from '@angular/common/http';
4 | import Prediction from '../interfces';
5 | import {LanguagesApiService} from '../languages-api.service'
6 |
7 | @Component({
8 | selector: 'app-imageuploader',
9 | templateUrl: './imageuploader.component.html',
10 | styleUrls: ['./imageuploader.component.scss'],
11 | providers: [MessageService, HttpClient],
12 | })
13 | export class ImageuploaderComponent implements OnInit {
14 | constructor(private messageService: MessageService, private languagesApi: LanguagesApiService) {
15 | }
16 |
17 | languages: SelectItem[];
18 | selectedLanguage: SelectItem;
19 | selectedLanguageName: string;
20 |
21 | uploadedFiles: any[] = [];
22 |
23 | @Output() updateImage = new EventEmitter();
24 | @Output() updateClassification = new EventEmitter();
25 | @Output() isLoading = new EventEmitter();
26 | @Output("resetFields") resetFields: EventEmitter = new EventEmitter();
27 |
28 | ngOnInit(): void {
29 | this.languagesApi.getLanguages().subscribe((data) => {
30 | const languagesArray = Object.values(data);
31 | this.languages = languagesArray.map(language => ({label: language, value: null}));
32 | this.selectedLanguage = this.languages[0];
33 | this.selectedLanguageName = this.getSelectedLanguageName();
34 | });
35 | }
36 |
37 | onChange(event) {
38 | this.selectedLanguageName = this.getSelectedLanguageName();
39 | //Reset component file field
40 | this.uploadedFiles=[];
41 | //Reset parent fields
42 | this.resetFields.emit();
43 | }
44 |
45 | onUpload(event) {
46 | const result = event.originalEvent.body.result as Prediction[];
47 | this.updateClassification.emit(result);
48 | this.uploadedFiles = [event.files[event.files.length - 1]];
49 | this.messageService.add({
50 | severity: 'info',
51 | summary: 'File Uploaded',
52 | detail: '',
53 | });
54 | this.isLoading.emit(true);
55 | }
56 |
57 | onSend(event) {
58 | this.isLoading.emit(false);
59 | this.uploadedFiles = [];
60 | this.updateImage.emit(event.formData.get('file'));
61 | }
62 | getSelectedLanguageName(){
63 | return this.selectedLanguage.label.toLowerCase();
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/playground/ui/src/app/interfces/index.ts:
--------------------------------------------------------------------------------
1 | export default interface Prediction {
2 | label: string;
3 | precision: number;
4 | }
5 |
--------------------------------------------------------------------------------
/playground/ui/src/app/languages-api.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 |
3 | import { LanguagesApiService } from './languages-api.service';
4 |
5 | describe('LanguagesApiService', () => {
6 | let service: LanguagesApiService;
7 |
8 | beforeEach(() => {
9 | TestBed.configureTestingModule({});
10 | service = TestBed.inject(LanguagesApiService);
11 | });
12 |
13 | it('should be created', () => {
14 | expect(service).toBeTruthy();
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/playground/ui/src/app/languages-api.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpClient } from '@angular/common/http';
3 |
4 |
5 | @Injectable({
6 | providedIn: 'root'
7 | })
8 | export class LanguagesApiService {
9 |
10 |
11 | constructor(private http:HttpClient) { }
12 |
13 | getLanguages(){
14 | return this.http.get('/api/languages');
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/playground/ui/src/app/note/note.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Note: Efficientnet API offers 8 checkpoints for object detection , each checkpoint change image resolution and prediction execution time
4 | this demo uses checkpoint B7
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/playground/ui/src/app/note/note.component.scss:
--------------------------------------------------------------------------------
1 | [note-container]{
2 | background-color: #E1F4FE;
3 | padding: 20px;
4 | font-family: 'Roboto', sans-serif;
5 | }
6 |
7 | ul {
8 | list-style: none;
9 | padding: 0;
10 | }
11 | li {
12 | padding-left: 1.3em;
13 | }
14 | li:before {
15 | content: "\f005"; /* FontAwesome Unicode */
16 | font-family: FontAwesome;
17 | display: inline-block;
18 | margin-left: -1.3em; /* same as padding-left set on li */
19 | width: 1.6em; /* same as padding-left set on li */
20 | }
21 |
--------------------------------------------------------------------------------
/playground/ui/src/app/note/note.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { NoteComponent } from './note.component';
4 |
5 | describe('NoteComponent', () => {
6 | let component: NoteComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async () => {
10 | await TestBed.configureTestingModule({
11 | declarations: [NoteComponent],
12 | }).compileComponents();
13 | });
14 |
15 | beforeEach(() => {
16 | fixture = TestBed.createComponent(NoteComponent);
17 | component = fixture.componentInstance;
18 | fixture.detectChanges();
19 | });
20 |
21 | it('should create', () => {
22 | expect(component).toBeTruthy();
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/playground/ui/src/app/note/note.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-note',
5 | templateUrl: './note.component.html',
6 | styleUrls: ['./note.component.scss'],
7 | })
8 | export class NoteComponent implements OnInit {
9 | constructor() {}
10 |
11 | ngOnInit(): void {}
12 | }
13 |
--------------------------------------------------------------------------------
/playground/ui/src/app/primeng-imports.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { ButtonModule } from 'primeng/button';
3 | import { PanelModule } from 'primeng/panel';
4 | import { TabViewModule } from 'primeng/tabview';
5 | import { InputTextModule } from 'primeng/inputtext';
6 | import { ToastModule } from 'primeng/toast';
7 | import { RippleModule } from 'primeng/ripple';
8 | import { FileUploadModule } from 'primeng/fileupload';
9 | import { DividerModule } from 'primeng/divider';
10 | import { ProgressBarModule } from 'primeng/progressbar';
11 | import { SkeletonModule } from 'primeng/skeleton';
12 | import {DropdownModule} from 'primeng/dropdown';
13 |
14 |
15 | @NgModule({
16 | exports: [
17 | ButtonModule,
18 | ProgressBarModule,
19 | PanelModule,
20 | TabViewModule,
21 | InputTextModule,
22 | ToastModule,
23 | RippleModule,
24 | FileUploadModule,
25 | DividerModule,
26 | SkeletonModule,
27 | DropdownModule
28 | ],
29 | })
30 | export class PrimeNgModuleLoaders {}
31 |
--------------------------------------------------------------------------------
/playground/ui/src/app/results/results.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/playground/ui/src/app/results/results.component.scss:
--------------------------------------------------------------------------------
1 | [ results-container]{
2 | display: flex;
3 | padding-right: 40px;
4 | padding-left: 40px;
5 | padding-bottom: 20px;
6 | justify-content: space-between;
7 | max-height: 300px;
8 | }
9 | [flex-container]{
10 | min-height: 200px;
11 | padding: 20px;
12 | flex: 1;
13 | box-shadow: var(--devsite-page-box-shadow,0 1px 2px 0 rgba(60,64,67,.3),0 1px 3px 1px rgba(60,64,67,.15));
14 | }
15 |
16 | [results]{
17 |
18 | }
19 | [image-contianer]{
20 | img {
21 | max-width: 100%;
22 | max-height: 100%;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/playground/ui/src/app/results/results.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { ResultsComponent } from './results.component';
4 |
5 | describe('ResultsComponent', () => {
6 | let component: ResultsComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async () => {
10 | await TestBed.configureTestingModule({
11 | declarations: [ResultsComponent],
12 | }).compileComponents();
13 | });
14 |
15 | beforeEach(() => {
16 | fixture = TestBed.createComponent(ResultsComponent);
17 | component = fixture.componentInstance;
18 | fixture.detectChanges();
19 | });
20 |
21 | it('should create', () => {
22 | expect(component).toBeTruthy();
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/playground/ui/src/app/results/results.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, OnInit, OnChanges } from '@angular/core';
2 | import Prediction from '../interfces';
3 |
4 | @Component({
5 | selector: 'app-results',
6 | templateUrl: './results.component.html',
7 | styleUrls: ['./results.component.scss'],
8 | })
9 | export class ResultsComponent implements OnInit, OnChanges {
10 | @Input() image2Display: string | ArrayBuffer;
11 | @Input() loading: boolean;
12 | @Input() classifications: Prediction[];
13 |
14 | constructor() {}
15 |
16 | show(): boolean {
17 | if (this.loading === undefined) {
18 | return false;
19 | }
20 | return this.loading;
21 | }
22 |
23 | ngOnChanges() {}
24 |
25 | ngOnInit(): void {}
26 | }
27 |
--------------------------------------------------------------------------------
/playground/ui/src/app/single-result/single-result.component.html:
--------------------------------------------------------------------------------
1 |
5 |
8 |
--------------------------------------------------------------------------------
/playground/ui/src/app/single-result/single-result.component.scss:
--------------------------------------------------------------------------------
1 | [placeholder] {
2 | padding: 24px;
3 | min-height: 10px;
4 | }
5 |
--------------------------------------------------------------------------------
/playground/ui/src/app/single-result/single-result.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { SingleResultComponent } from './single-result.component';
4 |
5 | describe('SingleResultComponent', () => {
6 | let component: SingleResultComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async () => {
10 | await TestBed.configureTestingModule({
11 | declarations: [SingleResultComponent],
12 | }).compileComponents();
13 | });
14 |
15 | beforeEach(() => {
16 | fixture = TestBed.createComponent(SingleResultComponent);
17 | component = fixture.componentInstance;
18 | fixture.detectChanges();
19 | });
20 |
21 | it('should create', () => {
22 | expect(component).toBeTruthy();
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/playground/ui/src/app/single-result/single-result.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-single-result',
5 | templateUrl: './single-result.component.html',
6 | styleUrls: ['./single-result.component.scss'],
7 | })
8 | export class SingleResultComponent implements OnInit {
9 | @Input() acc: number;
10 | @Input() title: string;
11 | @Input() loading: boolean;
12 |
13 | constructor() {}
14 |
15 | show(): boolean {
16 | return this.loading;
17 | }
18 |
19 | ngOnInit(): void {}
20 | }
21 |
--------------------------------------------------------------------------------
/playground/ui/src/app/uploader/uploader.component.html:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/playground/ui/src/app/uploader/uploader.component.scss:
--------------------------------------------------------------------------------
1 | [upload-page]{
2 | background-color: white;
3 | width: 60vw;
4 | max-width: 1024px;
5 | min-width: 900px;
6 | box-shadow: var(--devsite-page-box-shadow,0 1px 2px 0 rgba(60,64,67,.3),0 1px 3px 1px rgba(60,64,67,.15));
7 | display: flex;
8 | flex-direction: column;
9 | }
10 |
--------------------------------------------------------------------------------
/playground/ui/src/app/uploader/uploader.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { UploaderComponent } from './uploader.component';
4 |
5 | describe('UploaderComponent', () => {
6 | let component: UploaderComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async () => {
10 | await TestBed.configureTestingModule({
11 | declarations: [UploaderComponent],
12 | }).compileComponents();
13 | });
14 |
15 | beforeEach(() => {
16 | fixture = TestBed.createComponent(UploaderComponent);
17 | component = fixture.componentInstance;
18 | fixture.detectChanges();
19 | });
20 |
21 | it('should create', () => {
22 | expect(component).toBeTruthy();
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/playground/ui/src/app/uploader/uploader.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import Prediction from '../interfces';
3 |
4 | @Component({
5 | selector: 'app-uploader',
6 | templateUrl: './uploader.component.html',
7 | styleUrls: ['./uploader.component.scss'],
8 | })
9 | export class UploaderComponent implements OnInit {
10 | constructor() {}
11 |
12 | image2Display: string | ArrayBuffer;
13 | classifications: Prediction[];
14 | loading: boolean;
15 |
16 | updateImage(imgPath: File) {
17 | const reader = new FileReader();
18 | reader.readAsDataURL(imgPath);
19 | reader.onload = (_event) => {
20 | this.image2Display = reader.result;
21 | };
22 | }
23 | isLoading(loading: boolean) {
24 | this.loading = loading;
25 | }
26 |
27 | updateClassification(result: Prediction[]) {
28 | console.log('updateClassification');
29 | console.log(result);
30 | this.classifications = result;
31 | }
32 |
33 | resetFields(){
34 | this.image2Display=null;
35 | this.classifications=null;
36 | this.loading=false;
37 | }
38 |
39 | ngOnInit(): void {}
40 | }
41 |
--------------------------------------------------------------------------------
/playground/ui/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/playground/ui/src/assets/.gitkeep
--------------------------------------------------------------------------------
/playground/ui/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | };
4 |
--------------------------------------------------------------------------------
/playground/ui/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // This file can be replaced during build by using the `fileReplacements` array.
2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
3 | // The list of file replacements can be found in `angular.json`.
4 |
5 | export const environment = {
6 | production: false,
7 | };
8 |
9 | /*
10 | * For easier debugging in development mode, you can import the following file
11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
12 | *
13 | * This import should be commented out in production mode because it will have a negative impact
14 | * on performance if an error is thrown.
15 | */
16 | // import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
17 |
--------------------------------------------------------------------------------
/playground/ui/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/playground/ui/src/favicon.ico
--------------------------------------------------------------------------------
/playground/ui/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Node Efficientnet Playground
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/playground/ui/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic()
12 | .bootstrapModule(AppModule)
13 | .catch((err) => console.error(err));
14 |
--------------------------------------------------------------------------------
/playground/ui/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /**
22 | * By default, zone.js will patch all possible macroTask and DomEvents
23 | * user can disable parts of macroTask/DomEvents patch by setting following flags
24 | * because those flags need to be set before `zone.js` being loaded, and webpack
25 | * will put import in the top of bundle, so user need to create a separate file
26 | * in this directory (for example: zone-flags.ts), and put the following flags
27 | * into that file, and then add the following code before importing zone.js.
28 | * import './zone-flags';
29 | *
30 | * The flags allowed in zone-flags.ts are listed here.
31 | *
32 | * The following flags will work for all browsers.
33 | *
34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
37 | *
38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
40 | *
41 | * (window as any).__Zone_enable_cross_context_check = true;
42 | *
43 | */
44 |
45 | /***************************************************************************************************
46 | * Zone JS is required by default for Angular itself.
47 | */
48 | import 'zone.js'; // Included with Angular CLI.
49 |
50 | /***************************************************************************************************
51 | * APPLICATION IMPORTS
52 | */
53 |
--------------------------------------------------------------------------------
/playground/ui/src/proxy.conf.json:
--------------------------------------------------------------------------------
1 | {
2 | "/api/upload/*": {
3 | "target": "http://localhost:3000",
4 | "secure": false,
5 | "logLevel": "debug"
6 | },
7 | "/api/languages": {
8 | "target": "http://localhost:3000",
9 | "secure": false,
10 | "logLevel": "debug"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/playground/ui/src/styles.scss:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | [window] {
3 | position: absolute;
4 | left: 0;
5 | right: 0;
6 | top: 0;
7 | bottom: 0;
8 | width: 100%;
9 | min-height: 100%;
10 | display: flex;
11 | justify-content: center;
12 | align-items: center;
13 | background-color: #E7EAED;
14 | }
15 | [text]{
16 | font-family: 'Roboto', sans-serif;
17 | }
18 |
--------------------------------------------------------------------------------
/playground/ui/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/testing';
4 | import { getTestBed } from '@angular/core/testing';
5 | import {
6 | BrowserDynamicTestingModule,
7 | platformBrowserDynamicTesting,
8 | } from '@angular/platform-browser-dynamic/testing';
9 |
10 | declare const require: {
11 | context(
12 | path: string,
13 | deep?: boolean,
14 | filter?: RegExp
15 | ): {
16 | keys(): string[];
17 | (id: string): T;
18 | };
19 | };
20 |
21 | // First, initialize the Angular testing environment.
22 | getTestBed().initTestEnvironment(
23 | BrowserDynamicTestingModule,
24 | platformBrowserDynamicTesting(), {
25 | teardown: { destroyAfterEach: false }
26 | }
27 | );
28 | // Then we find all the tests.
29 | const context = require.context('./', true, /\.spec\.ts$/);
30 | // And load the modules.
31 | context.keys().map(context);
32 |
--------------------------------------------------------------------------------
/playground/ui/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts",
10 | "src/polyfills.ts"
11 | ],
12 | "include": [
13 | "src/**/*.d.ts"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/playground/ui/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "outDir": "./dist/out-tsc",
7 | "sourceMap": true,
8 | "declaration": false,
9 | "downlevelIteration": true,
10 | "experimentalDecorators": true,
11 | "moduleResolution": "node",
12 | "importHelpers": true,
13 | "target": "es2020",
14 | "module": "es2020",
15 | "lib": [
16 | "es2018",
17 | "dom"
18 | ]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/playground/ui/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "files": [
11 | "src/test.ts",
12 | "src/polyfills.ts"
13 | ],
14 | "include": [
15 | "src/**/*.spec.ts",
16 | "src/**/*.d.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/playground/ui/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tslint:recommended",
3 | "rulesDirectory": [
4 | "codelyzer"
5 | ],
6 | "rules": {
7 | "align": {
8 | "options": [
9 | "parameters",
10 | "statements"
11 | ]
12 | },
13 | "array-type": false,
14 | "arrow-return-shorthand": true,
15 | "curly": true,
16 | "deprecation": {
17 | "severity": "warning"
18 | },
19 | "eofline": true,
20 | "import-blacklist": [
21 | true,
22 | "rxjs/Rx"
23 | ],
24 | "import-spacing": true,
25 | "indent": {
26 | "options": [
27 | "spaces"
28 | ]
29 | },
30 | "max-classes-per-file": false,
31 | "max-line-length": [
32 | true,
33 | 140
34 | ],
35 | "member-ordering": [
36 | true,
37 | {
38 | "order": [
39 | "static-field",
40 | "instance-field",
41 | "static-method",
42 | "instance-method"
43 | ]
44 | }
45 | ],
46 | "no-console": [
47 | true,
48 | "debug",
49 | "info",
50 | "time",
51 | "timeEnd",
52 | "trace"
53 | ],
54 | "no-empty": false,
55 | "no-inferrable-types": [
56 | true,
57 | "ignore-params"
58 | ],
59 | "no-non-null-assertion": true,
60 | "no-redundant-jsdoc": true,
61 | "no-switch-case-fall-through": true,
62 | "no-var-requires": false,
63 | "object-literal-key-quotes": [
64 | true,
65 | "as-needed"
66 | ],
67 | "quotemark": [
68 | true,
69 | "single"
70 | ],
71 | "semicolon": {
72 | "options": [
73 | "always"
74 | ]
75 | },
76 | "space-before-function-paren": {
77 | "options": {
78 | "anonymous": "never",
79 | "asyncArrow": "always",
80 | "constructor": "never",
81 | "method": "never",
82 | "named": "never"
83 | }
84 | },
85 | "typedef": [
86 | true,
87 | "call-signature"
88 | ],
89 | "typedef-whitespace": {
90 | "options": [
91 | {
92 | "call-signature": "nospace",
93 | "index-signature": "nospace",
94 | "parameter": "nospace",
95 | "property-declaration": "nospace",
96 | "variable-declaration": "nospace"
97 | },
98 | {
99 | "call-signature": "onespace",
100 | "index-signature": "onespace",
101 | "parameter": "onespace",
102 | "property-declaration": "onespace",
103 | "variable-declaration": "onespace"
104 | }
105 | ]
106 | },
107 | "variable-name": {
108 | "options": [
109 | "ban-keywords",
110 | "check-format",
111 | "allow-pascal-case"
112 | ]
113 | },
114 | "whitespace": {
115 | "options": [
116 | "check-branch",
117 | "check-decl",
118 | "check-operator",
119 | "check-separator",
120 | "check-type",
121 | "check-typecast"
122 | ]
123 | },
124 | "component-class-suffix": true,
125 | "contextual-lifecycle": true,
126 | "directive-class-suffix": true,
127 | "no-conflicting-lifecycle": true,
128 | "no-host-metadata-property": true,
129 | "no-input-rename": true,
130 | "no-inputs-metadata-property": true,
131 | "no-output-native": true,
132 | "no-output-on-prefix": true,
133 | "no-output-rename": true,
134 | "no-outputs-metadata-property": true,
135 | "template-banana-in-box": true,
136 | "template-no-negated-async": true,
137 | "use-lifecycle-interface": true,
138 | "use-pipe-transform-interface": true,
139 | "directive-selector": [
140 | true,
141 | "attribute",
142 | "app",
143 | "camelCase"
144 | ],
145 | "component-selector": [
146 | true,
147 | "element",
148 | "app",
149 | "kebab-case"
150 | ]
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/samples/car.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/samples/car.jpg
--------------------------------------------------------------------------------
/samples/fish.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/samples/fish.jpg
--------------------------------------------------------------------------------
/samples/gun.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/samples/gun.jpg
--------------------------------------------------------------------------------
/samples/panda.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/samples/panda.jpg
--------------------------------------------------------------------------------
/src/EfficientNetCheckPoint.ts:
--------------------------------------------------------------------------------
1 | export enum EfficientNetCheckPoint {
2 | B0,
3 | B1,
4 | B2,
5 | B3,
6 | B4,
7 | B5,
8 | B6,
9 | B7,
10 | }
11 |
--------------------------------------------------------------------------------
/src/EfficientNetCheckPointFactory.ts:
--------------------------------------------------------------------------------
1 | import * as tf from "@tensorflow/tfjs-node-gpu";
2 | import { io } from "@tensorflow/tfjs-core";
3 |
4 | import EfficientNetModel from "./EfficientnetModel";
5 | import { EfficientNetCheckPoint } from "./EfficientNetCheckPoint";
6 | import { EfficientNetLabelLanguage } from "./EfficientNetLanguageProvider";
7 | const defaultModelsUrl =
8 | "https://raw.githubusercontent.com/ntedgi/efficientnet-tensorflowjs-binaries/main/models/B";
9 | const modelFileName = "model.json";
10 | const inputLayerImageSize = [224, 240, 260, 300, 380, 456, 528, 600];
11 |
12 | interface EfficientNetCheckPointFactoryOptions {
13 | localModelRootDirectory?: string;
14 | locale?: EfficientNetLabelLanguage;
15 | }
16 |
17 | export default class EfficientNetCheckPointFactory {
18 | static async create(
19 | checkPoint: EfficientNetCheckPoint,
20 | options?: EfficientNetCheckPointFactoryOptions
21 | ): Promise {
22 | const { localModelRootDirectory, locale } = options || {};
23 | let modelPath:
24 | | string
25 | | io.IOHandler = `${defaultModelsUrl}${checkPoint}/${modelFileName}`;
26 |
27 | if (localModelRootDirectory) {
28 | modelPath = tf.io.fileSystem(
29 | `${localModelRootDirectory}/B${checkPoint}/${modelFileName}`
30 | );
31 | }
32 |
33 | const model = new EfficientNetModel(
34 | modelPath,
35 | inputLayerImageSize[checkPoint],
36 | locale
37 | );
38 | await model.load();
39 | return model;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/EfficientNetLanguageProvider.ts:
--------------------------------------------------------------------------------
1 | import * as fs from "fs";
2 | import * as path from "path";
3 |
4 | export enum EfficientNetLabelLanguage {
5 | ENGLISH,
6 | CHINESE,
7 | SPANISH,
8 | ARABIC,
9 | FRENCH,
10 | RUSSIAN,
11 | HEBREW,
12 | }
13 | export class EfficientNetLanguageProvider {
14 | private filePath = "misc/en.json";
15 | private labelsMap = null;
16 |
17 | constructor(language: EfficientNetLabelLanguage | undefined) {
18 | let fileName = null;
19 | if (language) {
20 | language as EfficientNetLabelLanguage;
21 | switch (+language) {
22 | case EfficientNetLabelLanguage.CHINESE:
23 | fileName = "zh";
24 | break;
25 | case EfficientNetLabelLanguage.ENGLISH:
26 | fileName = "en";
27 | break;
28 | case EfficientNetLabelLanguage.SPANISH:
29 | fileName = "es";
30 | break;
31 | case EfficientNetLabelLanguage.RUSSIAN:
32 | fileName = "ru";
33 | break;
34 | case EfficientNetLabelLanguage.ARABIC:
35 | fileName = "ar";
36 | break;
37 | case EfficientNetLabelLanguage.HEBREW:
38 | fileName = "he";
39 | break;
40 | case EfficientNetLabelLanguage.FRENCH:
41 | fileName = "fr";
42 | break;
43 | }
44 | }
45 | this.filePath = fileName ? `misc/${fileName}.json` : this.filePath;
46 | }
47 |
48 | async load(): Promise {
49 | const jsonFile = path.join(__dirname, this.filePath);
50 | const translationFile = await fs.readFileSync(jsonFile, "utf8");
51 | this.labelsMap = JSON.parse(translationFile);
52 | }
53 |
54 | get(value: number): string | undefined {
55 | return this.labelsMap?.[value];
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/EfficientNetResult.ts:
--------------------------------------------------------------------------------
1 | import { EfficientNetLanguageProvider } from "./EfficientNetLanguageProvider";
2 | interface Prediction {
3 | label: string;
4 | precision: number;
5 | }
6 |
7 | export default class EfficientNetResult {
8 | result: Prediction[] = [];
9 |
10 | constructor(
11 | values: Float32Array,
12 | topK: number,
13 | languageProvider: EfficientNetLanguageProvider
14 | ) {
15 | const arr = Array.from(values);
16 | const topValues = values
17 | .sort((a: number, b: number) => b - a)
18 | .slice(0, topK);
19 | const indexes = topValues.map((e: number) => arr.indexOf(e));
20 | const sum = topValues.reduce((a: number, b: number) => {
21 | return a + b;
22 | }, 0);
23 | indexes.forEach((value: number, index: number) => {
24 | this.result.push({
25 | label: languageProvider.get(value),
26 | precision: (topValues[index] / sum) * 100,
27 | } as Prediction);
28 | });
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/EfficientnetModel.ts:
--------------------------------------------------------------------------------
1 | import * as tf from "@tensorflow/tfjs-node-gpu";
2 | import * as Jimp from "jimp";
3 | import * as cliProgress from "cli-progress";
4 | import { io } from "@tensorflow/tfjs-core";
5 | import {
6 | EfficientNetLabelLanguage,
7 | EfficientNetLanguageProvider,
8 | } from "./EfficientNetLanguageProvider";
9 | import EfficientNetResult from "./EfficientNetResult";
10 |
11 | const NUM_OF_CHANNELS = 3;
12 |
13 | interface EfficientNetModelInferenceOptions {
14 | topK?: number;
15 | }
16 |
17 | export default class EfficientNetModel {
18 | modelPath: string | io.IOHandler;
19 | imageSize: number;
20 | model: tf.GraphModel | undefined;
21 | languageProvider: EfficientNetLanguageProvider;
22 | constructor(
23 | modelPath: string | io.IOHandler,
24 | imageSize: number,
25 | local: EfficientNetLabelLanguage | undefined
26 | ) {
27 | this.modelPath = modelPath;
28 | this.imageSize = imageSize;
29 | this.languageProvider = new EfficientNetLanguageProvider(local);
30 | }
31 |
32 | async load(): Promise {
33 | await this.languageProvider.load();
34 |
35 | const bar = new cliProgress.SingleBar(
36 | {},
37 | cliProgress.Presets.shades_classic
38 | );
39 | bar.start(100, 0);
40 | const model = await tf.loadGraphModel(this.modelPath, {
41 | onProgress: (p) => {
42 | bar.update(p * 100);
43 | },
44 | });
45 | bar.stop();
46 | this.model = model;
47 | }
48 |
49 | private async createTensor(image: Jimp): Promise {
50 | const values = new Float32Array(
51 | this.imageSize * this.imageSize * NUM_OF_CHANNELS
52 | );
53 | let i = 0;
54 | image.scan(
55 | 0,
56 | 0,
57 | image.bitmap.width,
58 | image.bitmap.height,
59 | (x: number, y: number) => {
60 | const pixel = Jimp.intToRGBA(image.getPixelColor(x, y));
61 | pixel.r = ((pixel.r - 1) / 127.0) >> 0;
62 | pixel.g = ((pixel.g - 1) / 127.0) >> 0;
63 | pixel.b = ((pixel.b - 1) / 127.0) >> 0;
64 | values[i * NUM_OF_CHANNELS + 0] = pixel.r;
65 | values[i * NUM_OF_CHANNELS + 1] = pixel.g;
66 | values[i * NUM_OF_CHANNELS + 2] = pixel.b;
67 | i++;
68 | }
69 | );
70 | const outShape: [number, number, number] = [
71 | this.imageSize,
72 | this.imageSize,
73 | NUM_OF_CHANNELS,
74 | ];
75 | let imageTensor = tf.tensor3d(values, outShape, "float32");
76 | imageTensor = imageTensor.expandDims(0);
77 | return imageTensor;
78 | }
79 |
80 | private async cropAndResize(image: Jimp): Promise {
81 | const width = image.bitmap.width;
82 | const height = image.bitmap.height;
83 | const cropPadding = 32;
84 | const paddedCenterCropSize =
85 | ((this.imageSize / (this.imageSize + cropPadding)) *
86 | Math.min(height, width)) >>
87 | 0;
88 | const offsetHeight = ((height - paddedCenterCropSize + 1) / 2) >> 0;
89 | const offsetWidth = (((width - paddedCenterCropSize + 1) / 2) >> 0) + 1;
90 |
91 | await image.crop(
92 | offsetWidth,
93 | offsetHeight,
94 | paddedCenterCropSize,
95 | paddedCenterCropSize
96 | );
97 | await image.resize(this.imageSize, this.imageSize, Jimp.RESIZE_BICUBIC);
98 | return image;
99 | }
100 |
101 | private async predict(
102 | tensor: tf.Tensor3D,
103 | topK: number,
104 | overrideLanguageProvider?: EfficientNetLanguageProvider
105 | ): Promise {
106 | const objectArray = this.model!.predict(tensor) as tf.Tensor;
107 | const values = objectArray.dataSync() as Float32Array;
108 | const languageProvider = overrideLanguageProvider
109 | ? overrideLanguageProvider
110 | : this.languageProvider;
111 | return new EfficientNetResult(values, topK, languageProvider);
112 | }
113 |
114 | async inference(
115 | imgPath: string | Buffer,
116 | options?: EfficientNetModelInferenceOptions,
117 | overrideLanguageProvider?: EfficientNetLanguageProvider
118 | ): Promise {
119 | const { topK = NUM_OF_CHANNELS } = options || {};
120 | // @ts-ignore
121 | let image = await Jimp.read(imgPath);
122 | image = await this.cropAndResize(image);
123 | const tensor = await this.createTensor(image);
124 | return this.predict(tensor, topK, overrideLanguageProvider);
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/src/ModelResourcesProvider.ts:
--------------------------------------------------------------------------------
1 | import { EfficientNetCheckPoint } from "./EfficientNetCheckPoint";
2 | import * as fs from "fs";
3 | import * as nodeFetch from "node-fetch";
4 |
5 | const workspaceDir = "./workspace";
6 |
7 | export default class ModelResourcesProvider {
8 | private static downloadUri = (checkPoint: EfficientNetCheckPoint) =>
9 | `https://tfhub.dev/tensorflow/efficientnet/b${checkPoint}/classification/1?tf-hub-format=compressed`;
10 |
11 | private static async download(url: string, outputFilePath: string) {
12 | const response = await nodeFetch.default(url);
13 | const buffer = await response.buffer();
14 | await fs.writeFileSync(outputFilePath, buffer);
15 | }
16 |
17 | static async get(checkPoint: EfficientNetCheckPoint): Promise {
18 | const modelDir = `${workspaceDir}/B${checkPoint}/model.tgz`;
19 | if (!fs.existsSync(workspaceDir)) {
20 | fs.mkdirSync(workspaceDir);
21 | await this.download(this.downloadUri(checkPoint), modelDir);
22 | }
23 | return "";
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/misc/he.json:
--------------------------------------------------------------------------------
1 | {
2 | "0": "טנץ', דג טנקה",
3 | "1": "דג זהב,קָרַס זָהָב, Carassius auratus",
4 | "2": "כריש לבן גדול, כריש לבן, כריש אוכל אדם, Carcharodon carcharias",
5 | "3": "כריש נמר, Galeocerdo cuvieri",
6 | "4": "פטישן, כריש פטיש, Sphyrnidae",
7 | "5": "חשמלנאים, Torpediniformes",
8 | "6": "טחניים, סטינגריי, Stingray",
9 | "7": "תרנגול זכרי",
10 | "8": "תרנגולת",
11 | "9": "יען, יען מצוי",
12 | "10": "פרוש הררי, Fringilla montifringilla",
13 | "11": "חוחית, Carduelis carduelis",
14 | "12": "חוחית בית, Carpodacus mexicanus",
15 | "13": "יונקו, junco",
16 | "14": "כחלית, Indigo bunting",
17 | "15": "רובין, אדום חזה אמריקאי , Turdus migratorius",
18 | "16": "בולבוליים",
19 | "17": "עורבני",
20 | "18": "עקעקים, Magpie",
21 | "19": "צ'יקדי, Chickadee",
22 | "20": "אמודאיים, Dippers",
23 | "21": "עפיפון",
24 | "22": "עיטם לבן-ראש, Haliaeetus leucocephalus",
25 | "23": "נשר",
26 | "24": "לילית אפורה, Strix nebulosa",
27 | "25": "סלמנדרה אש",
28 | "26": "לטאה מסוג Triturus vulgaris",
29 | "27": "eft",
30 | "28": "סלמנדרה מנומרת, Ambystoma maculatum",
31 | "29": "axolotl, Ambystoma mexicanum",
32 | "30": "צפרדע השור, bullfrog",
33 | "31": "צפרדע עצים, treefrog",
34 | "32": "tailed frog, bell toad, ribbed toad, tailed toad, Ascaphus trui",
35 | "33": "צב ים חום",
36 | "34": "צב ים גלדי, Dermochelys coriacea",
37 | "35": "צב בוץ, mud turtle",
38 | "36": "טראפין היהלום",
39 | "37": "צב סגיר",
40 | "38": "עַפְעַפִּית אֲמֶרִיקָה",
41 | "39": "איגואנה ירוקה",
42 | "40": "American chameleon, anole, Anolis carolinensis",
43 | "41": "לטאת טגו",
44 | "42": "חרדון",
45 | "43": "חרדון הצווארון, Chlamydosaurus kingi",
46 | "44": "לטאה תנין, alligator lizard",
47 | "45": "הלודרמה מרירית, Heloderma suspectum",
48 | "46": "לְטָאָה אִזְמָרַגְדִּית, Lacerta viridis",
49 | "47": "זיקית אפריקאית, Chamaeleo chamaeleon",
50 | "48": "דרקון קומודו, לטאת קומודו, לטאת דרקון, Varanus komodoensis",
51 | "49": "תנין אפריקאי, תנין נילוס, Crocodylus niloticus",
52 | "50": "אליגטור אמריקני, Alligator mississipiensis",
53 | "51": "טריצרטופס",
54 | "52": "נחש רעם, נחש תולעת, Carphophis amoenus",
55 | "53": "נחש טבעת, נחש קצוץ, ring snake",
56 | "54": "נפוח נפוח, צפע חול, sand viper",
57 | "55": "נחש מים, grass snake",
58 | "56": "נחש מלך",
59 | "57": "נחשי בירית",
60 | "58": "נחשי בירית, water snake",
61 | "59": "נחש-שוטני ירוק",
62 | "60": "נחש לילה, Hypsiglena torquata",
63 | "61": "רב חנק מצוי",
64 | "62": "פיתון סלעים אפריקני",
65 | "63": "קוברה הודית, נג'ה נג'ה",
66 | "64": "ממבה ירוקה מזרחית",
67 | "65": "פתני הים",
68 | "66": "צפע קרניים, צפע, צפע חול, צפע קרני, Cerastes cornutus",
69 | "67": "עכסן גב יהלום מערבי, Crotalus adamanteus",
70 | "68": "עכסן עכני, Crotalus cerastes",
71 | "69": "טרילוביטים",
72 | "70": "ארך-רגליים קרני, פלנגיום אופיליו, Phalangium opilio",
73 | "71": "עקרב",
74 | "72": "עכביש גן שחור וזהב, Argiope aurantia",
75 | "73": "עכביש אסם, Araneus cavaticus",
76 | "74": "עכביש גן, Aranea diademata",
77 | "75": "אלמנה שחורה, Latrodectus mactans",
78 | "76": "טרנטולה",
79 | "77": "עכביש זאב, עכביש ציד",
80 | "78": "קרציה",
81 | "79": "מרבה רגליים",
82 | "80": "שכווי שחור",
83 | "81": "שכווי הצפון",
84 | "82": "שכווי הצווארון",
85 | "83": "שכווי ערבות ענק, שכווי הערבה",
86 | "84": "טווס",
87 | "85": "שליו",
88 | "86": "חוגלה",
89 | "87": "אפרור אפריקני, Psittacus erithacus",
90 | "88": "מקאו",
91 | "89": "קקדו צהוב-ציצית, Kakatoe galerita, Cacatua galerita",
92 | "90": "לורים",
93 | "91": "קוקל, coucal",
94 | "92": "שרקרקיים",
95 | "93": "קלאוניים",
96 | "94": "קוליבריים",
97 | "95": "יקמראים",
98 | "96": "טוקניים",
99 | "97": "ציפור דרייק",
100 | "98": "מרגון בינוני",
101 | "99": "אווז",
102 | "100": "ברבור שחור, Cygnus atratus",
103 | "101": "tusker",
104 | "102": "echidna, דוב נמלים קוצני, דוב נמלים",
105 | "103": "פלטיפוס, פלטיפוס ברווז, Ornithorhynchus anatinus",
106 | "104": "וואלבי, Western brush wallaby",
107 | "105": "קואלה, דוב קואלה, Phascolarctos cinereus",
108 | "106": "וומבט",
109 | "107": "מדוזה",
110 | "108": "שושנת ים",
111 | "109": "אלמוגים מוח",
112 | "110": "תולעת שטוחה, platyhelminth",
113 | "111": "נמטודה, תולעים נימיות",
114 | "112": "קונכייה",
115 | "113": "חילזון",
116 | "114": "חשופיות",
117 | "115": "חשופיות ים",
118 | "116": "chiton, coat-of-mail shell, sea cradle, polyplacophora",
119 | "117": "Nautilus pompilius, nautilus",
120 | "118": "סרטן דנג'נס",
121 | "119": "rock crab, Cancer irroratus",
122 | "120": "סרטן כנר",
123 | "121": "סרטן מלך, סרטן אלסקה, סרטן מלך אלסקה, סרטן מלך אלסקה, Paralithodes camtschatica",
124 | "122": "לובסטר אמריקאי, Homarus americanus",
125 | "123": "סרטן נהרות",
126 | "124": "סרטן נהרות, קראודדי",
127 | "125": "סרטן נזיר",
128 | "126": "שווה-רגלאים, איזופוד",
129 | "127": "חסידה לבנה, Ciconia ciconia",
130 | "128": "חסידה שחורה, Ciconia nigra",
131 | "129": "כפן",
132 | "130": "פלמינגו",
133 | "131": "אנפה כחולה קטנה, Egretta caerulea",
134 | "132": "אנפה אמריקאית, אנפה לבנה גדולה, אגרטה אלבוס",
135 | "133": "אנפיות",
136 | "134": "עגורן",
137 | "135": "ארמוס, Aramus pictus",
138 | "136": "גלינול אירופי, Porphyrio porphyrio",
139 | "137": "אגמייה אמריקאית",
140 | "138": "חובתיים",
141 | "139": "ארנריה אדמונית, Arenaria interpres",
142 | "140": "חופית אלפינית, Erolia alpina",
143 | "141": "redshank, ביצנית לבנת-כנף",
144 | "142": "חרטומנית",
145 | "143": "שלצדף אמריקני, שלצדף החוף",
146 | "144": "שקנאי",
147 | "145": "פינגווין מלכותי, Aptenodytes patagonica",
148 | "146": "אלבטרוס, mollymawk",
149 | "147": "לווייתן אפור, Eschrichtius gibbosus, Eschrichtius robustus",
150 | "148": "לוויתן קטלן, אורקה, אורקינוס אורקה",
151 | "149": "תחש המשכן",
152 | "150": "אריה ים",
153 | "151": "צ'יוואווה",
154 | "152": "ספנייל יפני, צ'ין יפני",
155 | "153": "כלב מלטזי, טרייר מלטזי, מלטזי",
156 | "154": "פקינז, פקינז, פקה",
157 | "155": "שי טסו",
158 | "156": "קינג צ'ארלס ספניאל",
159 | "157": "כלב פפיון",
160 | "158": "טוי רוסי",
161 | "159": "רידג'בק רודזי",
162 | "160": "כלב אפגני",
163 | "161": "באסט האונד",
164 | "162": "ביגל",
165 | "163": "loodhound, כלב דם",
166 | "164": "בלוטיק קונהאונד",
167 | "165": "קונהאונד שחור וחום",
168 | "166": "Walker hound",
169 | "167": "פוקסהאונד אנגלי",
170 | "168": "Redbone Coonhound",
171 | "169": "בורזוי, כלב זאב רוסי",
172 | "170": "וולפהאונד אירי, כלב זאב אירי",
173 | "171": "כלב גרייהאונד איטלקי",
174 | "172": "ויפט",
175 | "173": "איביזן האונד",
176 | "174": "כלב נורווגי, אלקהאונד נורבגי",
177 | "175": "אוטרהאונד",
178 | "176": "סלוקי, כלב צבי",
179 | "177": "דירהאונד סקוטי, כלב צבי",
180 | "178": "ויימרנר",
181 | "179": "סטפורדשייר בולטרייר, סטפורדשייר בולטרייר",
182 | "180": "סטאפורדשייר טרייר אמריקאי",
183 | "181": "בדלינגטון טרייר",
184 | "182": "בורדר טרייר",
185 | "183": "קרי כחול טרייר",
186 | "184": "טרייר אירי",
187 | "185": "נורפולק טרייר",
188 | "186": "נוריץ' טרייר",
189 | "187": "יורקשייר טרייר",
190 | "188": "פוקס טרייר מסומר שיער",
191 | "189": "טרייר לייקלנד",
192 | "190": "טרייר סיליהאם, סיליהאם",
193 | "191": "איירדייל, טרייר איירדייל",
194 | "192": "קאירן טרייר",
195 | "193": "טרייר אוסטרלי",
196 | "194": "דנדי דינמונט טרייר",
197 | "195": "בוסטון בול, טרייר בוסטון",
198 | "196": "שנאוצר זעיר",
199 | "197": "שנאוצר ענק",
200 | "198": "שנאוצר בינוני",
201 | "199": "סקוטיש טרייר",
202 | "200": "טרייר טיבטי, chrysanthemum dog",
203 | "201": "טרייר סילקי אוסטרלי",
204 | "202": "טרייר חיטה רך-פרווה",
205 | "203": "וסט היילנד וייט טרייר",
206 | "204": "כלב להאסה אפסו",
207 | "205": "רטריבר חלק-שיער",
208 | "206": "רטריבר מתולתל",
209 | "207": "גולדן רטריבר",
210 | "208": "לברדור רטריבר",
211 | "209": "צ'ספיק ביי רטריבר",
212 | "210": "פוינטר גרמני קצר שיער",
213 | "211": "vizsla, ויסלה",
214 | "212": "סטר אנגלי",
215 | "213": "סטר אירי",
216 | "214": "גורדון סטר",
217 | "215": "ספנייל בריטני",
218 | "216": "קלמבר, ספנייל קלמבר",
219 | "217": "ספרינגר אנגלי, ספרינגר ספנייל אנגלי",
220 | "218": "ספרינגר ספנייל וולשי",
221 | "219": "קוקר ספנייל, קוקר ספנייל אנגלי, קוקר",
222 | "220": "ספנייל סאסקס",
223 | "221": "ספנייל מים אירי",
224 | "222": "קוואז",
225 | "223": "סכיפרקה",
226 | "224": "גרוננדל",
227 | "225": "מלינואה, רועה בלגי",
228 | "226": "בריארד",
229 | "227": "קלפי, קלפי אוסטראלי",
230 | "228": "קומונדור",
231 | "229": "כלב רועים אנגלי ישן, בובטייל",
232 | "230": "כלב רועים שלטי",
233 | "231": "קולי",
234 | "232": "בורדר קולי",
235 | "233": "בוביה דה פלאנדר",
236 | "234": "רוטוויילר",
237 | "235": "רועה גרמני, כלב רועה גרמני, כלב משטרה גרמני, אלזס",
238 | "236": "דוברמן, פינצ'ר דוברמן",
239 | "237": "פינשר מיניאטורי",
240 | "238": "כלב ההרים השוויצרי ענק",
241 | "239": "ברנר זננהונד",
242 | "240": "אפנצלר זננהונד",
243 | "241": "אנטלבוכר זננהונד",
244 | "242": "בוקסר",
245 | "243": "בול מסטיף",
246 | "244": "מסטיף טיבטי",
247 | "245": "בולדוג צרפתי",
248 | "246": "דני ענק",
249 | "247": "סנט ברנרד, סנט ברנרד",
250 | "248": "אסקימו אמריקאי",
251 | "249": "אלסקן מלמוט",
252 | "250": "האסקי סיבירי",
253 | "251": "דלמטי, כלב מאמן, כלב כרכרה",
254 | "252": "אפנפינצ'ר",
255 | "253": "בסנג'י",
256 | "254": "פאג, פאג-כלב",
257 | "255": "לאונברג",
258 | "256": "כלב ניופאונדלנד, ניופאונדלנד",
259 | "257": "כלב הרים פירנאי",
260 | "258": "סמויד",
261 | "259": "פומרניאן",
262 | "260": "צ'או צ'או",
263 | "261": "קייסהונד",
264 | "262": "ברבנקון גריפון",
265 | "263": "ולש קורגי",
266 | "264": "קרדיגן, קרדיגן וולשי קורגי",
267 | "265": "פודל צעצוע",
268 | "266": "פודל מיניאטורי",
269 | "267": "פודל רגיל",
270 | "268": "כלב מקסיקני חסר שיער",
271 | "269": "זאב מזרחי",
272 | "270": "זאב טונדרה אלסקי",
273 | "271": "זאב אדמוני",
274 | "272": "זאב ערבות",
275 | "273": "Canis dingo ,כלב דינגו ",
276 | "274": "דול מצוי",
277 | "275": "זאב טלוא",
278 | "276": "צבוע, צבוע",
279 | "277": "שועל מצוי",
280 | "278": "שועל מקרוטיס",
281 | "279": "שועל שלג",
282 | "280": "שועל אפור מצוי",
283 | "281": "טאבי, חתול טאבי",
284 | "282": "חתול נמר",
285 | "283": "חתול פרסי",
286 | "284": "חתול סיאמי, סיאמי",
287 | "285": "חתול מצרי",
288 | "286": "קוגר, פומה, פומת ההרים",
289 | "287": "catamount ,לינקס",
290 | "288": "נמר, פנתרה פרדוס",
291 | "289": "נמר שלג",
292 | "290": "יגואר",
293 | "291": "אריה, מלך החיות, פנתרה ליאו",
294 | "292": "נמר, פנתרה טיגריס",
295 | "293": "צ'יטה, ברדלס",
296 | "294": "דוב חום",
297 | "295": "דוב שחור אמריקאי",
298 | "296": "דוב קוטב",
299 | "297": "דוב שפתני",
300 | "298": "נמייה",
301 | "299": "סוריקטה",
302 | "300": "חיפושית נמר, גדיתים",
303 | "301": "פרת משה רבנו",
304 | "302": "חיפושית טחונה, רצניתיים",
305 | "303": "חיפושית ארוכת קרן, יקרוניתיים",
306 | "304": "חיפושית עלים, עליתיים",
307 | "305": "חיפושית זבל",
308 | "306": "חיפושית קרנף",
309 | "307": "חדקונית",
310 | "308": "לעוף",
311 | "309": "דבורה",
312 | "310": "נמלה",
313 | "311": "חגב=",
314 | "312": "קריקט",
315 | "313": "חרק מקל",
316 | "314": "ג'וק, מקק",
317 | "315": "גמל שלמה",
318 | "316": "ציקדה",
319 | "317": "חגב leafhopper",
320 | "318": "זבוב lacewing",
321 | "319": "שפירית",
322 | "320": "שפרירית",
323 | "321": "אדמירל",
324 | "322": "פרפר צלצול",
325 | "323": "מונרך, פרפר מונרך, פרפר חלב, דנאוס מקלעת",
326 | "324": "פרפר כרוב",
327 | "325": "פרפר גופרית, פרפר גופרית",
328 | "326": "פרפר כחליליים",
329 | "327": "כוכב ים, כוכב ים",
330 | "328": "קיפוד ים",
331 | "329": "מלפפון ים",
332 | "330": "ארנב cottontail",
333 | "331": "ארנבת",
334 | "332": "ארנב אנגורה",
335 | "333": "אוגר",
336 | "334": "דורבן, קיפוד",
337 | "335": "סנאי ניגר",
338 | "336": "מרמיטה",
339 | "337": "בונה",
340 | "338": "שרקן",
341 | "339": "סוס",
342 | "340": "זברה",
343 | "341": "חזיר בר hog",
344 | "342": "חזיר בר",
345 | "343": "חזיר יבלות",
346 | "344": "היפופוטם, היפופוטם, סוס יאור, היפופוטם אמפיביוס",
347 | "345": "שור",
348 | "346": "תאו מים",
349 | "347": "ביזון",
350 | "348": "ראם",
351 | "349": "כבש גדול-קרניים",
352 | "350": "יעל האלפים",
353 | "351": "בובאל איילי",
354 | "352": "אימפלה",
355 | "353": "צבי",
356 | "354": "גמל ערבי, דרומדרי, קמלוס דרומדריוס",
357 | "355": "לאמה",
358 | "356": "סמור",
359 | "357": "מינק",
360 | "358": "חמוס מבאיש",
361 | "359": "חמוס שחור רגל",
362 | "360": "לוטרה",
363 | "361": "בואש",
364 | "362": "גירית",
365 | "363": "ארמדיל",
366 | "364": "עצלן חיוור-גרון",
367 | "365": "אורנגאוטן, אורנגאוטנג",
368 | "366": "גורילה",
369 | "367": "שימפנזה",
370 | "368": "גיבון לבן-יד",
371 | "369": "קוף סיאמנג",
372 | "370": "גנון, קוף גנון",
373 | "371": "פטאס, קוף הוסאר, אריתרוסבוס פאטאס",
374 | "372": "בבון",
375 | "373": "macaque, מקוק",
376 | "374": "לנגור",
377 | "375": "קולובוס, קוף קולובוס",
378 | "376": "קוף חוטמני",
379 | "377": "פרמיט מרמוסט",
380 | "378": "קפוצ'ין לבן-ראש",
381 | "379": "קוף שאגן",
382 | "380": "titi, titi monkey",
383 | "381": "קוף עכביש שחור",
384 | "382": "קוף סנאי מצוי",
385 | "383": "חתול מדגסקר, למור טבעת זנב",
386 | "384": "אינדרי",
387 | "385": "פיל הודי, פיל אסייתי",
388 | "386": "פיל סוואנה אפריקני",
389 | "387": "פנדה אדומה",
390 | "388": "פנדה ענקית",
391 | "389": "אספירנה ברקודה",
392 | "390": "צלופח",
393 | "391": "טרכון רב-מגנים",
394 | "392": "rock beauty, Holocanthus tricolor דג מסוג",
395 | "393": "שושנונים, דג ליצן",
396 | "394": "חדקן",
397 | "395": "שיפודן מובהק",
398 | "396": "זהרון",
399 | "397": "דג נפוח",
400 | "398": "חשבונייה",
401 | "399": "לבוש אביה",
402 | "400": "חלוק אקדמי, חלוק שופט",
403 | "401": "אקורדיון",
404 | "402": "גיטרה אקוסטית",
405 | "403": "נושאת מטוסים, נושאת מטוסים, נושאת מטוסים תקיפה",
406 | "404": "מטוס נוסעים",
407 | "405": "ספינת אוויר, ניתנת לניהול",
408 | "406": "מזבח",
409 | "407": "אמבולנס",
410 | "408": "רכב אמפיבי",
411 | "409": "שעון אנלוגי",
412 | "410": "כוורת, בית דבורים",
413 | "411": "סינר",
414 | "412": "פח אשפה",
415 | "413": "רובה סער, אקדח סער",
416 | "414": "תרמיל",
417 | "415": "מאפייה",
418 | "416": "חמור התעמלות",
419 | "417": "בלון",
420 | "418": "עט כדור",
421 | "419": "פלסטר",
422 | "420": "בנג'ו",
423 | "421": "מעקה",
424 | "422": "משקולת",
425 | "423": "כיסא ספר",
426 | "424": "מספרה",
427 | "425": "אסם",
428 | "426": "ברומטר",
429 | "427": "חבית, חבית",
430 | "428": "מריצה",
431 | "429": "בייסבול",
432 | "430": "כדורסל",
433 | "431": "כיסנית",
434 | "432": "כלי נגינה בסון",
435 | "433": "כובע רחצה, כובע שחייה",
436 | "434": "מגבת רחצה",
437 | "435": "אמבטיה, אמבטיה, אמבטיה, אמבטיה",
438 | "436": "עגלת חוף, סטיישן, עגלה, מכונית אחוזה, עגלה חוף, סטיישן, עגלה",
439 | "437": "משואה, מגדלור, אור משואה, פארוס",
440 | "438": "כוס מדעית",
441 | "439": "כובע פרוותי של שומרים אנגלים",
442 | "440": "בקבוק בירה",
443 | "441": "כוס בירה",
444 | "442": "מיטת פעמון, מיטת פעמון",
445 | "443": "סינר תינוקות",
446 | "444": "אופניים שנבנו לשניים",
447 | "445": "ביקיני,בגד ים דו חלקי",
448 | "446": "קלסר, קלסר טבעת",
449 | "447": "משקפת, משקפי שטח, משקפי אופרה",
450 | "448": "בית ציפורים",
451 | "449": "בית סירות",
452 | "450": "מזחלת",
453 | "451": "עניבת קאובוי",
454 | "452": "מצנפת",
455 | "453": "ארון ספרים",
456 | "454": "חנות ספרים, חנות ספרים, דוכן ספרים",
457 | "455": "פקק בקבוק",
458 | "456": "קשת",
459 | "457": "עניבת פרפר, עניבת פרפר, עניבת פרפר",
460 | "458": "פליז, פלאק",
461 | "459": "חזייה, חזייה, בנדו",
462 | "460": "שובר גלים, חומת ים",
463 | "461": "חושן, אגיס, אגיס",
464 | "462": "מטאטא",
465 | "463": "דלי, דלי",
466 | "464": "אבזם",
467 | "465": "אפוד חסין כדורים",
468 | "466": "רכבת מהירה",
469 | "467": "קצבייה, שוק בשר",
470 | "468": "מונית, פריצה, מונית, מונית",
471 | "469": "קלחת, קלחת",
472 | "470": "נר, אור שעווה",
473 | "471": "תותח",
474 | "472": "קאנו",
475 | "473": "פותחן קופסאות שימורים",
476 | "474": "קרדיגן",
477 | "475": "מראת לרכב",
478 | "476": "קרוסלה, קרוסלה, קרוסלה, סיבוב, מערבולת",
479 | "477": "ערכת נגר, ערכת כלים",
480 | "478": "קרטון",
481 | "479": "גלגל מכונית",
482 | "480": "כספומט, מנפק מזומנים",
483 | "481": "קסטה",
484 | "482": "נגן קסטות",
485 | "483": "טירה",
486 | "484": "קטמרן",
487 | "485": "נגן תקליטורים",
488 | "486": "צ'לו",
489 | "487": "טלפון סלולרי, טלפון נייד",
490 | "488": "שרשרת",
491 | "489": "גדר שרשרת",
492 | "490": "דואר שרשרת",
493 | "491": "מסור שרשרת, מסור שרשרת",
494 | "492": "תיבה",
495 | "493": "שידה",
496 | "494": "פעמון, גונג",
497 | "495": "ארון חרסינה, ארון חרסינה",
498 | "496": "גרב חג המולד",
499 | "497": "כנסייה, בניין כנסייה",
500 | "498": "קולנוע, קולנוע, קולנוע, בית קולנוע, ארמון תמונות",
501 | "499": "סכין קבצים",
502 | "500": "משכן צוק",
503 | "501": "גלימה",
504 | "502": "נעל עץ הולנדית",
505 | "503": "שייקר קוקטיילים",
506 | "504": "ספל קפה",
507 | "505": "קומקום קפה",
508 | "506": "סליל, ספירלה",
509 | "507": "מנעול שילוב תוים",
510 | "508": "מקלדת מחשב, לוח מקשים",
511 | "509": "חנות ממתקים, קונדיטוריה",
512 | "510": "ספינת מכולות",
513 | "511": "מכונית קביורלה",
514 | "512": "חולץ פקקים, בורג בקבוק",
515 | "513": "קורנט, קרן, חצוצרה, חצוצרה",
516 | "514": "מגף בוקרים",
517 | "515": "כובע בוקרים",
518 | "516": "עריסה",
519 | "517": "עגורן",
520 | "518": "קסדת התרסקות",
521 | "519": "ארגז",
522 | "520": "עריסה, מיטת תינוק",
523 | "521": "סיר חרס",
524 | "522": "כדור קרוקט",
525 | "523": "קב",
526 | "524": "קסדת קיראס",
527 | "525": "סכר",
528 | "526": "שולחן עבודה",
529 | "527": "מחשב שולחני",
530 | "528": "טלפון חיוג",
531 | "529": "חיתול",
532 | "530": "שעון דיגיטלי",
533 | "531": "שעון יד דיגיטלי",
534 | "532": "שולחן אוכל, לוח",
535 | "533": "מטלית כלים",
536 | "534": "מדיח כלים, מדיח כלים, מכונת מדיח",
537 | "535": "בלם דיסק, בלם דיסק",
538 | "536": "מזח, רציף, מתקן עגינה",
539 | "537": "מזחלת כלבים, מזחלת כלבים, מזחלת כלבים",
540 | "538": "מבנה כיפתי",
541 | "539": "שטיח לדלת, מחצלת קבלת פנים",
542 | "540": "פלטפורמת קידוח, אסדה ימית",
543 | "541": "תוף, ממברנופון, טימפן",
544 | "542": "מקל תיפוף",
545 | "543": "משקולת",
546 | "544": "תנור הולנדי",
547 | "545": "מאוורר חשמלי, מפוח",
548 | "546": "גיטרה חשמלית",
549 | "547": "קטר חשמלי",
550 | "548": "מרכז בידור",
551 | "549": "מעטפה",
552 | "550": "מכונת אספרסו",
553 | "551": "פודרה",
554 | "552": "צעיף נוצה",
555 | "553": "ארונית תיוק",
556 | "554": "סירת כיבוי אש",
557 | "555": "כבאית",
558 | "556": "מסך אש",
559 | "557": "עמוד דגל",
560 | "558": "חליל, חליל רוחבי",
561 | "559": "כיסא מתקפל",
562 | "560": "קסדת כדורגל",
563 | "561": "מלגזה",
564 | "562": "מזרקה",
565 | "563": "עט נובע",
566 | "564": "מתקן מעל מיטה מיוחדת",
567 | "565": "מכונית משא",
568 | "566": "צופר, קרן",
569 | "567": "מחבת",
570 | "568": "מעיל פרווה",
571 | "569": "משאית זבל, עגלת אבק",
572 | "570": "מסיכת גז, מכונת הנשמה, קסדת גז",
573 | "571": "משאבת דלק, משאבת בנזין",
574 | "572": "גביע",
575 | "573": "קארטינג",
576 | "574": "כדור גולף",
577 | "575": "עגלת גולף, עגלת גולף",
578 | "576": "גונדולה",
579 | "577": "גונג, טם-טאם",
580 | "578": "שמלה",
581 | "579": "פסנתר כנף",
582 | "580": "חממה",
583 | "581": "גריל",
584 | "582": "חנות מכולת, מכולת, שוק מזון, שוק",
585 | "583": "גיליוטינה",
586 | "584": "קליפ לשיער",
587 | "585": "ספריי לשיער",
588 | "586": "חצי רצועה",
589 | "587": "פטיש",
590 | "588": "מקשה",
591 | "589": "מפוח ידני, מייבש שיער, מייבש שיער, מייבש שיער",
592 | "590": "מחשב כף יד, מיקרו מחשב כף יד",
593 | "591": "מטפחת, ממחטה",
594 | "592": "דיסק קשיח, דיסק קשיח, דיסק קבוע",
595 | "593": "מפוחית",
596 | "594": "נבל",
597 | "595": "קוצר, קוצר",
598 | "596": "גרזן",
599 | "597": "נרתיק",
600 | "598": "קולנוע ביתי, קולנוע ביתי",
601 | "599": "חלת דבש",
602 | "600": "וו, טופר",
603 | "601": "חצאית חישוקים, קרינולינה",
604 | "602": "מתקן מתח",
605 | "603": "עגלת סוסים, עגלת סוסים",
606 | "604": "שעון חול",
607 | "605": "אייפוד",
608 | "606": "מגהץ",
609 | "607": "ג'ק-או-לנטרן",
610 | "608": "ג'ינס, ג'ינס כחול, ג'ינס",
611 | "609": "ג'יפ, לנדרובר",
612 | "610": "ג'רזי, חולצת טריקו, חולצת טי",
613 | "611": "פאזל",
614 | "612": "ג'ינריקישה, ריקשה, ריקשה",
615 | "613": "ג'ויסטיק",
616 | "614": "קימונו",
617 | "615": "מגן ברכיים",
618 | "616": "קשר",
619 | "617": "מעיל מעבדה, מעיל מעבדה",
620 | "618": "מצקת",
621 | "619": "אהיל, אהיל",
622 | "620": "מחשב נייד, מחשב נייד",
623 | "621": "מכסחת דשא, מכסחת",
624 | "622": "כובע עדשה, כיסוי עדשה",
625 | "623": "פותחן מכתבים, סכין נייר, סכין נייר",
626 | "624": "ספרייה",
627 | "625": "סירת הצלה",
628 | "626": "מצית, אור, מצת, מצת",
629 | "627": "לימוזינה, לימוזינה",
630 | "628": "אנית, אוניית אוקיינוס",
631 | "629": "שפתון, אודם שפתיים",
632 | "630": "כפכף",
633 | "631": "תחליב",
634 | "632": "רמקול, רמקול, יחידת רמקול, מערכת רמקול, מערכת רמקול",
635 | "633": "זכוכית מגדלת של תכשיטנים",
636 | "634": "טחנת עצים, מנסרה",
637 | "635": "מצפן מגנטי",
638 | "636": "שקית דואר, שקית דואר",
639 | "637": "תיבת דואר, תיבת מכתבים",
640 | "638": "בגד ים חתיכה אחת",
641 | "639": "maillot, חליפת טנק",
642 | "640": "מכסה ביוב",
643 | "641": "מאראקס",
644 | "642": "מרימבה, קסילופון",
645 | "643": "מסכה",
646 | "644": "גפרור",
647 | "645": "קוטב מאי",
648 | "646": "מבוך, מבוך",
649 | "647": "כוס מדידה",
650 | "648": "תיבת תרופות, ארון תרופות",
651 | "649": "מגלית, megalith",
652 | "650": "מיקרופון, מיקרופון",
653 | "651": "מיקרוגל, מיקרוגל",
654 | "652": "מדים צבאיים",
655 | "653": "פחית חלב",
656 | "654": "מיניבוס",
657 | "655": "מיני חצאית, מיני",
658 | "656": "מיניוואן",
659 | "657": "טיל",
660 | "658": "כפפה",
661 | "659": "קערת ערבוב",
662 | "660": "בית נייד",
663 | "661": "פורד דגם T",
664 | "662": "מודם",
665 | "663": "מנזר",
666 | "664": "מוניטור",
667 | "665": "טוסטוס",
668 | "666": "מרגמה",
669 | "667": "לוח מרגמה",
670 | "668": "מסגד",
671 | "669": "רשת יתושים",
672 | "670": "קטנוע, קטנוע",
673 | "671": "אופני הרים, אופני שטח, אופני שטח",
674 | "672": "אוהל הרים",
675 | "673": "עכבר, עכבר מחשב",
676 | "674": "מלכודת עכברים",
677 | "675": "טנדר נוסע",
678 | "676": "זמם",
679 | "677": "מסמר",
680 | "678": "סד צוואר",
681 | "679": "שרשרת",
682 | "680": "פטמה",
683 | "681": "מחשב נייד",
684 | "682": "אובליסק",
685 | "683": "אבוב",
686 | "684": "בטטה",
687 | "685": "מד מרחק",
688 | "686": "מסנן שמן",
689 | "687": "עוגב, עוגב מקטרת",
690 | "688": "אוסילוסקופ",
691 | "689": "חצאית על",
692 | "690": "עגלת שוורים",
693 | "691": "מסכת חמצן",
694 | "692": "חבילה",
695 | "693": "משוט, משוט בסירה",
696 | "694": "גלגל ההנעה, גלגל ההנעה",
697 | "695": "מנעול",
698 | "696": "מכחול",
699 | "697": "פיג'מה",
700 | "698": "ארמון",
701 | "699": "חליל פאן",
702 | "700": "מגבת נייר",
703 | "701": "מצנח, מצנח",
704 | "702": "ברים מקבילים, ברים",
705 | "703": "ספסל בפארק",
706 | "704": "מד חניה",
707 | "705": "מכונית נוסעים, אוטובוס, כרכרה",
708 | "706": "פטיו, מרפסת",
709 | "707": "טלפון ציבורי, תחנת תשלום",
710 | "708": "כן, בסיס, דוכן",
711 | "709": "קלמר, קלמר",
712 | "710": "מחדד עפרונות",
713 | "711": "בושם, תמצית",
714 | "712": "צלחת פטרי",
715 | "713": "מכונת צילום",
716 | "714": "מפרט גיטרה",
717 | "715": "קסדת פיקלהאובה",
718 | "716": "גדר כלונס, מחווירה",
719 | "717": "טנדר",
720 | "718": "מזח",
721 | "719": "בנק חזירון, בנק פרוטה",
722 | "720": "בקבוק גלולות",
723 | "721": "כרית",
724 | "722": "כדור פינג-פונג",
725 | "723": "שבשבת",
726 | "724": "פיראט, ספינת פיראטים",
727 | "725": "כד, קנקן",
728 | "726": "מקצועה",
729 | "727": "פלנטריום",
730 | "728": "שקית פלסטיק",
731 | "729": "מתלה לצלחות",
732 | "730": "מחרשה",
733 | "731": "בוכנה",
734 | "732": "מצלמת פולארויד, מצלמת פולארויד לנד",
735 | "733": "עמוד",
736 | "734": "ניידת משטרה",
737 | "735": "פונצ'ו",
738 | "736": "שולחן ביליארד, שולחן ביליארד, שולחן סנוקר",
739 | "737": "בקבוק סודה",
740 | "738": "עציץ, עציץ",
741 | "739": "גלגל קדרים",
742 | "740": "מקדחה כוח",
743 | "741": "שטיח תפילה, מחצלת תפילה",
744 | "742": "מדפסת",
745 | "743": "כלא, בית כלא",
746 | "744": "טיל",
747 | "745": "מקרן",
748 | "746": "פאק הוקי",
749 | "747": "שק אגרוף",
750 | "748": "ארנק",
751 | "749": "נוצה, עט נוצה",
752 | "750": "שמיכה",
753 | "751": "מכונית מירוץ",
754 | "752": "מחבט, מחבט",
755 | "753": "רדיאטור",
756 | "754": "רדיו, אלחוטי",
757 | "755": "צלחת רדיו",
758 | "756": "חבית גשם",
759 | "757": "רכב פנאי, קרוואנים, קרוואנים",
760 | "758": "סליל",
761 | "759": "מצלמת רפלקס",
762 | "760": "מקרר, קופסת קרח",
763 | "761": "שלט רחוק, שלט",
764 | "762": "מסעדה, בית אוכל, מקום אוכל, מסעדה",
765 | "763": "אקדח תופי",
766 | "764": "רובה",
767 | "765": "כיסא נדנדה, נדנדה",
768 | "766": "רוטיסרי",
769 | "767": "מחק גומי, גומי, מחק עיפרון",
770 | "768": "כדור רוגבי",
771 | "769": "סרגל",
772 | "770": "נעל ריצה",
773 | "771": "כספת",
774 | "772": "סיכת ביטחון",
775 | "773": "מלחייה, מלחייה",
776 | "774": "סנדל",
777 | "775": "סרונג, sarong",
778 | "776": "סקסופון, סקסופון",
779 | "777": "נדן",
780 | "778": "קנה מידה, מכונת שקילה",
781 | "779": "אוטובוס בית ספר",
782 | "780": "סירת סקונר",
783 | "781": "לוח תוצאות",
784 | "782": "מסך, טלויזיית CRT",
785 | "783": "בורג",
786 | "784": "מברג",
787 | "785": "חגורת בטיחות, חגורת בטיחות",
788 | "786": "מכונת תפירה",
789 | "787": "אבזם",
790 | "788": "חנות נעליים, חנות נעליים, חנות נעליים",
791 | "789": "שוג'י",
792 | "790": "סל קניות",
793 | "791": "עגלת קניות",
794 | "792": "את",
795 | "793": "כובע מקלחת",
796 | "794": "וילון מקלחת",
797 | "795": "סקי",
798 | "796": "מסיכת סקי",
799 | "797": "שק שינה",
800 | "798": "סרגל חישוב",
801 | "799": "דלת הזזה",
802 | "800": "חריץ, שודד חד זרוע",
803 | "801": "שנורקל",
804 | "802": "אופנוע שלג",
805 | "803": "מפלסת שלג",
806 | "804": "מתקן סבון",
807 | "805": "כדור כדורגל",
808 | "806": "גרב",
809 | "807": "צלחת שמש, קולט שמש, תנור סולארי",
810 | "808": "סומבררו",
811 | "809": "קערת מרק",
812 | "810": "מקש רווח",
813 | "811": "גוף חימום",
814 | "812": "מעבורת חלל",
815 | "813": "מרית",
816 | "814": "סירת מנוע מהירה",
817 | "815": "קורי עכביש, קורי עכביש",
818 | "816": "פלך",
819 | "817": "מכונית ספורט, מכונית ספורט",
820 | "818": "זרקור",
821 | "819": "במה",
822 | "820": "קטר קיטור",
823 | "821": "גשר קשת פלדה",
824 | "822": "תוף פלדה",
825 | "823": "סטטוסקופ",
826 | "824": "שָׁל, רְדִיד, צָעִיף",
827 | "825": "קיר אבן",
828 | "826": "שעון עצר, שעון עצר",
829 | "827": "כיריים",
830 | "828": "מסננת",
831 | "829": "קרונית, חשמלית, חשמלית, עגלה, קרונית עגלה",
832 | "830": "אלונקה",
833 | "831": "ספת סטודיו, מיטת יום",
834 | "832": "סטופה",
835 | "833": "צוללת",
836 | "834": "חליפה, חליפת בגדים",
837 | "835": "משקפי שמש",
838 | "836": "משקפי שמש",
839 | "837": "משקפי שמש, משקפיים כהים, גוונים",
840 | "838": "קרם הגנה, קרם הגנה, חוסם שמש",
841 | "839": "גשר תלוי",
842 | "840": "ספוגית, ספוג, מגב",
843 | "841": "סווטשירט",
844 | "842": "בגדי שחייה, בגדי רחצה",
845 | "843": "נדנדה",
846 | "844": "מתג, מתג חשמלי, מתג חשמלי",
847 | "845": "מזרק",
848 | "846": "מנורת שולחן",
849 | "847": "טנק, טנק צבאי, רכב קרבי משוריין, רכב קרבי משוריין",
850 | "848": "נגן קלטות",
851 | "849": "קומקום",
852 | "850": "טדי, דובון",
853 | "851": "טלוויזיה, מערכת טלוויזיה",
854 | "852": "כדור טניס",
855 | "853": "סכך, גג סכך",
856 | "854": "וילון תיאטרון, וילון תיאטרון",
857 | "855": "אצבעון",
858 | "856": "גורן, גורן, מכונת דיש",
859 | "857": "כס המלכות",
860 | "858": "גג רעפים",
861 | "859": "טוסטר",
862 | "860": "חנות טבק, חנות טבק, חנות טבק",
863 | "861": "מושב שירותים",
864 | "862": "לפיד",
865 | "863": "עמוד טוטם",
866 | "864": "גרר, מכונית גרר",
867 | "865": "חנות צעצועים",
868 | "866": "טרקטור",
869 | "867": "משאית נגרר, נגרר לטרקטור, מתקן הובלה",
870 | "868": "מגש",
871 | "869": "מעיל גשם",
872 | "870": "תלת אופן, תלת אופניים, מנוע מנוע",
873 | "871": "טרימרן",
874 | "872": "חצובה",
875 | "873": "שער הניצחון",
876 | "874": "טרוליבוס",
877 | "875": "טרומבון",
878 | "876": "אמבט, מיכל",
879 | "877": "קרוסלה",
880 | "878": "מקלדת מכונת כתיבה",
881 | "879": "מטריה",
882 | "880": "חד אופן, חד אופן",
883 | "881": "פסנתר זקוף",
884 | "882": "שואב אבק",
885 | "883": "אגרטל",
886 | "884": "כספת",
887 | "885": "קטיפה",
888 | "886": "מכונה אוטומטית",
889 | "887": "חלוק מיוחד",
890 | "888": "ויאדוקט",
891 | "889": "כינור",
892 | "890": "כדורעף",
893 | "891": "טוסטר וופלים",
894 | "892": "שעון קיר",
895 | "893": "ארנק, פנקס",
896 | "894": "ארון בגדים, ארון",
897 | "895": "מטוס קרב, מטוס צבאי",
898 | "896": "כיור",
899 | "897": "מכונת כביסה, מכונת כביסה אוטומטית, מכונת כביסה",
900 | "898": "בקבוק מים",
901 | "899": "כד מים",
902 | "900": "מגדל מים",
903 | "901": "כד וויסקי",
904 | "902": "שריקה",
905 | "903": "פאה",
906 | "904": "רשת",
907 | "905": "וילון",
908 | "906": "עניבת וינדזור",
909 | "907": "בקבוק יין",
910 | "908": "כנף",
911 | "909": "ווק",
912 | "910": "כף עץ",
913 | "911": "צמר",
914 | "912": "גדר עצים",
915 | "913": "הריסות",
916 | "914": "סירת מפרש yawl",
917 | "915": "יורט",
918 | "916": "אתר אינטרנט, אתר אינטרנט, אתר אינטרנט, אתר",
919 | "917": "ספר קומיקס",
920 | "918": "תשבץ, תשבץ",
921 | "919": "תמרור רחוב",
922 | "920": "רמזור, איתות תנועה, רמזור",
923 | "921": "כריכת ספרים",
924 | "922": "תפריט",
925 | "923": "צלחת",
926 | "924": "גוואקמולי",
927 | "925": "קונסומה",
928 | "926": "הוטפוט",
929 | "927": "טרייפל",
930 | "928": "גלידה",
931 | "929": "סוכרייה על מקל",
932 | "930": "בגט",
933 | "931": "בייגל, בייגל",
934 | "932": "בייגלה",
935 | "933": "צ'יזבורגר",
936 | "934": "נקניקייה, נקניקייה, נקניקייה אדומה",
937 | "935": "פירה",
938 | "936": "כרוב הבר",
939 | "937": "ברוקולי",
940 | "938": "כרובית",
941 | "939": "קישוא, קישואים",
942 | "940": "דלעת ספגטי",
943 | "941": "דלעת ערמונים",
944 | "942": "דלעת",
945 | "943": "מלפפון",
946 | "944": "ארטישוק",
947 | "945": "פלפל, גמבה",
948 | "946": "קנרס הגבעול",
949 | "947": "פטריה",
950 | "948": "תפוח גרני סמית'",
951 | "949": "תות",
952 | "950": "תפוז",
953 | "951": "לימון",
954 | "952": "תאנה",
955 | "953": "אננס, אנאנס",
956 | "954": "בננה",
957 | "955": "פרי הג'ק",
958 | "956": "אנונה קשקשית",
959 | "957": "רימון",
960 | "958": "חציר",
961 | "959": "קרבונרה",
962 | "960": "רוטב שוקולד, סירופ שוקולד",
963 | "961": "בצק",
964 | "962": "קציץ בשר",
965 | "963": "פיצה",
966 | "964": "סוג של פאי",
967 | "965": "בוריטו",
968 | "966": "יין אדום",
969 | "967": "אספרסו",
970 | "968": "כוס",
971 | "969": "ליקר ביצים",
972 | "970": "alp",
973 | "971": "בועה",
974 | "972": "צוק",
975 | "973": "שונית אלמוגים",
976 | "974": "גייזר",
977 | "975": "שפת האגם, שפת האגם",
978 | "976": "צוק, לשון יבשה, ראש, חזית",
979 | "977": "שרטון",
980 | "978": "חוף ים, חוף",
981 | "979": "עמק, עמק",
982 | "980": "הר געש",
983 | "981": "שחקן כדור, שחקן בייסבול",
984 | "982": "חתן, חתן",
985 | "983": "צוללן",
986 | "984": "לפתית",
987 | "985": "חיננית",
988 | "986": "פרח נעלי גברת צהובה, נעלי בית צהובות, Cypripedium calceolus, Cypripedium parviflorum",
989 | "987": "תירס",
990 | "988": "בלוט",
991 | "989": "יפ, ורדרד, ורדרד",
992 | "990": "באקי, ערמון סוס, קונקר",
993 | "991": "פטריית אלמוגים",
994 | "992": "אגריק",
995 | "993": "gyromitra",
996 | "994": "קרן סירחון, פטריית נבלות",
997 | "995": "earthstar ,סוג של פטרייה",
998 | "996": "פטריית מאיטקה, תרנגולת היער",
999 | "997": "bolete פטריית",
1000 | "998": "אוזן, ספייק, קפיטול",
1001 | "999": "טישו לשירותים, נייר טואלט, טישו לאמבטיה"
1002 | }
--------------------------------------------------------------------------------
/src/misc/zh.json:
--------------------------------------------------------------------------------
1 | {
2 | "0": "丁鲷",
3 | "1": "金鱼",
4 | "2": "大白鲨",
5 | "3": "虎鲨",
6 | "4": "锤头鲨",
7 | "5": "电鳐",
8 | "6": "黄貂鱼",
9 | "7": "公鸡",
10 | "8": "母鸡",
11 | "9": "鸵鸟",
12 | "10": "燕雀",
13 | "11": "金翅雀",
14 | "12": "家朱雀",
15 | "13": "灯芯草雀",
16 | "14": "靛蓝雀,靛蓝鸟",
17 | "15": "蓝鹀",
18 | "16": "夜莺",
19 | "17": "松鸦",
20 | "18": "喜鹊",
21 | "19": "山雀",
22 | "20": "河鸟",
23 | "21": "鸢(猛禽)",
24 | "22": "秃头鹰",
25 | "23": "秃鹫",
26 | "24": "大灰猫头鹰",
27 | "25": "欧洲火蝾螈",
28 | "26": "普通蝾螈",
29 | "27": "水蜥",
30 | "28": "斑点蝾螈",
31 | "29": "蝾螈,泥狗",
32 | "30": "牛蛙",
33 | "31": "树蛙",
34 | "32": "尾蛙,铃蟾蜍,肋蟾蜍,尾蟾蜍",
35 | "33": "红海龟",
36 | "34": "皮革龟",
37 | "35": "泥龟",
38 | "36": "淡水龟",
39 | "37": "箱龟",
40 | "38": "带状壁虎",
41 | "39": "普通鬣蜥",
42 | "40": "美国变色龙",
43 | "41": "鞭尾蜥蜴",
44 | "42": "飞龙科蜥蜴",
45 | "43": "褶边蜥蜴",
46 | "44": "鳄鱼蜥蜴",
47 | "45": "毒蜥",
48 | "46": "绿蜥蜴",
49 | "47": "非洲变色龙",
50 | "48": "科莫多蜥蜴",
51 | "49": "非洲鳄,尼罗河鳄鱼",
52 | "50": "美国鳄鱼,鳄鱼",
53 | "51": "三角龙",
54 | "52": "雷蛇,蠕虫蛇",
55 | "53": "环蛇,环颈蛇",
56 | "54": "希腊蛇",
57 | "55": "绿蛇,草蛇",
58 | "56": "国王蛇",
59 | "57": "袜带蛇,草蛇",
60 | "58": "水蛇",
61 | "59": "藤蛇",
62 | "60": "夜蛇",
63 | "61": "大蟒蛇",
64 | "62": "岩石蟒蛇,岩蛇,蟒蛇",
65 | "63": "印度眼镜蛇",
66 | "64": "绿曼巴",
67 | "65": "海蛇",
68 | "66": "角腹蛇",
69 | "67": "菱纹响尾蛇",
70 | "68": "角响尾蛇",
71 | "69": "三叶虫",
72 | "70": "盲蜘蛛",
73 | "71": "蝎子",
74 | "72": "黑金花园蜘蛛",
75 | "73": "谷仓蜘蛛",
76 | "74": "花园蜘蛛",
77 | "75": "黑寡妇蜘蛛",
78 | "76": "狼蛛",
79 | "77": "狼蜘蛛,狩猎蜘蛛",
80 | "78": "壁虱",
81 | "79": "蜈蚣",
82 | "80": "黑松鸡",
83 | "81": "松鸡,雷鸟",
84 | "82": "披肩鸡,披肩榛鸡",
85 | "83": "草原鸡,草原松鸡",
86 | "84": "孔雀",
87 | "85": "鹌鹑",
88 | "86": "鹧鸪",
89 | "87": "非洲灰鹦鹉",
90 | "88": "金刚鹦鹉",
91 | "89": "硫冠鹦鹉",
92 | "90": "短尾鹦鹉",
93 | "91": "褐翅鸦鹃",
94 | "92": "蜜蜂",
95 | "93": "犀鸟",
96 | "94": "蜂鸟",
97 | "95": "鹟䴕",
98 | "96": "犀鸟",
99 | "97": "野鸭",
100 | "98": "红胸秋沙鸭",
101 | "99": "鹅",
102 | "100": "黑天鹅",
103 | "101": "大象",
104 | "102": "针鼹鼠",
105 | "103": "鸭嘴兽",
106 | "104": "沙袋鼠",
107 | "105": "考拉,考拉熊",
108 | "106": "袋熊",
109 | "107": "水母",
110 | "108": "海葵",
111 | "109": "脑珊瑚",
112 | "110": "扁形虫扁虫",
113 | "111": "线虫,蛔虫",
114 | "112": "海螺",
115 | "113": "蜗牛",
116 | "114": "鼻涕虫",
117 | "115": "海参",
118 | "116": "石鳖",
119 | "117": "鹦鹉螺",
120 | "118": "珍宝蟹",
121 | "119": "石蟹",
122 | "120": "招潮蟹",
123 | "121": "帝王蟹,阿拉斯加蟹,阿拉斯加帝王蟹",
124 | "122": "美国龙虾,缅因州龙虾",
125 | "123": "大螯虾",
126 | "124": "小龙虾",
127 | "125": "寄居蟹",
128 | "126": "等足目动物(明虾和螃蟹近亲)",
129 | "127": "白鹳",
130 | "128": "黑鹳",
131 | "129": "鹭",
132 | "130": "火烈鸟",
133 | "131": "小蓝鹭",
134 | "132": "美国鹭,大白鹭",
135 | "133": "麻鸦",
136 | "134": "鹤",
137 | "135": "秧鹤",
138 | "136": "欧洲水鸡,紫水鸡",
139 | "137": "沼泽泥母鸡,水母鸡",
140 | "138": "鸨",
141 | "139": "红翻石鹬",
142 | "140": "红背鹬,黑腹滨鹬",
143 | "141": "红脚鹬",
144 | "142": "半蹼鹬",
145 | "143": "蛎鹬",
146 | "144": "鹈鹕",
147 | "145": "国王企鹅",
148 | "146": "信天翁,大海鸟",
149 | "147": "灰鲸",
150 | "148": "杀人鲸,逆戟鲸,虎鲸",
151 | "149": "海牛",
152 | "150": "海狮",
153 | "151": "奇瓦瓦",
154 | "152": "日本猎犬",
155 | "153": "马尔济斯犬",
156 | "154": "狮子狗",
157 | "155": "西施犬",
158 | "156": "布莱尼姆猎犬",
159 | "157": "巴比狗",
160 | "158": "玩具犬",
161 | "159": "罗得西亚长背猎狗",
162 | "160": "阿富汗猎犬",
163 | "161": "猎犬",
164 | "162": "比格犬,猎兔犬",
165 | "163": "侦探犬",
166 | "164": "蓝色快狗",
167 | "165": "黑褐猎浣熊犬",
168 | "166": "沃克猎犬",
169 | "167": "英国猎狐犬",
170 | "168": "美洲赤狗",
171 | "169": "俄罗斯猎狼犬",
172 | "170": "爱尔兰猎狼犬",
173 | "171": "意大利灰狗",
174 | "172": "惠比特犬",
175 | "173": "依比沙猎犬",
176 | "174": "挪威猎犬",
177 | "175": "奥达猎犬,水獭猎犬",
178 | "176": "沙克犬,瞪羚猎犬",
179 | "177": "苏格兰猎鹿犬,猎鹿犬",
180 | "178": "威玛猎犬",
181 | "179": "斯塔福德郡牛头梗,斯塔福德郡斗牛梗",
182 | "180": "美国斯塔福德郡梗,美国比特斗牛梗,斗牛梗",
183 | "181": "贝德灵顿梗",
184 | "182": "边境梗",
185 | "183": "凯丽蓝梗",
186 | "184": "爱尔兰梗",
187 | "185": "诺福克梗",
188 | "186": "诺维奇梗",
189 | "187": "约克郡梗",
190 | "188": "刚毛猎狐梗",
191 | "189": "莱克兰梗",
192 | "190": "锡利哈姆梗",
193 | "191": "艾尔谷犬",
194 | "192": "凯恩梗",
195 | "193": "澳大利亚梗",
196 | "194": "丹迪丁蒙梗",
197 | "195": "波士顿梗",
198 | "196": "迷你雪纳瑞犬",
199 | "197": "巨型雪纳瑞犬",
200 | "198": "标准雪纳瑞犬",
201 | "199": "苏格兰梗",
202 | "200": "西藏梗,菊花狗",
203 | "201": "丝毛梗",
204 | "202": "软毛麦色梗",
205 | "203": "西高地白梗",
206 | "204": "拉萨阿普索犬",
207 | "205": "平毛寻回犬",
208 | "206": "卷毛寻回犬",
209 | "207": "金毛猎犬",
210 | "208": "拉布拉多猎犬",
211 | "209": "乞沙比克猎犬",
212 | "210": "德国短毛猎犬",
213 | "211": "维兹拉犬",
214 | "212": "英国谍犬",
215 | "213": "爱尔兰雪达犬,红色猎犬",
216 | "214": "戈登雪达犬",
217 | "215": "布列塔尼犬猎犬",
218 | "216": "黄毛,黄毛猎犬",
219 | "217": "英国史宾格犬",
220 | "218": "威尔士史宾格犬",
221 | "219": "可卡犬,英国可卡犬",
222 | "220": "萨塞克斯猎犬",
223 | "221": "爱尔兰水猎犬",
224 | "222": "哥威斯犬",
225 | "223": "舒柏奇犬",
226 | "224": "比利时牧羊犬",
227 | "225": "马里努阿犬",
228 | "226": "伯瑞犬",
229 | "227": "凯尔皮犬",
230 | "228": "匈牙利牧羊犬",
231 | "229": "老英国牧羊犬",
232 | "230": "喜乐蒂牧羊犬",
233 | "231": "牧羊犬",
234 | "232": "边境牧羊犬",
235 | "233": "法兰德斯牧牛狗",
236 | "234": "罗特韦尔犬",
237 | "235": "德国牧羊犬,德国警犬,阿尔萨斯",
238 | "236": "多伯曼犬,杜宾犬",
239 | "237": "迷你杜宾犬",
240 | "238": "大瑞士山地犬",
241 | "239": "伯恩山犬",
242 | "240": "Appenzeller狗",
243 | "241": "EntleBucher狗",
244 | "242": "拳师狗",
245 | "243": "斗牛獒",
246 | "244": "藏獒",
247 | "245": "法国斗牛犬",
248 | "246": "大丹犬",
249 | "247": "圣伯纳德狗",
250 | "248": "爱斯基摩犬,哈士奇",
251 | "249": "雪橇犬,阿拉斯加爱斯基摩狗",
252 | "250": "哈士奇",
253 | "251": "达尔马提亚,教练车狗",
254 | "252": "狮毛狗",
255 | "253": "巴辛吉狗",
256 | "254": "哈巴狗,狮子狗",
257 | "255": "莱昂贝格狗",
258 | "256": "纽芬兰岛狗",
259 | "257": "大白熊犬",
260 | "258": "萨摩耶犬",
261 | "259": "博美犬",
262 | "260": "松狮,松狮",
263 | "261": "荷兰卷尾狮毛狗",
264 | "262": "布鲁塞尔格林芬犬",
265 | "263": "彭布洛克威尔士科基犬",
266 | "264": "威尔士柯基犬",
267 | "265": "玩具贵宾犬",
268 | "266": "迷你贵宾犬",
269 | "267": "标准贵宾犬",
270 | "268": "墨西哥无毛犬",
271 | "269": "灰狼",
272 | "270": "白狼,北极狼",
273 | "271": "红太狼,鬃狼,犬犬鲁弗斯",
274 | "272": "狼,草原狼,刷狼,郊狼",
275 | "273": "澳洲野狗,澳大利亚野犬",
276 | "274": "豺",
277 | "275": "非洲猎犬,土狼犬",
278 | "276": "鬣狗",
279 | "277": "红狐狸",
280 | "278": "沙狐",
281 | "279": "北极狐狸,白狐狸",
282 | "280": "灰狐狸",
283 | "281": "虎斑猫",
284 | "282": "山猫,虎猫",
285 | "283": "波斯猫",
286 | "284": "暹罗暹罗猫,",
287 | "285": "埃及猫",
288 | "286": "美洲狮,美洲豹",
289 | "287": "猞猁,山猫",
290 | "288": "豹子",
291 | "289": "雪豹",
292 | "290": "美洲虎",
293 | "291": "狮子",
294 | "292": "老虎",
295 | "293": "猎豹",
296 | "294": "棕熊",
297 | "295": "美洲黑熊",
298 | "296": "冰熊,北极熊",
299 | "297": "懒熊",
300 | "298": "猫鼬",
301 | "299": "猫鼬,海猫",
302 | "300": "虎甲虫",
303 | "301": "瓢虫",
304 | "302": "土鳖虫",
305 | "303": "天牛",
306 | "304": "龟甲虫",
307 | "305": "粪甲虫",
308 | "306": "犀牛甲虫",
309 | "307": "象甲",
310 | "308": "苍蝇",
311 | "309": "蜜蜂",
312 | "310": "蚂蚁",
313 | "311": "蚱蜢",
314 | "312": "蟋蟀",
315 | "313": "竹节虫",
316 | "314": "蟑螂",
317 | "315": "螳螂",
318 | "316": "蝉",
319 | "317": "叶蝉",
320 | "318": "草蜻蛉",
321 | "319": "蜻蜓",
322 | "320": "豆娘,蜻蛉",
323 | "321": "优红蛱蝶",
324 | "322": "小环蝴蝶",
325 | "323": "君主蝴蝶,大斑蝶",
326 | "324": "菜粉蝶",
327 | "325": "白蝴蝶",
328 | "326": "灰蝶",
329 | "327": "海星",
330 | "328": "海胆",
331 | "329": "海参,海黄瓜",
332 | "330": "野兔",
333 | "331": "兔",
334 | "332": "安哥拉兔",
335 | "333": "仓鼠",
336 | "334": "刺猬,豪猪,",
337 | "335": "黑松鼠",
338 | "336": "土拨鼠",
339 | "337": "海狸",
340 | "338": "豚鼠,豚鼠",
341 | "339": "栗色马",
342 | "340": "斑马",
343 | "341": "猪",
344 | "342": "野猪",
345 | "343": "疣猪",
346 | "344": "河马",
347 | "345": "牛",
348 | "346": "水牛,亚洲水牛",
349 | "347": "野牛",
350 | "348": "公羊",
351 | "349": "大角羊,洛矶山大角羊",
352 | "350": "山羊",
353 | "351": "狷羚",
354 | "352": "黑斑羚",
355 | "353": "瞪羚",
356 | "354": "阿拉伯单峰骆驼,骆驼",
357 | "355": "骆驼",
358 | "356": "黄鼠狼",
359 | "357": "水貂",
360 | "358": "臭猫",
361 | "359": "黑足鼬",
362 | "360": "水獭",
363 | "361": "臭鼬,木猫",
364 | "362": "獾",
365 | "363": "犰狳",
366 | "364": "树懒",
367 | "365": "猩猩,婆罗洲猩猩",
368 | "366": "大猩猩",
369 | "367": "黑猩猩",
370 | "368": "长臂猿",
371 | "369": "合趾猿长臂猿,合趾猿",
372 | "370": "长尾猴",
373 | "371": "赤猴",
374 | "372": "狒狒",
375 | "373": "恒河猴,猕猴",
376 | "374": "白头叶猴",
377 | "375": "疣猴",
378 | "376": "长鼻猴",
379 | "377": "狨(美洲产小型长尾猴)",
380 | "378": "卷尾猴",
381 | "379": "吼猴",
382 | "380": "伶猴",
383 | "381": "蜘蛛猴",
384 | "382": "松鼠猴",
385 | "383": "马达加斯加环尾狐猴,鼠狐猴",
386 | "384": "大狐猴,马达加斯加大狐猴",
387 | "385": "印度大象,亚洲象",
388 | "386": "非洲象,非洲象",
389 | "387": "小熊猫",
390 | "388": "大熊猫",
391 | "389": "杖鱼",
392 | "390": "鳗鱼",
393 | "391": "银鲑,银鲑鱼",
394 | "392": "三色刺蝶鱼",
395 | "393": "海葵鱼",
396 | "394": "鲟鱼",
397 | "395": "雀鳝",
398 | "396": "狮子鱼",
399 | "397": "河豚",
400 | "398": "算盘",
401 | "399": "长袍",
402 | "400": "学位袍",
403 | "401": "手风琴",
404 | "402": "原声吉他",
405 | "403": "航空母舰",
406 | "404": "客机",
407 | "405": "飞艇",
408 | "406": "祭坛",
409 | "407": "救护车",
410 | "408": "水陆两用车",
411 | "409": "模拟时钟",
412 | "410": "蜂房",
413 | "411": "围裙",
414 | "412": "垃圾桶",
415 | "413": "攻击步枪,枪",
416 | "414": "背包",
417 | "415": "面包店,面包铺,",
418 | "416": "平衡木",
419 | "417": "热气球",
420 | "418": "圆珠笔",
421 | "419": "创可贴",
422 | "420": "班卓琴",
423 | "421": "栏杆,楼梯扶手",
424 | "422": "杠铃",
425 | "423": "理发师的椅子",
426 | "424": "理发店",
427 | "425": "牲口棚",
428 | "426": "晴雨表",
429 | "427": "圆筒",
430 | "428": "园地小车,手推车",
431 | "429": "棒球",
432 | "430": "篮球",
433 | "431": "婴儿床",
434 | "432": "巴松管,低音管",
435 | "433": "游泳帽",
436 | "434": "沐浴毛巾",
437 | "435": "浴缸,澡盆",
438 | "436": "沙滩车,旅行车",
439 | "437": "灯塔",
440 | "438": "高脚杯",
441 | "439": "熊皮高帽",
442 | "440": "啤酒瓶",
443 | "441": "啤酒杯 ",
444 | "442": "钟塔",
445 | "443": "(小儿用的)围嘴",
446 | "444": "串联自行车,",
447 | "445": "比基尼",
448 | "446": "装订册",
449 | "447": "双筒望远镜",
450 | "448": "鸟舍",
451 | "449": "船库",
452 | "450": "雪橇",
453 | "451": "饰扣式领带",
454 | "452": "阔边女帽",
455 | "453": "书橱",
456 | "454": "书店,书摊",
457 | "455": "瓶盖",
458 | "456": "弓箭",
459 | "457": "蝴蝶结领结",
460 | "458": "铜制牌位",
461 | "459": "奶罩",
462 | "460": "防波堤,海堤",
463 | "461": "铠甲",
464 | "462": "扫帚",
465 | "463": "桶",
466 | "464": "扣环",
467 | "465": "防弹背心",
468 | "466": "动车,子弹头列车",
469 | "467": "肉铺,肉菜市场",
470 | "468": "出租车",
471 | "469": "大锅",
472 | "470": "蜡烛",
473 | "471": "大炮",
474 | "472": "独木舟",
475 | "473": "开瓶器,开罐器",
476 | "474": "开衫",
477 | "475": "车镜",
478 | "476": "旋转木马",
479 | "477": "木匠的工具包,工具包",
480 | "478": "纸箱",
481 | "479": "车轮",
482 | "480": "取款机,自动取款机",
483 | "481": "盒式录音带",
484 | "482": "卡带播放器",
485 | "483": "城堡",
486 | "484": "双体船",
487 | "485": "CD播放器",
488 | "486": "大提琴",
489 | "487": "移动电话,手机",
490 | "488": "铁链",
491 | "489": "围栏",
492 | "490": "链甲",
493 | "491": "电锯,油锯",
494 | "492": "箱子",
495 | "493": "衣柜,洗脸台",
496 | "494": "编钟,钟,锣",
497 | "495": "中国橱柜",
498 | "496": "圣诞袜",
499 | "497": "教堂,教堂建筑",
500 | "498": "电影院,剧场",
501 | "499": "切肉刀,菜刀",
502 | "500": "悬崖屋",
503 | "501": "斗篷",
504 | "502": "木屐,木鞋",
505 | "503": "鸡尾酒调酒器",
506 | "504": "咖啡杯",
507 | "505": "咖啡壶",
508 | "506": "螺旋结构(楼梯)",
509 | "507": "组合锁",
510 | "508": "电脑键盘,键盘",
511 | "509": "糖果,糖果店",
512 | "510": "集装箱船",
513 | "511": "敞篷车",
514 | "512": "开瓶器,瓶螺杆",
515 | "513": "短号,喇叭",
516 | "514": "牛仔靴",
517 | "515": "牛仔帽",
518 | "516": "摇篮",
519 | "517": "起重机",
520 | "518": "头盔",
521 | "519": "板条箱",
522 | "520": "小儿床",
523 | "521": "砂锅",
524 | "522": "槌球",
525 | "523": "拐杖",
526 | "524": "胸甲",
527 | "525": "大坝,堤防",
528 | "526": "书桌",
529 | "527": "台式电脑",
530 | "528": "有线电话",
531 | "529": "尿布湿",
532 | "530": "数字时钟",
533 | "531": "数字手表",
534 | "532": "餐桌板",
535 | "533": "抹布",
536 | "534": "洗碗机,洗碟机",
537 | "535": "盘式制动器",
538 | "536": "码头,船坞,码头设施",
539 | "537": "狗拉雪橇",
540 | "538": "圆顶",
541 | "539": "门垫,垫子",
542 | "540": "钻井平台,海上钻井",
543 | "541": "鼓,乐器,鼓膜",
544 | "542": "鼓槌",
545 | "543": "哑铃",
546 | "544": "荷兰烤箱",
547 | "545": "电风扇,鼓风机",
548 | "546": "电吉他",
549 | "547": "电力机车",
550 | "548": "电视,电视柜",
551 | "549": "信封",
552 | "550": "浓缩咖啡机",
553 | "551": "扑面粉",
554 | "552": "女用长围巾",
555 | "553": "文件,文件柜,档案柜",
556 | "554": "消防船",
557 | "555": "消防车",
558 | "556": "火炉栏",
559 | "557": "旗杆",
560 | "558": "长笛",
561 | "559": "折叠椅",
562 | "560": "橄榄球头盔",
563 | "561": "叉车",
564 | "562": "喷泉",
565 | "563": "钢笔",
566 | "564": "有四根帷柱的床",
567 | "565": "运货车厢",
568 | "566": "圆号,喇叭",
569 | "567": "煎锅",
570 | "568": "裘皮大衣",
571 | "569": "垃圾车",
572 | "570": "防毒面具,呼吸器",
573 | "571": "汽油泵",
574 | "572": "高脚杯",
575 | "573": "卡丁车",
576 | "574": "高尔夫球",
577 | "575": "高尔夫球车",
578 | "576": "狭长小船",
579 | "577": "锣",
580 | "578": "礼服",
581 | "579": "钢琴",
582 | "580": "温室,苗圃",
583 | "581": "散热器格栅",
584 | "582": "杂货店,食品市场",
585 | "583": "断头台",
586 | "584": "小发夹",
587 | "585": "头发喷雾",
588 | "586": "半履带装甲车",
589 | "587": "锤子",
590 | "588": "大篮子",
591 | "589": "手摇鼓风机,吹风机",
592 | "590": "手提电脑",
593 | "591": "手帕",
594 | "592": "硬盘",
595 | "593": "口琴,口风琴",
596 | "594": "竖琴",
597 | "595": "收割机",
598 | "596": "斧头",
599 | "597": "手枪皮套",
600 | "598": "家庭影院",
601 | "599": "蜂窝",
602 | "600": "钩爪",
603 | "601": "衬裙",
604 | "602": "单杠",
605 | "603": "马车",
606 | "604": "沙漏",
607 | "605": "手机,iPad",
608 | "606": "熨斗",
609 | "607": "南瓜灯笼",
610 | "608": "牛仔裤,蓝色牛仔裤",
611 | "609": "吉普车",
612 | "610": "运动衫,T恤",
613 | "611": "拼图",
614 | "612": "人力车",
615 | "613": "操纵杆",
616 | "614": "和服",
617 | "615": "护膝",
618 | "616": "蝴蝶结",
619 | "617": "大褂,实验室外套",
620 | "618": "长柄勺",
621 | "619": "灯罩",
622 | "620": "笔记本电脑",
623 | "621": "割草机",
624 | "622": "镜头盖",
625 | "623": "开信刀,裁纸刀",
626 | "624": "图书馆",
627 | "625": "救生艇",
628 | "626": "点火器,打火机",
629 | "627": "豪华轿车",
630 | "628": "远洋班轮",
631 | "629": "唇膏,口红",
632 | "630": "平底便鞋",
633 | "631": "洗剂",
634 | "632": "扬声器",
635 | "633": "放大镜",
636 | "634": "锯木厂",
637 | "635": "磁罗盘",
638 | "636": "邮袋",
639 | "637": "信箱",
640 | "638": "女游泳衣",
641 | "639": "有肩带浴衣",
642 | "640": "窨井盖",
643 | "641": "沙球(一种打击乐器)",
644 | "642": "马林巴木琴",
645 | "643": "面膜",
646 | "644": "火柴",
647 | "645": "花柱",
648 | "646": "迷宫",
649 | "647": "量杯",
650 | "648": "药箱",
651 | "649": "巨石,巨石结构",
652 | "650": "麦克风",
653 | "651": "微波炉",
654 | "652": "军装",
655 | "653": "奶桶",
656 | "654": "迷你巴士",
657 | "655": "迷你裙",
658 | "656": "面包车",
659 | "657": "导弹",
660 | "658": "连指手套",
661 | "659": "搅拌钵",
662 | "660": "活动房屋(由汽车拖拉的)",
663 | "661": "T型发动机小汽车",
664 | "662": "调制解调器",
665 | "663": "修道院",
666 | "664": "显示器",
667 | "665": "电瓶车",
668 | "666": "砂浆",
669 | "667": "学士",
670 | "668": "清真寺",
671 | "669": "蚊帐",
672 | "670": "摩托车",
673 | "671": "山地自行车",
674 | "672": "登山帐",
675 | "673": "鼠标,电脑鼠标",
676 | "674": "捕鼠器",
677 | "675": "搬家车",
678 | "676": "口套",
679 | "677": "钉子",
680 | "678": "颈托",
681 | "679": "项链",
682 | "680": "乳头(瓶)",
683 | "681": "笔记本,笔记本电脑",
684 | "682": "方尖碑",
685 | "683": "双簧管",
686 | "684": "陶笛,卵形笛",
687 | "685": "里程表",
688 | "686": "滤油器",
689 | "687": "风琴,管风琴",
690 | "688": "示波器",
691 | "689": "罩裙",
692 | "690": "牛车",
693 | "691": "氧气面罩",
694 | "692": "包装",
695 | "693": "船桨",
696 | "694": "明轮,桨轮",
697 | "695": "挂锁,扣锁",
698 | "696": "画笔",
699 | "697": "睡衣",
700 | "698": "宫殿",
701 | "699": "排箫,鸣管",
702 | "700": "纸巾",
703 | "701": "降落伞",
704 | "702": "双杠",
705 | "703": "公园长椅",
706 | "704": "停车收费表,停车计时器",
707 | "705": "客车,教练车",
708 | "706": "露台,阳台",
709 | "707": "付费电话",
710 | "708": "基座,基脚",
711 | "709": "铅笔盒",
712 | "710": "卷笔刀",
713 | "711": "香水(瓶)",
714 | "712": "培养皿",
715 | "713": "复印机",
716 | "714": "拨弦片,拨子",
717 | "715": "尖顶头盔",
718 | "716": "栅栏,栅栏",
719 | "717": "皮卡,皮卡车",
720 | "718": "桥墩",
721 | "719": "存钱罐",
722 | "720": "药瓶",
723 | "721": "枕头",
724 | "722": "乒乓球",
725 | "723": "风车",
726 | "724": "海盗船",
727 | "725": "水罐",
728 | "726": "木工刨",
729 | "727": "天文馆",
730 | "728": "塑料袋",
731 | "729": "板架",
732 | "730": "犁型铲雪机",
733 | "731": "手压皮碗泵",
734 | "732": "宝丽来相机",
735 | "733": "电线杆",
736 | "734": "警车,巡逻车",
737 | "735": "雨披",
738 | "736": "台球桌",
739 | "737": "充气饮料瓶",
740 | "738": "花盆",
741 | "739": "陶工旋盘",
742 | "740": "电钻",
743 | "741": "祈祷垫,地毯",
744 | "742": "打印机",
745 | "743": "监狱",
746 | "744": "炮弹,导弹",
747 | "745": "投影仪",
748 | "746": "冰球",
749 | "747": "沙包,吊球",
750 | "748": "钱包",
751 | "749": "羽管笔",
752 | "750": "被子",
753 | "751": "赛车",
754 | "752": "球拍",
755 | "753": "散热器",
756 | "754": "收音机",
757 | "755": "射电望远镜,无线电反射器",
758 | "756": "雨桶",
759 | "757": "休闲车,房车",
760 | "758": "卷轴,卷筒",
761 | "759": "反射式照相机",
762 | "760": "冰箱,冰柜",
763 | "761": "遥控器",
764 | "762": "餐厅,饮食店,食堂",
765 | "763": "左轮手枪",
766 | "764": "步枪",
767 | "765": "摇椅",
768 | "766": "电转烤肉架",
769 | "767": "橡皮",
770 | "768": "橄榄球",
771 | "769": "直尺",
772 | "770": "跑步鞋",
773 | "771": "保险柜",
774 | "772": "安全别针",
775 | "773": "盐瓶(调味用)",
776 | "774": "凉鞋",
777 | "775": "纱笼,围裙",
778 | "776": "萨克斯管",
779 | "777": "剑鞘",
780 | "778": "秤,称重机",
781 | "779": "校车",
782 | "780": "帆船",
783 | "781": "记分牌",
784 | "782": "屏幕",
785 | "783": "螺丝",
786 | "784": "螺丝刀",
787 | "785": "安全带",
788 | "786": "缝纫机",
789 | "787": "盾牌,盾牌",
790 | "788": "皮鞋店,鞋店",
791 | "789": "障子",
792 | "790": "购物篮",
793 | "791": "购物车",
794 | "792": "铁锹",
795 | "793": "浴帽",
796 | "794": "浴帘",
797 | "795": "滑雪板",
798 | "796": "滑雪面罩",
799 | "797": "睡袋",
800 | "798": "滑尺",
801 | "799": "滑动门",
802 | "800": "角子老虎机",
803 | "801": "潜水通气管",
804 | "802": "雪橇",
805 | "803": "扫雪机,扫雪机",
806 | "804": "皂液器",
807 | "805": "足球",
808 | "806": "袜子",
809 | "807": "碟式太阳能,太阳能集热器,太阳能炉",
810 | "808": "宽边帽",
811 | "809": "汤碗",
812 | "810": "空格键",
813 | "811": "空间加热器",
814 | "812": "航天飞机",
815 | "813": "铲(搅拌或涂敷用的)",
816 | "814": "快艇",
817 | "815": "蜘蛛网",
818 | "816": "纺锤,纱锭",
819 | "817": "跑车",
820 | "818": "聚光灯",
821 | "819": "舞台",
822 | "820": "蒸汽机车",
823 | "821": "钢拱桥",
824 | "822": "钢滚筒",
825 | "823": "听诊器",
826 | "824": "女用披肩",
827 | "825": "石头墙",
828 | "826": "秒表",
829 | "827": "火炉",
830 | "828": "过滤器",
831 | "829": "有轨电车,电车",
832 | "830": "担架",
833 | "831": "沙发床",
834 | "832": "佛塔",
835 | "833": "潜艇,潜水艇",
836 | "834": "套装,衣服",
837 | "835": "日晷",
838 | "836": "太阳镜",
839 | "837": "太阳镜,墨镜",
840 | "838": "防晒霜,防晒剂",
841 | "839": "悬索桥",
842 | "840": "拖把",
843 | "841": "运动衫",
844 | "842": "游泳裤",
845 | "843": "秋千",
846 | "844": "开关,电器开关",
847 | "845": "注射器",
848 | "846": "台灯",
849 | "847": "坦克,装甲战车,装甲战斗车辆",
850 | "848": "磁带播放器",
851 | "849": "茶壶",
852 | "850": "泰迪,泰迪熊",
853 | "851": "电视",
854 | "852": "网球",
855 | "853": "茅草,茅草屋顶",
856 | "854": "幕布,剧院的帷幕",
857 | "855": "顶针",
858 | "856": "脱粒机",
859 | "857": "宝座",
860 | "858": "瓦屋顶",
861 | "859": "烤面包机",
862 | "860": "烟草店,烟草",
863 | "861": "马桶",
864 | "862": "火炬",
865 | "863": "图腾柱",
866 | "864": "拖车,牵引车,清障车",
867 | "865": "玩具店",
868 | "866": "拖拉机",
869 | "867": "拖车,铰接式卡车",
870 | "868": "托盘",
871 | "869": "风衣",
872 | "870": "三轮车",
873 | "871": "三体船",
874 | "872": "三脚架",
875 | "873": "凯旋门",
876 | "874": "无轨电车",
877 | "875": "长号",
878 | "876": "浴盆,浴缸",
879 | "877": "旋转式栅门",
880 | "878": "打字机键盘",
881 | "879": "伞",
882 | "880": "独轮车",
883 | "881": "直立式钢琴",
884 | "882": "真空吸尘器",
885 | "883": "花瓶",
886 | "884": "拱顶",
887 | "885": "天鹅绒",
888 | "886": "自动售货机",
889 | "887": "祭服",
890 | "888": "高架桥",
891 | "889": "小提琴,小提琴",
892 | "890": "排球",
893 | "891": "松饼机",
894 | "892": "挂钟",
895 | "893": "钱包,皮夹",
896 | "894": "衣柜,壁橱",
897 | "895": "军用飞机",
898 | "896": "洗脸盆,洗手盆",
899 | "897": "洗衣机,自动洗衣机",
900 | "898": "水瓶",
901 | "899": "水壶",
902 | "900": "水塔",
903 | "901": "威士忌壶",
904 | "902": "哨子",
905 | "903": "假发",
906 | "904": "纱窗",
907 | "905": "百叶窗",
908 | "906": "温莎领带",
909 | "907": "葡萄酒瓶",
910 | "908": "飞机翅膀,飞机",
911 | "909": "炒菜锅",
912 | "910": "木制的勺子",
913 | "911": "毛织品,羊绒",
914 | "912": "栅栏,围栏",
915 | "913": "沉船",
916 | "914": "双桅船",
917 | "915": "蒙古包",
918 | "916": "网站,互联网网站",
919 | "917": "漫画",
920 | "918": "纵横字谜",
921 | "919": "路标",
922 | "920": "交通信号灯",
923 | "921": "防尘罩,书皮",
924 | "922": "菜单",
925 | "923": "盘子",
926 | "924": "鳄梨酱",
927 | "925": "清汤",
928 | "926": "罐焖土豆烧肉",
929 | "927": "蛋糕",
930 | "928": "冰淇淋",
931 | "929": "雪糕,冰棍,冰棒",
932 | "930": "法式面包",
933 | "931": "百吉饼",
934 | "932": "椒盐脆饼",
935 | "933": "芝士汉堡",
936 | "934": "热狗",
937 | "935": "土豆泥",
938 | "936": "结球甘蓝",
939 | "937": "西兰花",
940 | "938": "菜花",
941 | "939": "绿皮密生西葫芦",
942 | "940": "西葫芦",
943 | "941": "小青南瓜",
944 | "942": "南瓜",
945 | "943": "黄瓜",
946 | "944": "朝鲜蓟",
947 | "945": "甜椒",
948 | "946": "刺棘蓟",
949 | "947": "蘑菇",
950 | "948": "绿苹果",
951 | "949": "草莓",
952 | "950": "橘子",
953 | "951": "柠檬",
954 | "952": "无花果",
955 | "953": "菠萝",
956 | "954": "香蕉",
957 | "955": "菠萝蜜",
958 | "956": "蛋奶冻苹果",
959 | "957": "石榴",
960 | "958": "干草",
961 | "959": "烤面条加干酪沙司",
962 | "960": "巧克力酱,巧克力糖浆",
963 | "961": "面团",
964 | "962": "瑞士肉包,肉饼",
965 | "963": "披萨,披萨饼",
966 | "964": "馅饼",
967 | "965": "卷饼",
968 | "966": "红葡萄酒",
969 | "967": "意大利浓咖啡",
970 | "968": "杯子",
971 | "969": "蛋酒",
972 | "970": "高山",
973 | "971": "泡泡",
974 | "972": "悬崖",
975 | "973": "珊瑚礁",
976 | "974": "间歇泉",
977 | "975": "湖边,湖岸",
978 | "976": "海角",
979 | "977": "沙洲,沙坝",
980 | "978": "海滨,海岸",
981 | "979": "峡谷",
982 | "980": "火山",
983 | "981": "棒球,棒球运动员",
984 | "982": "新郎",
985 | "983": "潜水员",
986 | "984": "油菜",
987 | "985": "雏菊",
988 | "986": "杓兰",
989 | "987": "玉米",
990 | "988": "橡子",
991 | "989": "玫瑰果",
992 | "990": "七叶树果实",
993 | "991": "珊瑚菌",
994 | "992": "木耳",
995 | "993": "鹿花菌",
996 | "994": "鬼笔菌",
997 | "995": "地星(菌类)",
998 | "996": "多叶奇果菌",
999 | "997": "牛肝菌",
1000 | "998": "玉米穗",
1001 | "999": "卫生纸"
1002 | }
--------------------------------------------------------------------------------
/tester/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-efficientnet-tester",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "jest --clearCache"
8 | },
9 | "author": "",
10 | "license": "ISC",
11 | "dependencies": {
12 | "jest": "^26.6.3",
13 | "shelljs": "^0.8.4"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/tester/samples/car.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/tester/samples/car.jpg
--------------------------------------------------------------------------------
/tester/samples/fish.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/tester/samples/fish.jpg
--------------------------------------------------------------------------------
/tester/samples/gun.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/tester/samples/gun.jpg
--------------------------------------------------------------------------------
/tester/samples/panda.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/tester/samples/panda.jpg
--------------------------------------------------------------------------------
/tester/tests/language-provider.test.js:
--------------------------------------------------------------------------------
1 | const {
2 | EfficientNetLabelLanguage,
3 | EfficientNetLanguageProvider,
4 | } = require("node-efficientnet");
5 |
6 | test("EfficientNetLanguageProvider - check english translation file", (done) => {
7 | const englishProvider = new EfficientNetLanguageProvider(
8 | EfficientNetLabelLanguage.ENGLISH
9 | );
10 | englishProvider
11 | .load()
12 | .then(() => {
13 | const result = englishProvider.get(0);
14 | expect(result).toBeDefined();
15 | expect(result).toEqual("tench, Tinca tinca");
16 | done();
17 | })
18 | .catch((error) => done(error));
19 | });
20 |
21 | test("EfficientNetLanguageProvider - check chinese translation file", (done) => {
22 | const chineseProvider = new EfficientNetLanguageProvider(
23 | EfficientNetLabelLanguage.CHINESE
24 | );
25 | chineseProvider
26 | .load()
27 | .then(() => {
28 | const result = chineseProvider.get(0);
29 | expect(result).toBeDefined();
30 | expect(result).toEqual("丁鲷");
31 | done();
32 | })
33 | .catch((error) => done(error));
34 | });
35 |
36 | test("EfficientNetLanguageProvider - check russian translation file", (done) => {
37 | const russianLanguageProvider = new EfficientNetLanguageProvider(
38 | EfficientNetLabelLanguage.RUSSIAN
39 | );
40 | russianLanguageProvider
41 | .load()
42 | .then(() => {
43 | const result = russianLanguageProvider.get(0);
44 | expect(result).toBeDefined();
45 | expect(result).toEqual("линь, Тинка-тинка");
46 | done();
47 | })
48 | .catch((error) => done(error));
49 | });
50 |
51 | test("EfficientNetLanguageProvider - check spanish translation file", (done) => {
52 | const spanishProvider = new EfficientNetLanguageProvider(
53 | EfficientNetLabelLanguage.SPANISH
54 | );
55 | spanishProvider
56 | .load()
57 | .then(() => {
58 | const result = spanishProvider.get(0);
59 | expect(result).toBeDefined();
60 | expect(result).toEqual("tenca, Tinca tinca");
61 | done();
62 | })
63 | .catch((error) => done(error));
64 | });
65 |
--------------------------------------------------------------------------------
/tester/tests/model.test.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const shelljs = require("shelljs");
3 |
4 | const {
5 | EfficientNetCheckPoint,
6 | EfficientNetCheckPointFactory,
7 | EfficientNetLabelLanguage,
8 | } = require("node-efficientnet");
9 |
10 | const rootDir = path.join(__dirname, "../../lib/tfjs/web_model");
11 |
12 | beforeAll((done) => {
13 | shelljs.mkdir("-p", path.join(rootDir, "B0"));
14 | shelljs.cp("-r", path.join(rootDir, "*.json"), path.join(rootDir, "B0"));
15 | shelljs.cp("-r", path.join(rootDir, "*.bin"), path.join(rootDir, "B0"));
16 | done();
17 | });
18 |
19 | afterAll((done) => {
20 | shelljs.rm("-rf", path.join(rootDir, "B0"));
21 | done();
22 | });
23 |
24 | test("EfficientNetCheckPointFactory - create checkpoint B0 without throwing exception", (done) => {
25 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0, {
26 | localModelRootDirectory: rootDir,
27 | })
28 | .then((model) => {
29 | expect(model).toBeDefined();
30 | expect(model).toHaveProperty("modelPath");
31 | expect(model).toHaveProperty("imageSize");
32 | expect(model).toHaveProperty("model");
33 | done();
34 | })
35 | .catch((error) => done(error));
36 | });
37 |
38 | test("EfficientNetCheckPointFactory - checkpoint B0 should predict panda at top precision without throwing exception", (done) => {
39 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0, {
40 | localModelRootDirectory: rootDir,
41 | })
42 | .then(async (model) => {
43 | expect(model).toBeDefined();
44 | const image = "samples/panda.jpg";
45 | model.inference(image).then((predictions) => {
46 | expect(predictions.result[0].label).toEqual(
47 | "giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca"
48 | );
49 | done();
50 | });
51 | })
52 | .catch((error) => done(error));
53 | });
54 |
55 | test("EfficientNetCheckPointFactory - checkpoint B0 should predict car at top precision without throwing exception", (done) => {
56 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0, {
57 | localModelRootDirectory: rootDir,
58 | })
59 | .then(async (model) => {
60 | expect(model).toBeDefined();
61 | const image = "samples/car.jpg";
62 | model.inference(image).then((predictions) => {
63 | expect(predictions.result[0].label).toEqual("sports car, sport car");
64 | done();
65 | });
66 | })
67 | .catch((error) => done(error));
68 | });
69 |
70 | test("EfficientNetCheckPointFactory - checkpoint B0 should return top 5 answers", (done) => {
71 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0, {
72 | localModelRootDirectory: rootDir,
73 | })
74 | .then(async (model) => {
75 | expect(model).toBeDefined();
76 | const image = "samples/car.jpg";
77 | model
78 | .inference(image, {
79 | topK: 5,
80 | })
81 | .then((predictions) => {
82 | expect(predictions.result[0].label).toEqual("sports car, sport car");
83 | expect(predictions.result.length).toEqual(5);
84 | done();
85 | });
86 | })
87 | .catch((error) => done(error));
88 | });
89 |
90 | test("EfficientNetCheckPointFactory - load model from local file", (done) => {
91 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0, {
92 | localModelRootDirectory: rootDir,
93 | })
94 | .then(async (model) => {
95 | expect(model).toBeDefined();
96 | const image = "samples/car.jpg";
97 | model.inference(image).then((predictions) => {
98 | expect(predictions.result[0].label).toEqual("sports car, sport car");
99 | done();
100 | });
101 | })
102 | .catch((error) => {
103 | done(error);
104 | });
105 | });
106 |
107 | test("EfficientNetCheckPointFactory - load model from remote default", (done) => {
108 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0)
109 | .then(async (model) => {
110 | expect(model).toBeDefined();
111 | const image = "samples/car.jpg";
112 | model.inference(image).then((predictions) => {
113 | expect(predictions.result[0].label).toEqual("sports car, sport car");
114 | done();
115 | });
116 | })
117 | .catch((error) => {
118 | done(error);
119 | });
120 | });
121 |
122 | test("EfficientNetModel - use different locale chinese", (done) => {
123 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0, {
124 | locale: EfficientNetLabelLanguage.CHINESE,
125 | })
126 | .then(async (model) => {
127 | expect(model).toBeDefined();
128 | const image = "samples/car.jpg";
129 | model.inference(image).then((localeZhResult) => {
130 | expect(localeZhResult.result[0].label).toEqual("跑车");
131 | done();
132 | });
133 | })
134 | .catch((error) => {
135 | done(error);
136 | });
137 | });
138 |
139 | test("EfficientNetModel - use different locale english", (done) => {
140 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0, {
141 | locale: EfficientNetLabelLanguage.ENGLISH,
142 | })
143 | .then(async (model) => {
144 | expect(model).toBeDefined();
145 | const image = "samples/car.jpg";
146 | model.inference(image).then((localeEnResult) => {
147 | expect(localeEnResult.result[0].label).toEqual("sports car, sport car");
148 | done();
149 | });
150 | })
151 | .catch((error) => {
152 | done(error);
153 | });
154 | });
155 |
--------------------------------------------------------------------------------
/tests/examples/fish.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/tests/examples/fish.gif
--------------------------------------------------------------------------------
/tests/examples/fish.heic:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/tests/examples/fish.heic
--------------------------------------------------------------------------------
/tests/examples/fish.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/tests/examples/fish.png
--------------------------------------------------------------------------------
/tests/examples/fish.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ntedgi/node-efficientnet/d30b27fb650ff752877f0bc64fc60699a335ae07/tests/examples/fish.webp
--------------------------------------------------------------------------------
/tests/language-provider.test.js:
--------------------------------------------------------------------------------
1 | const {
2 | EfficientNetLabelLanguage,
3 | EfficientNetLanguageProvider,
4 | } = require("../index");
5 |
6 | test("EfficientNetLanguageProvider - check english translation file", (done) => {
7 | const englishProvider = new EfficientNetLanguageProvider(
8 | EfficientNetLabelLanguage.ENGLISH
9 | );
10 | englishProvider
11 | .load()
12 | .then(() => {
13 | const result = englishProvider.get(0);
14 | expect(result).toBeDefined();
15 | expect(result).toEqual("tench, Tinca tinca");
16 | done();
17 | })
18 | .catch((error) => done(error));
19 | });
20 |
21 | test("EfficientNetLanguageProvider - check chinese translation file", (done) => {
22 | const chineseProvider = new EfficientNetLanguageProvider(
23 | EfficientNetLabelLanguage.CHINESE
24 | );
25 | chineseProvider
26 | .load()
27 | .then(() => {
28 | const result = chineseProvider.get(0);
29 | expect(result).toBeDefined();
30 | expect(result).toEqual("丁鲷");
31 | done();
32 | })
33 | .catch((error) => done(error));
34 | });
35 |
36 | test("EfficientNetLanguageProvider - check spanish translation file", (done) => {
37 | const spanishProvider = new EfficientNetLanguageProvider(
38 | EfficientNetLabelLanguage.SPANISH
39 | );
40 | spanishProvider
41 | .load()
42 | .then(() => {
43 | const result = spanishProvider.get(0);
44 | expect(result).toBeDefined();
45 | expect(result).toEqual("tenca, Tinca tinca");
46 | done();
47 | })
48 | .catch((error) => done(error));
49 | });
50 |
51 | test("EfficientNetLanguageProvider - check russian translation file", (done) => {
52 | const russianLanguageProvider = new EfficientNetLanguageProvider(
53 | EfficientNetLabelLanguage.RUSSIAN
54 | );
55 |
56 | russianLanguageProvider
57 | .load()
58 | .then(() => {
59 | const result = russianLanguageProvider.get(0);
60 | expect(result).toBeDefined();
61 | expect(result).toEqual("линь, Тинка-тинка");
62 | done();
63 | })
64 | .catch((error) => done(error));
65 | });
66 |
67 | test("EfficientNetLanguageProvider - check arabic translation file", (done) => {
68 | const arabicProvider = new EfficientNetLanguageProvider(
69 | EfficientNetLabelLanguage.ARABIC
70 | );
71 |
72 | arabicProvider
73 | .load()
74 | .then(() => {
75 | const result = arabicProvider.get(0);
76 | expect(result).toBeDefined();
77 | expect(result).toEqual("تنش ، تينكا تينكا");
78 | done();
79 | })
80 | .catch((error) => done(error));
81 | });
82 |
83 | test("EfficientNetLanguageProvider - check hebrew translation file", (done) => {
84 | const hebrewProvider = new EfficientNetLanguageProvider(
85 | EfficientNetLabelLanguage.HEBREW
86 | );
87 |
88 | hebrewProvider
89 | .load()
90 | .then(() => {
91 | const result = hebrewProvider.get(0);
92 | expect(result).toBeDefined();
93 | expect(result).toEqual("טנץ', דג טנקה");
94 | done();
95 | })
96 | .catch((error) => done(error));
97 | });
98 |
99 | test("EfficientNetLanguageProvider - check hebrew translation file with special punctuation", (done) => {
100 |
101 | const hebrewProvider = new EfficientNetLanguageProvider(
102 | EfficientNetLabelLanguage.HEBREW
103 | );
104 |
105 | hebrewProvider
106 | .load()
107 | .then(() => {
108 | const result = hebrewProvider.get(38);
109 | expect(result).toBeDefined();
110 | expect(result).toEqual("עַפְעַפִּית אֲמֶרִיקָה");
111 | done()
112 | });
113 | });
114 |
115 | test("EfficientNetLanguageProvider - check french translation file", (done) => {
116 | const frenchProvider = new EfficientNetLanguageProvider(
117 | EfficientNetLabelLanguage.FRENCH
118 | );
119 |
120 | frenchProvider
121 | .load()
122 | .then(() => {
123 | const result = frenchProvider.get(0);
124 | expect(result).toBeDefined();
125 | expect(result).toEqual("tanche, Tinca tinca");
126 | done();
127 | })
128 | .catch((error) => done(error));
129 | });
130 |
--------------------------------------------------------------------------------
/tests/model.test.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const shelljs = require("shelljs");
3 |
4 | const {
5 | EfficientNetCheckPoint,
6 | EfficientNetCheckPointFactory,
7 | EfficientNetLabelLanguage,
8 | } = require("../index");
9 |
10 | const rootDir = path.join(__dirname, "../lib/tfjs/web_model");
11 |
12 | beforeAll((done) => {
13 | shelljs.mkdir("-p", path.join(rootDir, "B0"));
14 | shelljs.cp("-r", path.join(rootDir, "*.json"), path.join(rootDir, "B0"));
15 | shelljs.cp("-r", path.join(rootDir, "*.bin"), path.join(rootDir, "B0"));
16 | done();
17 | });
18 |
19 | afterAll((done) => {
20 | shelljs.rm("-rf", path.join(rootDir, "B0"));
21 | done();
22 | });
23 |
24 | test("EfficientNetCheckPointFactory - create checkpoint B0 without throwing exception", (done) => {
25 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0, {
26 | localModelRootDirectory: rootDir,
27 | })
28 | .then((model) => {
29 | expect(model).toBeDefined();
30 | expect(model).toHaveProperty("modelPath");
31 | expect(model).toHaveProperty("imageSize");
32 | expect(model).toHaveProperty("model");
33 | done();
34 | })
35 | .catch((error) => done(error));
36 | });
37 |
38 | test("EfficientNetCheckPointFactory - checkpoint B0 should predict panda at top precision without throwing exception", (done) => {
39 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0, {
40 | localModelRootDirectory: rootDir,
41 | })
42 | .then(async (model) => {
43 | expect(model).toBeDefined();
44 | const image = "samples/panda.jpg";
45 | model.inference(image).then((predictions) => {
46 | expect(predictions.result[0].label).toEqual(
47 | "giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca"
48 | );
49 | done();
50 | });
51 | })
52 | .catch((error) => done(error));
53 | });
54 |
55 | test("EfficientNetCheckPointFactory - checkpoint B0 should predict car at top precision without throwing exception", (done) => {
56 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0, {
57 | localModelRootDirectory: rootDir,
58 | })
59 | .then(async (model) => {
60 | expect(model).toBeDefined();
61 | const image = "samples/car.jpg";
62 | model.inference(image).then((predictions) => {
63 | expect(predictions.result[0].label).toEqual("sports car, sport car");
64 | done();
65 | });
66 | })
67 | .catch((error) => done(error));
68 | });
69 |
70 | test("EfficientNetCheckPointFactory - checkpoint B0 should return top 5 answers", (done) => {
71 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0, {
72 | localModelRootDirectory: rootDir,
73 | })
74 | .then(async (model) => {
75 | expect(model).toBeDefined();
76 | const image = "samples/car.jpg";
77 | model
78 | .inference(image, {
79 | topK: 5,
80 | })
81 | .then((predictions) => {
82 | expect(predictions.result[0].label).toEqual("sports car, sport car");
83 | expect(predictions.result.length).toEqual(5);
84 | done();
85 | });
86 | })
87 | .catch((error) => done(error));
88 | });
89 |
90 | test("EfficientNetCheckPointFactory - load model from local file", (done) => {
91 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0, {
92 | localModelRootDirectory: rootDir,
93 | })
94 | .then(async (model) => {
95 | expect(model).toBeDefined();
96 | const image = "samples/car.jpg";
97 | model.inference(image).then((predictions) => {
98 | expect(predictions.result[0].label).toEqual("sports car, sport car");
99 | done();
100 | });
101 | })
102 | .catch((error) => {
103 | done(error);
104 | });
105 | });
106 |
107 | test("EfficientNetCheckPointFactory - load model from remote default", (done) => {
108 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0)
109 | .then(async (model) => {
110 | expect(model).toBeDefined();
111 | const image = "samples/car.jpg";
112 | model.inference(image).then((predictions) => {
113 | expect(predictions.result[0].label).toEqual("sports car, sport car");
114 | done();
115 | });
116 | })
117 | .catch((error) => {
118 | done(error);
119 | });
120 | });
121 |
122 | test("EfficientNetModel - use different locale chinese", (done) => {
123 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0, {
124 | locale: EfficientNetLabelLanguage.CHINESE,
125 | })
126 | .then(async (model) => {
127 | expect(model).toBeDefined();
128 | const image = "samples/car.jpg";
129 | model.inference(image).then((localeZhResult) => {
130 | expect(localeZhResult.result[0].label).toEqual("跑车");
131 | done();
132 | });
133 | })
134 | .catch((error) => {
135 | done(error);
136 | });
137 | });
138 |
139 | test("EfficientNetModel - use different locale english", (done) => {
140 | EfficientNetCheckPointFactory.create(EfficientNetCheckPoint.B0, {
141 | locale: EfficientNetLabelLanguage.ENGLISH,
142 | })
143 | .then(async (model) => {
144 | expect(model).toBeDefined();
145 | const image = "samples/car.jpg";
146 | model.inference(image).then((localeEnResult) => {
147 | expect(localeEnResult.result[0].label).toEqual("sports car, sport car");
148 | done();
149 | });
150 | })
151 | .catch((error) => {
152 | done(error);
153 | });
154 | });
155 |
156 | test("EfficientNetModel - use different locale hebrew", async () => {
157 | const model = await EfficientNetCheckPointFactory.create(
158 | EfficientNetCheckPoint.B0,
159 | {
160 | locale: EfficientNetLabelLanguage.HEBREW,
161 | }
162 | );
163 | try {
164 | expect(model).toBeDefined();
165 | const image = "samples/car.jpg";
166 | model.inference(image).then((localeEnResult) => {
167 | expect(localeEnResult.result[0].label).toEqual(
168 | "מכונית ספורט, מכונית ספורט"
169 | );
170 | });
171 | } catch (error) {
172 | throw error;
173 | }
174 | });
175 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "module": "commonjs",
5 | "declaration": true,
6 | "outDir": "./dist",
7 | "strict": true,
8 | "skipLibCheck": true,
9 | "types": [],
10 | "typeRoots": [
11 | "./node_modules",
12 | "./node_modules/@types"
13 | ],
14 | "resolveJsonModule": true,
15 | "moduleResolution": "node"
16 | },
17 | "exclude": [
18 | "node_modules",
19 | "example.ts",
20 | "playground"
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------