Giter VIP home page Giter VIP logo

nadia's Introduction

Nadia

Elixir CI Module Version Hex Docs Total Download License Last Updated

Telegram Bot API Wrapper written in Elixir (document)

Installation

Add :nadia to your mix.exs dependencies:

def deps do
  [
    {:nadia, "~> 0.7.0"}
  ]
end

And run $ mix deps.get.

Configuration

In config/config.exs, add your Telegram Bot token like this

config :nadia,
  token: "bot token"

You can also add an optional recv_timeout in seconds (defaults to 5s):

config :nadia,
  recv_timeout: 10

You can also add a proxy support:

config :nadia,
  proxy: "http://proxy_host:proxy_port", # or {:socks5, 'proxy_host', proxy_port}
  proxy_auth: {"user", "password"},
  ssl: [versions: [:'tlsv1.2']]

You can also configure the the base url for the api if you need to for some reason:

config :nadia,
  # Telegram API. Default: https://api.telegram.org/bot
  base_url: "http://my-own-endpoint.com/whatever/",

  # Telegram Graph API. Default: https://api.telegra.ph
  graph_base_url: "http://my-own-endpoint.com/whatever/"

Environment variables may be used as well:

config :nadia,
  token: {:system, "ENVVAR_WITH_MYAPP_TOKEN", "default_value_if_needed"}

Usage

get_me

iex> Nadia.get_me
{:ok,
 %Nadia.Model.User{first_name: "Nadia", id: 666, last_name: nil,
  username: "nadia_bot"}}

get_updates

iex> Nadia.get_updates limit: 5
{:ok, []}

iex> {:ok,
 [%Nadia.Model.Update{callback_query: nil, chosen_inline_result: nil,
   edited_message: nil, inline_query: nil,
   message: %Nadia.Model.Message{audio: nil, caption: nil,
    channel_chat_created: nil,
    chat: %Nadia.Model.Chat{first_name: "Nadia", id: 123,
     last_name: "TheBot", title: nil, type: "private", username: "nadia_the_bot"},
    contact: nil, date: 1471208260, delete_chat_photo: nil, document: nil,
    edit_date: nil, entities: nil, forward_date: nil, forward_from: nil,
    forward_from_chat: nil,
    from: %Nadia.Model.User{first_name: "Nadia", id: 123,
     last_name: "TheBot", username: "nadia_the_bot"}, group_chat_created: nil,
    left_chat_member: nil, location: nil, message_id: 543,
    migrate_from_chat_id: nil, migrate_to_chat_id: nil, new_chat_member: nil,
    new_chat_photo: [], new_chat_title: nil, photo: [], pinned_message: nil,
    reply_to_message: nil, sticker: nil, supergroup_chat_created: nil,
    text: "rew", venue: nil, video: nil, voice: nil}, update_id: 98765}]}

send_message

iex> case Nadia.send_message(tlg_id, "The message text goes here") do
  {:ok, _result} ->
    :ok
  {:error, %Nadia.Model.Error{reason: "Please wait a little"}} ->
    :wait
  end

:ok

Refer to Nadia document and Telegram Bot API document for more details.

Copyright and License

Copyright (c) 2015 Yu Zhang

This library licensed under the MIT license.

nadia's People

Contributors

anronin avatar artemk avatar ayrat555 avatar dependabot-preview[bot] avatar dependabot[bot] avatar dotboris avatar eliottramirez avatar feliperenan avatar kalys avatar kianmeng avatar konstantinzolotarev avatar linjunpop avatar luishurtado avatar luizparreira avatar m1ome avatar mendab1e avatar milmazz avatar pothix avatar rastopyr avatar rhruiz avatar rockneurotiko avatar rrrene avatar samm81 avatar sanrodari avatar sergioaugrod avatar shouya avatar skie avatar tokitori avatar voronchuk avatar zhyu avatar

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

nadia's Issues

Support multiple bots

The way the token configuration is handled at the moment means that this library can only be used for a single bot. I'd like to have multiple bots running within the same Erlang VM.

It would be nice if the token could be specified when making an API call. For example:

Nadia.send_message(chat_id, text, token: token)

How use with proxy?

How use with proxy?
I try like:

config :nadia,
  token: System.get_env("NADIA_KEY"),
  proxy: "socks5://buff_10.n-3.mtproxy.me&port=3914&secret=c6ac5fc89ac8e6829e7c6bb44214c65e"

or

config :nadia,
  token: System.get_env("NADIA_KEY"),
  proxy: "socks5://server:port",
  socks5_user: "user",
  socks5_pass: "pass"

or

config :nadia,
  token: System.get_env("NADIA_KEY"),
  proxy: tg://proxy?server=server&port=443&secret=secret

allways {:error, %HTTPoison.Error{id: nil, reason: :nxdomain}}

function :updates.__struct__/0 is undefined (module :updates is not available)

My application crashed because of this last night. I find it very weird, that it searches for an :updates module. Any idea what this could be? Sadly I don't have the message that produced this (if any).

** (UndefinedFunctionError) function :updates.__struct__/0 is undefined (module :updates is no
t available)
    :updates.__struct__()
    (elixir) lib/kernel.ex:1974: Kernel.struct/3
    (nadia) lib/nadia/api.ex:14: Nadia.API.process_response/2
    (databerg) lib/databerg/telegram/poller.ex:18: Databerg.Telegram.Poller.handle_cast/2
    (stdlib) gen_server.erl:616: :gen_server.try_dispatch/4
    (stdlib) gen_server.erl:686: :gen_server.handle_msg/6
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: {:"$gen_cast", :update}

In that line on lib/nadia/api.ex:14 it is calling the method Nadia.Parser.parse_result/2 in which there is this case line: "getUpdates" -> parse(:updates, result). But how does that lead to this error? And if it does, why is this line not in the stack trace?

EDIT: Added a link to the parser.

Missing git tag

Hi,
Could you please add git tags for releases? It would make using git dependencies (and packaging) easier :)

Unable to use Nadia in Mix.Tasks

Right now, I'm on able to use Nadia in iex -S mix.

However, I would like to run it as a task. But with the same command of Nadia.send_message(_), I'm getting some errors:

** (exit) exited in: :gen_server.call(:hackney_manager, {:new_request, #PID<0.172.0>, #Reference<0.0.2.124>, {:client, :undefined, :hackney_dummy_metrics, :hackney_ssl_transport, 'api.telegram.org', 443, "api.telegram.org", [], nil, nil, nil, true, :hackney_pool, 5000, false, 5, false, 5, nil, nil, nil, :undefined, :start, nil, :normal, false, false, false, :undefined, false, nil, :waiting, nil, 4096, "", [], :undefined, nil, nil, nil, nil, :undefined, nil}}, :infinity)
    ** (EXIT) no process
    (stdlib) gen_server.erl:212: :gen_server.call/3
             src/hackney_manager.erl:66: :hackney_manager.init_request/1
             src/hackney_manager.erl:56: :hackney_manager.new_request/1
             src/socket/hackney_connect.erl:183: :hackney_connect.socket_from_pool/4
             src/socket/hackney_connect.erl:36: :hackney_connect.connect/5
             src/hackney.erl:321: :hackney.request/5
             lib/httpoison/base.ex:395: HTTPoison.Base.request/9
             lib/nadia/api.ex:58: Nadia.API.request/3

I'm wondering if there are any dependencies/default task being called by Nadia that I'm not including in my task?

Error while loading project :nadia

first of all I'm new to elixir
I followed the instruction in readme but when I try to run the bot I got this error:

Error while loading project :nadia at /home/abdo/Desktop/tg-bots/nadia/deps/nadia
** (Mix) Trying to load Nadia.Mixfile from "/home/abdo/Desktop/tg-bots/nadia/deps/nadia/mix.exs" but another project with the same name was already defined at "/home/abdo/Desktop/tg-bots/nadia/mix.exs"     

note: I run the bot using this command: sudo iex -S mix

Recent code is not being loaded with 0.5.0

Hi again! Newly added code that implemented Jason protocols for KeyboardMarkup (and several other structs) and the renaming of KeyboardHide to KeyboardRemove is not being loaded with mix deps.get when the dependency is set to be ~> 0.5.0
I had to hack it in the deps myself for the bot to work.
Could you please update the release? Thanks in advance!!

Argument error with Nadia.API.build_url on Heroku

Problem

I try to build a Telegram webhook service running on Heroku.
I've received an incoming update via webhook and try to send a message back with Nadia.

Anyway, this error occurred with Nadia.send_message function on running service on Heroku.
I try to reproduce it by running an interactive shell and input with the same data but no error from the local test.

Are there any clues for it?


Logging from Heroku Console

2019-05-06T15:40:28.289290+00:00 app[web.1]: ** (exit) an exception was raised:
2019-05-06T15:40:28.289292+00:00 app[web.1]:     ** (ArgumentError) argument error
2019-05-06T15:40:28.289294+00:00 app[web.1]:         :erlang.bit_size(nil)
2019-05-06T15:40:28.289296+00:00 app[web.1]:         (nadia) lib/nadia/api.ex:9: Nadia.API.build_url/1
2019-05-06T15:40:28.289297+00:00 app[web.1]:         (nadia) lib/nadia/api.ex:118: Nadia.API.request/3

Add jason to applications

I tried deploying something that depended on nadia with the new mix release.
It told me that the module jason had not been found. What I understand is the following:

Jason should either be included in the applications in mix.exs. Or we remove the list of applications there and require a decent elixir version. Then this stuff is handled automatically via extra_applications.

get_updates timeout option doesn't appear to be working

I was expecting this command to not timeout for 120 seconds.
Nadia.get_updates([timeout: 120])

Unfortunately no matter what I set it to I get the following error after about 8 seconds.
{:error, %Nadia.Model.Error{reason: :timeout}}

Configurable API-Endpoint

Since i'm not only new to Elixir, but to Telegram as well - i was trying to proxy every request (inbound to my server as well as outbound to telegrams server). For their webhooks that worked pretty well, because you can put in every url you like as long as its https.

i wasn't able to make it work for/with Nadia, since the API-Endpoint is hardcoded in lib/nadia/api.ex.

i'm guessing that switching the API-Endpoint isn't a thing that is often done (completely understandable) but i still think it's a good idea to have that option. especially in the beginning when you start to make requests, it would be helpful if the requests could be send to any http endpoint .. so one would be able to verify what he/she is actually trying to send out :)

not yet sure about the tests for this, but the idea would probably be make it work the same way as config_or_env is already doing its job for the token.

I'll try to come up with a PR, depending on how much time there is .. somewhere in the next weeks.

WDYT @zhyu?

Support for Bot API 2.0

https://core.telegram.org/bots/api#recent-changes
https://core.telegram.org/bots/2-0-intro
I can help with it any time.

  • New inline keyboards with callback and URL buttons. Added new objects InlineKeyboardMarkup, InlineKeyboardButton and CallbackQuery, added reply_markup fields to all InlineQueryResult objects. Added field callback_query to the Update object, new method answerCallbackQuery.
  • Bots can now edit their messages.
  • Bots can request location and phone number from the user.

Inline bots

  • Added support for all content types available on Telegram. 19 types of InlineQueryResult objects are now supported.
  • Inline bots can now subsitute all kinds of content with text. Added 4 types of InputMessageContent objects.
  • You inline bot can also ask users for permission to use their location. Added the new Botfather command /setinlinegeo, added field location to the InlineQuery object, added fields location and inline_message_id to the ChosenInlineResult object.
  • Added an easy way to switch between inline mode and a private chat with the bot – useful for settings, establishing external connections and teaching users how to use your bot in inline mode. Added parameters switch_pm_text and switch_pm_parameter to the method answerInlineQuery.

Miscellaneous

  • Added group administration tools. New methods kickChatMember and unbanChatMember.
  • Added fields venue, pinned_message and entities to the Message object. Added new objects MessageEntity and Venue, new methods sendVenue and sendContact.
  • Renamed the fields new_chat_participant and left_chat_participant of the Message object to new_chat_member and left_chat_member.

function :photo.__struct__/0 is undefined (module :photo is not available)

Nadia.get_chat MY_TELEGRAM_USER_ID
** (UndefinedFunctionError) function :photo.__struct__/0 is undefined (module :photo is not available)
    :photo.__struct__()
    (elixir) lib/kernel.ex:1791: Kernel.struct/3
    (nadia) lib/nadia/parser.ex:53: Nadia.Parser.parse/1
    (elixir) lib/enum.ex:1274: anonymous fn/3 in Enum.map/2
    (stdlib) lists.erl:1263: :lists.foldl/3
    (elixir) lib/enum.ex:1843: Enum.map/2
    (nadia) lib/nadia/parser.ex:41: Nadia.Parser.parse/2
    (nadia) lib/nadia/api.ex:32: Nadia.API.process_response/2```

InlineKeyboardButton only works with the :url key

I'm trying to send a message with some inline keyboard buttons.

According to Telegram's documentation. When specifying a InlineKeyboardButton I should pass only one of the optional keys.

For some reason, I can only get the url key to work.

The following code works:

button = %Nadia.Model.InlineKeyboardButton{text: "test", url: "https://google.com"}
markup = %Nadia.Model.InlineKeyboardMarkup{inline_keyboard: [[button]]}
Nadia.send_message(chat_id, "Hello?", reply_markup: markup)

The chat message will show with a working link button.

If I use something like callback_data instead of url I get an error complaining about the url key not being a string.

button = %Nadia.Model.InlineKeyboardButton{text: "test", callback_data: "something"}
markup = %Nadia.Model.InlineKeyboardMarkup{inline_keyboard: [[button]]}
Nadia.send_message(chat_id, "Hello?", reply_markup: markup)

The error:

{:error,
 %Nadia.Model.Error{reason: 
   "Bad Request: can't parse inline keyboard button: Field \"url\" must be of type String"}}

I'm not sure if this is a problem with nadia or if this is an issue with the Telegram bot api.

Can't deploy with exrm

Deploys with exrm require production dependencies to be added to applications list.

This is not the case for the poison dependency.

PR comming...

Realtime updates?

Hi, is there any way to get the updates in real time or get notified instead of calling Nadia.get_updates?

Thanks!

TLS failure on OTP/23

Running Nadia on OTP/23 results in failure with rather strange error message:

{:options, {:sslv3, {:versions, [:"tlsv1.2", :"tlsv1.1", :tlsv1, :sslv3]}}}

After enabling hackney tracing with :hackney_trace.enable(:max, :io)
I get this:

[hackney trace 80 <0.214.0> 2020:05:20 16:00:43 4915] connect error                                                                                                                                                
   Content: [{module,hackney_connect},{line,293}]

The issue is likely due to sslv3 being removed in OTP/23
Similar problem: https://elixirforum.com/t/erlang-v-23-0-and-httpoison-error/31615

Sending media group raises FunctionClauseError

Hello,

thank you for developing this library.

I have been trying to send a media group (e.g. multiple images in one message) and I encounter the following issue:

iex(3)> Nadia.API.request("sendMediaGroup", [chat_id: chat_id, media: Jason.encode!([%{type: "photo", media: file_id_1}, %{type: "photo", media: file_id_2}])])
** (FunctionClauseError) no function clause matching in anonymous fn/2 in Kernel.struct/2    
    
    The following arguments were given to anonymous fn/2 in Kernel.struct/2:
    
        # 1
        %{
          chat: %{first_name: "first_name", id: 123456789, type: "private"},
          date: 1606318961,
          from: %{...},
          media_group_id: "...",
          message_id: 30,
          photo: [
            %{
              file_id: "...",
              file_size: 544,
              file_unique_id: "...",
              height: 38,
              width: 64
            }
          ]
        }
    
        # 2
        %Nadia.Model.Message{
          audio: nil,
          caption: nil,
          channel_chat_created: nil,
          chat: nil,
          contact: nil,
          date: nil,
          delete_chat_photo: nil,
          document: nil,
          edit_date: nil,
          entities: nil,
          forward_date: nil,
          forward_from: nil,
          forward_from_chat: nil,
          from: nil,
          group_chat_created: nil,
          left_chat_member: nil,
          location: nil,
          message_id: nil,
          migrate_from_chat_id: nil,
          migrate_to_chat_id: nil,
          new_chat_member: nil,
          new_chat_photo: [],
          new_chat_title: nil,
          photo: [],
          pinned_message: nil,
          reply_to_message: nil,
          sticker: nil,
          supergroup_chat_created: nil,
          text: nil,
          venue: nil,
          video: nil,
          voice: nil
        }
    
    (elixir) lib/kernel.ex:2112: anonymous fn/2 in Kernel.struct/2
    (elixir) lib/enum.ex:1948: Enum."-reduce/3-lists^foldl/2-0-"/3
    (nadia) lib/nadia/api.ex:15: Nadia.API.process_response/2

The message is sent correctly, but it crashes on parsing the response.
Would be nice if you could add support for that :-)

Compilation fail on 0.4 in dependency ssl_verify_fun

Compilation on my Digital Ocean Ubuntu 15.04 LTS x64 failed with this message:

ERROR: compile failed while processing /root/api/deps/ssl_verify_fun: rebar_abort                                    │
==> api                                                                                                              │
** (Mix) Could not compile dependency :ssl_verify_fun, "/root/.mix/rebar compile skip_deps=true deps_dir="/root/api/_│
build/dev/lib"" command failed. You can recompile this dependency with "mix deps.compile ssl_verify_fun", update it w│
ith "mix deps.update ssl_verify_fun" or clean it with "mix deps.clean ssl_verify_fun"    

[v0.7.0] Nadia.Model.Update.MessageEntities is always empty when picture is received

Example of such post:

https://t.me/econ_papers/269

image

As you can see there should be a MessageEntity with type=text_link that points to https://economics.mit.edu/files/14084

This is a dump of Model.Update received from Nadia:

%Nadia.Model.Update{callback_query: nil, channel_post: nil, chosen_inline_result: nil, edited_message: nil, inline_query: nil, message: %Nadia.Model.Message{audio: nil, caption: "Страны со средним достатком накапливают резервы опережающим темпом, в основном для борьбы со скачками курса после резкого оттока нерезидентов. Fanelli and Straub (2020) показывают минусы такого подхода.", channel_chat_created: nil, chat: %Nadia.Model.Chat{first_name: "AAA", id: 0000000, last_name: nil, photo: nil, title: nil, type: "private", username: "AAA"}, contact: nil, date: 1601834873, delete_chat_photo:
 nil, document: nil, edit_date: nil, entities: nil, forward_date: 1601832687, forward_from: nil, forward_from_chat: %{id: -1001209908412, title: "Econ Papers", type: "channel", username: "econ_papers"}, from: %Nadia.Model.User{first_name: "AAAA", id: 36577752, last_name: nil, username: "AAAAA"}, group_chat_created: nil, left_chat_member: nil, location: nil, message_id: 297, migrate_from_chat_id: nil, migrate_to_chat_id: nil, new_chat_member: nil, new_chat_photo: [], new_chat_title: nil, photo: [%Nadia.Model.PhotoSize{file_id: "AgACAgIAAxkBAAIBKV96D3lClnbbc-w1kbGWgHgf9-YPAAKBsDEb7-XQSy7BODOkDbZ4zbN3ly4AAwEAAwIAA20AAxheAQABGwQ", file_size: 10368, height: 250, width: 320}, %Nadia.Model.PhotoSize{file_id: "AgACAgIAAxkBAAIBKV96D3lClnbbc-w1kbGWgHgf9-YPAAKBsDEb7-XQSy7BODOkDbZ4zbN3ly4AAwEAAwIAA3gAAxpeAQABGwQ", file_size: 33624, height: 626, width: 800}, %Nadia.Model.PhotoSize{file_id: "AgACAgIAAxkBAAIBKV96D3lClnbbc-w1kbGWgHgf9-YPAAKBsDEb7-XQSy7BODOkDbZ4zbN3ly4AAwEAAwIAA3kAAxleAQABGwQ", file_size: 45715, height: 837, width: 1069}], pinned_message: nil, reply_to_message: nil, sticker: nil, supergroup_chat_created: nil, text: nil, venue: nil, video: nil, voice: nil}, update_id: AAAA}

Spec and function mismatch

nadia/lib/nadia.ex

Lines 578 to 580 in a78da4f

@spec edit_message_text(integer | binary, integer, binary, [{atom, any}]) ::
{:ok, Message.t()} | {:error, Error.t()}
def edit_message_text(chat_id, message_id, inline_message_id, text, options \\ []) do

I think spec should be:

  @spec edit_message_text(integer | binary, integer, binary, binary, [{atom, any}]) ::
          {:ok, Message.t()} | {:error, Error.t()}
  def edit_message_text(chat_id, message_id, inline_message_id, text, options \\ []) 

Difficulty using library

I started using the library just now, but I can't get pass this small issue:

$ iex -S mix
iex> Nadia.get_me
** (exit) exited in: :gen_server.call(:hackney_manager, {:new_request, #PID<0.128.0>,      #Reference<0.0.1.70>, {:client, :undefined, :hackney_dummy_metrics, :hackney_ssl_transport,     'api.telegram.org', 443, "api.telegram.org", [], nil, nil, nil, true, :hackney_pool, 5000, false, 5, false, 5, nil, nil, nil, :undefined, :start, nil, :normal, false, false, false, :undefined, false, nil, :waiting, nil, 4096, "", [],  :undefined, nil, nil, nil, nil, :undefined, nil}}, :infinity)
    ** (EXIT) no process
    (stdlib) gen_server.erl:212: :gen_server.call/3
             src/hackney_client/hackney_manager.erl:66: :hackney_manager.init_request/1
             src/hackney_client/hackney_manager.erl:56: :hackney_manager.new_request/1
             src/hackney_connect/hackney_connect.erl:183: :hackney_connect.socket_from_pool/4
             src/hackney_connect/hackney_connect.erl:36: :hackney_connect.connect/5
             src/hackney_client/hackney.erl:321: :hackney.request/5
             lib/httpoison.ex:60: HTTPoison.request/5
             lib/nadia/api.ex:50: Nadia.API.request/3

I'm using Elixir v1.0.5 and Nadia v0.3.1

Parse mode for files

Hi.
parse_mode option is available for files (like photos, videos and documents) on Telegram API but Nadia does not support them. Please add this option.

Terminating due to Poison JSON parsing error

This looks like Telegram is returning XML instead of JSON, possibly an error case on their side, but Nadia probably shouldn't crash when it happens (maybe pattern match on Poison.decode instead of using decode!).

01:39:52.529 [error] GenServer #PID<0.262.0> terminating                                
** (Poison.SyntaxError) Unexpected token at position 0: <                               
    (poison) lib/poison/parser.ex:57: Poison.Parser.parse!/2                            
    (poison) lib/poison.ex:83: Poison.decode!/2                                         
    (nadia) lib/nadia/api.ex:40: Nadia.API.decode_response/1                            
    (nadia) lib/nadia/api.ex:30: Nadia.API.process_response/2     

Unfortunately I don't know how to get more information about the message contents...

How to test code when using Nadia.

I wan't to test code which calls Nadia.get_updates() How can I mock this Nadia instance to not rely on an external telegram chat?

I'm pretty new to elixir so I'm not really sure how to do this.

Greetings, Bart

Update poison to 1.6.2

Hi there! Could you update poison dependency to 1.6.2? Having issues with dependency resolution and mix.lock . Had to unlock, but still. Thanks in advance!

Parser doesn't consider CallbackQuery

If an update was a callback query, parser completely skips the "callback_query" field from the update, and just returns it as a map. but In models you do have CallbackQuery struct. It's strange.

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.