act_as_api_client 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a90b4aea75a3d4fffe79dc9d882cc6560c464409cfa07aa9227806573cef5055
4
- data.tar.gz: 70429d7b213697175b2283bfa2aabca4b019a7c7272b097e34fa9786904ae6cd
3
+ metadata.gz: 54f1e0502d9d834fafe3dcd401882b7948d7240d49784d8601bb6312d3982518
4
+ data.tar.gz: d6099660de91fe0317dd9e55db6343a0e599c299f889ca129ed94e57efe7162d
5
5
  SHA512:
6
- metadata.gz: b2f6b525f14bf39b4463d40cba93aa2cf84d98b92e5e5a77ddc9bc34cb8ba8f02a5e098d38788657317b6b5f0774a22f5345de6338e4b47e2548896b9216c794
7
- data.tar.gz: 64a64300293bf60782357e32c7909dc8d01a95e47e22c6df36226f6278d4dc941449d38d6fc135e42620ecf7efa9a8a874dbad4d523e175cba22a90f7c762c99
6
+ metadata.gz: 6feb43b2e5f850c53770ea912187e514efa9c2986ad9a117ee7e260a8a4813e28c9c2a0054531ececc35821247d60f1670cd1f8e7b8db877e25a75cc697af930
7
+ data.tar.gz: b99cb6cee4fff9e10f86d367564283cbd19565ced49aee598a943c8e4a9aa706fd09fe3d06d57a5d1865944f0a630cd4e0d6aa916239592cdb614fe453b5310d
@@ -23,7 +23,7 @@ jobs:
23
23
  matrix:
24
24
  ruby-version: ["3.0"]
25
25
  steps:
26
- - uses: actions/checkout@v3
26
+ - uses: actions/checkout@v4
27
27
  - name: Set up Ruby
28
28
  uses: ruby/setup-ruby@2b019609e2b0f1ea1a2bc8ca11cb82ab46ada124
29
29
  with:
@@ -38,7 +38,7 @@ jobs:
38
38
  os: [ubuntu-latest, macos-latest]
39
39
  ruby-version: ["2.6", "2.7", "3.0", "3.1", "3.2", "3.3"]
40
40
  steps:
41
- - uses: actions/checkout@v3
41
+ - uses: actions/checkout@v4
42
42
  - name: Set up Ruby
43
43
  uses: ruby/setup-ruby@v1
44
44
  with:
@@ -0,0 +1,51 @@
1
+ name: Deploy Jekyll with GitHub Pages dependencies preinstalled
2
+
3
+ on:
4
+ # Runs on pushes targeting the default branch
5
+ push:
6
+ branches:
7
+ - main
8
+
9
+ workflow_dispatch:
10
+
11
+ # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
12
+ permissions:
13
+ contents: read
14
+ pages: write
15
+ id-token: write
16
+
17
+ # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
18
+ # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
19
+ concurrency:
20
+ group: "pages"
21
+ cancel-in-progress: false
22
+
23
+ jobs:
24
+ # Build job
25
+ build:
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - name: Checkout
29
+ uses: actions/checkout@v4
30
+ - name: Setup Pages
31
+ uses: actions/configure-pages@v5
32
+ - name: Build with Jekyll
33
+ uses: actions/jekyll-build-pages@v1
34
+ with:
35
+ source: ./docs
36
+ destination: ./_site
37
+ baseurl: act_as_api_client
38
+ - name: Upload artifact
39
+ uses: actions/upload-pages-artifact@v3
40
+
41
+ # Deployment job
42
+ deploy:
43
+ environment:
44
+ name: github-pages
45
+ url: ${{ steps.deployment.outputs.page_url }}
46
+ runs-on: ubuntu-latest
47
+ needs: build
48
+ steps:
49
+ - name: Deploy to GitHub Pages
50
+ id: deployment
51
+ uses: actions/deploy-pages@v4
data/.gitignore CHANGED
@@ -12,8 +12,9 @@
12
12
 
13
13
  .idea
14
14
  .byebug_history
15
- spec/credentials.yml
16
15
 
17
16
  *.gem
18
17
 
19
- .DS_Store
18
+ .DS_Store
19
+
20
+ vendor
data/Gemfile.lock CHANGED
@@ -2,6 +2,7 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  act_as_api_client (1.3.0)
5
+ event_stream_parser
5
6
 
6
7
  GEM
7
8
  remote: https://rubygems.org/
@@ -13,6 +14,7 @@ GEM
13
14
  crack (0.4.5)
14
15
  rexml
15
16
  diff-lcs (1.5.0)
17
+ event_stream_parser (1.0.0)
16
18
  hashdiff (1.0.1)
17
19
  parallel (1.22.1)
18
20
  parser (3.1.2.0)
@@ -68,4 +70,4 @@ DEPENDENCIES
68
70
  rubocop (~> 0.80)
69
71
  rubocop-rspec
70
72
  vcr (~> 6.1)
71
- webmock (~> 3.14)
73
+ webmock (~> 3.14)
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = "act_as_api_client"
5
- spec.version = "1.3.0"
5
+ spec.version = "1.3.1"
6
6
  spec.authors = ["Max Rukomoynikov"]
7
7
  spec.email = ["rukomoynikov@gmail.com"]
8
8
 
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
15
15
  spec.metadata = {
16
16
  "source_code_uri" => "https://github.com/Rukomoynikov/act_as_api_client",
17
17
  "homepage_uri" => spec.homepage,
18
- "documentation_uri" => "https://rubydoc.info/github/Rukomoynikov/act_as_api_client/main",
18
+ "documentation_uri" => "https://rukomoynikov.github.io/act_as_api_client/",
19
19
  "bug_tracker_uri" => "https://github.com/Rukomoynikov/act_as_api_client/issues"
20
20
  }
21
21
 
@@ -26,6 +26,8 @@ Gem::Specification.new do |spec|
26
26
  end
27
27
  spec.require_paths = ["lib"]
28
28
 
29
+ spec.add_dependency "event_stream_parser"
30
+
29
31
  # Uncomment to register a new dependency of your gem
30
32
  spec.add_development_dependency "byebug", "~> 11.1"
31
33
  spec.add_development_dependency "rake", "~> 13.0"
data/docs/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ _site
2
+ .sass-cache
3
+ .jekyll-cache
4
+ .jekyll-metadata
5
+ vendor
data/docs/404.html ADDED
@@ -0,0 +1,25 @@
1
+ ---
2
+ permalink: /404.html
3
+ layout: default
4
+ ---
5
+
6
+ <style type="text/css" media="screen">
7
+ .container {
8
+ margin: 10px auto;
9
+ max-width: 600px;
10
+ text-align: center;
11
+ }
12
+ h1 {
13
+ margin: 30px 0;
14
+ font-size: 4em;
15
+ line-height: 1;
16
+ letter-spacing: -1px;
17
+ }
18
+ </style>
19
+
20
+ <div class="container">
21
+ <h1>404</h1>
22
+
23
+ <p><strong>Page not found :(</strong></p>
24
+ <p>The requested page could not be found.</p>
25
+ </div>
data/docs/Gemfile ADDED
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+ # Hello! This is where you manage which Jekyll version is used to run.
5
+ # When you want to use a different version, change it below, save the
6
+ # file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
7
+ #
8
+ # bundle exec jekyll serve
9
+ #
10
+ # This will help ensure the proper Jekyll version is running.
11
+ # Happy Jekylling!
12
+ gem "jekyll", "~> 4.3.4"
13
+ # This is the default theme for new Jekyll sites. You may change this to anything you like.
14
+ gem "minima", "~> 2.5"
15
+ # If you want to use GitHub Pages, remove the "gem "jekyll"" above and
16
+ # uncomment the line below. To upgrade, run `bundle update github-pages`.
17
+ # gem "github-pages", group: :jekyll_plugins
18
+ # If you have any plugins, put them here!
19
+ group :jekyll_plugins do
20
+ gem "jekyll-feed", "~> 0.12"
21
+ end
22
+
23
+ # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem
24
+ # and associated library.
25
+ platforms :mingw, :x64_mingw, :mswin, :jruby do
26
+ gem "tzinfo", ">= 1", "< 3"
27
+ gem "tzinfo-data"
28
+ end
29
+
30
+ # Performance-booster for watching directories on Windows
31
+ gem "wdm", "~> 0.1", platforms: %i[mingw x64_mingw mswin]
32
+
33
+ # Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem
34
+ # do not have a Java counterpart.
35
+ gem "http_parser.rb", "~> 0.6.0", platforms: [:jruby]
data/docs/Gemfile.lock ADDED
@@ -0,0 +1,181 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ addressable (2.8.7)
5
+ public_suffix (>= 2.0.2, < 7.0)
6
+ bigdecimal (3.1.8)
7
+ colorator (1.1.0)
8
+ concurrent-ruby (1.3.4)
9
+ em-websocket (0.5.3)
10
+ eventmachine (>= 0.12.9)
11
+ http_parser.rb (~> 0)
12
+ eventmachine (1.2.7)
13
+ ffi (1.17.0)
14
+ ffi (1.17.0-aarch64-linux-gnu)
15
+ ffi (1.17.0-aarch64-linux-musl)
16
+ ffi (1.17.0-arm-linux-gnu)
17
+ ffi (1.17.0-arm-linux-musl)
18
+ ffi (1.17.0-arm64-darwin)
19
+ ffi (1.17.0-x86-linux-gnu)
20
+ ffi (1.17.0-x86-linux-musl)
21
+ ffi (1.17.0-x86_64-darwin)
22
+ ffi (1.17.0-x86_64-linux-gnu)
23
+ ffi (1.17.0-x86_64-linux-musl)
24
+ forwardable-extended (2.6.0)
25
+ google-protobuf (4.28.3)
26
+ bigdecimal
27
+ rake (>= 13)
28
+ google-protobuf (4.28.3-aarch64-linux)
29
+ bigdecimal
30
+ rake (>= 13)
31
+ google-protobuf (4.28.3-arm64-darwin)
32
+ bigdecimal
33
+ rake (>= 13)
34
+ google-protobuf (4.28.3-x86-linux)
35
+ bigdecimal
36
+ rake (>= 13)
37
+ google-protobuf (4.28.3-x86_64-darwin)
38
+ bigdecimal
39
+ rake (>= 13)
40
+ google-protobuf (4.28.3-x86_64-linux)
41
+ bigdecimal
42
+ rake (>= 13)
43
+ http_parser.rb (0.8.0)
44
+ i18n (1.14.6)
45
+ concurrent-ruby (~> 1.0)
46
+ jekyll (4.3.4)
47
+ addressable (~> 2.4)
48
+ colorator (~> 1.0)
49
+ em-websocket (~> 0.5)
50
+ i18n (~> 1.0)
51
+ jekyll-sass-converter (>= 2.0, < 4.0)
52
+ jekyll-watch (~> 2.0)
53
+ kramdown (~> 2.3, >= 2.3.1)
54
+ kramdown-parser-gfm (~> 1.0)
55
+ liquid (~> 4.0)
56
+ mercenary (>= 0.3.6, < 0.5)
57
+ pathutil (~> 0.9)
58
+ rouge (>= 3.0, < 5.0)
59
+ safe_yaml (~> 1.0)
60
+ terminal-table (>= 1.8, < 4.0)
61
+ webrick (~> 1.7)
62
+ jekyll-feed (0.17.0)
63
+ jekyll (>= 3.7, < 5.0)
64
+ jekyll-sass-converter (3.0.0)
65
+ sass-embedded (~> 1.54)
66
+ jekyll-seo-tag (2.8.0)
67
+ jekyll (>= 3.8, < 5.0)
68
+ jekyll-watch (2.2.1)
69
+ listen (~> 3.0)
70
+ kramdown (2.5.1)
71
+ rexml (>= 3.3.9)
72
+ kramdown-parser-gfm (1.1.0)
73
+ kramdown (~> 2.0)
74
+ liquid (4.0.4)
75
+ listen (3.9.0)
76
+ rb-fsevent (~> 0.10, >= 0.10.3)
77
+ rb-inotify (~> 0.9, >= 0.9.10)
78
+ mercenary (0.4.0)
79
+ minima (2.5.2)
80
+ jekyll (>= 3.5, < 5.0)
81
+ jekyll-feed (~> 0.9)
82
+ jekyll-seo-tag (~> 2.1)
83
+ pathutil (0.16.2)
84
+ forwardable-extended (~> 2.6)
85
+ public_suffix (6.0.1)
86
+ rake (13.2.1)
87
+ rb-fsevent (0.11.2)
88
+ rb-inotify (0.11.1)
89
+ ffi (~> 1.0)
90
+ rexml (3.3.9)
91
+ rouge (4.5.1)
92
+ safe_yaml (1.0.5)
93
+ sass-embedded (1.81.0)
94
+ google-protobuf (~> 4.28)
95
+ rake (>= 13)
96
+ sass-embedded (1.81.0-aarch64-linux-android)
97
+ google-protobuf (~> 4.28)
98
+ sass-embedded (1.81.0-aarch64-linux-gnu)
99
+ google-protobuf (~> 4.28)
100
+ sass-embedded (1.81.0-aarch64-linux-musl)
101
+ google-protobuf (~> 4.28)
102
+ sass-embedded (1.81.0-aarch64-mingw-ucrt)
103
+ google-protobuf (~> 4.28)
104
+ sass-embedded (1.81.0-arm-linux-androideabi)
105
+ google-protobuf (~> 4.28)
106
+ sass-embedded (1.81.0-arm-linux-gnueabihf)
107
+ google-protobuf (~> 4.28)
108
+ sass-embedded (1.81.0-arm-linux-musleabihf)
109
+ google-protobuf (~> 4.28)
110
+ sass-embedded (1.81.0-arm64-darwin)
111
+ google-protobuf (~> 4.28)
112
+ sass-embedded (1.81.0-riscv64-linux-android)
113
+ google-protobuf (~> 4.28)
114
+ sass-embedded (1.81.0-riscv64-linux-gnu)
115
+ google-protobuf (~> 4.28)
116
+ sass-embedded (1.81.0-riscv64-linux-musl)
117
+ google-protobuf (~> 4.28)
118
+ sass-embedded (1.81.0-x86-cygwin)
119
+ google-protobuf (~> 4.28)
120
+ sass-embedded (1.81.0-x86-linux-android)
121
+ google-protobuf (~> 4.28)
122
+ sass-embedded (1.81.0-x86-linux-gnu)
123
+ google-protobuf (~> 4.28)
124
+ sass-embedded (1.81.0-x86-linux-musl)
125
+ google-protobuf (~> 4.28)
126
+ sass-embedded (1.81.0-x86-mingw-ucrt)
127
+ google-protobuf (~> 4.28)
128
+ sass-embedded (1.81.0-x86_64-cygwin)
129
+ google-protobuf (~> 4.28)
130
+ sass-embedded (1.81.0-x86_64-darwin)
131
+ google-protobuf (~> 4.28)
132
+ sass-embedded (1.81.0-x86_64-linux-android)
133
+ google-protobuf (~> 4.28)
134
+ sass-embedded (1.81.0-x86_64-linux-gnu)
135
+ google-protobuf (~> 4.28)
136
+ sass-embedded (1.81.0-x86_64-linux-musl)
137
+ google-protobuf (~> 4.28)
138
+ terminal-table (3.0.2)
139
+ unicode-display_width (>= 1.1.1, < 3)
140
+ unicode-display_width (2.6.0)
141
+ webrick (1.9.0)
142
+
143
+ PLATFORMS
144
+ aarch64-linux-android
145
+ aarch64-linux-gnu
146
+ aarch64-linux-musl
147
+ aarch64-mingw-ucrt
148
+ arm-linux-androideabi
149
+ arm-linux-gnu
150
+ arm-linux-gnueabihf
151
+ arm-linux-musl
152
+ arm-linux-musleabihf
153
+ arm64-darwin
154
+ riscv64-linux-android
155
+ riscv64-linux-gnu
156
+ riscv64-linux-musl
157
+ ruby
158
+ x86-cygwin
159
+ x86-linux
160
+ x86-linux-android
161
+ x86-linux-gnu
162
+ x86-linux-musl
163
+ x86-mingw-ucrt
164
+ x86_64-cygwin
165
+ x86_64-darwin
166
+ x86_64-linux
167
+ x86_64-linux-android
168
+ x86_64-linux-gnu
169
+ x86_64-linux-musl
170
+
171
+ DEPENDENCIES
172
+ http_parser.rb (~> 0.6.0)
173
+ jekyll (~> 4.3.4)
174
+ jekyll-feed (~> 0.12)
175
+ minima (~> 2.5)
176
+ tzinfo (>= 1, < 3)
177
+ tzinfo-data
178
+ wdm (~> 0.1)
179
+
180
+ BUNDLED WITH
181
+ 2.5.11
data/docs/_config.yml ADDED
@@ -0,0 +1,50 @@
1
+ # Welcome to Jekyll!
2
+ #
3
+ # This config file is meant for settings that affect your whole blog, values
4
+ # which you are expected to set up once and rarely edit after that. If you find
5
+ # yourself editing this file very often, consider using Jekyll's data files
6
+ # feature for the data you need to update frequently.
7
+ #
8
+ # For technical reasons, this file is *NOT* reloaded automatically when you use
9
+ # 'bundle exec jekyll serve'. If you change this file, please restart the server process.
10
+ #
11
+ # If you need help with YAML syntax, here are some quick references for you:
12
+ # https://learn-the-web.algonquindesign.ca/topics/markdown-yaml-cheat-sheet/#yaml
13
+ # https://learnxinyminutes.com/docs/yaml/
14
+ #
15
+ # Site settings
16
+ # These are used to personalize your new site. If you look in the HTML files,
17
+ # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on.
18
+ # You can create any custom variable you would like, and they will be accessible
19
+ # in the templates via {{ site.myvariable }}.
20
+
21
+ title: Act as API client
22
+ description: >- # this means to ignore newlines until "baseurl:"
23
+ Simple gem to cover all your API needs.
24
+ baseurl: "/act_as_api_client"
25
+ url: "https://rukomoynikov.github.io"
26
+ # twitter_username: rukomoynikov
27
+ # github_username: rukomoynikov
28
+
29
+ # Build settings
30
+ theme: minima
31
+ # plugins:
32
+ # Exclude from processing.
33
+ # The following items will not be processed, by default.
34
+ # Any item listed under the `exclude:` key here will be automatically added to
35
+ # the internal "default list".
36
+ #
37
+ # Excluded items can be processed by explicitly listing the directories or
38
+ # their entries' file path in the `include:` list.
39
+ #
40
+ # exclude:
41
+ # - .sass-cache/
42
+ # - .jekyll-cache/
43
+ # - gemfiles/
44
+ # - Gemfile
45
+ # - Gemfile.lock
46
+ # - node_modules/
47
+ # - vendor/bundle/
48
+ # - vendor/cache/
49
+ # - vendor/gems/
50
+ # - vendor/ruby/
@@ -0,0 +1 @@
1
+ baseurl: ""
Binary file
@@ -0,0 +1,92 @@
1
+ ---
2
+ layout: home
3
+ image: "./assets/thumbnail.jpg"
4
+ ---
5
+
6
+ The Messages API lets you send messages with text or images, and receive a response from the AI model. You can use it in two main ways:
7
+
8
+ **Simple sync request:**
9
+ {% highlight ruby %}
10
+ require "act_as_api_client"
11
+
12
+ class AnthropicClient < ApiClient
13
+ act_as_api_client for: %i[anthropic messages],
14
+ with: { x_api_key: ENV["ANTHROPIC_API_KEY"] }
15
+ end
16
+
17
+ anthropic_client = AnthropicClient.new
18
+
19
+ pp anthropic_client.create(
20
+ model: "claude-3-5-sonnet-20241022",
21
+ messages: [
22
+ { "role": "user", "content": "Hello there." },
23
+ { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
24
+ { "role": "user", "content": "Can you explain LLMs in plain English?" }
25
+ ],
26
+ max_tokens: 1024
27
+ )
28
+ {% endhighlight %}
29
+
30
+ **Async (stream) request:**
31
+ {% highlight ruby %}
32
+ anthropic_client.create(
33
+ model: "claude-3-5-sonnet-20241022",
34
+ messages: [
35
+ { "role": "user", "content": "Hello there." },
36
+ { "role": "assistant", "content": "Hi, I'm Claude. How can I help you?" },
37
+ { "role": "user", "content": "Can you explain LLMs in plain English?" }
38
+ ],
39
+ max_tokens: 1024,
40
+ stream: true
41
+ ) do |event, data|
42
+ p event
43
+ p data
44
+ end
45
+ {% endhighlight %}
46
+
47
+ **Response:**
48
+ {% highlight ruby %}
49
+ {"id"=>"msg_017gdUbYuH8Y51y5TngCNbnN",
50
+ "type"=>"message",
51
+ "role"=>"assistant",
52
+ "model"=>"claude-3-5-sonnet-20241022",
53
+ "content"=>
54
+ [{"type"=>"text",
55
+ "text"=>
56
+ "Sure! Let me explain Large Language Models (LLMs) in simple terms:\n" +
57
+ "\n" +
58
+ "LLMs are computer programs that have been trained on massive amounts of text from the internet, books, and other sources. Think of them like incredibly well-read students who have absorbed information from millions of documents.\n" +
59
+ "\n" +
60
+ "These models learn patterns in language - how words fit together, how sentences are structured, and how ideas connect. They can then use these patterns to:\n" +
61
+ "- Generate human-like text\n" +
62
+ "- Answer questions\n" +
63
+ "- Summarize information \n" +
64
+ "- Translate languages\n" +
65
+ "- Help with writing\n" +
66
+ "- And much more\n" +
67
+ "\n" +
68
+ "I'm an LLM myself. When you write something to me, I look at the patterns I learned during training to understand what you're saying and formulate relevant responses. However, I don't actually \"understand\" things the way humans do - I work by recognizing and generating patterns in text.\n" +
69
+ "\n" +
70
+ "The \"Large\" in LLM refers to both the massive amount of training data used and the number of parameters (connection points) in the model - often billions or trillions.\n" +
71
+ "\n" +
72
+ "Think of it like a very sophisticated autocomplete system, but one that can maintain context and generate much longer, more coherent responses.\n" +
73
+ "\n" +
74
+ "Would you like me to elaborate on any part of this explanation?"}],
75
+ "stop_reason"=>"end_turn",
76
+ "stop_sequence"=>nil,
77
+ "usage"=>{"input_tokens"=>38, "output_tokens"=>272}}
78
+ {% endhighlight %}
79
+
80
+ **Supported options:**
81
+ - `model (string)` - [LLM model](https://docs.anthropic.com/en/docs/about-claude/models) to process your request
82
+ - `messages (list)` - list of messages (see example above)
83
+ - `max_tokens (number)` - the maximum number of tokens to generate before stopping
84
+ - `metadata (hash)` - an object describing metadata about the request
85
+ - `stop_sequences (list)` - custom text sequences that will cause the model to stop generating
86
+ - `stream (boolean)` - whether to incrementally stream the response using server-sent events
87
+ - `system (string)` - system prompt
88
+ - `temperature (float)` - system prompt
89
+ - `tool_choice (hash)` - how the model should use the provided tools
90
+ - `tools (list)` - definitions of tools that the model may use
91
+ - `top_k (number)` - only sample from the top K options for each subsequent token
92
+ - `top_p (float)` - use nucleus sampling
@@ -0,0 +1,13 @@
1
+ services:
2
+ app:
3
+ build:
4
+ dockerfile_inline: |
5
+ FROM ruby:bullseye
6
+ COPY Gemfile Gemfile.lock .
7
+ RUN bundle install
8
+ working_dir: /app
9
+ volumes:
10
+ - ./:/app
11
+ ports:
12
+ - 4000:4000
13
+ command: bundle exec jekyll serve -H 0.0.0.0 --watch --config _config.yml,_config_development.yml
@@ -0,0 +1,39 @@
1
+ ---
2
+ layout: home
3
+ image: "./assets/thumbnail.jpg"
4
+ ---
5
+
6
+ ![Act as api logo](/assets/thumbnail.jpg)
7
+
8
+ ## Supported clients:
9
+
10
+ - [Anthropic](clients/anthropic)
11
+
12
+ ## Example of usage:
13
+
14
+ Any API client can be used with or withour Rails. All what you need to do is
15
+ inherit from ApiClient and choose service through `act_as_api_client for:`. Also
16
+ some clients may require some settings token etc.
17
+
18
+ **Add to Gemfile:**
19
+ {% highlight ruby %}
20
+ gem 'act_as_api_client'
21
+ {% endhighlight %}
22
+
23
+ **Request service:**
24
+ {% highlight ruby %}
25
+ require "act_as_api_client"
26
+
27
+ class AnthropicClient < ApiClient
28
+ act_as_api_client for: %i[anthropic messages],
29
+ with: { x_api_key: ENV["ANTHROPIC_API_KEY"] }
30
+ end
31
+
32
+ anthropic_client = AnthropicClient.new
33
+
34
+ anthropic_client.create(
35
+ model: "claude-3-5-sonnet-20241022",
36
+ messages: [{ "role": "user", "content": "Hello there." }],
37
+ max_tokens: 1024
38
+ )
39
+ {% endhighlight %}
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../http_client"
4
-
5
- # See the documentation on https://docs.anthropic.com/en/api/messages
3
+ require "act_as_api_client/clients/http/simple_client"
4
+ require "act_as_api_client/clients/http/streaming_client"
6
5
 
7
6
  module ActAsApiClient
8
7
  module Clients
@@ -11,8 +10,6 @@ module ActAsApiClient
11
10
  ANTHROPIC_VERSION = "2023-06-01"
12
11
  BASE_URL = "https://api.anthropic.com/v1/messages"
13
12
 
14
- include HttpClient
15
-
16
13
  # Sends request to Anthropic API https://docs.anthropic.com/en/api/messages
17
14
  #
18
15
  # @param model [String] The model that will complete your prompt
@@ -29,8 +26,18 @@ module ActAsApiClient
29
26
  # @param top_p [Float] Use nucleus sampling
30
27
  #
31
28
  # @return [Hash] Response from Anthropic API
32
- def create(**params)
33
- post(BASE_URL, headers: headers, body: body(**params))
29
+ def create(**params, &block)
30
+ client = if params.fetch(:stream, false)
31
+ ActAsApiClient::Clients::Http::StreamingClient.new
32
+ else
33
+ ActAsApiClient::Clients::Http::SimpleClient.new
34
+ end
35
+
36
+ client.post(BASE_URL,
37
+ headers: headers,
38
+ stream: params.fetch(:stream, false),
39
+ body: body(**params),
40
+ &block)
34
41
  end
35
42
 
36
43
  private
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "http_client"
3
+ require "act_as_api_client/clients/http/simple_client"
4
4
 
5
5
  module ActAsApiClient
6
6
  module Clients
7
7
  module GithubRepositoriesClient
8
- include HttpClient
9
-
10
8
  # Searches Github for one repository by it's owner and repository names.
11
9
  # More details look at the corresponding {https://docs.github.com/en/rest/repos/repos#get-a-repository Github Docs page}
12
10
  #
@@ -18,9 +16,11 @@ module ActAsApiClient
18
16
  raise StandardError, "repository_name parameter is not valid"
19
17
  end
20
18
 
21
- get("https://api.github.com/repos/#{repository_name}",
22
- headers: { "Accept" => "application/vnd.github.v3+json",
23
- "Authorization" => (options[:token] ? "token #{options[:token]}" : nil) })
19
+ http_client = ActAsApiClient::Clients::Http::SimpleClient.new
20
+
21
+ http_client.get("https://api.github.com/repos/#{repository_name}",
22
+ headers: { "Accept" => "application/vnd.github.v3+json",
23
+ "Authorization" => (options[:token] ? "token #{options[:token]}" : nil) })
24
24
  end
25
25
 
26
26
  # Search through Github repositories using query string and additional parameters explained on the {https://docs.github.com/en/rest/search#search-repositories Github Docs page}
@@ -38,10 +38,12 @@ module ActAsApiClient
38
38
  #
39
39
  # @return [Array] list of repositories
40
40
  def where(query_string, parameters = {})
41
- get("https://api.github.com/search/repositories",
42
- headers: { "Accept" => "application/vnd.github.v3+json",
43
- "Authorization" => (options[:token] ? "token #{options[:token]}" : nil) },
44
- params: { q: query_string }.merge(parameters))
41
+ http_client = ActAsApiClient::Clients::Http::SimpleClient.new
42
+
43
+ http_client.get("https://api.github.com/search/repositories",
44
+ headers: { "Accept" => "application/vnd.github.v3+json",
45
+ "Authorization" => (options[:token] ? "token #{options[:token]}" : nil) },
46
+ params: { q: query_string }.merge(parameters))
45
47
  end
46
48
 
47
49
  # Use this method if you need to get list of repositories selected by one of this conditions: user, authenticated_user, organization
@@ -72,23 +74,12 @@ module ActAsApiClient
72
74
  "https://api.github.com/repositories"
73
75
  end
74
76
 
75
- get(url,
76
- headers: { "Accept" => "application/vnd.github.v3+json",
77
- "Authorization" => (options[:token] ? "token #{options[:token]}" : nil) })
78
- end
77
+ http_client = ActAsApiClient::Clients::Http::SimpleClient.new
79
78
 
80
- # def delete
81
- # # Call only on queried before repository and repository is not 404/400 and has right to delete (write)
82
- # "delete"
83
- # end
84
- #
85
- # def create
86
- # "create"
87
- # end
88
- #
89
- # def update
90
- # "update"
91
- # end
79
+ http_client.get(url,
80
+ headers: { "Accept" => "application/vnd.github.v3+json",
81
+ "Authorization" => (options[:token] ? "token #{options[:token]}" : nil) })
82
+ end
92
83
  end
93
84
  end
94
85
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActAsApiClient
4
+ module Clients
5
+ module Http
6
+ module BaseClient
7
+ private
8
+
9
+ def build_uri(url, **options)
10
+ uri = URI(url)
11
+ uri.query = URI.encode_www_form(options.fetch(:params, {}))
12
+
13
+ uri
14
+ end
15
+
16
+ def set_request_headers(headers:, request:)
17
+ headers.each do |key, value|
18
+ request[key] = value
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "json"
5
+
6
+ require "act_as_api_client/errors/invalid_response_error"
7
+ require "act_as_api_client/errors/network_error"
8
+
9
+ require "act_as_api_client/clients/http/base_client"
10
+
11
+ module ActAsApiClient
12
+ module Clients
13
+ module Http
14
+ class SimpleClient
15
+ include BaseClient
16
+
17
+ def get(url, **options)
18
+ uri = build_uri(url, **options)
19
+
20
+ request = Net::HTTP::Get.new(uri)
21
+ set_request_headers(headers: options.fetch(:headers, {}),
22
+ request: request)
23
+
24
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
25
+ http.request(request)
26
+ end
27
+
28
+ parse_response(response)
29
+ rescue Net::OpenTimeout, Net::ReadTimeout, SocketError => e
30
+ raise ActAsApiClient::Errors::NetworkError, "Network error occurred: #{e.message}"
31
+ end
32
+
33
+ def post(url, headers: {}, **options)
34
+ uri = build_uri(url, **options)
35
+ request = Net::HTTP::Post.new(uri)
36
+ set_request_headers(headers: headers, request: request)
37
+ request.body = options.fetch(:body, {}).to_json
38
+
39
+ response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
40
+ http.request(request)
41
+ end
42
+
43
+ parse_response(response)
44
+ rescue Net::OpenTimeout, Net::ReadTimeout, SocketError => e
45
+ raise ActAsApiClient::Errors::NetworkError, "Network error occurred: #{e.message}"
46
+ end
47
+
48
+ private
49
+
50
+ def parse_response(response)
51
+ case response
52
+ when Net::HTTPSuccess, Net::HTTPBadRequest
53
+ ::JSON.parse(response.body)
54
+ when Net::HTTPNotFound, Net::HTTPUnprocessableEntity, Net::HTTPUnauthorized
55
+ ::JSON.parse(response.body)
56
+ end
57
+ rescue JSON::ParserError => e
58
+ raise ActAsApiClient::Errors::InvalidResponseError, "Invalid JSON response: #{e.message}"
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "json"
5
+ require "event_stream_parser"
6
+
7
+ require "act_as_api_client/errors/invalid_response_error"
8
+ require "act_as_api_client/errors/network_error"
9
+
10
+ module ActAsApiClient
11
+ module Clients
12
+ module Http
13
+ class StreamingClient
14
+ include BaseClient
15
+
16
+ def post(url, headers: {}, **options) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
17
+ uri = URI(url)
18
+ uri.query = URI.encode_www_form(options.fetch(:params, {}))
19
+
20
+ request = Net::HTTP::Post.new(uri)
21
+
22
+ request.body = options.fetch(:body, {}).to_json
23
+ set_request_headers(headers: headers, request: request)
24
+
25
+ parser = EventStreamParser::Parser.new
26
+
27
+ Net::HTTP.start(uri.hostname, use_ssl: true) do |http|
28
+ http.request(request) do |response|
29
+ case response
30
+ when Net::HTTPSuccess, Net::HTTPBadRequest
31
+ response.read_body do |chunk|
32
+ parser.feed(chunk) do |_type, data, _id, _reconnection_time|
33
+ yield(::JSON.parse(data)) if block_given?
34
+ end
35
+ end
36
+ when Net::HTTPNotFound, Net::HTTPUnprocessableEntity, Net::HTTPUnauthorized
37
+ response.read_body do |chunk|
38
+ parser.feed(chunk) do |_type, data, _id, _reconnection_time|
39
+ yield(::JSON.parse(data)) if block_given?
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ rescue Net::OpenTimeout, Net::ReadTimeout, SocketError => e
46
+ raise ActAsApiClient::Errors::NetworkError, "Network error occurred: #{e.message}"
47
+ rescue JSON::ParserError => e
48
+ raise ActAsApiClient::Errors::InvalidResponseError, "Invalid JSON response: #{e.message}"
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -1,12 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "act_as_api_client/base_api_methods"
4
3
  require "act_as_api_client/errors/non_existing_client_error"
5
4
  require "act_as_api_client/client_loader"
6
5
 
7
6
  class ApiClient
8
- include ActAsApiClient::BaseApiMethods
9
-
10
7
  class << self
11
8
  def act_as_api_client(**args)
12
9
  set_general_client(client_for: args.fetch(:for, nil))
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: act_as_api_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Max Rukomoynikov
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-21 00:00:00.000000000 Z
11
+ date: 2025-11-07 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: event_stream_parser
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: byebug
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -118,6 +132,7 @@ extra_rdoc_files: []
118
132
  files:
119
133
  - ".devcontainer.json"
120
134
  - ".github/workflows/main.yml"
135
+ - ".github/workflows/update_docs.yml"
121
136
  - ".gitignore"
122
137
  - ".rspec"
123
138
  - ".rubocop.yml"
@@ -132,16 +147,26 @@ files:
132
147
  - act_as_api_client.gemspec
133
148
  - bin/console
134
149
  - bin/setup
135
- - demo.rb
136
150
  - docker-compose.yml
151
+ - docs/.gitignore
152
+ - docs/404.html
153
+ - docs/Gemfile
154
+ - docs/Gemfile.lock
155
+ - docs/_config.yml
156
+ - docs/_config_development.yml
157
+ - docs/assets/thumbnail.jpg
158
+ - docs/clients/anthropic.markdown
159
+ - docs/docker-compose.yml
160
+ - docs/index.markdown
137
161
  - examples/anthropic_playground.rb
138
162
  - examples/github_repositories.rb
139
163
  - lib/act_as_api_client.rb
140
- - lib/act_as_api_client/base_api_methods.rb
141
164
  - lib/act_as_api_client/client_loader.rb
142
165
  - lib/act_as_api_client/clients/anthropic/messages_client.rb
143
166
  - lib/act_as_api_client/clients/github_repositories_client.rb
144
- - lib/act_as_api_client/clients/http_client.rb
167
+ - lib/act_as_api_client/clients/http/base_client.rb
168
+ - lib/act_as_api_client/clients/http/simple_client.rb
169
+ - lib/act_as_api_client/clients/http/streaming_client.rb
145
170
  - lib/act_as_api_client/errors/invalid_response_error.rb
146
171
  - lib/act_as_api_client/errors/network_error.rb
147
172
  - lib/act_as_api_client/errors/non_existing_client_error.rb
@@ -151,9 +176,9 @@ licenses:
151
176
  metadata:
152
177
  source_code_uri: https://github.com/Rukomoynikov/act_as_api_client
153
178
  homepage_uri: https://rubygems.org/gems/act_as_api_client
154
- documentation_uri: https://rubydoc.info/github/Rukomoynikov/act_as_api_client/main
179
+ documentation_uri: https://rukomoynikov.github.io/act_as_api_client/
155
180
  bug_tracker_uri: https://github.com/Rukomoynikov/act_as_api_client/issues
156
- post_install_message:
181
+ post_install_message:
157
182
  rdoc_options: []
158
183
  require_paths:
159
184
  - lib
@@ -168,8 +193,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
193
  - !ruby/object:Gem::Version
169
194
  version: '0'
170
195
  requirements: []
171
- rubygems_version: 3.0.3.1
172
- signing_key:
196
+ rubygems_version: 3.3.27
197
+ signing_key:
173
198
  specification_version: 4
174
199
  summary: Collection of predefined API clients
175
200
  test_files: []
data/demo.rb DELETED
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "lib/act_as_api_client"
4
-
5
- class GithubClient < ApiClient
6
- act_as_api_client for: :github_repositories
7
- end
8
-
9
- p GithubClient.ancestors
10
- p GithubClient.new.method(:find).source_location
11
-
12
- GithubClient.new.find
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActAsApiClient
4
- module BaseApiMethods
5
- def find
6
- raise StandardError, "Should be defined in inherited class"
7
- end
8
-
9
- def where
10
- raise StandardError, "Should be defined in inherited class"
11
- end
12
-
13
- def find_by
14
- raise StandardError, "Should be defined in inherited class"
15
- end
16
-
17
- def delete
18
- raise StandardError, "Should be defined in inherited class"
19
- end
20
-
21
- def create
22
- raise StandardError, "Should be defined in inherited class"
23
- end
24
-
25
- def update
26
- raise StandardError, "Should be defined in inherited class"
27
- end
28
- end
29
- end
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "net/http"
4
- require "json"
5
-
6
- require "act_as_api_client/errors/invalid_response_error"
7
- require "act_as_api_client/errors/network_error"
8
-
9
- module ActAsApiClient
10
- module Clients
11
- module HttpClient
12
- private
13
-
14
- def get(url, **options)
15
- # Request part
16
- uri = URI(url)
17
- uri.query = URI.encode_www_form(options.fetch(:params, {}))
18
-
19
- request = Net::HTTP::Get.new(uri)
20
- set_request_headers(headers: options.fetch(:headers, {}),
21
- request: request)
22
-
23
- # Response part
24
- response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
25
- http.request(request)
26
- end
27
-
28
- case response
29
- when Net::HTTPNotFound, Net::HTTPSuccess, Net::HTTPUnprocessableEntity, Net::HTTPUnauthorized
30
- ::JSON.parse(response.body)
31
- end
32
- end
33
-
34
- def post(url, headers: {}, **options) # rubocop:disable Metrics/AbcSize
35
- # Request part
36
- uri = URI(url)
37
- uri.query = URI.encode_www_form(options.fetch(:params, {}))
38
-
39
- request = Net::HTTP::Post.new(uri)
40
-
41
- request.body = options.fetch(:body, {}).to_json
42
- set_request_headers(headers: headers, request: request)
43
-
44
- # Response part
45
- response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
46
- http.request(request)
47
- end
48
-
49
- case response
50
- when Net::HTTPSuccess
51
- ::JSON.parse(response.body)
52
- when Net::HTTPNotFound, Net::HTTPUnprocessableEntity, Net::HTTPUnauthorized
53
- ::JSON.parse(response.body)
54
- end
55
- rescue Net::OpenTimeout, Net::ReadTimeout, SocketError => e
56
- raise ActAsApiClient::NetworkError, "Network error occurred: #{e.message}"
57
- rescue JSON::ParserError => e
58
- raise ActAsApiClient::InvalidResponseError, "Invalid JSON response: #{e.message}"
59
- end
60
-
61
- def put
62
- # HTTParty.put
63
- end
64
-
65
- def update
66
- # HTTParty.update
67
- end
68
-
69
- def delete
70
- # HTTParty.delete
71
- end
72
-
73
- def set_request_headers(headers:, request:)
74
- headers.each do |key, value|
75
- request[key] = value
76
- end
77
- end
78
- end
79
- end
80
- end