├── dist
├── featured.json
├── favicon.ico
├── css
│ ├── fonts
│ │ ├── icomoon.eot
│ │ ├── icomoon.ttf
│ │ └── icomoon.woff
│ └── icomoon.css
├── webfonts
│ └── fa-solid-900.woff2
└── index.html
├── src
├── components
│ ├── service
│ │ ├── moses-service
│ │ │ ├── style.css
│ │ │ ├── MosesOptionsSummary.js
│ │ │ ├── MosesServiceResult.js
│ │ │ ├── DatasetUpload.js
│ │ │ ├── CrossValOpts.js
│ │ │ └── TargetFeature.js
│ │ ├── gene-annotation-service
│ │ │ ├── mozi_globe.png
│ │ │ ├── AnnotationSelection.js
│ │ │ ├── GOFilter.js
│ │ │ ├── visualizer.config.js
│ │ │ └── GenePathwayFilter.js
│ │ ├── emotion-recognition-service
│ │ │ ├── emotion_recognition.css.cs.js
│ │ │ └── EmotionVisualizer.js
│ │ ├── image-viewer-helpers
│ │ │ ├── ImageGridViewer.js
│ │ │ └── MasonryLayout.js
│ │ ├── standardComponents
│ │ │ └── HoverIcon.js
│ │ ├── NewsSummaryService.js
│ │ ├── MosesService.js
│ │ ├── analysis-helpers
│ │ │ └── DatasetUploaderHelper.js
│ │ ├── TranslationService.js
│ │ ├── HolisticEdgeDetectionService.js
│ │ ├── EmotionRecognitionService.js
│ │ ├── SemanticSegmentation.js
│ │ ├── TemplateService.js
│ │ ├── ExampleService.js
│ │ ├── FaceDetectService.js
│ │ ├── FaceAlignService.js
│ │ ├── NeuralSpeechSynthesis.js
│ │ ├── BinarySemanticSimilarity.js
│ │ ├── LongQuestionAsnswering.js
│ │ └── ShortQuestionAnswering.js
│ ├── Landing.js
│ ├── feedback
│ │ ├── vote.js
│ │ └── comment.js
│ ├── Footer.js
│ ├── DAppModal.js
│ ├── ConnectWallet.js
│ ├── ReactStyles.js
│ ├── Pricing.js
│ ├── GetStarted.js
│ ├── CardDeckers.js
│ ├── Header.js
│ └── ChannelHelper.js
├── models
│ ├── NullGRPCV3Service.js
│ ├── GRPCV3Service.js
│ └── GRPCProtoV3Spec.js
├── sandbox
│ ├── index.js
│ ├── index.html
│ ├── JobDetailsStandalone.js
│ └── Standalone.js
├── requests.js
├── service_state.js
├── index.js
├── networks.js
├── index.html
├── grpc.js
├── css
│ ├── profile.css
│ └── background.css
├── protobuf.js
├── js
│ └── gdpr.js
└── util.js
├── config
├── paths.js
├── webpack.dev.js
├── webpack.prod-analyze.js
├── webpack.prod.js
└── webpack.common.js
├── .circleci
└── config.yml
├── scripts
├── serveDist.js
└── deploy.js
├── .github
└── ISSUE_TEMPLATE
│ ├── feature_request.md
│ └── bug_report.md
├── LICENSE
├── .gitignore
├── package.json
└── README.md
/dist/featured.json:
--------------------------------------------------------------------------------
1 | [
2 | "0x2ed982c220fed6c9374e63804670fc16bd481b8f"
3 | ]
4 |
--------------------------------------------------------------------------------
/dist/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singnet/snet-betav1-dapp/HEAD/dist/favicon.ico
--------------------------------------------------------------------------------
/dist/css/fonts/icomoon.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singnet/snet-betav1-dapp/HEAD/dist/css/fonts/icomoon.eot
--------------------------------------------------------------------------------
/dist/css/fonts/icomoon.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singnet/snet-betav1-dapp/HEAD/dist/css/fonts/icomoon.ttf
--------------------------------------------------------------------------------
/dist/css/fonts/icomoon.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singnet/snet-betav1-dapp/HEAD/dist/css/fonts/icomoon.woff
--------------------------------------------------------------------------------
/dist/webfonts/fa-solid-900.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singnet/snet-betav1-dapp/HEAD/dist/webfonts/fa-solid-900.woff2
--------------------------------------------------------------------------------
/src/components/service/moses-service/style.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Roboto');
2 | body {
3 | font-family: 'roboto';
4 | }
5 |
--------------------------------------------------------------------------------
/src/components/service/gene-annotation-service/mozi_globe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/singnet/snet-betav1-dapp/HEAD/src/components/service/gene-annotation-service/mozi_globe.png
--------------------------------------------------------------------------------
/config/paths.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | module.exports = {
4 | srcPath: path.join(__dirname, '..', 'src'),
5 | sandBoxPath: path.join(__dirname, '..', 'src','sandbox'),
6 | outPath: path.join(__dirname, '..', 'dist')
7 | }
8 |
--------------------------------------------------------------------------------
/src/models/NullGRPCV3Service.js:
--------------------------------------------------------------------------------
1 | import GRPCV3Service from "./GRPCV3Service";
2 |
3 | export default class NullGRPCV3Service extends GRPCV3Service {
4 | constructor() {
5 | super('NullService', null)
6 | }
7 |
8 | get methodNames() {
9 | return [];
10 | }
11 |
12 | hasSameName(_serviceName) {
13 | return false;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/config/webpack.dev.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge');
2 | var common = require('./webpack.common.js');
3 | var MiniCssExtractPlugin = require("mini-css-extract-plugin");
4 |
5 | module.exports = env => {
6 | return merge(common(env.sandBox), {
7 | mode: 'development',
8 | plugins: [
9 | new MiniCssExtractPlugin({
10 | filename: 'css/[name].css'
11 | })
12 | ]
13 | });
14 | }
15 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | docker:
5 | - image: circleci/golang:1.9-node
6 | working_directory: ~/singnet/snet-dapp
7 | environment:
8 | TRIGGER_BUILD_BRANCH: master
9 | steps:
10 | - checkout
11 | - run:
12 | name: Run install script
13 | command: npm install
14 | - run:
15 | name: Run build script
16 | command: npm run build
17 |
18 |
--------------------------------------------------------------------------------
/src/models/GRPCV3Service.js:
--------------------------------------------------------------------------------
1 | export default class GRPCV3Service {
2 | constructor(serviceName, serviceObject) {
3 | this._serviceName = serviceName;
4 |
5 | this._methodNames = Object.keys(serviceObject["methods"]);
6 | }
7 |
8 | get serviceName() {
9 | return this._serviceName;
10 | }
11 |
12 | get methodNames() {
13 | return [...this._methodNames];
14 | }
15 |
16 | hasSameName(serviceName) {
17 | return this._serviceName === serviceName;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/scripts/serveDist.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var express = require('express');
3 |
4 | var paths = require('./../config/paths.js');
5 |
6 | var app = express();
7 |
8 | var PORT = 3000;
9 |
10 | app.get('/bundle*', (req, res, next) => {
11 | res.set('Content-Encoding', 'gzip');
12 | res.set('Content-Type', 'text/javascript');
13 | next();
14 | })
15 |
16 | app.use(express.static(paths.outPath));
17 |
18 | app.listen(PORT, () => { console.log('Beta DApp running at http://localhost:' + PORT) });
19 |
--------------------------------------------------------------------------------
/src/sandbox/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import Standalone from "./Standalone";
4 | import {BrowserRouter,Route,Switch} from 'react-router-dom';
5 |
6 | require('../css/style.css');
7 | require('../css/background.css');
8 | require('../css/profile.css');
9 |
10 | ReactDOM.render(
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | ,
19 | document.getElementById('react-root')
20 | );
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/src/components/service/emotion-recognition-service/emotion_recognition.css.cs.js:
--------------------------------------------------------------------------------
1 | export default {
2 | outsideWrapper: {
3 | width: '256px',
4 | height: '256px',
5 | margin: '20px 60px',
6 | border: '0px'
7 | },
8 | insideWrapper: {
9 | width: '100%',
10 | height: '100%',
11 | position: 'relative'
12 | },
13 | coveredImage: {
14 | width: '100%',
15 | height: '100%',
16 | position: 'absolute',
17 | top: '0px',
18 | left: '0px'
19 | },
20 | coveringCanvas: {
21 | width: '100%',
22 | height: '100%',
23 | position: 'absolute',
24 | top: '0px',
25 | left: '0px'
26 | }
27 | };
28 |
--------------------------------------------------------------------------------
/config/webpack.prod-analyze.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var merge = require('webpack-merge');
3 | var UglifyJSPlugin = require('uglifyjs-webpack-plugin');
4 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
5 |
6 | var common = require('./webpack.common.js');
7 |
8 | module.exports = merge(common, {
9 | mode: 'production',
10 |
11 | plugins: [
12 | new BundleAnalyzerPlugin(),
13 | new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify('production') }),
14 | new UglifyJSPlugin({
15 | sourceMap: true,
16 | uglifyOptions: {
17 | compress: true,
18 | mangle: true,
19 | warnings: false
20 | }
21 | })
22 | ]
23 | });
24 |
--------------------------------------------------------------------------------
/src/components/Landing.js:
--------------------------------------------------------------------------------
1 | import React, { props } from 'react';
2 | import SampleServices from './Services';
3 | import Homepage from './ConnectWallet.js';
4 | import BlockchainHelper from "./BlockchainHelper.js";
5 |
6 | export default class Landing extends React.Component {
7 | constructor() {
8 | super(props)
9 | this.network = new BlockchainHelper();
10 | }
11 |
12 | componentDidMount() {
13 | window.addEventListener('load', () => this.handleWindowLoad());
14 | this.handleWindowLoad();
15 | }
16 |
17 | handleWindowLoad() {
18 | this.network.initialize().then().catch(err => {
19 | console.error(err);
20 | })
21 | }
22 |
23 | render() {
24 | return (
25 |
26 | {(typeof web3 !== 'undefined') ? : }
27 |
28 | )
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/requests.js:
--------------------------------------------------------------------------------
1 | export class Requests {
2 |
3 | static getPostBody(requestObject) {
4 | const body = {
5 | 'mode': 'cors',
6 | headers: {
7 | "Content-Type": "application/json",
8 | },
9 | method: 'POST',
10 | body: JSON.stringify(requestObject)
11 | }
12 | return body
13 | }
14 |
15 | static async post(url, requestObject) {
16 | try {
17 | const data = await fetch(url, Requests.getPostBody(requestObject))
18 | .then(response => response.json())
19 | .then(json => {
20 | return json;
21 | })
22 | .catch(err => {
23 | return err
24 | });
25 | return data
26 | } catch (err) {
27 | console.log(err)
28 | }
29 | }
30 |
31 | static async get(url) {
32 | try {
33 | const resp = await fetch(url)
34 | const data = await resp.json()
35 | return data
36 | } catch (err) {
37 | console.log(err)
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/src/sandbox/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
18 | return(
19 |
20 |
21 |
22 |
23 |
24 | {(this.props.showProgress)?
25 | :
26 | null
27 | }
28 |
29 |
30 | {this.props.message}
31 |
32 |
33 | {(typeof this.props.link !== 'undefined')?
34 |
35 |
36 | :null}
37 |
38 |
39 |
40 |
41 |
42 | )
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/components/feedback/comment.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { TextField } from '@material-ui/core/es';
4 |
5 | const Comment = ({userComment, handleUserComment}) =>{
6 | return(
7 |
8 |
39 |
40 | );
41 | }
42 |
43 | Comment.propTypes={
44 | userComment: PropTypes.string,
45 | handleUserComment: PropTypes.func
46 | }
47 | export default Comment;
--------------------------------------------------------------------------------
/src/components/service/moses-service/MosesOptionsSummary.js:
--------------------------------------------------------------------------------
1 | import React, { Component, Fragment } from "react";
2 | import Typography from "@material-ui/core/Typography";
3 | import Modal from "@material-ui/core/Modal";
4 | import Table from "@material-ui/core/Table";
5 | import TableBody from "@material-ui/core/TableBody";
6 | import TableCell from "@material-ui/core/TableCell";
7 | import TableHead from "@material-ui/core/TableHead";
8 | import TableRow from "@material-ui/core/TableRow";
9 | import Paper from "@material-ui/core/Paper";
10 | import Button from "@material-ui/core/Button";
11 |
12 | export default class MosesOptionsSummary extends Component {
13 | constructor(props) {
14 | super(props);
15 | }
16 |
17 | render() {
18 | return (
19 |
20 |
21 |
32 |
33 | Moses Options
34 |
35 |
36 |
37 |
38 | Moses Option
39 | Value
40 |
41 |
42 |
43 | {this.props.options.map(option => (
44 |
45 |
46 | {option.name}
47 |
48 | {option.value}
49 |
50 | ))}
51 |
52 |
53 |
54 |
55 |
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/components/service/moses-service/MosesServiceResult.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { CheckCircle, Cancel } from "@material-ui/icons";
3 | import { Grid, Card, CardContent } from "@material-ui/core";
4 |
5 | export default class MosesServiceResult extends React.Component {
6 | renderError() {
7 | return (
8 |
14 |
15 |
16 |
17 | {this.props.result.description}
18 |
19 |
20 | );
21 | }
22 |
23 | renderCompleted() {
24 | return (
25 |
31 |
32 |
33 |
34 |
35 | Anlaysis started!
36 |
37 | Follow the link below to check the status of the analysis.
38 |
47 |
52 | {this.props.result.resultUrl}
53 |
54 |
55 |
56 |
57 | );
58 | }
59 |
60 | render() {
61 | return (
62 |
63 |
64 |
65 | {this.props.result.resultUrl
66 | ? this.renderCompleted()
67 | : this.renderError()}
68 |
69 |
70 |
71 | );
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/components/service/image-viewer-helpers/ImageGridViewer.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Grid, Button, Hidden } from '@material-ui/core';
3 | import { ArrowDownward } from '@material-ui/icons';
4 | import MasonryLayout from './MasonryLayout';
5 | import withWidth from '@material-ui/core/withWidth';
6 |
7 | export class ImageGridViewer extends React.Component {
8 | constructor(props) {
9 | super(props);
10 | }
11 |
12 | downloadImage(image) {
13 | const link = document.createElement('a');
14 | link.setAttribute("type", "hidden");
15 | link.setAttribute('href', image);
16 | link.setAttribute('download', 'result-image');
17 | document.body.appendChild(link);
18 | link.click();
19 | link.remove();
20 | }
21 |
22 | renderContent(response, key) {
23 | return (
24 |
32 |
this.downloadImage("data:image/"+response.image_type+";base64,"+response.image)}
37 | >
38 |
39 |
40 |
47 |
48 | );
49 | }
50 |
51 | render() {
52 | return (
53 |
54 | this.renderContent(r, i))}
56 | />
57 |
58 | );
59 | }
60 | }
61 |
62 | export default withWidth()(ImageGridViewer);
63 |
--------------------------------------------------------------------------------
/src/components/ConnectWallet.js:
--------------------------------------------------------------------------------
1 | import React, { props } from 'react';
2 | import { Link } from 'react-router-dom';
3 |
4 | export default class ConnectWallet extends React.Component {
5 | constructor() {
6 | super(props)
7 | }
8 |
9 | render() {
10 | return (
11 |
12 |
13 |
14 |
15 |
20 |
21 |
22 |
23 |
Welcome to SingularityNET
24 |
25 |
SingularityNET is an open and decentralized network of AI services made accessible through blockchain. AI developers publish their services onto the SingularityNET network where they can be used by anyone with an internet connection. This Dapp is a front-end for exploring available AI services and interacting with them through a web-UI
26 | View Services
27 |
28 |
29 |
30 | This Dapp allows you to browse the list of SingularityNET Agents from the SingularityNET Registry. You need a Metamask wallet to invoke a service.
31 |
Install Metamask
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | )
40 | }
41 | }
--------------------------------------------------------------------------------
/src/components/ReactStyles.js:
--------------------------------------------------------------------------------
1 | import { createMuiTheme } from "@material-ui/core/styles"
2 | import Typography from '@material-ui/core/Typography'
3 | import PropTypes from 'prop-types'
4 | import React from 'react'
5 |
6 | /*
7 | const styles = theme => ({
8 | root: {
9 | flexGrow: 1,
10 | backgroundColor: theme.palette.background.paper,
11 | },
12 | });*/
13 |
14 | export const ProfileTabContainer = (props) => {
15 | return (
16 |
17 | {props.children}
18 |
19 | );
20 | }
21 | ProfileTabContainer.propTypes = {
22 | children: PropTypes.node.isRequired,
23 | };
24 |
25 | export const TabContainer = (props) => {
26 | return (
27 |
28 | {props.children}
29 |
30 | );
31 | }
32 |
33 | TabContainer.propTypes = {
34 | children: PropTypes.node.isRequired,
35 | };
36 |
37 | export const ModalStylesAlertWait = {
38 | position: 'center',
39 | borderRadius: '6px',
40 | backgroundColor: 'white',
41 | fontFamily: "Muli",
42 | fontSize: "13px",
43 | color: 'black',
44 | height: '100px',
45 | width: '450px',
46 | padding: '10px',
47 | boxShadow: '#e8e8e8 0px 2px 2px 2px',
48 | margin: 'auto'
49 | }
50 |
51 | //Get modalstyles for alert//
52 | export const ModalStylesAlert = {
53 | fontFamily: "Muli",
54 | position: 'relative',
55 | borderRadius: 3,
56 | border: 5,
57 | color: 'white',
58 | lineHeight: 40,
59 | height: 100,
60 | width: 750,
61 | padding: '0 10px',
62 | boxShadow: '0 3px 5px 2px gray',
63 | top: 450,
64 | left: 350,
65 | }
66 | export const theme = createMuiTheme({
67 | typography: {
68 | useNextVariants: true,
69 | },
70 | overrides: {
71 | MuiButton: {
72 | root: {
73 | background: 'white',
74 | borderRadius: 3,
75 | border: 0,
76 | color: 'white',
77 | height: 38,
78 | padding: '0 30px',
79 | boxShadow: '0 3px 5px 2px lightblue',
80 | fontFamily: "Muli",
81 | fontSize: "12px",
82 | },
83 | },
84 | },
85 | });
--------------------------------------------------------------------------------
/src/components/service/gene-annotation-service/GOFilter.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { TextField, Grid, Checkbox, FormControlLabel } from "@material-ui/core";
3 |
4 | const namespaces = [
5 | { label: "Biological process", value: "biological_process" },
6 | { label: "Cellular component", value: "cellular_component" },
7 | { label: "Molecular function", value: "molecular_function" }
8 | ];
9 |
10 | export default class GOFilter extends React.Component {
11 | constructor(props) {
12 | super(props);
13 | this.namespaces = this.props.defaults.namespace;
14 | }
15 | render() {
16 | return (
17 |
18 |
64 |
65 | );
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/dist/css/icomoon.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "icomoon";
3 | src: url("fonts/icomoon.eot?d067fx");
4 | src: url("fonts/icomoon.eot?d067fx#iefix") format("embedded-opentype"),
5 | url("fonts/icomoon.ttf?d067fx") format("truetype"),
6 | url("fonts/icomoon.woff?d067fx") format("woff"),
7 | url("fonts/icomoon.svg?d067fx#icomoon") format("svg");
8 | font-weight: normal;
9 | font-style: normal;
10 | }
11 |
12 | [class^="icon-"],
13 | [class*=" icon-"] {
14 | /* use !important to prevent issues with browser extensions that change fonts */
15 | font-family: "icomoon" !important;
16 | speak: none;
17 | font-style: normal;
18 | font-weight: normal;
19 | font-variant: normal;
20 | text-transform: none;
21 | line-height: 1;
22 |
23 | /* Better Font Rendering =========== */
24 | -webkit-font-smoothing: antialiased;
25 | -moz-osx-font-smoothing: grayscale;
26 | }
27 |
28 | .icon-count-dislike:before {
29 | content: "\e900";
30 | color: #fff;
31 | text-shadow: -1px 0 #4086ff, 0 1px #4086ff, 1px 0 #4086ff, 0 -1px #4086ff;
32 | font-size: 26px;
33 | }
34 |
35 | .icon-count-like:before {
36 | content: "\e901";
37 | color: #fff;
38 | text-shadow: -1px 0 #4086ff, 0 1px #4086ff, 1px 0 #4086ff, 0 -1px #4086ff;
39 | font-size: 26px;
40 | }
41 |
42 | .icon-count-dislike-enabled:before {
43 | content: "\e900";
44 | color: #4086ff;
45 | font-size: 26px;
46 | }
47 |
48 | .icon-count-like-enabled:before {
49 | content: "\e901";
50 | color: #4086ff;
51 | font-size: 26px;
52 | }
53 |
54 | .icon-dislike:before {
55 | content: "\e900";
56 | color: #757577;
57 | font-size: 26px;
58 | cursor: pointer;
59 | }
60 | .icon-like:before {
61 | content: "\e901";
62 | color: #4086ff;
63 | font-size: 26px;
64 | cursor: pointer;
65 | }
66 |
67 | .icon-like-disabled:before {
68 | content: "\e901";
69 | color: #757577;
70 | font-size: 26px;
71 | cursor: pointer;
72 | }
73 |
74 | .icon-dislike-enabled:before {
75 | content: "\e900";
76 | color: #4086ff;
77 | font-size: 26px;
78 | cursor: pointer;
79 | }
80 |
81 | .icon-home-icon-silhouette:before {
82 | content: "\e902";
83 | font-size: 20px;
84 | }
85 |
86 | .icon-logo:before {
87 | content: "\e903";
88 | color: #fff;
89 | font-size: 50px
90 | }
91 |
92 | .icon-user-3:before {
93 | content: "\e904";
94 | font-size: 20px;
95 | }
--------------------------------------------------------------------------------
/src/components/service/standardComponents/HoverIcon.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Typography from "@material-ui/core/Typography";
3 | import { Tooltip, IconButton } from "@material-ui/core";
4 | import PropTypes from "prop-types";
5 | import { blue, grey } from "@material-ui/core/colors";
6 |
7 | export default class HoverIcon extends React.Component{
8 | constructor(props){
9 | super(props);
10 | this.state={
11 | hover: false,
12 | };
13 | this.renderIconButton = this.renderIconButton.bind(this);
14 | }
15 |
16 | renderIconButton(){
17 | let {children} = this.props;
18 | return(
19 |
31 | {children}
32 |
33 | )
34 | }
35 |
36 | render(){
37 | return(
38 | this.props.text ?
39 |
47 | {this.props.text}
48 |
49 | }>
50 | {this.renderIconButton()}
51 |
52 | :
53 | this.renderIconButton()
54 | )
55 | }
56 |
57 | }
58 |
59 | HoverIcon.propTypes = {
60 | text: PropTypes.string,
61 | textColor: PropTypes.string,
62 | fontFamily: PropTypes.string,
63 | fontSize: PropTypes.number,
64 | href: PropTypes.string,
65 | onColor: PropTypes.string,
66 | offColor: PropTypes.string,
67 | };
68 |
69 | HoverIcon.defaultProps = {
70 | text: null,
71 | fontFamily: "Muli",
72 | fontSize: 14,
73 | textColor: "white",
74 | onColor: blue[500],
75 | offColor: grey[600],
76 | };
77 |
--------------------------------------------------------------------------------
/config/webpack.common.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 |
4 | var HtmlWebpackPlugin = require('html-webpack-plugin');
5 | var MiniCssExtractPlugin = require("mini-css-extract-plugin");
6 |
7 | var paths = require('./paths.js')
8 |
9 | module.exports = function(isSandBox) {
10 | var codePath = isSandBox === 'true' ? paths.sandBoxPath : paths.srcPath;
11 |
12 | return {
13 | entry: path.join(codePath, 'index.js'),
14 |
15 | output: {
16 | path: paths.outPath,
17 | filename: 'bundle.[chunkhash:8].js'
18 | },
19 |
20 | devtool: 'source-map',
21 | devServer: {
22 | historyApiFallback: true,
23 | contentBase: paths.outPath,
24 | disableHostCheck: true
25 | },
26 |
27 | module: {
28 | rules: [
29 | {
30 | test: /\.js$/,
31 | loader: 'babel-loader',
32 | include: paths.srcPath,
33 | exclude: /node_modules/,
34 | options: {
35 | presets: [
36 | ['es2015', { modules: false }], 'react'
37 | ],
38 | plugins: [
39 | ['import', { libraryName: 'antd', libraryDirectory: 'es', style: true }]
40 | ]
41 | }
42 | },
43 | {
44 | test: /\.css$/,
45 | use: [
46 | 'style-loader',
47 | MiniCssExtractPlugin.loader,
48 | 'css-loader'
49 | ]
50 | },
51 | {
52 | test: /\.less$/,
53 | use: [{
54 | loader: "style-loader"
55 | }, {
56 | loader: "css-loader"
57 | }, {
58 | loader: "less-loader",
59 | options: {
60 | javascriptEnabled: true
61 | }
62 | }]
63 | },
64 | {
65 | test: /\.(jpg|png|svg)$/,
66 | use: {
67 | loader: "file-loader",
68 | options: {
69 | name: "[path][name].[hash].[ext]",
70 | },
71 | },
72 | },
73 | ]
74 | },
75 |
76 | plugins: [
77 | new HtmlWebpackPlugin({
78 | inject: true,
79 | template: path.join(paths.srcPath, 'index.html'),
80 | minify: {
81 | removeComments: true,
82 | collapseWhitespace: true,
83 | removeRedundantAttributes: true,
84 | useShortDoctype: true,
85 | removeEmptyAttributes: true,
86 | removeStyleLinkTypeAttributes: true,
87 | keepClosingSlash: true,
88 | minifyJS: true,
89 | minifyCSS: true,
90 | minifyURLs: true,
91 | },
92 | })
93 | ]
94 | }
95 | };
96 |
--------------------------------------------------------------------------------
/src/components/Pricing.js:
--------------------------------------------------------------------------------
1 | import {AGI} from '../util'
2 |
3 | export default class PricingStrategy {
4 | constructor(pricingJSON) {
5 | let pricingData = JSON.parse(pricingJSON);
6 | this.priceModel = pricingData.price_model;
7 | if(this.priceModel === 'fixed_price') {
8 | this.pricingModel = new FixedPricing(pricingData);
9 | } else if(this.priceModel === 'fixed_price_per_method') {
10 | this.pricingModel = new MethodPricing(pricingData);
11 | } else {
12 | console.log("Unsupported pricing model - " + pricingJSON);
13 | }
14 | }
15 |
16 | getPriceModel() {
17 | return this.priceModel;
18 | }
19 |
20 | getPriceInCogs(serviceName, methodName) {
21 | return this.pricingModel.getPriceInCogs(serviceName, methodName);
22 | }
23 |
24 | getPriceInAGI(serviceName, methodName) {
25 | return this.pricingModel.getPriceInAGI(serviceName, methodName);
26 | }
27 |
28 | getMaxPriceInCogs() {
29 | return this.pricingModel.getMaxPriceInCogs();
30 | }
31 | }
32 |
33 | class FixedPricing {
34 | constructor(pricingData) {
35 | this.priceInCogs = pricingData.price_in_cogs;
36 | this.priceInAGI = AGI.inAGI(pricingData.price_in_cogs);
37 | }
38 |
39 | getPriceInCogs(serviceName, methodName) {
40 | return this.priceInCogs;
41 | }
42 |
43 | getPriceInAGI(serviceName, methodName) {
44 | return this.priceInAGI;
45 | }
46 |
47 | getMaxPriceInCogs() {
48 | return this.priceInCogs;
49 | }
50 | }
51 |
52 | class MethodPricing {
53 | constructor(pricingData) {
54 | this.maxPriceInCogs = 0;
55 | this.pricing = {};
56 |
57 | pricingData.details.map((servicePrice, index) => {
58 | console.log("Method pricing " + servicePrice.service_name)
59 | this.pricing[servicePrice.service_name] = {};
60 | servicePrice.method_pricing.map((methodPrice) => {
61 | if(methodPrice.price_in_cogs > this.maxPriceInCogs) {
62 | this.maxPriceInCogs = methodPrice.price_in_cogs;
63 | }
64 | this.pricing[servicePrice.service_name][methodPrice.method_name] = methodPrice.price_in_cogs;
65 | });
66 | });
67 | }
68 |
69 | getPriceInCogs(serviceName, methodName) {
70 | let methodPricing = this.pricing[serviceName];
71 | return methodPricing[methodName];
72 | }
73 |
74 | getPriceInAGI(serviceName, methodName) {
75 | let priceInCogs = this.getPriceInCogs(serviceName, methodName);
76 | return AGI.inAGI(priceInCogs);
77 | }
78 |
79 | getMaxPriceInCogs() {
80 | return this.maxPriceInCogs;
81 | }
82 | }
--------------------------------------------------------------------------------
/src/components/service/gene-annotation-service/visualizer.config.js:
--------------------------------------------------------------------------------
1 | export const MAXIMUM_GRAPH_SIZE = 1500;
2 |
3 | export const CYTOSCAPE_COLA_CONFIG = {
4 | name: "cola",
5 | animate: true,
6 | maxSimulationTime: 3000,
7 | ungrabifyWhileSimulating: true,
8 | fit: true,
9 | padding: 10,
10 | randomize: true,
11 | avoidOverlap: true,
12 | handleDisconnected: true,
13 | nodeSpacing: 20,
14 | infinite: false
15 | };
16 |
17 | export const CYTOSCAPE_STYLE = [
18 | // Node styles
19 | {
20 | selector: "node",
21 | css: {
22 | shape: "round-rectangle",
23 | width: "mapData(id.length, 0, 20, 50, 300)",
24 | height: "40",
25 | content: "data(id)",
26 | color: "#fff",
27 | "text-wrap": "wrap",
28 | "text-max-width": "350px",
29 | "text-valign": "center",
30 | "text-halign": "center",
31 | "background-color": "#565656",
32 | "text-outline-color": "#565656",
33 | "text-outline-width": 1
34 | }
35 | },
36 | {
37 | selector: 'node[group="biogrid_interaction_annotation"]',
38 | css: {
39 | shape: "ellipse",
40 | width: 75,
41 | height: 75
42 | }
43 | },
44 | {
45 | selector: 'node[id^="Uni"]',
46 | css: {
47 | shape: "hexagon"
48 | }
49 | },
50 | {
51 | selector: 'node[id^="ChEBI"]',
52 | css: {
53 | shape: "diamond",
54 | height: 75
55 | }
56 | },
57 | {
58 | selector: "node:selected",
59 | css: {
60 | "border-width": 5,
61 | "border-color": "#AAD8FF",
62 | "border-opacity": 1
63 | }
64 | },
65 | {
66 | selector: 'node[group="Gene"]',
67 | style: {
68 | shape: "ellipse",
69 | content: "data(id)",
70 | height: 75,
71 | color: "#fff",
72 | "text-outline-color": "#005bcd",
73 | "background-color": "#005bcd"
74 | }
75 | },
76 | {
77 | selector: 'node[group="main"]',
78 | style: {
79 | shape: "ellipse",
80 | content: "data(id)",
81 | width: 75,
82 | height: 75,
83 | color: "#fff",
84 | "background-color": "#005bcd",
85 | "text-outline-color": "#005bcd"
86 | }
87 | },
88 | // Edge styles
89 | {
90 | selector: "edge",
91 | css: {
92 | "curve-style": "haystack",
93 | "line-color": "#ccc",
94 | width: 4
95 | }
96 | },
97 | {
98 | selector: "edge[group='gene_go_annotation']",
99 | css: {
100 | "curve-style": "straight",
101 | "target-arrow-shape": "triangle",
102 | "target-arrow-fill": "filled"
103 | }
104 | }
105 | ];
106 |
--------------------------------------------------------------------------------
/src/grpc.js:
--------------------------------------------------------------------------------
1 | const { ChunkParser, ChunkType } = require("grpc-web-client/dist/ChunkParser")
2 |
3 | async function processResponse(response, callback) {
4 | console.log(response);
5 | let error = null, chunk = null;
6 |
7 | if (response.ok) {
8 | var buffer = await response.arrayBuffer();
9 | chunk = parseChunk(buffer);
10 | var grpcMessage = response.headers.get('Grpc-Message');
11 | if (grpcMessage != null && chunk == null) {
12 | error = grpcMessage;
13 | }
14 | }
15 | else {
16 | let errorStatus = "Connection failed"
17 | if(typeof response.statusText !== 'undefined') {
18 | errorStatus = response.statusText;
19 | }
20 | error = "Request failed with error ["+errorStatus+"]. Please retry in some time."
21 | }
22 |
23 | try
24 | {
25 | callback(error, chunk && chunk.data ? new Uint8Array(chunk.data) : null);
26 | }
27 | catch(err) {
28 | console.log(err);
29 | callback(err);
30 | }
31 | }
32 |
33 | export function rpcImpl(host, packageName, serviceName, methodName, requestHeaders) {
34 | return (method, requestObject, callback) => {
35 | const service = [ packageName, serviceName ].filter(Boolean).join(".")
36 | window.fetch(`${host}/${service}/${methodName}`, {
37 | "method": "POST",
38 | "headers": Object.assign(
39 | {},
40 | {
41 | "content-type": "application/grpc-web+proto",
42 | "x-grpc-web": "1"
43 | },
44 | requestHeaders
45 | ),
46 | "body": frameRequest(requestObject)
47 | })
48 | .then(response => {processResponse(response, callback)}).catch(err => callback(err))
49 | }
50 | }
51 |
52 | function grpcJSONResponseToString(arrayBuffer) {
53 | const responseLength = new DataView(arrayBuffer).getUint8(4)
54 | const unframedResponse = new Uint8Array(arrayBuffer.slice(5, responseLength+5))
55 | return String.fromCharCode(...unframedResponse)
56 | }
57 |
58 | function frameRequest(bytes) {
59 | const frame = new ArrayBuffer(bytes.byteLength + 5)
60 | new DataView(frame, 1, 4).setUint32(0, bytes.length, false)
61 | new Uint8Array(frame, 5).set(bytes)
62 | return new Uint8Array(frame)
63 | }
64 |
65 | function parseChunk(buffer) {
66 | return new ChunkParser()
67 | .parse(new Uint8Array(buffer))
68 | .find(chunk => chunk.chunkType === ChunkType.MESSAGE)
69 | }
70 |
71 | export function grpcRequest(serviceObject, methodName, requestObject) {
72 | methodName = methodName.charAt(0).toLowerCase() + methodName.substr(1)
73 | if (!serviceObject[methodName]) throw new Error(`Service does not have method ${methodName}. ${serviceObject}`)
74 |
75 | return serviceObject[methodName](requestObject)
76 | }
77 |
--------------------------------------------------------------------------------
/src/css/profile.css:
--------------------------------------------------------------------------------
1 | .ProfilegridWrapper {
2 | display: grid;
3 | height: 250px;
4 | width: 100%;
5 | grid-template-rows: 250px 1fr;
6 | grid-template-columns: 5% 40% 5% 40%;
7 | }
8 |
9 | .profilegridspacer { width:100%; }
10 |
11 | .wrapper {
12 | width: 75%;
13 | margin: 30px auto;
14 | }
15 |
16 | .amount-type { width: 100% !important; }
17 | .authorize-deposit-withdraw { padding-bottom: 32px; }
18 |
19 | .authorize-deposit-withdraw a {
20 | border-bottom: 2px solid #959595;
21 | padding: 0 10px 7px;
22 | margin-right: 35px;
23 | font-size: 15px;
24 | text-transform: uppercase;
25 | color: #959595;
26 | }
27 |
28 | .authorize-deposit-withdraw a:hover {
29 | border-bottom: 2px solid #0066ff;
30 | text-decoration: none;
31 | color: #0066ff;
32 | }
33 |
34 | .authorize-deposit-withdraw .active {
35 | border-bottom: 2px solid #0066ff;
36 | color: #0066ff;
37 | }
38 |
39 |
40 | .confirm-btn {
41 | float: right;
42 | color: #fff;
43 | background-color: #0066ff;
44 | border: 1px solid #0066ff;
45 | border-radius: 50px;
46 | padding: 7px 28px;
47 | margin-top: 10px;
48 | font-size: 14px;
49 | }
50 |
51 | .channel-header {
52 | padding: 15px 0;
53 | border-radius: 5px;
54 | font-size: 15px;
55 | font-weight: bold;
56 | border-top: 3px solid #0066ff;
57 | box-shadow: 1px 1px 10px #e0dbdb;
58 | }
59 |
60 | .channel-detail-block {
61 | margin: 25px 0;
62 | box-shadow: 1px 1px 11px 0px #bcd7ff;
63 | }
64 |
65 | .toggle-btn {
66 | float: right;
67 | border: none;
68 | background: none;
69 | }
70 |
71 | .channel-confirmation {
72 | display: none;
73 | background: #f1f1f1;
74 | text-align: right;
75 | }
76 |
77 | .show-confirmation { display: block; }
78 |
79 | .channel-confirmation div {
80 | padding-top: 10px;
81 | padding-bottom: 10px;
82 | }
83 |
84 | .channel-confirmation div input {
85 | border: none;
86 | padding: 7px 0;
87 | margin-right: 10px;
88 | }
89 |
90 | .channel-confirmation button {
91 | margin-top: 0;
92 | float: none;
93 | }
94 |
95 | /* width */
96 | .channel-info::-webkit-scrollbar {
97 | width: 8px;
98 | background-color: #c3c3c3;
99 | }
100 |
101 | /* Track */
102 | .channel-info::-webkit-scrollbar-track {
103 | box-shadow: inset 0 0 5px grey;
104 | border-radius: 10px;
105 | }
106 |
107 | /* Handle */
108 | .channel-info::-webkit-scrollbar-thumb {
109 | background: #676767;
110 | border-radius: 10px;
111 | }
112 |
113 | .MuiCardContent-root-29 { padding-top:0px !important; }
114 |
115 | .MuiTab-root-81 {
116 | min-height:30px !important;
117 | font-size:13px !important;
118 | }
119 |
120 | .MuiTabs-root-72 { min-height:34px !important; }
121 | .MuiInputLabel-shrink-110 { transform: translate(0, 1.5px) scale(1) !important; }
--------------------------------------------------------------------------------
/src/components/service/NewsSummaryService.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class NewSummaryService extends React.Component {
4 |
5 | constructor(props) {
6 | super(props);
7 | this.submitAction = this.submitAction.bind(this);
8 | this.handleFormUpdate = this.handleFormUpdate.bind(this);
9 |
10 | this.state = {
11 | serviceName: "TextSummary",
12 | methodName: "summary",
13 | article_content: 'Analysts are predicting record highs as a global shortage of teddy bears sweeps the nation. "The market these products is way up". The advice is to stay indoors as society collapses under the demand.'
14 | };
15 | }
16 |
17 | canBeInvoked() {
18 | return (this.state.text !== "");
19 | }
20 |
21 | handleFormUpdate(event) {
22 | this.setState({
23 | [event.target.name]: event.target.value
24 | });
25 | }
26 |
27 | submitAction() {
28 | this.props.callApiCallback(this.state.serviceName,
29 | this.state.methodName, {
30 | article_content: this.state.article_content
31 | });
32 | }
33 |
34 | renderForm() {
35 | return (
36 |
37 |
38 |
News text to summarise:
39 |
40 |
43 |
44 |
45 |
46 | Invoke
47 |
48 |
49 |
50 | )
51 | }
52 |
53 | renderComplete() {
54 | const response = this.props.response
55 |
56 | return (
57 |
58 |
Summary of article: {response.article_summary}
59 |
60 | );
61 | }
62 |
63 | render() {
64 | if (this.props.isComplete)
65 | return (
66 |
67 | {this.renderComplete()}
68 |
69 | );
70 | else {
71 | return (
72 |
73 | {this.renderForm()}
74 |
75 | )
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/components/service/gene-annotation-service/GenePathwayFilter.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import {
3 | Grid,
4 | Checkbox,
5 | FormControlLabel,
6 | FormLabel,
7 | Switch
8 | } from "@material-ui/core";
9 |
10 | const options = [
11 | { label: "Reactome", value: "reactome" }
12 | ];
13 |
14 | export default class GenePathwayFilter extends React.Component {
15 | constructor(props) {
16 | super(props);
17 | this.namespaces = this.props.defaults.namespace;
18 | }
19 |
20 | render() {
21 | return (
22 |
23 |
83 |
84 | );
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/components/service/moses-service/DatasetUpload.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { relative } from "path";
3 | import Dropzone from "react-dropzone";
4 | import classNames from "classnames";
5 | import { CloudUpload, Check } from "@material-ui/icons";
6 | import fileSize from "filesize";
7 |
8 | export default class DatasetUpload extends React.Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = {
12 | fileError: false
13 | };
14 | }
15 | componentDidUpdate() {
16 | this.props.setValidationStatus(this.props.uploadedFile ? true : false);
17 | }
18 |
19 | render() {
20 | const props = {
21 | name: "dataset",
22 | multiple: false,
23 | onDrop: files => {
24 | const file = files[0];
25 | this.props.handleFileUpload(file);
26 | return false;
27 | }
28 | };
29 |
30 | return (
31 |
32 |
37 | {({ getRootProps, getInputProps, isDragActive }) => {
38 | return (
39 |
50 |
51 | {this.props.uploadedFile ? (
52 |
53 | ) : (
54 |
55 | )}
56 | {isDragActive ? (
57 |
Drop dataset here...
58 | ) : (
59 |
60 | Click here to select a dataset file, or drag and drop it
61 | over this text.
62 |
63 | )}
64 |
65 | );
66 | }}
67 |
68 | {this.props.uploadedFile && (
69 |
81 | {this.props.uploadedFile.name +
82 | " " +
83 | fileSize(this.props.uploadedFile.size)}
84 |
85 | )}
86 |
87 | );
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/components/service/image-viewer-helpers/MasonryLayout.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | export default class MasonryLayout extends React.Component {
4 | constructor(props) {
5 | super(props);
6 | this.state = {
7 | columns: []
8 | };
9 | this.items = this.props.items;
10 | }
11 |
12 | determineColumnCount() {
13 | const width = this.refs.wrapper.clientWidth;
14 | return width > 960 ? 3 : width > 600 ? 2 : 1;
15 | }
16 |
17 | initializeColumns() {
18 | const columnCount = this.determineColumnCount();
19 | const arr = new Array(columnCount);
20 | for (var i = 0; i < columnCount; i++) {
21 | arr[i] = [];
22 | }
23 | this.setState({ columns: arr });
24 | }
25 |
26 | componentDidMount() {
27 | this.initializeColumns();
28 | }
29 |
30 | componentDidUpdate(prevProps) {
31 | if (prevProps.items !== this.props.items) {
32 | this.items = this.props.items;
33 | this.initializeColumns();
34 | return;
35 | }
36 | if (this.items && this.items.length) {
37 | const columnIndex = this.getShortestColumnIndex();
38 | this.setState(state => {
39 | const columns = state.columns.slice();
40 | columns[columnIndex].push(this.items.pop());
41 | return { columns: columns };
42 | });
43 | }
44 | }
45 |
46 | renderColumns() {
47 | return this.state.columns.map((c, i) => (
48 |
58 | {this.state.columns[i].map((content, j) => (
59 |
{content}
60 | ))}
61 |
62 | ));
63 | }
64 |
65 | getShortestColumnIndex() {
66 | let shortestColumnHeight = this.refs[`col1`].clientHeight;
67 | let shortestColumn = 0;
68 | for (let i = 0; i < this.state.columns.length; i++) {
69 | if (this.refs[`col${i + 1}`].clientHeight < shortestColumnHeight) {
70 | shortestColumnHeight = this.refs[`col${i + 1}`].clientHeight;
71 | shortestColumn = i;
72 | }
73 | }
74 | return shortestColumn;
75 | }
76 |
77 | render() {
78 | return (
79 |
87 | {this.renderColumns()}
88 |
89 | );
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/components/GetStarted.js:
--------------------------------------------------------------------------------
1 | import React, { props } from 'react';
2 | import {Link} from 'react-router-dom';
3 | import Header from "./Header.js";
4 |
5 | export default class GetStarted extends React.Component {
6 | constructor() {
7 | super(props)
8 | }
9 | render() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 | Step 1
18 |
19 |
20 |
21 | Ethereum testnet coins are free and used to test the platform. You will need ether to cover the Gas costs associated with transactions within the platform.
22 | You can get the tokens for Ropsten from
here and for Kovan from
here .
23 | In order to receive these tokens, the user must log in into the Faucet with their GitHub account.
24 |
25 |
26 |
27 |
28 |
29 | Step 2
30 |
31 |
32 |
33 | In order to have AGI to test the platform, users are required to visit the AGI Faucet
here , which is a per-request Kovan/Ropsten AGI distribution hub.
34 | In order to receive these tokens, the user must log in into the AGI Faucet with their GitHub account.
35 |
36 |
37 |
38 |
39 | Step 3
40 |
41 |
42 |
43 | You can add the AGI tokens to the Escrow from the Deposit tab of the {Account } page. You are now set to start invoking services.
44 |
45 |
46 |
47 |
48 |
49 | Step 4
50 |
51 |
52 |
53 | Click on the Job details button of the agent you are interested in to view details of the agent. You can invoke the agent by clicking on the Start Job button. The DApp will attempt to reuse any existing payment channel and if none exist it will create one. Its a good idea to create a channel with enough tokens to cover the number of times you invoke the service. This will optimize your gas costs while invoking services.
54 |
55 |
56 |
57 |
58 |
59 | )
60 | }
61 | }
--------------------------------------------------------------------------------
/src/components/service/MosesService.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import MosesServiceForm from "./moses-service/MosesServiceForm";
3 | import MosesServiceResult from "./moses-service/MosesServiceResult";
4 | import { Snackbar, SnackbarContent, CircularProgress } from "@material-ui/core";
5 | import { withStyles } from "@material-ui/core/styles";
6 | import red from "@material-ui/core/colors/red";
7 |
8 | const ErrorSnackbarContent = withStyles({
9 | root: { background: red[600] },
10 | message: { color: "#fff" }
11 | })(SnackbarContent);
12 |
13 | const showNotification = ({ message, busy }, callBack) => {
14 | return (
15 |
30 | {busy ? (
31 |
34 |
39 | {message}
40 |
41 | }
42 | />
43 | ) : (
44 | {message}} />
45 | )}
46 |
47 | );
48 | };
49 |
50 | export default class MosesService extends React.Component {
51 | constructor(props) {
52 | super(props);
53 | this.state = {
54 | busy: false,
55 | error: null,
56 | notification: null
57 | };
58 | this.handleSubmit = this.handleSubmit.bind(this);
59 | }
60 |
61 | componentDidUpdate(nextProps) {
62 | if (this.props.isComplete !== nextProps.isComplete) {
63 | if (!this.props.response || !this.props.response.resultUrl) {
64 | this.state.notification = {
65 | message: nextProps.response.description,
66 | busy: false
67 | };
68 | } else {
69 | this.state.notification = null;
70 | }
71 | }
72 | }
73 |
74 | parseResponse() {
75 | const { response } = this.props;
76 | if (typeof response !== "undefined") {
77 | return response;
78 | }
79 | }
80 |
81 | handleSubmit(analysisParameters) {
82 | this.setState({
83 | busy: true,
84 | notification: { message: "Attempting to start analysis ...", busy: true }
85 | });
86 | this.props.callApiCallback(
87 | "MosesService",
88 | "StartAnalysis",
89 | analysisParameters
90 | );
91 | }
92 |
93 | renderForm() {
94 | return (
95 |
100 | );
101 | }
102 |
103 | renderComplete() {
104 | return ;
105 | }
106 |
107 | render() {
108 | return (
109 |
110 | {this.props.isComplete ? this.renderComplete() : this.renderForm()}
111 | {this.state.notification &&
112 | showNotification(this.state.notification, () => {
113 | this.setState({ notification: null });
114 | })}
115 |
116 | );
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/components/service/analysis-helpers/DatasetUploaderHelper.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import {relative} from "path";
3 | import Dropzone from "react-dropzone";
4 | import classNames from "classnames";
5 | import {CloudUpload, Check} from "@material-ui/icons";
6 | import fileSize from "filesize";
7 |
8 | export default class DatasetUpload extends React.Component {
9 | constructor(props) {
10 | super(props);
11 | this.state = {
12 | fileError: false
13 | };
14 | }
15 |
16 | componentDidUpdate() {
17 | this.props.setValidationStatus(this.props.uploadedFile ? true : false);
18 | }
19 |
20 | render() {
21 | const props = {
22 | name: "dataset",
23 | multiple: false,
24 | onDrop: files => {
25 | const file = files[0];
26 | this.props.handleFileUpload(file);
27 | return false;
28 | }
29 | };
30 |
31 | return (
32 |
33 |
38 | {({getRootProps, getInputProps, isDragActive}) => {
39 | return (
40 |
51 |
52 | {this.props.uploadedFile ? (
53 |
54 | ) : (
55 |
56 | )}
57 | {isDragActive ? (
58 |
Drop dataset here...
59 | ) : (
60 |
61 | Click here to select a dataset file, or drag and drop it
62 | over this text. We expect {this.props.fileAccept} to be uploaded. Other files
63 | are disabled.
64 |
65 | )}
66 |
67 | );
68 | }}
69 |
70 | {this.props.uploadedFile && (
71 |
83 | {this.props.uploadedFile.name +
84 | " " +
85 | fileSize(this.props.uploadedFile.size)}
86 |
87 | )}
88 |
89 | );
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "beta-dapp",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "serve-sandbox": "webpack-dev-server --env.sandBox=true --config ./config/webpack.dev.js --progress --colors --open",
7 | "serve": "webpack-dev-server --env.sandBox=false --config ./config/webpack.dev.js --progress --colors --open",
8 | "build": "webpack --config ./config/webpack.prod.js -p --progress --colors",
9 | "build-analyze": "webpack --config ./config/webpack.prod-analyze.js -p --progress --colors",
10 | "serve-dist": "node scripts/serveDist.js",
11 | "deploy": "node scripts/deploy.js beta.singularitynet.io us-east-1"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/singnet/snet-dapp.git"
16 | },
17 | "author": "SingularityNET Foundation",
18 | "license": "MIT",
19 | "bugs": {
20 | "url": "https://github.com/singnet/snet-dapp/issues"
21 | },
22 | "homepage": "https://github.com/singnet/snet-dapp#readme",
23 | "dependencies": {
24 | "@fortawesome/fontawesome-svg-core": "^1.2.12",
25 | "@fortawesome/free-brands-svg-icons": "^5.6.3",
26 | "@fortawesome/free-regular-svg-icons": "^5.6.3",
27 | "@fortawesome/free-solid-svg-icons": "^5.6.3",
28 | "@fortawesome/react-fontawesome": "^0.1.3",
29 | "abi-decoder": "^1.1.0",
30 | "bitcoinjs-lib": "^3.3.2",
31 | "cytoscape": "^3.3.3",
32 | "cytoscape-cola": "^2.3.0",
33 | "file-loader": "^1.1.11",
34 | "filesize": "^4.0.0",
35 | "grpc-web-client": "^0.6.3",
36 | "html2canvas": "^1.0.0-alpha.12",
37 | "jquery": "^3.3.1",
38 | "lodash": "^4.17.5",
39 | "md5": "^2.2.1",
40 | "prop-types": "^15.6.2",
41 | "protobufjs": "^6.8.8",
42 | "qrcode.react": "^0.8.0",
43 | "react": "^16.3.1",
44 | "react-bootstrap": "^0.32.1",
45 | "react-copy-to-clipboard": "^5.0.1",
46 | "react-dom": "^16.3.1",
47 | "react-dropzone": "^8.0.4",
48 | "react-file-drop": "^0.2.7",
49 | "react-google-charts": "^3.0.10",
50 | "react-json-view": "^1.19.1",
51 | "react-masonry-component": "^6.2.1",
52 | "react-perfect-scrollbar": "^1.4.4",
53 | "react-swipeable-views": "^0.13.1",
54 | "styled-components": "^3.2.5",
55 | "underscore": "^1.9.1",
56 | "web3": "0.20.1"
57 | },
58 | "devDependencies": {
59 | "@material-ui/core": "^3.5.1",
60 | "@material-ui/icons": "^3.0.1",
61 | "@material-ui/lab": "^3.0.0-alpha.30",
62 | "aws-sdk": "^2.279.1",
63 | "babel-core": "^6.26.0",
64 | "babel-loader": "^7.1.4",
65 | "babel-plugin-import": "^1.7.0",
66 | "babel-preset-es2015": "^6.24.1",
67 | "babel-preset-react": "^6.24.1",
68 | "bignumber.js": "^8.0.1",
69 | "bn.js": "^4.11.8",
70 | "compression-webpack-plugin": "^1.1.11",
71 | "css-loader": "^0.28.11",
72 | "ethereumjs-abi": "^0.6.5",
73 | "ethjs": "^0.3.9",
74 | "express": "^4.16.3",
75 | "html-webpack-plugin": "^3.2.0",
76 | "less": "^3.8.0",
77 | "less-loader": "^4.1.0",
78 | "material-ui-flat-pagination": "^3.1.0",
79 | "material-ui-pagination": "^1.1.6",
80 | "mini-css-extract-plugin": "^0.5.0",
81 | "react-circular-progressbar": "^1.0.0",
82 | "react-dropdown": "^1.6.2",
83 | "react-hot-loader": "^4.0.1",
84 | "react-router-dom": "^4.3.1",
85 | "recursive-readdir": "^2.2.2",
86 | "singularitynet-platform-contracts": "^0.3.0",
87 | "singularitynet-token-contracts": "^2.0.1",
88 | "style-loader": "^0.20.3",
89 | "uglifyjs-webpack-plugin": "^1.2.5",
90 | "webpack": "^4.16.2",
91 | "webpack-bundle-analyzer": "^2.11.1",
92 | "webpack-cli": "^3.1.0",
93 | "webpack-dev-middleware": "^3.1.2",
94 | "webpack-dev-server": "^3.1.14",
95 | "webpack-hot-middleware": "^2.22.3",
96 | "webpack-merge": "^4.1.2"
97 | },
98 | "sideEffects": false
99 | }
100 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # snet-dapp
2 |
3 | This Dapp allows you to browse the list of services from the SingularityNET Registry and call them.
4 | By default it uses the SingularityNET contracts deployed on the Kovan testnet.
5 |
6 | To get Kovan AGI to use the Dapp you can use the official [SingularityNET AGI Faucet](https://faucet.singularitynet.io/).
7 | To get Kovan ETH to pay for gas costs you should refer to [this repo](https://github.com/kovan-testnet/faucet).
8 |
9 | # The beta dapp is under active development and will see several changes in the upcoming weeks
10 | ## How to call a Service
11 |
12 | 1. Get [Ether](https://github.com/kovan-testnet/faucet) and [AGI](https://faucet.singularitynet.io/) on the Kovan network
13 | 2. Navigate to the SingularityNET beta [dapp](http://beta.singularitynet.io/)
14 | 3. Unlock MetaMask
15 | 4. Authorize tokens for transfer to the Multi party escrow in the profile page
16 | 5. Transfer tokens to the Multi party escrow in the profile page
17 | 6. Click the "Details" button on the agent list in the home page. This will bring out a job slide out
18 | 7. Click the "Start Job" button to initiate the invocation flow in the slide out
19 | 6. To invoke an agent you first need to create a channel by allocating funds from the escrow. You can also set an expiry block number.
20 | 7. Click on the Reserve funds button which will open the channel
21 | 8. Once the channel has been created you can invoke the agent by selecting the service and method and passing in the expected input.
22 | 9. The result from the operation is displayed in the result tab
23 |
24 | ## Development instructions
25 | * Install [Node.js and npm](https://nodejs.org/)
26 | * `npm install` to get dependencies
27 | * `npm run serve` to serve the application locally and watch source files for modifications
28 |
29 | ### Deployment instructions
30 | * `npm run build` builds the application distributable files to the `dist` directory
31 | * `npm run deploy`; the target S3 Bucket for the deployment and its region are specified as command line parameters in the package.json file npm script
32 |
33 | ### Additional commands
34 | * `npm run build-analyze` shows the size of the application's bundle components; the original size, the parsed size (uglified + tree-shaken) and the gzipped size
35 | * `npm run serve-dist` serves the `dist` directory locally
36 |
37 |
38 | ### UI for Services
39 | Currently the UI needed by a service to capture inputs and render the output must be provided by the service developer as a PR. It must be provided in the form of a React component. The component will be contructed with the following properties
40 | * isComplete - Flag indicating if the service call has completed
41 | * serviceSpec - JSON object corresponding to the protobuf service definition
42 | * callApiCallback - Function to be called when the service needs to be called. The signature of this function is `callApiCallback(serviceName,methodName, requestObject)`. The component must invoke this callback with the service name, method name and the request object for the call to succeed.
43 | * response - The response object returned by the service call. This is sent only when isComplete is true. If the service call fails the DApp will display the error
44 |
45 | To aid testing of the service before its published to the platform, the DApp has a standalone mode in which the UI can be tested. Here is how you use it
46 | 1. Set up the AI service with the snet daemon
47 | 2. The snet daemon should have the `blockchain_enabled` flag set to false
48 | 3. Update the `src/components/service/ServiceMappings.js` with the mapping for the service
49 | 4. Run the DApp `npm run serve-sandbox`
50 | 5. Enter the service id, org id, proto file contents and the daemon endpoint to start testing the UI
51 |
52 | This approach will change in the future as we support a generic mechanism to declaratively describe a service's API. See [this](https://github.com/singnet/custom-ui-research) for more details
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/src/protobuf.js:
--------------------------------------------------------------------------------
1 | import protobuf from "protobufjs";
2 |
3 | /**
4 | * @class Protobuf
5 | * @param jsonDescriptor
6 | */
7 | export default class ProtoBuf {
8 | constructor({ jsonDescriptor }) {
9 | this.json = jsonDescriptor;
10 | this.root = protobuf.Root.fromJSON(jsonDescriptor);
11 |
12 | this.services = {};
13 |
14 | this.mockValue = this.mockValue.bind(this);
15 | this.generateStubs = this.generateStubs.bind(this)
16 | this.isValidMessage = this.isValidMessage.bind(this);
17 | this.findServiceByMethod = this.findServiceByMethod.bind(this);
18 | this.getFieldsFromMessage = this.getFieldsFromMessage.bind(this);
19 | }
20 |
21 | mockValue(type, rule) {
22 | let defaultValue = "";
23 |
24 | if (rule === "repeated") {
25 | //TODO handle array types
26 | //It's an array of type
27 | return [];
28 | }
29 |
30 | switch (type) {
31 | case "string":
32 | return new String();
33 | case "bool":
34 | return new Boolean();
35 | case "float":
36 | return new Number();
37 | case "double":
38 | return new Number();
39 | case "bytes":
40 | return new Uint8Array();
41 | default:
42 | return "";
43 | }
44 | }
45 |
46 | getFieldsFromMessage(message) {
47 | let fields = {};
48 | Object.entries(message.fields).forEach(([fieldKey, fieldValue]) => {
49 | fieldValue = this.mockValue(fieldValue.type, fieldValue.rule);
50 | Object.assign(fields, { [fieldKey]: fieldValue });
51 | });
52 | return fields;
53 | }
54 |
55 | findServiceByMethod(methodName) {
56 | let found = undefined;
57 | Object.entries(this.services).forEach(([serviceName, service]) => {
58 | const methods = Object.keys(service.methods);
59 | if (methods.indexOf(methodName) !== -1) {
60 | found = serviceName;
61 | }
62 | })
63 | return found;
64 | }
65 |
66 | isValidMessage(message, payload) {
67 | if (message.verify(payload))
68 | return false;
69 | else
70 | return true;
71 | }
72 |
73 | generateStubs(rpcCallMethod) {
74 | rpcCallMethod = rpcCallMethod || (() => undefined)
75 | traverseServices(this.root, service => {
76 | const CurrentClass = this.root.lookup(service.name);
77 | const currentClass = CurrentClass.create(rpcCallMethod, false, false);
78 |
79 | Object.entries(service.methods)
80 | .forEach(([methodName, { requestType, responseType }]) => {
81 | const RequestType = this.root.lookupType(requestType);
82 | const ResponseType = this.root.lookupType(responseType);
83 | const call = (params) => currentClass[methodName](params);
84 | Object.assign(this.services, { [service.name]: { methods: { [methodName]: { call, RequestType, ResponseType } } } });
85 | });
86 | });
87 | }
88 | }
89 |
90 |
91 | function traverseServices(current, fn) {
92 | if (current instanceof protobuf.Service) // and/or protobuf.Enum, protobuf.Service etc.
93 | fn(current);
94 | if (current.nestedArray)
95 | current.nestedArray.forEach(function (nested) {
96 | traverseServices(nested, fn);
97 | });
98 | }
99 |
100 | function traverseTypes(current, fn) {
101 | if (current instanceof protobuf.Type) // and/or protobuf.Enum, protobuf.Service etc.
102 | fn(current);
103 | if (current.nestedArray)
104 | current.nestedArray.forEach(function (nested) {
105 | traverseTypes(nested, fn);
106 | });
107 | }
108 |
--------------------------------------------------------------------------------
/src/js/gdpr.js:
--------------------------------------------------------------------------------
1 | export default function(){
2 | var elem = document.createElement('script');
3 | elem.src = 'https://quantcast.mgr.consensu.org/cmp.js';
4 | elem.async = true;
5 | elem.type = "text/javascript";
6 | var scpt = document.getElementsByTagName('script')[0];
7 | scpt.parentNode.insertBefore(elem, scpt);
8 | (function() {
9 | var gdprAppliesGlobally = false;
10 | function addFrame() {
11 | if (!window.frames['__cmpLocator']) {
12 | if (document.body) {
13 | var body = document.body,
14 | iframe = document.createElement('iframe');
15 | iframe.style = 'display:none';
16 | iframe.name = '__cmpLocator';
17 | body.appendChild(iframe);
18 | } else {
19 | // In the case where this stub is located in the head,
20 | // this allows us to inject the iframe more quickly than
21 | // relying on DOMContentLoaded or other events.
22 | setTimeout(addFrame, 5);
23 | }
24 | }
25 | }
26 | addFrame();
27 | function cmpMsgHandler(event) {
28 | var msgIsString = typeof event.data === "string";
29 | var json;
30 | if(msgIsString) {
31 | json = event.data.indexOf("__cmpCall") != -1 ? JSON.parse(event.data) : {};
32 | } else {
33 | json = event.data;
34 | }
35 | if (json.__cmpCall) {
36 | var i = json.__cmpCall;
37 | window.__cmp(i.command, i.parameter, function(retValue, success) {
38 | var returnMsg = {"__cmpReturn": {
39 | "returnValue": retValue,
40 | "success": success,
41 | "callId": i.callId
42 | }};
43 | event.source.postMessage(msgIsString ?
44 | JSON.stringify(returnMsg) : returnMsg, '*');
45 | });
46 | }
47 | }
48 | window.__cmp = function (c) {
49 | var b = arguments;
50 | if (!b.length) {
51 | return __cmp.a;
52 | }
53 | else if (b[0] === 'ping') {
54 | b[2]({"gdprAppliesGlobally": gdprAppliesGlobally,
55 | "cmpLoaded": false}, true);
56 | } else if (c == '__cmp')
57 | return false;
58 | else {
59 | if (typeof __cmp.a === 'undefined') {
60 | __cmp.a = [];
61 | }
62 | __cmp.a.push([].slice.apply(b));
63 | }
64 | }
65 | window.__cmp.gdprAppliesGlobally = gdprAppliesGlobally;
66 | window.__cmp.msgHandler = cmpMsgHandler;
67 | if (window.addEventListener) {
68 | window.addEventListener('message', cmpMsgHandler, false);
69 | }
70 | else {
71 | window.attachEvent('onmessage', cmpMsgHandler);
72 | }
73 | })();
74 | window.__cmp('init', {
75 | 'Language': 'en',
76 | 'Initial Screen Reject Button Text': 'I do not accept',
77 | 'Initial Screen Accept Button Text': 'I accept',
78 | 'Purpose Screen Body Text': 'You can set your consent preferences and determine how you want your data to be used based on the purposes below. You may set your preferences for us independently from those of third-party partners. Each purpose has a description so that you know how we and partners use your data.',
79 | 'Vendor Screen Body Text': 'You can set consent preferences for each individual third-party company below. Expand each company list item to see what purposes they use data for to help make your choices. In some cases, companies may disclose that they use your data without asking for your consent, based on their legitimate interests. You can click on their privacy policies for more information and to opt out.',
80 | 'Vendor Screen Accept All Button Text': 'Accept all',
81 | 'Vendor Screen Reject All Button Text': 'Reject all',
82 | 'Initial Screen Body Text': 'We and our partners use technology such as cookies on our site to personalise content and ads, provide social media features, and analyse our traffic. Click below to consent to the use of this technology across the web. You can change your mind and change your consent choices at anytime by returning to this site.',
83 | 'Initial Screen Body Text Option': 1,
84 | 'Publisher Name': 'Stichting SingularityNET',
85 | 'Min Days Between UI Displays': 90,
86 | 'Publisher Purpose IDs': [1,2,3,4,5],
87 | 'No Option': false,
88 | });
89 | }
90 |
91 |
--------------------------------------------------------------------------------
/src/components/CardDeckers.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export class Carddeckers extends React.Component {
4 | constructor(props) {
5 | super(props);
6 |
7 | this.state = {
8 | visible: false,
9 | };
10 | this.toggleVisible = this.toggleVisible.bind(this);
11 | }
12 |
13 | toggleVisible() {
14 |
15 | this.setState({ visible: !this.state.visible });
16 | }
17 |
18 | render()
19 | {
20 | const cursor = {
21 | cursor: 'pointer'
22 | };
23 | if (!this.state.visible) return (
24 |
25 |
26 |
New & Hot in Community ...
27 |
28 |
29 | )
30 | else
31 | return (
32 |
33 |
34 |
New & Hot in Community x
35 |
36 |
37 |
38 |
39 |
Joe Rogan Learns About Blockchain
40 |
Revisiting the basics of blockchain technology on the Joe Rogan Experience podcast.
41 |
42 | Read
43 |
44 |
45 |
46 |
47 |
48 |
Singularity Studio
49 |
SingularityNET & Singularity Studio Blitzscaling Toward the Singularity
50 |
51 | Read
52 |
53 |
54 |
55 |
56 |
57 |
Data as Labor
58 |
Rethinking Jobs In The Information age as AI gets more prevalant and ubiqutious
59 |
60 | Read
61 |
62 |
63 |
64 |
65 |
66 |
AGI & The New Space Frontier
67 |
Exploring the evolution of technologies that will shape our lives
68 |
69 | Read
70 |
71 |
72 |
73 |
74 |
75 |
76 | )
77 | }
78 | }
79 |
80 |
81 |
--------------------------------------------------------------------------------
/src/components/service/moses-service/CrossValOpts.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { TextField, Grid, Tooltip } from "@material-ui/core";
3 | import { checkRequired, checkMin, checkBetween } from "./utils";
4 |
5 | export default class CrossValidationOptionsForm extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = {
9 | validationErrors: {
10 | folds: null,
11 | randomSeed: null,
12 | testSize: null
13 | }
14 | };
15 | }
16 |
17 | updateValidationStatus() {
18 | this.props.setValidationStatus(
19 | Object.values(this.state.validationErrors).filter(v => v).length === 0
20 | );
21 | }
22 |
23 | validateForm(oldValues, newValues) {
24 | const validationErrors = Object.assign({}, this.state.validationErrors);
25 | let valuesChanged = false;
26 | if (newValues.folds !== oldValues.folds) {
27 | validationErrors.folds =
28 | checkRequired(newValues.folds) || checkMin(newValues.folds, 1);
29 | valuesChanged = true;
30 | }
31 | if (newValues.randomSeed !== oldValues.randomSeed) {
32 | validationErrors.randomSeed = checkRequired(newValues.randomSeed);
33 | valuesChanged = true;
34 | }
35 | if (newValues.testSize !== oldValues.testSize) {
36 | validationErrors.testSize =
37 | checkRequired(newValues.testSize) ||
38 | checkBetween(newValues.testSize, 0, 1);
39 | valuesChanged = true;
40 | }
41 | return valuesChanged
42 | ? this.setState({ validationErrors: validationErrors })
43 | : null;
44 | }
45 |
46 | componentDidUpdate(prevProps, prevState, snapshot) {
47 | this.validateForm(prevProps.defaults, this.props.defaults);
48 | }
49 |
50 | render() {
51 | this.updateValidationStatus();
52 | return (
53 |
57 |
116 |
117 | );
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/components/service/TranslationService.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class TranslationService extends React.Component {
4 |
5 | constructor(props) {
6 | super(props);
7 | this.submitAction = this.submitAction.bind(this);
8 | this.handleFormUpdate = this.handleFormUpdate.bind(this);
9 |
10 | this.state = {
11 | serviceName: "Translation",
12 | methodName: "translate",
13 | source_language: "en",
14 | target_language: "de",
15 | text: "Welcome to the future!"
16 | };
17 | }
18 |
19 | canBeInvoked() {
20 | return (this.state.text !== "");
21 | }
22 |
23 | handleFormUpdate(event) {
24 | this.setState({
25 | [event.target.name]: event.target.value
26 | });
27 | }
28 |
29 | submitAction() {
30 | this.props.callApiCallback(this.state.serviceName,
31 | this.state.methodName, {
32 | source_language: this.state.source_language,
33 | target_language: this.state.target_language,
34 | text: this.state.text
35 | });
36 | }
37 |
38 | renderForm() {
39 | // One day this should come from the service when free method calls are allowed.
40 | const languages = ["en", "de"];
41 | const languageOptions = languages.map((lang, index) => {
42 | return {lang} ;
43 | });
44 | return (
45 |
46 |
47 |
Source Language:
48 |
49 |
53 | {languageOptions}
54 |
55 |
56 |
57 |
58 |
Target Language:
59 |
60 |
64 | {languageOptions}
65 |
66 |
67 |
68 |
69 |
Text to translate:
70 |
71 |
74 |
75 |
76 |
77 | Invoke
78 |
79 |
80 |
81 | )
82 | }
83 |
84 | renderComplete() {
85 | const response = this.props.response
86 |
87 | return (
88 |
89 |
Response from service is: {response.translation}
90 |
91 | );
92 | }
93 |
94 | render() {
95 | if (this.props.isComplete)
96 | return (
97 |
98 | {this.renderComplete()}
99 |
100 | );
101 | else {
102 | return (
103 |
104 | {this.renderForm()}
105 |
106 | )
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/css/background.css:
--------------------------------------------------------------------------------
1 |
2 | /***************** Full Width Section ******************/
3 | .full-width-section {
4 | background-size:cover;
5 | -moz-background-size:cover;
6 | -webkit-background-size:cover;
7 | box-sizing:content-box!important;
8 | -moz-box-sizing:content-box!important;
9 | -webkit-box-sizing:content-box!important;
10 | width:100%;
11 | position:relative;
12 | visibility:hidden;
13 | }
14 |
15 | .full-width-content.parallax_section {
16 | background-size:cover;
17 | -moz-background-size:cover;
18 | -webkit-background-size:cover;
19 | }
20 |
21 | .full-width-content.vc_row-fluid .wpb_column {
22 | background-position:center;
23 | background-size:cover;
24 | -moz-background-size:cover;
25 | -webkit-background-size:cover;
26 | }
27 |
28 | .wpb_row { position:relative; }
29 |
30 | .wpb_row .row-bg,
31 | .full-width-section .row-bg {
32 | position:absolute; top:0;
33 | left:0;
34 | width:100%;
35 | height:100%;
36 | background-size:cover;
37 | -moz-background-size:cover;
38 | -webkit-background-size:cover;
39 | }
40 |
41 | .wpb_row .row-bg-wrap:after,
42 | .wpb_row .row-bg[data-enable_gradient="true"][data-overlay_strength="image_trans"]:before {
43 | display:block;
44 | position:absolute;
45 | top:0;
46 | left:0;
47 | width:100%;
48 | height:100%;
49 | content:' ';
50 | z-index:2;
51 | }
52 |
53 | /* shape divider */
54 | .nectar-shape-divider-wrap {
55 | position: absolute;
56 | top: auto;
57 | bottom: 0;
58 | left: 0;
59 | right: 0;
60 | width: 100%;
61 | height: 200px;
62 | z-index: 2;
63 | transform: translateZ(0);
64 | }
65 |
66 | .post-area.span_9 .nectar-shape-divider-wrap { overflow: hidden; }
67 |
68 | .nectar-shape-divider-wrap[data-position="top"] {
69 | top: -1px;
70 | bottom: auto;
71 | }
72 |
73 | .nectar-shape-divider-wrap[data-position="top"] { transform: rotate(180deg); }
74 | .nectar-shape-divider-wrap[data-front="true"] { z-index: 50; }
75 |
76 | /*fix jagged edges*/
77 | .nectar-shape-divider-wrap[data-style="curve"] .nectar-shape-divider {
78 | filter: blur(0.5px);
79 | transform: scale(1.03);
80 | }
81 |
82 | .nectar-shape-divider-wrap[data-style="waves_opacity"] svg path:first-child { opacity: 0.6; }
83 |
84 | .nectar-shape-divider-wrap[data-style="fan"] svg { width: 102%; left: -1%; }
85 | .nectar-shape-divider-wrap[data-style="fan"] svg polygon:nth-child(2) { opacity: 0.15; }
86 | .nectar-shape-divider-wrap[data-style="fan"] svg rect { opacity: 0.3; }
87 |
88 | .nectar-shape-divider-wrap[data-style="mountains"] svg path:first-child { opacity: 0.1; }
89 | .nectar-shape-divider-wrap[data-style="mountains"] svg path:nth-child(2) { opacity: 0.12; }
90 | .nectar-shape-divider-wrap[data-style="mountains"] svg path:nth-child(3) { opacity: 0.18; }
91 | .nectar-shape-divider-wrap[data-style="mountains"] svg path:nth-child(4) { opacity: 0.33; }
92 |
93 | .nectar-shape-divider-wrap[data-style="curve_opacity"] svg path:nth-child(1),
94 | .nectar-shape-divider-wrap[data-style="waves_opacity_alt"] svg path:nth-child(1) { opacity: 0.15; }
95 | .nectar-shape-divider-wrap[data-style="curve_opacity"] svg path:nth-child(2),
96 | .nectar-shape-divider-wrap[data-style="waves_opacity_alt"] svg path:nth-child(2) { opacity: 0.3; }
97 |
98 | .nectar-shape-divider {
99 | width: 100%;
100 | left: 0;
101 | bottom: -1px;
102 | height: 100%;
103 | position: absolute;
104 | }
105 |
106 | .nectar-shape-divider-wrap.no-color .nectar-shape-divider { fill: #fff; }
107 |
108 | .row-bg-wrap.instance-0:after {
109 | background: #40ceff;
110 | background: linear-gradient(90deg,#40ceff 0%,#5a2ff1 100%);
111 | opacity: 1;
112 | }
113 |
114 | .row-bg-wrap.instance-2:after {
115 | background: #40ceff;
116 | background: linear-gradient(90deg,#40ceff 0%,#5a2ff1 100%);
117 | opacity: 1;
118 | }
119 |
120 | .row-bg-wrap.instance-4:after {
121 | background: #40ceff;
122 | background: linear-gradient(135deg,#40ceff 0%,#5a2ff1 100%);
123 | opacity: 0.8;
124 | }
125 |
126 | @media only screen and (max-width: 1000px) {
127 | .nectar-shape-divider { height: 75%; }
128 | .nectar-shape-divider-wrap[data-style="clouds"] .nectar-shape-divider { height: 55%; }
129 | .nectar-shape-divider-wrap[data-style="clouds"] .nectar-shape-divider { min-width: 800px; }
130 | }
131 |
132 | @media only screen and (max-width: 690px) {
133 | .nectar-shape-divider { height: 33%; }
134 | .nectar-shape-divider-wrap[data-style="clouds"] .nectar-shape-divider { height: 33%; }
135 | .nectar-shape-divider-wrap[data-style="clouds"] .nectar-shape-divider { min-width: 690px; }
136 | }
137 |
138 | @media only screen and (min-width: 1000px) {
139 | .nectar-shape-divider-wrap[data-style="clouds"] .nectar-shape-divider { min-width: 1700px; }
140 | }
--------------------------------------------------------------------------------
/src/components/service/HolisticEdgeDetectionService.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Grid} from '@material-ui/core';
3 | import SNETImageUpload from "./standardComponents/SNETImageUpload";
4 | import {ImageGridViewer} from "./image-viewer-helpers/ImageGridViewer";
5 |
6 | export default class HolisticEdgeDetectionService extends React.Component {
7 |
8 | constructor(props) {
9 | super(props);
10 | this.handleImageUpload = this.handleImageUpload.bind(this);
11 | this.handleServiceName = this.handleServiceName.bind(this);
12 | this.handleFormUpdate = this.handleFormUpdate.bind(this);
13 | this.submitAction = this.submitAction.bind(this);
14 |
15 | this.state = {
16 | serviceName: "Edgedetect",
17 | methodName: "Select a method",
18 | uploadedImage: null,
19 | uploadedImageType: null
20 | };
21 | }
22 |
23 | canBeInvoked() {
24 | // When the image isn't uploaded yet and when function name isn't yet given.
25 | return (this.state.methodName !== "Select a method") && (this.state.uploadedImage !== null)
26 | }
27 |
28 | handleFormUpdate(event) {
29 | this.setState({
30 | [event.target.name]: event.target.value
31 | });
32 | }
33 |
34 | handleImageUpload(imageData, mimeType) {
35 | this.setState({
36 | uploadedImage: imageData,
37 | uploadedImageType: mimeType
38 | });
39 | }
40 |
41 | handleServiceName(event) {
42 | let strService = event.target.value;
43 | this.setState({
44 | serviceName: strService
45 | });
46 | }
47 |
48 | renderServiceMethodNames(serviceMethodNames) {
49 | const serviceNameOptions = ["Select a method", ...serviceMethodNames];
50 | return serviceNameOptions.map((serviceMethodName, index) => {
51 | return {serviceMethodName} ;
52 | });
53 | }
54 |
55 | submitAction() {
56 | this.props.callApiCallback(this.state.serviceName,
57 | this.state.methodName, {
58 | image: this.state.uploadedImage,
59 | image_type: this.state.uploadedImageType
60 | });
61 | }
62 |
63 | renderForm() {
64 | const service = this.props.protoSpec.findServiceByName(this.state.serviceName);
65 | const serviceMethodNames = service.methodNames;
66 |
67 | return (
68 |
69 |
70 |
Method Name:
72 |
73 |
74 |
78 | {this.renderServiceMethodNames(serviceMethodNames)}
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | Call Edge Detection Algorithm
88 |
89 |
90 |
91 | )
92 | }
93 |
94 | parseResponse() {
95 | const {response} = this.props;
96 | if (typeof response !== 'undefined') {
97 | if (typeof response === 'string') {
98 | return response;
99 | }
100 | return response;
101 | }
102 | }
103 |
104 | renderComplete() {
105 | const response = this.parseResponse();
106 | return (
107 |
108 |
109 |
110 |
111 |
112 | );
113 | }
114 |
115 | render() {
116 | if (this.props.isComplete)
117 | return (
118 |
119 | {this.renderComplete()}
120 |
121 | );
122 | else {
123 | return (
124 |
125 | {this.renderForm()}
126 |
127 | )
128 | }
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/components/service/EmotionRecognitionService.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SNETImageUpload from "./standardComponents/SNETImageUpload";
3 | import EmotionVisualizer from './emotion-recognition-service/EmotionVisualizer';
4 |
5 |
6 | export default class EmotionRecognitionService extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | this.handleImageUpload = this.handleImageUpload.bind(this);
10 | this.handleServiceName = this.handleServiceName.bind(this);
11 | this.handleFormUpdate = this.handleFormUpdate.bind(this);
12 | this.submitAction = this.submitAction.bind(this);
13 |
14 | this.state = {
15 | serviceName: "EmotionRecognition",
16 | methodName: "Select a method",
17 | uploadedImage: null,
18 | uploadedImageType: null
19 | }
20 | }
21 |
22 | canBeInvoked() {
23 | // When the image isn't uploaded yet and when function name isn't yet given.
24 | return (this.state.methodName !== 'Select a method') && (this.state.uploadedImage !== null)
25 | }
26 |
27 | handleFormUpdate(event) {
28 | this.setState({
29 | [event.target.name]: event.target.value
30 | });
31 | }
32 |
33 | handleImageUpload(imageData, mimeType) {
34 | this.setState({
35 | uploadedImage: imageData,
36 | uploadedImageType: mimeType
37 | });
38 | }
39 |
40 | handleServiceName(event) {
41 | let strService = event.target.value;
42 | this.setState({
43 | serviceName: strService
44 | });
45 | }
46 |
47 | renderServiceMethodNames(serviceMethodNames) {
48 | const serviceNameOptions = ["Select a method", ...serviceMethodNames];
49 | return serviceNameOptions.map((serviceMethodName, index) => {
50 | return {serviceMethodName} ;
51 | });
52 | }
53 |
54 | submitAction() {
55 | this.props.callApiCallback(this.state.serviceName,
56 | this.state.methodName, {
57 | image: this.state.uploadedImage,
58 | image_type: this.state.uploadedImageType
59 | });
60 | }
61 |
62 | renderForm() {
63 | const service = this.props.protoSpec.findServiceByName(this.state.serviceName);
64 | const serviceMethodNames = service.methodNames;
65 |
66 | return (
67 |
68 |
69 |
Method Name:
71 |
72 |
73 |
77 | {this.renderServiceMethodNames(serviceMethodNames)}
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | Call Emotion Recognizer
87 |
88 |
89 |
90 | )
91 | }
92 |
93 | parseResponse() {
94 | const {response} = this.props;
95 | if (typeof response !== 'undefined') {
96 | if (typeof response === 'string') {
97 | return response;
98 | }
99 | return response;
100 | }
101 | }
102 |
103 | renderComplete() {
104 | const response = this.parseResponse();
105 | return (
106 |
112 | );
113 | }
114 |
115 | render() {
116 | if (this.props.isComplete)
117 | return (
118 |
119 | {this.renderComplete()}
120 |
121 | );
122 | else {
123 | return (
124 |
125 | {this.renderForm()}
126 |
127 | )
128 | }
129 | }
130 | }
131 |
132 |
--------------------------------------------------------------------------------
/src/components/service/moses-service/TargetFeature.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import {
3 | TextField,
4 | Grid,
5 | Tooltip,
6 | FormControl,
7 | Select,
8 | MenuItem,
9 | OutlinedInput,
10 | FormLabel
11 | } from "@material-ui/core";
12 | import { checkRequired, checkBetween } from "./utils";
13 |
14 | export default class TargetFeatureForm extends React.Component {
15 | constructor(props) {
16 | super(props);
17 | this.state = {
18 | validationErrors: {
19 | targetFeature: null,
20 | filter: null
21 | }
22 | };
23 | }
24 |
25 | updateValidationStatus() {
26 | this.props.setValidationStatus(
27 | Object.values(this.state.validationErrors).filter(v => v).length === 0
28 | );
29 | }
30 |
31 | validateForm(oldValues, newValues) {
32 | const validationErrors = Object.assign({}, this.state.validationErrors);
33 | let valuesChanged = false;
34 | if (newValues.targetFeature !== oldValues.targetFeature) {
35 | validationErrors.targetFeature = checkRequired(newValues.targetFeature);
36 | valuesChanged = true;
37 | }
38 |
39 | if (
40 | newValues.filter.value !== oldValues.filter.value ||
41 | newValues.filter.name !== oldValues.filter.name
42 | ) {
43 | if (!newValues.filter.name) {
44 | validationErrors.filter = null;
45 | } else {
46 | validationErrors.filter =
47 | checkRequired(newValues.filter.value) ||
48 | checkBetween(newValues.filter.value, 0, 1);
49 | }
50 | valuesChanged = true;
51 | }
52 |
53 | return valuesChanged
54 | ? this.setState({ validationErrors: validationErrors })
55 | : null;
56 | }
57 |
58 | componentDidUpdate(prevProps, prevState, snapshot) {
59 | this.validateForm(prevProps.defaults, this.props.defaults);
60 | }
61 |
62 | render() {
63 | this.updateValidationStatus();
64 | return (
65 |
66 |
138 |
139 | );
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/components/service/SemanticSegmentation.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SNETImageUpload from "./standardComponents/SNETImageUpload";
3 | import {hasOwnDefinedProperty} from '../../util'
4 |
5 |
6 | const outsideWrapper = {
7 | width: '256px',
8 | height: '256px',
9 | margin: '0px 0px',
10 | border: '0px',
11 | };
12 | const insideWrapper = {
13 | width: '100%',
14 | height: '100%',
15 | position: 'relative',
16 | };
17 | const coveredImage = {
18 | width: '100%',
19 | height: '100%',
20 | position: 'absolute',
21 | top: '0px',
22 | left: '0px',
23 | };
24 | const coveringCanvas = {
25 | width: '100%',
26 | height: '100%',
27 | position: 'absolute',
28 | top: '0px',
29 | left: '0px',
30 | };
31 |
32 | export default class SemanticSegmentationService extends React.Component {
33 |
34 | constructor(props) {
35 | super(props);
36 | this.submitAction = this.submitAction.bind(this);
37 | this.handleFormUpdate = this.handleFormUpdate.bind(this);
38 | this.getData = this.getData.bind(this);
39 | this.canBeInvoked = this.canBeInvoked.bind(this);
40 |
41 | this.state = {
42 | serviceName: "SemanticSegmentation",
43 | methodName: "segment",
44 | imgsrc: undefined,
45 | imageData: undefined,
46 |
47 |
48 | };
49 | }
50 |
51 | handleFormUpdate(event) {
52 | this.setState({
53 | [event.target.name]: event.target.value
54 | });
55 | }
56 |
57 | canBeInvoked() {
58 | if (this.state.imageData !== undefined) {
59 | return true;
60 | }
61 | return false;
62 | }
63 |
64 | getData(imageData, mimetype, format, fn) {
65 | this.setState({imageData: imageData, mimetype: mimetype});
66 | var reader = new FileReader();
67 |
68 | reader.addEventListener("load", () => {
69 | var dataurl = reader.result;
70 | this.setState({imgsrc: "data:" + mimetype + ";base64," + dataurl.substr(dataurl.indexOf(',')+1)});
71 | }, false);
72 |
73 | reader.readAsDataURL(new Blob([imageData]));
74 | }
75 |
76 | submitAction() {
77 | this.props.callApiCallback(this.state.serviceName,
78 | this.state.methodName, {
79 | img: { content: this.state.imageData, mimetype: this.state.mimetype },
80 | visualise: true
81 | });
82 | }
83 |
84 | renderForm() {
85 | return (
86 |
87 |
88 |
89 | Please select image you'd like to be segmented:
90 |
91 |
92 |
97 |
98 |
99 | Invoke
100 |
101 |
102 |
103 | )
104 | }
105 |
106 | renderComplete() {
107 | const response = this.props.response;
108 |
109 | return (
110 |
111 |
112 |
113 | Semantic Segmentation Result:
114 |
115 |
116 |
117 |
118 |
124 |
125 |
126 |
127 | );
128 | }
129 |
130 | render() {
131 | if (this.props.isComplete)
132 | return (
133 |
134 | {this.renderComplete()}
135 |
136 | );
137 | else {
138 | return (
139 |
140 | {this.renderForm()}
141 |
142 | )
143 | }
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/src/components/service/TemplateService.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class TemplateService extends React.Component {
4 |
5 | constructor(props) {
6 | super(props);
7 | this.submitAction = this.submitAction.bind(this);
8 | this.handleFormUpdate = this.handleFormUpdate.bind(this);
9 |
10 | this.state = {
11 | // We currently are undecided about whether to allow a SNet service to publish
12 | // multiple grpc sub-services.
13 | //
14 | // While our tooling allows multiple services to be published, the Dapp has a bug
15 | // that will only ever pass a single service to your component.
16 | // https://github.com/singnet/snet-dapp/issues/110
17 | //
18 | // Best to stick with a one grpc service per SNet service, this is the name you used
19 | // inside the proto file, NOT the name used in the registry.
20 | serviceName: "TemplateService",
21 | // If your service provides multiple methods, then you'll want some way of
22 | // controlling which method is called.
23 | methodName: undefined,
24 | // You can initialise your service arguments to a sensible default here
25 | // ...
26 | };
27 | }
28 |
29 | handleFormUpdate(event) {
30 | // You can add more complex logic here when the user changes the form.
31 | // This just stores the value of the form component that changed, inside the service component's state.
32 | this.setState({
33 | [event.target.name]: event.target.value
34 | });
35 | }
36 |
37 | canBeInvoked() {
38 | // You should validate your form or component state is okay for calling your service.
39 | // The UI will allow the user to call the service if you return true.
40 | return true;
41 | }
42 |
43 | submitAction() {
44 | // This makes a call to your service and handles the blockchain interactions.
45 | this.props.callApiCallback(this.state.serviceName,
46 | this.state.methodName, {
47 | // this JSON object should match the structure of your grpc method arguments.
48 | });
49 | }
50 |
51 | renderServiceMethodNames(serviceMethodNames) {
52 | // This renders each method that belongs to a service, if you only have
53 | // one method you could skip this.
54 | const serviceNameOptions = ["Select a method", ...serviceMethodNames];
55 | return serviceNameOptions.map((serviceMethodName, index) => {
56 | return {serviceMethodName} ;
57 | });
58 | }
59 |
60 | renderForm() {
61 | // This is the UI for selecting arguments to your service.
62 | const service = this.props.protoSpec.findServiceByName(this.state.serviceName);
63 | const serviceMethodNames = service.methodNames;
64 | return (
65 | // This form only lets you select the method name for the service
66 |
67 |
68 |
Method Name:
69 |
70 |
74 | {this.renderServiceMethodNames(serviceMethodNames)}
75 |
76 |
77 |
78 |
79 |
80 | Invoke
81 |
82 |
83 |
84 | )
85 | }
86 |
87 | renderComplete() {
88 | // Here you can render your service's results.
89 | // This may be as simple as displaying an image or text response, or as complex as creating a canvas
90 | // and doing custom dynamic rendering of a binary result. It's up to you!
91 | const response = this.props.response;
92 |
93 | return (
94 |
95 |
Response from service is {response}
96 |
97 | );
98 | }
99 |
100 | render() {
101 | // This toggles whether we are showing a form to call the service, or showing the result.
102 | // Generally you can leave this method alone and focus on customising renderComplete and renderForm.
103 | if (this.props.isComplete)
104 | return (
105 |
106 | {this.renderComplete()}
107 |
108 | );
109 | else {
110 | return (
111 |
112 | {this.renderForm()}
113 |
114 | )
115 | }
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/src/components/service/ExampleService.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class ExampleService extends React.Component {
4 |
5 | constructor(props) {
6 | super(props);
7 | this.submitAction = this.submitAction.bind(this);
8 | this.handleFormUpdate = this.handleFormUpdate.bind(this);
9 |
10 | this.state = {
11 | serviceName: "Calculator",
12 | methodName: "Select a method",
13 | a: 0,
14 | b: 0
15 | };
16 | }
17 |
18 | canBeInvoked() {
19 | return (this.state.methodName !== "Select a method");
20 | }
21 |
22 | handleFormUpdate(event) {
23 | this.setState({
24 | [event.target.name]: event.target.value
25 | });
26 | }
27 |
28 | onKeyPressvalidator(event) {
29 | const keyCode = event.keyCode || event.which;
30 | if (!(keyCode == 8 || keyCode == 46) && (keyCode < 48 || keyCode > 57)) {
31 | event.preventDefault()
32 | } else {
33 | let dots = event.target.value.split('.');
34 | if (dots.length > 1 && keyCode == 46)
35 | event.preventDefault()
36 | }
37 | }
38 |
39 | submitAction() {
40 | this.props.callApiCallback(this.state.serviceName,
41 | this.state.methodName, {
42 | a: this.state.a,
43 | b: this.state.b
44 | });
45 | }
46 |
47 | renderServiceMethodNames(serviceMethodNames) {
48 | const serviceNameOptions = ["Select a method", ...serviceMethodNames];
49 | return serviceNameOptions.map((serviceMethodName, index) => {
50 | return {serviceMethodName} ;
51 | });
52 | }
53 |
54 | renderForm() {
55 | const service = this.props.protoSpec.findServiceByName(this.state.serviceName);
56 | const serviceMethodNames = service.methodNames;
57 | return (
58 |
59 |
60 |
Method Name:
61 |
62 |
66 | {this.renderServiceMethodNames(serviceMethodNames)}
67 |
68 |
69 |
70 |
71 |
Number 1:
72 |
73 | this.onKeyPressvalidator(e)}>
77 |
78 |
79 |
80 |
Number 2:
81 |
82 | this.onKeyPressvalidator(e)}>
86 |
87 |
88 |
89 |
90 | Invoke
91 |
92 |
93 |
94 | )
95 | }
96 |
97 | parseResponse() {
98 | const { response } = this.props;
99 | if(typeof response !== 'undefined') {
100 | if(typeof response === 'string') {
101 | return response;
102 | }
103 | return response.value;
104 | }
105 | }
106 |
107 | renderComplete() {
108 | const response = this.parseResponse();
109 |
110 | return (
111 |
112 |
Response from service is {response}
113 |
114 | );
115 | }
116 |
117 | render() {
118 | if (this.props.isComplete)
119 | return (
120 |
121 | {this.renderComplete()}
122 |
123 | );
124 | else {
125 | return (
126 |
127 | {this.renderForm()}
128 |
129 | )
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/util.js:
--------------------------------------------------------------------------------
1 | const bitcoin = require("bitcoinjs-lib")
2 | const BigNumber = require('bignumber.js');
3 | const { NETWORKS } = require("./networks.js")
4 |
5 | export const AGENT_STATE = {
6 | "ENABLED": 0,
7 | "DISABLED": 1,
8 | };
9 |
10 | export const STRINGS = {
11 | "NULL_ADDRESS": "0x0000000000000000000000000000000000000000"
12 | };
13 |
14 | export const MESSAGES = {
15 | "WAIT_FOR_MM": "Waiting for Metamask interaction",
16 | "WAIT_FOR_TRANSACTION": "Waiting for transaction to be mined",
17 | "WAIT_FOR_BC_CALL": "Waiting for blockchain call to complete",
18 | "WAIT_FOR_NEW_CHANNEL": "Waiting to get a new channel",
19 | "WAIT_FOR_RESPONSE": "Waiting for the response",
20 | "ZERO_ESCROW_BALANCE": "You do not have any balance in your escrow account. Please transfer tokens from your wallet to the escrow account to proceed.",
21 | "WAIT_FOR_CHANNEL_STATE": "Checking if the channel has balance for this call"
22 | };
23 |
24 | export class AGI {
25 | static toDecimal(agi) {
26 | return (agi / 100000000).toFixed(8);
27 | }
28 |
29 | static inAGI(cogs) {
30 | return (cogs / 100000000).toFixed(8);
31 | }
32 |
33 | static inCogs(web3, value) {
34 | return new BigNumber(web3.toWei(value, "ether") / (10 ** (10))).toNumber();
35 | }
36 | }
37 |
38 | export class FORMAT_UTILS {
39 | /**
40 | * Shortens a long ethereum address to a human-friendly abbreviated one. Assumes the address starts with '0x'.
41 | *
42 | * An address like 0x2ed982c220fed6c9374e63804670fc16bd481b8f provides no more value to a human than
43 | * a shortened version like 0x2ed9...1b8f. However, screen real estate is precious, especially to real users
44 | * and not developers with high-res monitors.
45 | */
46 | static toHumanFriendlyAddressPreview(address) {
47 | const addressPrefix = '0x';
48 | const previewLength = 4;
49 |
50 | const addressToShorten = address.startsWith(addressPrefix) ? address.substring(addressPrefix.length) : address;
51 | const previewPrefix = addressToShorten.substring(0, previewLength);
52 | const previewSuffix = addressToShorten.substring(addressToShorten.length - previewLength);
53 |
54 | return `0x${previewPrefix}...${previewSuffix}`;
55 | }
56 | }
57 |
58 | const ERROR_MESSAGE = {
59 | denied: "User denied permission to access ethereum account",
60 | reject: "User rejected transaction submission or message signing",
61 | failed: "Transaction mined, but not executed",
62 | internal: "Internal Server Error",
63 | unknown: "Error"
64 | };
65 |
66 | const RPC_ERROR_BOUNDS = {
67 | internal: [-31099, -32100]
68 | };
69 |
70 | export const DEFAULT_GAS_PRICE = 4700000;
71 | export const DEFAULT_GAS_ESTIMATE = 210000;
72 |
73 | export class ERROR_UTILS {
74 |
75 | static sanitizeError(error) {
76 | if (typeof error === 'string' && error.indexOf("provider access") != -1) {
77 | return ERROR_MESSAGE.denied;
78 | }
79 |
80 | if (typeof error === 'object') {
81 | if(error.hasOwnProperty("value")) {
82 | // It checks for rejection on both cases of message or transaction
83 | if (error.value.message.indexOf("User denied") != -1) {
84 | return ERROR_MESSAGE.reject;
85 | }
86 |
87 | //Checks for Internal server error
88 | if (error.value.code > RPC_ERROR_BOUNDS.internal[0] && error.value.code < RPC_ERROR_BOUNDS.internal[1]) {
89 | return ERROR_MESSAGE.internal
90 | }
91 | }
92 | else if(error.hasOwnProperty("message")) {
93 | return error.message;
94 | }
95 | }
96 |
97 | if (typeof error === 'object' && error.hasOwnProperty("status") && error.status === "0x0") {
98 | //This is the receipt
99 | return `${ERROR_MESSAGE.failed} TxHash: ${error.transactionHash}`
100 | }
101 |
102 | return ERROR_MESSAGE.unknown + " [" + String(error) + "]"
103 | }
104 | }
105 |
106 | export const isValidAddress = (address, coin, network) => {
107 | if (coin === 'bitcoin') {
108 | network = network === 'testnet' ? bitcoin.networks.testnet : bitcoin.networks.bitcoin
109 | try {
110 | bitcoin.address.toOutputScript(address, network)
111 | return true
112 | } catch (e) {
113 | return false
114 | }
115 | }
116 | return false
117 | }
118 |
119 | export function hasOwnDefinedProperty(object, property) { return object.hasOwnProperty(property) && typeof object[property] !== "undefined" }
120 |
121 |
122 | export function hexToAscii(hexString) {
123 | let asciiString = Eth.toAscii(hexString);
124 | return asciiString.substr(0,asciiString.indexOf("\0")); // name is right-padded with null bytes
125 | }
126 |
127 | export function base64ToHex(base64String) {
128 | var byteSig = Buffer.from(base64String, 'base64');
129 | let buff = new Buffer(byteSig);
130 | let hexString = "0x"+buff.toString('hex');
131 | return hexString;
132 | }
133 |
134 | export function getMarketplaceURL(chainId) {
135 | return (chainId in NETWORKS ? NETWORKS[chainId]['marketplace'] : undefined);
136 | }
137 |
138 | export function getProtobufjsURL(chainId) {
139 | return (chainId in NETWORKS ? NETWORKS[chainId]['protobufjs'] : undefined);
140 | }
141 |
142 | export function isSupportedNetwork(chainId) {
143 | const marketPlaceURL = getMarketplaceURL(chainId);
144 | if(typeof marketPlaceURL === 'undefined' || marketPlaceURL === "") {
145 | console.log("Ignore network " + chainId)
146 | return false;
147 | }
148 | return true;
149 | }
150 |
151 | export const BLOCK_OFFSET = 80640 //# Approximately blocks generated in 30 minutes
152 | export const BLOCK_TIME_SECONDS = 15 // Number of seconds, a single block unit corresponds to.
--------------------------------------------------------------------------------
/src/components/service/FaceDetectService.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SNETImageUpload from "./standardComponents/SNETImageUpload";
3 | import {hasOwnDefinedProperty} from '../../util'
4 |
5 |
6 | const outsideWrapper = {
7 | width: '256px',
8 | height: '256px',
9 | margin: '0px 0px',
10 | border: '0px',
11 | };
12 | const insideWrapper = {
13 | width: '100%',
14 | height: '100%',
15 | position: 'relative',
16 | };
17 | const coveredImage = {
18 | width: '100%',
19 | height: '100%',
20 | position: 'absolute',
21 | top: '0px',
22 | left: '0px',
23 | };
24 | const coveringCanvas = {
25 | width: '100%',
26 | height: '100%',
27 | position: 'absolute',
28 | top: '0px',
29 | left: '0px',
30 | };
31 |
32 | export default class FaceDetectService extends React.Component {
33 |
34 | constructor(props) {
35 | super(props);
36 | this.submitAction = this.submitAction.bind(this);
37 | this.getData = this.getData.bind(this);
38 |
39 | this.state = {
40 | serviceName: "FaceDetect",
41 | methodName: "FindFace",
42 | imageData: undefined,
43 | imgsrc: undefined,
44 | };
45 |
46 | }
47 |
48 | componentDidUpdate(prevProps, prevState) {
49 | if (this.props.isComplete && this.props.response !== undefined) {
50 | this.renderBoundingBox(this.props.response);
51 | }
52 | }
53 |
54 | submitAction() {
55 | this.props.callApiCallback(this.state.serviceName,
56 | this.state.methodName, {
57 | content: this.state.imageData
58 | });
59 | }
60 |
61 | canBeInvoked() {
62 | return (this.state.methodName !== "Select a method");
63 | }
64 |
65 | getData(imageData, mimetype, format, fn) {
66 | this.setState({imageData: imageData});
67 | var reader = new FileReader();
68 |
69 | reader.addEventListener("load", () => {
70 | var dataurl = reader.result;
71 | this.setState({imgsrc: "data:" + mimetype + ";base64," + dataurl.substr(dataurl.indexOf(',')+1)});
72 | }, false);
73 |
74 | reader.readAsDataURL(new Blob([imageData]));
75 | }
76 |
77 | renderBoundingBox(result) {
78 | // {"faces": [{"x": 511, "y": 170, "w": 283, "h": 312}, {"x": 61, "y": 252, "w": 236, "h": 259}]}
79 | let img = this.refs.sourceImg;
80 | let cnvs = this.refs.bboxCanvas;
81 | let outsideWrap = this.refs.outsideWrap;
82 | if (img === undefined || cnvs === undefined || outsideWrap == undefined)
83 | return;
84 | if (img.naturalWidth === 0 || img.naturalHeight === 0)
85 | {
86 | setTimeout ( () => this.renderBoundingBox(result), 200 );
87 | return;
88 | }
89 | let desiredWidth = this.props.sliderWidth;
90 | let scaleFactor = desiredWidth / img.naturalWidth;
91 | outsideWrap.style.width = img.naturalWidth * scaleFactor + "px";
92 | outsideWrap.style.height = img.naturalHeight * scaleFactor + "px";
93 | cnvs.style.position = "absolute";
94 | cnvs.style.left = img.offsetLeft + "px";
95 | cnvs.style.top = img.offsetTop + "px";
96 | cnvs.width = img.naturalWidth * scaleFactor;
97 | cnvs.height = img.naturalHeight * scaleFactor;
98 |
99 | let ctx = cnvs.getContext("2d");
100 | result.face_bbox.forEach((item) => {
101 | ctx.beginPath();
102 | ctx.rect(
103 | item.x * scaleFactor,
104 | item.y * scaleFactor,
105 | item.w * scaleFactor,
106 | item.h * scaleFactor
107 | );
108 | ctx.lineWidth = 3;
109 | ctx.strokeStyle = '#00ff00';
110 | ctx.stroke();
111 | });
112 | }
113 |
114 | renderForm() {
115 | return (
116 |
117 |
122 |
123 |
124 | Invoke
125 |
126 |
127 |
128 | )
129 | }
130 |
131 | renderComplete() {
132 | return (
133 |
134 |
Response from service is {JSON.stringify(this.props.response)}
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 | );
143 | }
144 |
145 | render() {
146 | if (this.props.isComplete)
147 | return (
148 |
149 | {this.renderComplete()}
150 |
151 | );
152 | else {
153 | return (
154 |
155 | {this.renderForm()}
156 |
157 | )
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/components/Header.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Link} from 'react-router-dom';
3 | import { library } from '@fortawesome/fontawesome-svg-core'
4 | import { fab } from '@fortawesome/free-brands-svg-icons'
5 | import { faCheckSquare, faCoffee } from '@fortawesome/free-solid-svg-icons'
6 | import { NETWORKS } from '../networks'
7 | import GetStarted from './GetStarted'
8 |
9 | export default class Header extends React.Component {
10 | constructor(props) {
11 | super(props);
12 | this.state = {
13 | showMenu: false
14 | }
15 | this.showMenu = this.showMenu.bind(this);
16 | library.add(fab, faCheckSquare, faCoffee);
17 | }
18 |
19 | showMenu(){
20 | this.setState({
21 | showMenu: !this.state.showMenu
22 | })
23 | }
24 |
25 |
26 | render() {
27 | const menuList =
28 | Get Started
29 | Home
30 | Account
31 | Blog
32 | {(typeof this.props.chainId !== 'undefined' && this.props.chainId !== "1") ?
33 | AGI Faucet
34 | : null}
35 |
36 |
37 | const networkName = (typeof NETWORKS[this.props.chainId] !== 'undefined' && typeof NETWORKS[this.props.chainId].name !== 'undefned') ?
38 |
39 | {NETWORKS[this.props.chainId].name}
40 |
41 | :
42 |
43 | return (
44 |
45 |
46 |
47 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | {(typeof web3 !== 'undefined')?
65 |
66 |
:
67 |
68 | }
69 |
70 | { networkName }
71 |
72 | { menuList }
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | {
81 | this.state.showMenu ?
82 |
83 | {menuList}
84 |
85 | :
86 | null
87 | }
88 |
89 |
90 |
91 | { networkName }
92 |
93 |
94 |
95 |
96 | {this.props.children}
97 |
98 | );
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/components/service/FaceAlignService.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SNETImageUpload from "./standardComponents/SNETImageUpload";
3 | import {hasOwnDefinedProperty} from '../../util'
4 |
5 |
6 | export default class FaceAlignService extends React.Component {
7 |
8 | constructor(props) {
9 | super(props);
10 | this.submitAction = this.submitAction.bind(this);
11 | this.getData = this.getData.bind(this);
12 |
13 | this.state = {
14 | serviceName: "FaceAlignment",
15 | methodName: "AlignFace",
16 | imageData: undefined,
17 | imgsrc: undefined,
18 | facesString: '[{"x":10,"y":10,"w":100,"h":100}]',
19 | };
20 |
21 | this.isComplete = false;
22 | }
23 |
24 | componentDidUpdate(prevProps, prevState) {
25 | if (this.state.facesString !== prevState.facesString) {
26 | let inputValid = this.checkValid();
27 | if (inputValid) {
28 | // TODO render the image inside the upload widget
29 | // renderBoundingBox
30 | }
31 | this.setState({inputValid: this.checkValid()});
32 | }
33 | if (this.state.imageData !== prevState.imageData)
34 | this.setState({inputValid: this.checkValid()});
35 | }
36 |
37 | handleChange(type, e) {
38 | this.setState({
39 | [type]: e.target.value,
40 | });
41 | }
42 |
43 | submitAction() {
44 | this.props.callApiCallback(this.state.serviceName,
45 | this.state.methodName, {
46 | header: {
47 | source_bboxes: JSON.parse(this.state.facesString),
48 | },
49 | image_chunk: {
50 | content: this.state.imageData,
51 | }
52 | });
53 | }
54 |
55 | checkValid() {
56 | let inputValid = true;
57 |
58 | try {
59 | let faces = JSON.parse(this.state.facesString);
60 | faces.forEach((item) => {
61 | let expectedKeys = ['x', 'y', 'w', 'h'];
62 | expectedKeys.forEach((k) => {
63 | if (!(k in item)) inputValid = false;
64 | });
65 | });
66 | } catch(e) {
67 | inputValid = false;
68 | }
69 |
70 | if (this.state.methodName === undefined ||this.state.methodName === "Select a method" || this.state.methodName.length == 0)
71 | inputValid = false;
72 |
73 | if (this.state.imageData === undefined)
74 | inputValid = false;
75 |
76 | return inputValid;
77 |
78 | }
79 |
80 |
81 | getData(imageData, mimetype, format, fn) {
82 | this.setState({imageData: imageData});
83 | var reader = new FileReader();
84 |
85 | reader.addEventListener("load", () => {
86 | var dataurl = reader.result;
87 | this.setState({imgsrc: "data:" + mimetype + ";base64," + dataurl.substr(dataurl.indexOf(',')+1)});
88 | }, false);
89 |
90 | reader.readAsDataURL(new Blob([imageData]));
91 | }
92 |
93 | renderForm() {
94 | return (
95 |
96 |
101 |
102 |
103 |
104 | Faces JSON (you can get this from face detect):
105 |
106 |
107 |
108 |
109 |
110 |
111 | Invoke
112 |
113 |
114 |
115 | )
116 | }
117 |
118 | renderComplete() {
119 | var alignedFaceImgList = this.props.response.image_chunk.map((item, idx) => {
120 | // Of course this is how JS requires you to convert a uint8array to base64,
121 | // because everything in JS has to be 10x harder than other languages...
122 | return (
123 |
124 |
125 |
126 | );
127 | });
128 | return(
129 |
130 |
133 |
134 | {alignedFaceImgList}
135 |
136 |
137 | );
138 | }
139 |
140 | render() {
141 | if (this.props.isComplete)
142 | return (
143 |
144 | {this.renderComplete()}
145 |
146 | );
147 | else {
148 | return (
149 |
150 | {this.renderForm()}
151 |
152 | )
153 | }
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/src/components/service/emotion-recognition-service/EmotionVisualizer.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import {Tabs, Tab} from '@material-ui/core';
3 | import ReactJson from 'react-json-view';
4 | import styles from './emotion_recognition.css.cs';
5 | import html2canvas from 'html2canvas';
6 |
7 | const ResultView = {Image: 0, JSON: 1};
8 |
9 | export default class EmotionVisualizer extends React.Component {
10 | constructor(props) {
11 | super(props);
12 | this.state = {
13 | resultView: ResultView.Image
14 | };
15 | this.download = this.download.bind(this);
16 | this.download_img = this.download_img.bind(this);
17 | this.changeResultView = this.changeResultView.bind(this);
18 | }
19 |
20 | componentDidUpdate() {
21 | if (this.state.resultView === ResultView.Image) {
22 | this.renderBoundingBox()
23 | }
24 | }
25 |
26 | changeResultView(e, value) {
27 | this.setState({resultView: value})
28 | }
29 |
30 |
31 | download() {
32 | const link = document.createElement('a');
33 | link.setAttribute("type", "hidden");
34 | link.setAttribute('href', "data:text/json," + JSON.stringify(this.props.jobResult));
35 | link.setAttribute('download', 'result.json');
36 | document.body.appendChild(link);
37 | link.click();
38 | link.remove();
39 | }
40 |
41 | download_img() {
42 | // this is a link to download the rendered boxes form the given image
43 | let cnvs = this.refs.outsideWrap;
44 | html2canvas(cnvs, {}).then((canvas) => {
45 | const link = document.createElement('a');
46 | link.setAttribute("type", "hidden");
47 | link.setAttribute('href', canvas.toDataURL(this.props.inputImageType));
48 | link.setAttribute('download', 'result.' + this.props.inputImageType.split('/')[1]);
49 | document.body.appendChild(link);
50 | link.click();
51 | link.remove();
52 | })
53 | }
54 |
55 | renderBoundingBox() {
56 | let img = this.refs.sourceImg;
57 | let cnvs = this.refs.bboxCanvas;
58 | let outsideWrap = this.refs.outsideWrap;
59 | if (img === undefined || cnvs === undefined || outsideWrap === undefined) {
60 | setTimeout(() => this.renderBoundingBox(), 200);
61 | return;
62 | }
63 |
64 | let width;
65 | if (this.props.sliderWidth === '100%') {
66 | width = Math.min(document.documentElement.clientWidth, window.innerWidth)
67 | } else {
68 | width = parseInt(this.props.sliderWidth, 10);
69 | }
70 | let scale = width / parseInt(img.naturalWidth, 10);
71 | outsideWrap.style.width = img.naturalWidth * scale + 'px';
72 | outsideWrap.style.height = img.naturalHeight * scale + 'px';
73 | cnvs.style.position = 'absolute';
74 | cnvs.style.left = img.offsetLeft + 'px';
75 | cnvs.style.top = img.offsetTop + 'px';
76 | cnvs.width = img.naturalWidth * scale;
77 | cnvs.height = img.naturalHeight * scale;
78 |
79 | let context = cnvs.getContext('2d');
80 | this.props.jobResult['faces'].forEach(item => {
81 | context.beginPath();
82 | context.rect(
83 | item.bounding_box['x'] * scale,
84 | item.bounding_box['y'] * scale,
85 | item.bounding_box['w'] * scale,
86 | item.bounding_box['h'] * scale
87 | );
88 | context.lineWidth = 3;
89 | context.strokeStyle = '#F70056';
90 | context.fillStyle = '#F70056';
91 | context.font = '18px Arial';
92 | context.fillText(
93 | item.emotion.charAt(0).toUpperCase() + item.emotion.substr(1),
94 | item.bounding_box['x'] * scale + 10,
95 | item.bounding_box['y'] * scale + 20
96 | );
97 | context.stroke();
98 | });
99 | return cnvs;
100 | }
101 |
102 | render() {
103 | return (
104 |
105 |
110 |
111 |
112 |
113 |
114 | {this.state.resultView === ResultView.Image && (
115 |
116 |
117 |
122 |
123 |
124 |
125 |
126 | Download Image with Bounding Boxes
127 |
128 |
129 |
130 | )}
131 | {this.state.resultView === ResultView.JSON && (
132 |
133 |
134 |
135 |
136 | Download Results JSON file
137 |
138 |
139 |
140 | )}
141 |
142 | );
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/components/service/NeuralSpeechSynthesis.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {hasOwnDefinedProperty} from '../../util'
3 | import Button from '@material-ui/core/Button';
4 |
5 | export default class NeuralSpeechSynthesis extends React.Component {
6 |
7 | constructor(props) {
8 | super(props);
9 | this.submitAction = this.submitAction.bind(this);
10 | this.handleFormUpdate = this.handleFormUpdate.bind(this);
11 |
12 | this.users_guide = "https://github.com/iktina/speech-synthesis-service";
13 | this.serviceName = "TTS";
14 | this.methodName = "t2s";
15 |
16 | this.state = {
17 | response: undefined,
18 | text: ""
19 | };
20 |
21 | this.isComplete = false;
22 | this.serviceMethods = [];
23 | this.allServices = [];
24 | this.methodsForAllServices = [];
25 | this.parseProps(props);
26 | }
27 | componentWillReceiveProps(nextProps) {
28 | if(this.isComplete !== nextProps.isComplete) {
29 | this.parseProps(nextProps);
30 | }
31 | }
32 | parseProps(nextProps) {
33 | this.isComplete = nextProps.isComplete;
34 | if (!this.isComplete) {
35 | this.parseServiceSpec(nextProps.serviceSpec);
36 | } else {
37 | if (typeof nextProps.response !== 'undefined') {
38 | if (typeof nextProps.response === 'string') {
39 | this.state.response = nextProps.response;
40 | } else {
41 | this.state.response = nextProps.response.data;
42 | }
43 | }
44 | }
45 | }
46 |
47 | parseServiceSpec(serviceSpec) {
48 | const packageName = Object.keys(serviceSpec.nested).find(key =>
49 | typeof serviceSpec.nested[key] === "object" &&
50 | hasOwnDefinedProperty(serviceSpec.nested[key], "nested"));
51 |
52 | var objects = undefined;
53 | var items = undefined;
54 | if (typeof packageName !== 'undefined') {
55 | items = serviceSpec.lookup(packageName);
56 | objects = Object.keys(items);
57 | } else {
58 | items = serviceSpec.nested;
59 | objects = Object.keys(serviceSpec.nested);
60 | }
61 |
62 | this.allServices.push("Select a service");
63 | this.methodsForAllServices = [];
64 | objects.map(rr => {
65 | if (typeof items[rr] === 'object' && items[rr] !== null && items[rr].hasOwnProperty("methods")) {
66 | this.allServices.push(rr);
67 | this.methodsForAllServices.push(rr);
68 |
69 | var methods = Object.keys(items[rr]["methods"]);
70 | methods.unshift("Select a method");
71 | this.methodsForAllServices[rr] = methods;
72 | }
73 | })
74 | }
75 |
76 | handleFormUpdate(event) {
77 | this.setState({
78 | [event.target.name]: event.target.value
79 | });
80 | }
81 |
82 | onKeyPressvalidator(event) {
83 | // console.log(event.target.value);
84 | }
85 |
86 | submitAction() {
87 | var btn = document.getElementById("invoke-button");
88 | btn.disabled = true;
89 | btn.innerHTML = "Wait...";
90 |
91 | this.props.callApiCallback(this.serviceName,
92 | this.methodName, {
93 | text: this.state.text
94 | });
95 | }
96 |
97 | renderForm() {
98 | return (
99 |
100 |
101 |
Sentence
102 |
103 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | Invoke
112 |
113 |
114 |
115 |
116 |
About
117 |
118 | Guide
119 |
120 |
121 |
122 |
123 | )
124 | }
125 |
126 | renderComplete() {
127 | return (
128 |
131 | );
132 | }
133 |
134 | componentDidUpdate() {
135 | if (this.isComplete) {
136 | var data = new Uint8Array(this.state.response);
137 | var blob = new Blob([data], {type : 'audio/wav'});
138 | var ac = document.getElementById("audio-container");
139 | ac.innerHTML = "";
140 | var audio = document.createElement('audio');
141 | audio.setAttribute('controls', '');
142 |
143 | var audioURL = window.URL.createObjectURL(blob);
144 | audio.src = audioURL;
145 | audio.style.width = "100%";
146 | ac.appendChild(audio);
147 | }
148 | }
149 |
150 | render() {
151 | if (this.isComplete)
152 | return (
153 |
154 | {this.renderComplete()}
155 |
156 | );
157 | else {
158 | return (
159 |
160 | {this.renderForm()}
161 |
162 | )
163 | }
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/src/sandbox/Standalone.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ServiceMappings from "../components/service/ServiceMappings.js"
3 | import PropTypes from 'prop-types'
4 | import GRPCProtoV3Spec from "../models/GRPCProtoV3Spec";
5 | import TextField from '@material-ui/core/TextField';
6 | import { JobdetailsStandalone } from './JobDetailsStandalone.js';
7 | import BlockchainHelper from "../components/BlockchainHelper.js"
8 |
9 | class Standalone extends React.Component {
10 | constructor(props) {
11 | super(props);
12 | this.state = {
13 | orgID:'snet',
14 | serviceID:'example-service',
15 | proto:'syntax = "proto3"; package example_service; message Numbers { float a = 1; float b = 2; } message Result { float value = 1; } service Calculator { rpc add(Numbers) returns (Result) {} rpc sub(Numbers) returns (Result) {} rpc mul(Numbers) returns (Result) {} rpc div(Numbers) returns (Result) {} }',
16 | endpoint:'http://localhost:7052',
17 | errorMessage:'',
18 | userAddress:undefined
19 | };
20 |
21 | this.network = new BlockchainHelper();
22 | this.serviceSpecJSON = '';
23 | this.serviceMappings = new ServiceMappings();
24 |
25 | this.handleField = this.handleField.bind(this);
26 | this.onOpenJobDetailsSlider = this.onOpenJobDetailsSlider.bind(this);
27 | this.fetchWeb3Account = this.fetchWeb3Account.bind(this);
28 | }
29 |
30 | componentDidMount() {
31 | window.addEventListener('load', () => this.handleWindowLoad());
32 | this.handleWindowLoad();
33 | this.fetchWeb3Account();
34 | }
35 |
36 | handleWindowLoad() {
37 | this.network.initialize();
38 | }
39 |
40 | handleField(e) {
41 | this.setState({errorMessage: ''})
42 | const { name, value } = e.target;
43 | this.setState({[name]: value,})
44 | }
45 |
46 | runJob() {
47 | this.errorMessage = ''
48 | this.generate_service_spec_json(this.proto);
49 | }
50 |
51 | generate_service_spec_json() {
52 | try {
53 | const protobuf = require("protobufjs");
54 | protobuf.parse.defaults.keepCase = true;
55 | let obj = protobuf.parse(this.state.proto)
56 | this.serviceSpecJSON = obj.root;
57 | this.protoSpec = new GRPCProtoV3Spec(this.serviceSpecJSON);
58 | this.onOpenJobDetailsSlider();
59 | }
60 | catch(ex) {
61 | this.setState({errorMessage: "Exception while parsing proto [" + ex + "]"});
62 | console.log("Unable to generate service spec json. Please ensure that " + this.proto + " is a valid proto file")
63 | console.log(ex)
64 | }
65 | }
66 |
67 | onOpenJobDetailsSlider() {
68 | let serviceState = {}
69 | serviceState["org_id"] = this.state.orgID;
70 | serviceState["service_id"] = this.state.serviceID;
71 | serviceState["is_available"] = 1;
72 | serviceState["serviceSpecJSON"] = this.serviceSpecJSON
73 | serviceState["endpoint"] =this.state.endpoint
74 | serviceState["protoSpec"] = this.protoSpec
75 |
76 | this.refs.jobdetailsComp.onOpenJobDetails(serviceState);
77 | }
78 |
79 | async fetchWeb3Account(){
80 | const getAccountDetails = await web3.eth.getAccounts;
81 | getAccountDetails((e,accounts)=>{
82 | this.setState({userAddress:accounts[0]});
83 | })
84 | }
85 |
86 | renderBase() {
87 | return(
88 |
89 |
90 |
91 |
92 | Org ID (Used to look up servicemappings)
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | Service ID (Used to look up servicemappings)
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | Proto Contents
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | Endpoint of daemon with blockchain disabled
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | this.runJob()}>Execute Component
128 |
129 | {(this.state.errorMessage === '') ?
130 | null :
131 |
132 | {this.state.errorMessage}
133 |
134 | }
135 |
136 |
137 | {}}/>
142 |
143 | )
144 | }
145 |
146 | render() {
147 | return (
148 |
149 | {this.renderBase()}
150 |
151 | )
152 | }
153 | }
154 |
155 | Standalone.propTypes = {
156 | account: PropTypes.string
157 | };
158 | export default Standalone;
--------------------------------------------------------------------------------
/src/components/service/BinarySemanticSimilarity.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {hasOwnDefinedProperty} from '../../util'
3 | import Button from '@material-ui/core/Button';
4 |
5 | export default class BinarySemanticSimilarity extends React.Component {
6 |
7 | constructor(props) {
8 | super(props);
9 | this.submitAction = this.submitAction.bind(this);
10 | this.handleFormUpdate = this.handleFormUpdate.bind(this);
11 |
12 | this.users_guide = "https://github.com/iktina/semantic-similarity-binary-service";
13 | this.serviceName = "SSBERT";
14 | this.methodName = "ss_bert";
15 |
16 | this.state = {
17 | response: undefined,
18 | a: "",
19 | b: ""
20 | };
21 |
22 | this.isComplete = false;
23 | this.serviceMethods = [];
24 | this.allServices = [];
25 | this.methodsForAllServices = [];
26 | this.parseProps(props);
27 | }
28 |
29 | componentWillReceiveProps(nextProps) {
30 | if(this.isComplete !== nextProps.isComplete) {
31 | this.parseProps(nextProps);
32 | }
33 | }
34 |
35 | parseProps(nextProps) {
36 | this.isComplete = nextProps.isComplete;
37 | if (!this.isComplete) {
38 | this.parseServiceSpec(nextProps.serviceSpec);
39 | } else {
40 | if (typeof nextProps.response !== 'undefined') {
41 | if (typeof nextProps.response === 'string') {
42 | this.state.response = nextProps.response;
43 | } else {
44 | this.state.response = nextProps.response.answer;
45 | }
46 | }
47 | }
48 | }
49 |
50 | parseServiceSpec(serviceSpec) {
51 | const packageName = Object.keys(serviceSpec.nested).find(key =>
52 | typeof serviceSpec.nested[key] === "object" &&
53 | hasOwnDefinedProperty(serviceSpec.nested[key], "nested"));
54 |
55 | var objects = undefined;
56 | var items = undefined;
57 | if (typeof packageName !== 'undefined') {
58 | items = serviceSpec.lookup(packageName);
59 | objects = Object.keys(items);
60 | } else {
61 | items = serviceSpec.nested;
62 | objects = Object.keys(serviceSpec.nested);
63 | }
64 |
65 | this.allServices.push("Select a service");
66 | this.methodsForAllServices = [];
67 | objects.map(rr => {
68 | if (typeof items[rr] === 'object' && items[rr] !== null && items[rr].hasOwnProperty("methods")) {
69 | this.allServices.push(rr);
70 | this.methodsForAllServices.push(rr);
71 |
72 | var methods = Object.keys(items[rr]["methods"]);
73 | methods.unshift("Select a method");
74 | this.methodsForAllServices[rr] = methods;
75 | }
76 | })
77 | }
78 |
79 | handleFormUpdate(event) {
80 | this.setState({
81 | [event.target.name]: event.target.value
82 | });
83 | }
84 |
85 | onKeyPressvalidator(event) {
86 | // console.log(event.target.value);
87 | }
88 |
89 | submitAction() {
90 | var btn = document.getElementById("invoke-button");
91 | btn.disabled = true;
92 | btn.innerHTML = "Wait...";
93 |
94 | this.props.callApiCallback(this.serviceName,
95 | this.methodName, {
96 | a: this.state.a,
97 | b: this.state.b
98 | });
99 | }
100 |
101 | renderForm() {
102 | return (
103 |
104 |
105 |
Sentence 1
106 |
107 |
109 |
110 |
111 |
112 |
113 |
Sentence 2
114 |
115 |
117 |
118 |
119 |
120 |
121 | Invoke
122 |
123 |
124 |
125 |
126 |
About
127 |
128 | Guide
129 |
130 |
131 |
132 |
133 | )
134 | }
135 |
136 | renderComplete() {
137 | return (
138 |
139 |
Response from service is This sentences is {this.state.response === "1" ? "similar" : "distinct"}
140 |
141 | );
142 | }
143 |
144 | render() {
145 | if (this.isComplete)
146 | return (
147 |
148 | {this.renderComplete()}
149 |
150 | );
151 | else {
152 | return (
153 |
154 | {this.renderForm()}
155 |
156 | )
157 | }
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/src/components/ChannelHelper.js:
--------------------------------------------------------------------------------
1 | import { base64ToHex } from '../util'
2 | import { Requests } from '../requests'
3 |
4 | export default class ChannelHelper {
5 | constructor() {
6 | this.channels = undefined;
7 | this.groupId = undefined;
8 | this.endpoint = undefined;
9 | this.channelId = undefined;
10 | this.recipient = undefined;
11 | this.currentSignedAmount = 0;
12 | }
13 |
14 | reInitialize(channelInfoUrl) {
15 | this.channels = undefined;
16 | this.groupId = undefined;
17 | this.endpoint = undefined;
18 | this.channelId = undefined;
19 | this.recipient = undefined;
20 | this.currentSignedAmount = 0;
21 | return this.fetchChannels(channelInfoUrl);
22 | }
23 |
24 | setCurrentSignedAmount(amount) {
25 | this.currentSignedAmount = amount;
26 | }
27 |
28 | getCurrentSignedAmount() {
29 | return this.currentSignedAmount;
30 | }
31 |
32 | getChannelId() {
33 | return this.channelId;
34 | }
35 |
36 | setChannelId(channelId) {
37 | return this.channelId = channelId;
38 | }
39 |
40 | getGroupId() {
41 | return this.groupId;
42 | }
43 |
44 | getEndpoint() {
45 | if(typeof this.endpoint === 'undefined') {
46 | return undefined
47 | }
48 | return this.endpoint[0];
49 | }
50 |
51 | getChannel(channelId) {
52 | let channels = this.getChannels();
53 | for(let ii=0; ii < channels.length; ii++) {
54 | if (channels[ii]["channelId"] === channelId)
55 | {
56 | return channels[ii];
57 | }
58 | }
59 | return undefined;
60 | }
61 |
62 | getExpiryBlock() {
63 | let channels = this.getChannels();
64 | let expiryBlock = 0;
65 | for(let ii=0; ii < channels.length; ii++) {
66 | var rrchannels = channels[ii];
67 | if (rrchannels["channelId"] === this.channelId)
68 | {
69 | expiryBlock = rrchannels["expiration"];
70 | break;
71 | }
72 | }
73 | return expiryBlock;
74 | }
75 |
76 | getRecipient() {
77 | return this.recipient;
78 | }
79 |
80 | setNonce(newNonce) {
81 | let channels = this.getChannels();
82 | for(let ii=0; ii < channels.length; ii++) {
83 | var rrchannels = channels[ii];
84 | if (rrchannels["channelId"] === this.channelId)
85 | {
86 | rrchannels["nonce"] = newNonce;
87 | console.log("Setting nonce for channel " + this.channelId + " to " + rrchannels["nonce"]);
88 | break;
89 | }
90 | }
91 | }
92 |
93 | getNonce(defaultValue) {
94 | let nonce = defaultValue;
95 | let channels = this.getChannels();
96 | for(let ii=0; ii < channels.length; ii++) {
97 | var rrchannels = channels[ii];
98 | if (rrchannels["channelId"] === this.channelId)
99 | {
100 | nonce = rrchannels["nonce"];
101 | break;
102 | }
103 | }
104 | return nonce;
105 | }
106 |
107 | getChannels() {
108 | let channels = this.channels;
109 | if (typeof channels === 'undefined'){
110 | channels = [];
111 | }
112 | return channels
113 | }
114 |
115 | fetchChannels(channelInfoUrl) {
116 | var caller = this;
117 | Requests.get(channelInfoUrl).then(channeldata =>
118 | new Promise(function(resolve) {
119 | caller.populateChannelDetails(channeldata["data"]);
120 | resolve();
121 | }));
122 | }
123 |
124 | populateChannelDetails(channels) {
125 | if(typeof channels === 'undefined' || channels.length === 0) {
126 | console.log("Unable to get channel information");
127 | return;
128 | }
129 |
130 | this.channels = channels[0]["channels"];
131 | this.endpoint = channels[0]["endpoint"]
132 | this.groupId = channels[0]["groupId"];
133 | this.recipient = channels[0]["recipient"];
134 | console.log("Populated channels");
135 | }
136 |
137 | matchEvent(evt, result, senderAddress, groupidgetter, recipientaddress) {
138 | console.log("result from event: " + result);
139 | var event = result.event;
140 | console.log("event: " + event);
141 | var agentGroupID = base64ToHex(groupidgetter);
142 | if (event == "ChannelOpen") {
143 | var MPEChannelId = result.args.channelId;
144 | var channelSender = result.args.sender;
145 | var channelRecipient = result.args.recipient;
146 | var channelGoupId = result.args.groupId;
147 |
148 | console.log("Channel details - [" + channelGoupId + "] [" + channelRecipient + "] [" + channelSender + "]");
149 | console.log("App details - [" + agentGroupID + "] [" + recipientaddress + "] [" + senderAddress + "]");
150 | if (channelGoupId === agentGroupID && channelSender.toLowerCase() === senderAddress.toLowerCase() && recipientaddress.toLowerCase() === channelRecipient.toLowerCase()) {
151 | console.log("Matched channel id " + MPEChannelId)
152 | this.channelId = MPEChannelId;
153 | evt.stopWatching();
154 | }
155 | console.log("channel id" + this.channelId);
156 | }
157 | }
158 |
159 | findExistingChannel(data, thresholdBlockNumber) {
160 | if (typeof this.channels !== 'undefined')
161 | {
162 | console.log('channel state information is ' + this.groupId);
163 | if (this.channels.length > 0)
164 | {
165 | let lowestChannelID = this.channels[0]["channelId"];
166 | for(let ii=0; ii < this.channels.length; ii++) {
167 | var rrchannels = this.channels[ii];
168 | if(rrchannels["channelId"] < lowestChannelID){
169 | lowestChannelID = rrchannels["channelId"];
170 | }
171 | if (parseInt(rrchannels["balance_in_cogs"]) >= parseInt(data.pricing_strategy.getMaxPriceInCogs())
172 | && parseInt(rrchannels["expiration"]) >= parseInt(thresholdBlockNumber))
173 | {
174 | console.log("Found a channel with adequate funds " + JSON.stringify(rrchannels));
175 | console.log("Setting channel ID to " + rrchannels["channelId"]);
176 | this.channelId = rrchannels["channelId"];
177 | return true;
178 | }
179 | }
180 |
181 | console.log("No channel is found with adequate funds and expiration");
182 | console.log("Choosing channel with lowest id");
183 | this.channelId = lowestChannelID;
184 | return true;
185 | }
186 | }
187 | console.log("Did not find a channel with adequate funds");
188 | return false;
189 | }
190 | }
--------------------------------------------------------------------------------
/src/components/service/LongQuestionAsnswering.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {hasOwnDefinedProperty} from '../../util'
3 | import Button from '@material-ui/core/Button';
4 |
5 | export default class LongQuestionAsnswering extends React.Component {
6 |
7 | constructor(props) {
8 | super(props);
9 | this.submitAction = this.submitAction.bind(this);
10 | this.handleFormUpdate = this.handleFormUpdate.bind(this);
11 |
12 | this.users_guide = "https://github.com/iktina/question-answering-long-seq-service";
13 | this.serviceName = "QA";
14 | this.methodName = "qa";
15 |
16 | this.state = {
17 | response: undefined,
18 | context: "",
19 | question: ""
20 | };
21 |
22 | this.isComplete = false;
23 | this.serviceMethods = [];
24 | this.allServices = [];
25 | this.methodsForAllServices = [];
26 | this.parseProps(props);
27 | }
28 | componentWillReceiveProps(nextProps) {
29 | if(this.isComplete !== nextProps.isComplete) {
30 | this.parseProps(nextProps);
31 | }
32 | }
33 | parseProps(nextProps) {
34 | this.isComplete = nextProps.isComplete;
35 | if (!this.isComplete) {
36 | this.parseServiceSpec(nextProps.serviceSpec);
37 | } else {
38 | if (typeof nextProps.response !== 'undefined') {
39 | if (typeof nextProps.response === 'string') {
40 | this.state.response = nextProps.response;
41 | } else {
42 | this.state.response = nextProps.response.answer;
43 | }
44 | }
45 | }
46 | }
47 |
48 | parseServiceSpec(serviceSpec) {
49 | const packageName = Object.keys(serviceSpec.nested).find(key =>
50 | typeof serviceSpec.nested[key] === "object" &&
51 | hasOwnDefinedProperty(serviceSpec.nested[key], "nested"));
52 |
53 | var objects = undefined;
54 | var items = undefined;
55 | if (typeof packageName !== 'undefined') {
56 | items = serviceSpec.lookup(packageName);
57 | objects = Object.keys(items);
58 | } else {
59 | items = serviceSpec.nested;
60 | objects = Object.keys(serviceSpec.nested);
61 | }
62 |
63 | this.allServices.push("Select a service");
64 | this.methodsForAllServices = [];
65 | objects.map(rr => {
66 | if (typeof items[rr] === 'object' && items[rr] !== null && items[rr].hasOwnProperty("methods")) {
67 | this.allServices.push(rr);
68 | this.methodsForAllServices.push(rr);
69 |
70 | var methods = Object.keys(items[rr]["methods"]);
71 | methods.unshift("Select a method");
72 | this.methodsForAllServices[rr] = methods;
73 | }
74 | })
75 | }
76 |
77 | handleFormUpdate(event) {
78 | this.setState({
79 | [event.target.name]: event.target.value
80 | });
81 | }
82 |
83 | onKeyPressvalidator(event) {
84 | // console.log(event.target.value);
85 | }
86 |
87 | submitAction() {
88 | var btn = document.getElementById("invoke-button");
89 | btn.disabled = true;
90 | btn.innerHTML = "Wait...";
91 |
92 | this.props.callApiCallback(this.serviceName,
93 | this.methodName, {
94 | context: this.state.context,
95 | question: this.state.question
96 | });
97 | }
98 |
99 | renderForm() {
100 | return (
101 |
102 |
103 |
Context
104 |
105 |
107 |
108 |
109 |
110 |
111 |
Question
112 |
113 |
115 |
116 |
117 |
118 |
119 | Invoke
120 |
121 |
122 |
123 |
124 |
About
125 |
126 | Guide
127 |
128 |
129 |
130 |
131 | )
132 | }
133 |
134 | renderComplete() {
135 | return (
136 |
137 |
Response from service is: {this.state.response}
138 |
139 | );
140 | }
141 |
142 | render() {
143 | if (this.isComplete)
144 | return (
145 |
146 | {this.renderComplete()}
147 |
148 | );
149 | else {
150 | return (
151 |
152 | {this.renderForm()}
153 |
154 | )
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------
/src/components/service/ShortQuestionAnswering.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {hasOwnDefinedProperty} from '../../util'
3 | import Button from '@material-ui/core/Button';
4 |
5 | export default class ShortQuestionAnswering extends React.Component {
6 |
7 | constructor(props) {
8 | super(props);
9 | this.submitAction = this.submitAction.bind(this);
10 | this.handleFormUpdate = this.handleFormUpdate.bind(this);
11 |
12 | this.users_guide = "https://github.com/iktina/question-answering-short-seq-service";
13 | this.serviceName = "QABERT";
14 | this.methodName = "qa_bert";
15 |
16 | this.state = {
17 | response: undefined,
18 | context: "",
19 | question: ""
20 | };
21 |
22 | this.isComplete = false;
23 | this.serviceMethods = [];
24 | this.allServices = [];
25 | this.methodsForAllServices = [];
26 | this.parseProps(props);
27 | }
28 | componentWillReceiveProps(nextProps) {
29 | if(this.isComplete !== nextProps.isComplete) {
30 | this.parseProps(nextProps);
31 | }
32 | }
33 | parseProps(nextProps) {
34 | this.isComplete = nextProps.isComplete;
35 | if (!this.isComplete) {
36 | this.parseServiceSpec(nextProps.serviceSpec);
37 | } else {
38 | if (typeof nextProps.response !== 'undefined') {
39 | if (typeof nextProps.response === 'string') {
40 | this.state.response = nextProps.response;
41 | } else {
42 | this.state.response = nextProps.response.answer;
43 | }
44 | }
45 | }
46 | }
47 |
48 | parseServiceSpec(serviceSpec) {
49 | const packageName = Object.keys(serviceSpec.nested).find(key =>
50 | typeof serviceSpec.nested[key] === "object" &&
51 | hasOwnDefinedProperty(serviceSpec.nested[key], "nested"));
52 |
53 | var objects = undefined;
54 | var items = undefined;
55 | if (typeof packageName !== 'undefined') {
56 | items = serviceSpec.lookup(packageName);
57 | objects = Object.keys(items);
58 | } else {
59 | items = serviceSpec.nested;
60 | objects = Object.keys(serviceSpec.nested);
61 | }
62 |
63 | this.allServices.push("Select a service");
64 | this.methodsForAllServices = [];
65 | objects.map(rr => {
66 | if (typeof items[rr] === 'object' && items[rr] !== null && items[rr].hasOwnProperty("methods")) {
67 | this.allServices.push(rr);
68 | this.methodsForAllServices.push(rr);
69 |
70 | var methods = Object.keys(items[rr]["methods"]);
71 | methods.unshift("Select a method");
72 | this.methodsForAllServices[rr] = methods;
73 | }
74 | })
75 | }
76 |
77 | handleFormUpdate(event) {
78 | this.setState({
79 | [event.target.name]: event.target.value
80 | });
81 | }
82 |
83 | onKeyPressvalidator(event) {
84 | // console.log(event.target.value);
85 | }
86 |
87 | submitAction() {
88 | var btn = document.getElementById("invoke-button");
89 | btn.disabled = true;
90 | btn.innerHTML = "Wait...";
91 |
92 | this.props.callApiCallback(this.serviceName,
93 | this.methodName, {
94 | context: this.state.context,
95 | question: this.state.question
96 | });
97 | }
98 |
99 | renderForm() {
100 | return (
101 |
102 |
103 |
Context
104 |
105 |
107 |
108 |
109 |
110 |
111 |
Question
112 |
113 |
115 |
116 |
117 |
118 |
119 | Invoke
120 |
121 |
122 |
123 |
124 |
About
125 |
126 | Guide
127 |
128 |
129 |
130 |
131 | )
132 | }
133 |
134 | renderComplete() {
135 | return (
136 |
137 |
Response from service is: {this.state.response}
138 |
139 | );
140 | }
141 |
142 | render() {
143 | if (this.isComplete)
144 | return (
145 |
146 | {this.renderComplete()}
147 |
148 | );
149 | else {
150 | return (
151 |
152 | {this.renderForm()}
153 |
154 | )
155 | }
156 | }
157 | }
158 |
--------------------------------------------------------------------------------