Giter Club home page Giter Club logo

genie-cloud's Introduction

Genie for Cloud Environments

Build Status Coverage Status Dependency Status Language grade: JavaScript Discord Discourse status

This repository is the cloud-native version of Genie, the open virtual-assistant. It includes the web frontend, the Genie backend, the embedded skill library, and the NLP model servers.

Genie is a research project led by prof. Monica Lam, from Stanford University. You can find more information at https://oval.cs.stanford.edu.

Development

  1. You need Git.

    Mac:

    1. Install Homebrew

    2. Install Git:

      brew install git
      
  2. Clone this repository.

    You can clone it wherever you want, but if you don't know where to put it I recommend:

    mkdir -p "${HOME}/src/github.com/stanford-oval" && cd "${HOME}/src/github.com/stanford-oval"
    

    to create a directory and change into it.

    Then

    git clone --branch wip/nrser/k8s-dev-setup https://github.com/stanford-oval/almond-cloud.git
    

    and change into the cloned repository with

    cd almond-cloud
    
  3. You need Kubernetes running locally. For Windows and Mac we recommend Docker Desktop. After installation, follow the instructions to enabled Kubernetes.

    On Linux, there are (of course) several options. Minikube, MicroK8s and Kind are the ones I've heard of. These instructions will follow a Docker Desktop installation, so adjust as needed.

  4. Build the Almond Cloud Docker image

    docker build -f docker/Dockerfile -t localhost/almond-cloud .
    
  5. Install the latest kustomize.

    Mac:

    brew install kustomize
    

    Windows and Linux: Follow their installation instructions.

    If you're on the Mac, I recommend the Homebrew option.

    NOTE

    Kustomize does come bundled with the kubectl utility that Kubernetes installations ship with, but some or all will be too out-of-date for our needs.

  6. Deploy the Kubernetes Dashboard

    kustomize build k8s/dashboard/dev | kubectl apply -f -
    

    In a separate terminal, run

    kubectl proxy
    

    and keep that terminal open.

    Visit

    http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/

    and use the Skip button to login and view the dashboard (there shouldn't be much there yet!).

  7. Deploy the Nginx Ingress Controller

    kustomize build k8s/ingress-nginx/dev | kubectl apply -f -
    
  8. Create a Mailgun account (if you don't already have one) and get the SMTP username and password for the domain you want to use to send emails.

    If you use the "sandbox" domain, make sure you add your email address to the Authorized Recipients and click the confirmation link they mail to you.

  9. Create a local dev environment file

    1. Create a text file in the dev directory named .env

    2. Add these lines to the file, replacing the stuff between the ' quotes with the SMTP credentials from the last step and your email address.

      MAILGUN_SMTP_USERNAME='[email protected]'
      MAILGUN_SMTP_PASSWORD='your-smtp-password'
      DEVELOPER_EMAIL='[email protected]'
      
    3. Save the file.

  10. Generate your kustomize secret file

    ./dev/bin/almond-dev.configure.bash
    

    The secret file is written to k8s/config/dev/secret.yaml.

  11. Check your config files build successfully with kustomize

    kustomize build ./k8s/dev
    

    You should see a big dump of YAML to the screen. If there is an error, try to figure it out or ask for help.

  12. Deploy Genie

    kustomize build ./k8s/dev | kubectl apply -f -
    
  13. Go back to the dashboard and switch to the almond-dev namespace.

    You should see the Genie components booting up. It can take a few minutes for everything to "go green", but after that you can use Almond Cloud at

    http://localhost:8080

genie-cloud's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

genie-cloud's Issues

example values for parameters

add a new field: example values for parameters for all interfaces

  • use them to generate synthetic sentences for bootstrapping
  • as hints in slot filling ui

can't use crypto prices?

price of btc
QUOTE: Look back over the past, with its changing empires that rose and fell, and you can foresee the future, too. By Marcus Aurelius .

get price of btc
You don't have a Uber

Do I nee to enable it or something for my account?

Handle gracefully when the user cancels OAuth 2

If the user cancels the OAuth flow, we are redirected to the specified URL, but we are passed an error instead of a code.
Right now, we try getting the token anyway, and we fail with a nasty "Error obtaining access token". We should recognize the common error and show a different message.

Clear View Cache does not work with load-balancing

If you click Clear View Cache, you only clear the cache of whatever website process happens to receive the request, while other ones run with the cache.
This results in inconsistent pages that appear to change randomly when you refresh (until you ssh in and clean it up)

error connecting to google contacts

  1. That’s an error.

Error: redirect_uri_mismatch

The redirect URI in the request, https://thingengine.stanford.edu/devices/oauth2/callback/com.google.contacts, does not match the ones authorized for the OAuth client. To update the authorized redirect URIs, visit: https://console.developers.google.com/apis/credentials/oauthclient/739906609557-o52ck15e1ge7deb8l0e80q92mpua1p55.apps.googleusercontent.com?project=739906609557

Learn more

Request Details
response_type=code
redirect_uri=https://thingengine.stanford.edu/devices/oauth2/callback/com.google.contacts
access_type=offline
scope=openid profile email https://www.googleapis.com/auth/contacts.readonly
client_id=739906609557-o52ck15e1ge7deb8l0e80q92mpua1p55.apps.googleusercontent.com
That’s all we know.

Implement organization UI

Currently promoting a user creates a single user organization, and the user has no way to join an organization, even when given the key.

Some better handling of this would be nice.

Replace homegrown sandbox with bwrap

The current sandbox is a modified fork of an old copy of the flatpak sandbox. Since then, flatpak has moved to using bwrap (bubblewrap), and we should do the same, as it is more secure.

Moving to bwrap would also allow us to close some loopholes, like access to /etc and the ability to read our real names from /etc/passwd (but not our passwords, which are in /etc/shadow)

Add infrastructure for platform-wide announcements

Such as outages, planned network maintenance (which happens often), new releases, etc.

Ideally it would be in the form of three banners:

  • one under Status & Logs + Developers for developers, when the outage impacts only them
  • one in My Almond for regular users, when the whole platform is down (like this week)
  • one in the front page for news items, releases, emergencies, etc.

Preserve history in Web Almond

platform-server preserves the history if you refresh, and so does platform-gnome.
platform-cloud probably should too.

Cache precomputed factories in the database

Having to load and parse the whole manifest for all devices just to compute the factories is wasteful. It would be better to compute the factory once and store it as a separate JSON field in the database.

Compatibility/versioning checks for Thingpedia interfaces

Thingpedia interfaces are always dynamically linked with whatever version of the Thingpedia library is available on the client.
This means that the library might be too old, or it might be too new and have breaking changes.
Packages can detect the Tp library version at runtime, but none do.

There should be a way to specify the compatibility with a specific Thingpedia version, ideally with some form of semver.

We could reuse the dependencies field in package.json but that would make it awkward for package builders, because you must npm install your own dependencies but not the thingpedia library itself.
So it's better to use a dedicated field for it.

Also we should avoid semver ranges and version pinning as much as possible. The thingpedia library is assumed compatible until the major version number is incremented.

Setup local instance Error

npm ERR! [email protected] preinstall: node-gyp clean && node-gyp configure
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] preinstall script 'node-gyp clean && node-gyp configure'.
npm ERR! This is most likely a problem with the journald package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! node-gyp clean && node-gyp configure
npm ERR! You can get their info via:
npm ERR! npm owner ls journald
npm ERR! There is likely additional logging output above.

Control channel to EngineManager severed error...

I have been working on getting the thingengine-platform-cloud project working, and I have successfully gotten the "almond" service running. However when I run the web front end with "node ./main.js", I get the following error:

'Control channel to EngineManager severed'

The error seems to be where the web front end attempts to connect to the ThingEngine using the socket addresses inside the "control" and "direct" files created when the Almond service starts running.

For your reference, I have disabled sandboxes, and manually set the database URL for my MySQL database instance I created for it. Running the schema was successful to create the tables in the database. No problems there.

Can you give me some insight into how to solve this? I am stuck...

Track app usage

So we can show the most popular apps

Given that installs are per user and not really associated with the thingpedia repository, this would probably be tracked by clicks on the install button.

TCP usage of website to master communication is insecure

If communication between the website process and the master process is setup to use TCP, it creates a large security hole: any sandboxed process can connect to the master process and start issuing commands or exfiltrating credentials for other users.

This problem does not occur when using Unix sockets (the default setup) as the sandbox cannot access the socket, thanks to mount namespaces.
TCP is a requirement for scaling and sharding to multiple machines though, so it must be supported.

The solution here could be a combination of network namespaces and firewalls to prevent the sandboxed processes from connecting where they should not, but I suspect it will be easier and more secure to just establish a secure channel (= TLS) between website and master process. It is a little more convoluted though, because it requires certificate setup.

Add translation support to gen_sentences

A basic way would be to add gettext markers to the grammar rules, and it should work well for Western
/ Indo-European languages.
(Asian and Semitic languages might require different grammar rules)

Getting Started with Almond Error

When I follow the commands under Getting Started with Almond Error I receive an error saying
Twitter ⇒ Notification had an error: _read() is not implemented.

Implement sharding of almond masters

A single master process does not scale well as the number of users increases.

Instead, we should shard the master load based on the user ID, so that each sharded master would be responsible for some number of users. Different masters would then be able to run on different machines.

Improve echo for \t commands

@monicalam says:

I type \t .... and the va says code: .... This is sad, because I cannot just cut and paste but have to change code into \t. Can we change it? Thanks.

Convert gen_synthetic into a library

With a class, SyntheticGenerator, that produces a stream of generated sentences, optionally limiting which devices to work on.

The library would be used by almond-training to generate the synthetic set, instead of calling a script with a complex command-line.

Missing documentation

  • subdevices
  • streaming and push notifications
  • documentation for loadng, state and configuration handling
  • how ThingTalk values are created and manipulated in JS
  • a full begin-to-end tutorial
  • error handling
  • debugging and logging

Add proper versioning to the Thingpedia API

The Thingpedia API must be backward compatible, because it is relied upon by all the client libraries.

From time to time though, we want to change existing APIs because some of the semantics are inconvienient.
So far, we have added new APIs, or new parameters to existing APIs, and we have been very inconsistent in doing so.
It would be better to add a global versioning scheme for the whole Thingpedia API, so that backward incompatible changes can happen by updating the version number, and over time we have a deprecation scheme for older versions.

Implement "Thingpedia Sets"

Requirements:

  • support subsetting of Thingpedia for domain specific assistants, eg Almondify
  • allow removing private devices from the default subset
  • private devices should require authentication before being revealed by any API

Proposed design:

  • introduce the concept of "Thingpedia sets" in the database
  • add the subset identifier alongside the language tag to identify a NL model; this should work the same as language tags (so almond-nnparser can pick the model up and expose it in the same way)
  • add the knowledge of set identifier to ThingTalk when talking to Thingpedia
  • each SQL query run by the Thingpedia API should do a join on the subset table to check ID and token
  • subsetting of thingpedia.json in prepare.py (in almond-nnparser)
  • subsetting of the dataset (in almond-training)
  • each subset gets a different training job and trained model

Problem Installing ThingEngine Platform Cloud

I got stuck with the 'yarn install' part. Hope you can assist.

https://github.com/Stanford-Mobisocial-IoT-Lab/thingengine-platform-cloud

_error /home/ubuntu/Almond/repo/thingengine-platform-cloud/node_modules/cvc4: Command failed.
Exit code: 1
Command: node-gyp rebuild
Arguments:
Directory: /home/ubuntu/Almond/repo/thingengine-platform-cloud/node_modules/cvc4
Output:
gyp info it worked if it ends with ok
gyp info using [email protected]
gyp info using [email protected] | linux | x64
gyp WARN download NVM_NODEJS_ORG_MIRROR is deprecated and will be removed in node-gyp v4, please use NODEJS_ORG_MIRROR
gyp WARN download NVM_NODEJS_ORG_MIRROR is deprecated and will be removed in node-gyp v4, please use NODEJS_ORG_MIRROR
gyp info spawn /usr/bin/python2
gyp info spawn args [ '/home/ubuntu/.nvm/versions/node/v7.0.0/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py',
gyp info spawn args 'binding.gyp',
gyp info spawn args '-f',
gyp info spawn args 'make',
gyp info spawn args '-I',
gyp info spawn args '/home/ubuntu/Almond/repo/thingengine-platform-cloud/node_modules/cvc4/build/config.gypi',
gyp info spawn args '-I',
gyp info spawn args '/home/ubuntu/.nvm/versions/node/v7.0.0/lib/node_modules/npm/node_modules/node-gyp/addon.gypi',
gyp info spawn args '-I',
gyp info spawn args '/home/ubuntu/.node-gyp/7.0.0/include/node/common.gypi',
gyp info spawn args '-Dlibrary=shared_library',
gyp info spawn args '-Dvisibility=default',
gyp info spawn args '-Dnode_root_dir=/home/ubuntu/.node-gyp/7.0.0',
gyp info spawn args '-Dnode_gyp_dir=/home/ubuntu/.nvm/versions/node/v7.0.0/lib/node_modules/npm/node_modules/node-gyp',
gyp info spawn args '-Dnode_lib_file=node.lib',
gyp info spawn args '-Dmodule_root_dir=/home/ubuntu/Almond/repo/thingengine-platform-cloud/node_modules/cvc4',
gyp info spawn args '--depth=.',
gyp info spawn args '--no-parallel',
gyp info spawn args '--generator-output',
gyp info spawn args 'build',
gyp info spawn args '-Goutput_dir=.' ]
gyp WARN download NVM_NODEJS_ORG_MIRROR is deprecated and will be removed in node-gyp v4, please use NODEJS_ORG_MIRROR
gyp info spawn make
gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ]
make: Entering directory '/home/ubuntu/Almond/repo/thingengine-platform-cloud/node_modules/cvc4/build'
CXX(target) Release/obj.target/cvc4/src/node-cvc4.o
../src/node-cvc4.cpp:12:23: fatal error: cvc4/cvc4.h: No such file or directory
compilation terminated.
cvc4.target.mk:94: recipe for target 'Release/obj.target/cvc4/src/node-cvc4.o' failed
make: *** [Release/obj.target/cvc4/src/node-cvc4.o] Error 1
make: Leaving directory '/home/ubuntu/Almond/repo/thingengine-platform-cloud/node_modules/cvc4/build'
gyp ERR! build error
gyp ERR! stack Error: make failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/home/ubuntu/.nvm/versions/node/v7.0.0/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:276:23)
gyp ERR! stack at emitTwo (events.js:106:13)
gyp ERR! stack at ChildProcess.emit (events.js:191:7)
gyp ERR! stack at Process.ChildProcess.handle.onexit (internal/child_process.js:215:12)
gyp ERR! System Linux 4.4.0-1055-aws
gyp ERR! command "/home/ubuntu/.nvm/versions/node/v7.0.0/bin/node" "/home/ubuntu/.nvm/versions/node/v7.0.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /home/ubuntu/Almond/repo/thingengine-platform-cloud/node_modules/cvc4

Thanks!

Staging branch bugs

Oct 15 11:54:56 crowdie node[7687]: TypeError: Cannot read property 'name' of undefined
Oct 15 11:54:56 crowdie node[7687]: at deviceModel.getByAnyKind.then (/opt/thingengine/routes/thingpedia_api.js:916:53)
Oct 15 11:54:56 crowdie node[7687]: at _combinedTickCallback (internal/process/next_tick.js:131:7)
Oct 15 11:54:56 crowdie node[7687]: at process._tickCallback (internal/process/next_tick.js:180:9)
Oct 15 11:54:56 crowdie node[7687]: From previous event:
Oct 15 11:54:56 crowdie node[7687]: at command.devices.map (/opt/thingengine/routes/thingpedia_api.js:915:61)
Oct 15 11:54:56 crowdie node[7687]: at Array.map ()
Oct 15 11:54:56 crowdie node[7687]: at commands.map (/opt/thingengine/routes/thingpedia_api.js:914:40)
Oct 15 11:54:56 crowdie node[7687]: at Array.map ()
Oct 15 11:54:56 crowdie node[7687]: at getCommandDetails (/opt/thingengine/routes/thingpedia_api.js:901:32)
Oct 15 11:54:56 crowdie node[7687]: at commandModel.getCommands.then (/opt/thingengine/routes/thingpedia_api.js:981:20)
Oct 15 11:54:56 crowdie node[7687]: From previous event:
Oct 15 11:54:56 crowdie node[7687]: at query.then (/opt/thingengine/util/db.js:116:44)
Oct 15 11:54:56 crowdie node[7687]: at _combinedTickCallback (internal/process/next_tick.js:131:7)
Oct 15 11:54:56 crowdie node[7687]: From previous event:
Oct 15 11:54:56 crowdie node[7687]: at Object.withTransaction (/opt/thingengine/util/db.js:114:26)
Oct 15 11:54:56 crowdie node[7687]: at v1.get (/opt/thingengine/routes/thingpedia_api.js:979:8)
Oct 15 11:54:56 crowdie node[7687]: at Layer.handle [as handle_request] (/opt/thingengine/node_modules/express/lib/router/layer.js:95:5)
Oct 15 11:54:56 crowdie node[7687]: at next (/opt/thingengine/node_modules/express/lib/router/route.js:137:13)
Oct 15 11:54:56 crowdie node[7687]: at Route.dispatch (/opt/thingengine/node_modules/express/lib/router/route.js:112:3)
Oct 15 11:54:56 crowdie node[7687]: at Layer.handle [as handle_request] (/opt/thingengine/node_modules/express/lib/router/layer.js:95:5)
Oct 15 11:54:56 crowdie node[7687]: at /opt/thingengine/node_modules/express/lib/router/index.js:281:22
Oct 15 11:54:56 crowdie node[7687]: at Function.process_params (/opt/thingengine/node_modules/express/lib/router/index.js:335:12)

Website service failure

May 16 18:11:03 thingpedia systemd[1]: [email protected] failed.
May 16 18:11:03 thingpedia systemd[1]: Unit [email protected] entered failed state.
May 16 18:11:03 thingpedia systemd[1]: [email protected]: main process exited, code=exited, status=1/FAILURE
May 16 18:11:03 thingpedia node[24378]: at readableAddChunk (_stream_readable.js:246:13)
May 16 18:11:03 thingpedia node[24378]: at addChunk (_stream_readable.js:263:12)
May 16 18:11:03 thingpedia node[24378]: at Socket.emit (events.js:211:7)
May 16 18:11:03 thingpedia node[24378]: at emitOne (events.js:116:13)
May 16 18:11:03 thingpedia node[24378]: at Socket.JsonDatagramSocket.reader.on (/opt/thingengine/almond/json_datagram_socket.js:48:18)
May 16 18:11:03 thingpedia node[24378]: at JsonDatagramSocket._tryReadMessage (/opt/thingengine/almond/json_datagram_socket.js:88:18)
May 16 18:11:03 thingpedia node[24378]: at JsonDatagramSocket.emit (events.js:211:7)
May 16 18:11:03 thingpedia node[24378]: at emitOne (events.js:116:13)
May 16 18:11:03 thingpedia node[24378]: at RpcSocket._handleMessage (/opt/thingengine/node_modules/transparent-rpc/rpc_socket.js:294:18)
May 16 18:11:03 thingpedia node[24378]: at RpcSocket._handleReply (/opt/thingengine/node_modules/transparent-rpc/rpc_socket.js:267:27)
May 16 18:11:03 thingpedia node[24378]: Error: this._delegate.terminate is not a function
May 16 18:11:03 thingpedia node[24378]: ^
May 16 18:11:03 thingpedia node[24378]: throw e;
May 16 18:11:03 thingpedia node[24378]: /opt/thingengine/node_modules/transparent-rpc/node_modules/q/q.js:155
May 16 18:11:03 thingpedia node[7132]: at Pipe.onread (net.js:607:20)
May 16 18:11:03 thingpedia node[7132]: at Socket.Readable.push (_stream_readable.js:208:10)
May 16 18:11:03 thingpedia node[7132]: at readableAddChunk (_stream_readable.js:246:13)
May 16 18:11:03 thingpedia node[7132]: at addChunk (_stream_readable.js:263:12)
May 16 18:11:03 thingpedia node[7132]: at Socket.emit (events.js:211:7)
May 16 18:11:03 thingpedia node[7132]: at emitOne (events.js:116:13)
May 16 18:11:03 thingpedia node[7132]: at Socket.JsonDatagramSocket.reader.on (/opt/thingengine/almond/json_datagram_socket.js:48:18)
May 16 18:11:03 thingpedia node[7132]: at JsonDatagramSocket._tryReadMessage (/opt/thingengine/almond/json_datagram_socket.js:88:18)
May 16 18:11:03 thingpedia node[7132]: at JsonDatagramSocket.emit (events.js:211:7)
May 16 18:11:03 thingpedia node[7132]: at emitOne (events.js:116:13)
May 16 18:11:03 thingpedia node[7132]: at RpcSocket._handleMessage (/opt/thingengine/node_modules/transparent-rpc/rpc_socket.js:290:18)
May 16 18:11:03 thingpedia node[7132]: at RpcSocket._handleCall (/opt/thingengine/node_modules/transparent-rpc/rpc_socket.js:221:23)
May 16 18:11:03 thingpedia node[7132]: From previous event:
May 16 18:11:03 thingpedia node[7132]: at process._tickCallback (internal/process/next_tick.js:180:9)
May 16 18:11:03 thingpedia node[7132]: at _combinedTickCallback (internal/process/next_tick.js:131:7)
May 16 18:11:03 thingpedia node[7132]: at RpcSocket.<anonymous> (/opt/thingengine/node_modules/transparent-rpc/rpc_socket.js:219:29)
May 16 18:11:03 thingpedia node[7132]: at RpcStub.events.EventEmitter.RpcStub.call (/opt/thingengine/node_modules/transparent-rpc/rpc_socket.js:332:32)
May 16 18:11:03 thingpedia node[7132]: at WebSocketWrapper.onMessage (/opt/thingengine/almond/platform.js:111:14)
May 16 18:11:03 thingpedia node[7132]: at WebSocketWrapper.emit (events.js:211:7)
May 16 18:11:03 thingpedia node[7132]: at emitOne (events.js:116:13)
May 16 18:11:03 thingpedia node[7132]: at WebSocketWrapper.socket.on (/opt/thingengine/node_modules/thingengine-core/lib/tiers/tier_connections.js:246:50)
May 16 18:11:03 thingpedia node[7132]: at WebSocketWrapper.terminate (/opt/thingengine/almond/platform.js:95:24)
May 16 18:11:03 thingpedia node[7132]: TypeError: this._delegate.terminate is not a function

Use a different fulltext search engine

Currently /thingpedia/api/examples takes between 12 and 41 ms to process. That's too much, and it's because the query is complex.

(On a decent dbms, we would materialize the query and call it a day. But mysql is not decent)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.