mistral-ai 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 19bfd295de85b2f506daf1623bddc5966c34a0844b823fef2b30fd9de46f0dc9
4
+ data.tar.gz: b1bdd0da891f5280da914601a32ec351a4a848791d5f67c3304ab9ca96f87b1c
5
+ SHA512:
6
+ metadata.gz: e7ec9676abe38edca924552c4bc010cb1e04e91406f0cf1c28000dd69f76ebad53567bb48fe18977e1ead0751772d75af537fa5541bd5cf4affb8a7671a8f9fe
7
+ data.tar.gz: 0ca1dd38cba7bff0cd21934a0a9626ab97ff74cac5fef2fa572f7a1e87aafc8bc5191ba3a919535e7f87b8508ab7083c80cc037b7a6adb39be43fb66f8789a5c
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *.gem
2
+ .devcontainer
data/.rubocop.yml ADDED
@@ -0,0 +1,6 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.1.0
3
+ NewCops: enable
4
+
5
+ Style/Documentation:
6
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.1.0
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
6
+
7
+ group :test, :development do
8
+ gem 'pry-byebug', '~> 3.10', '>= 3.10.1'
9
+ gem 'rubocop', '~> 1.58'
10
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,64 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ mistral-ai (1.0.0)
5
+ event_stream_parser (~> 1.0)
6
+ faraday (~> 2.8, >= 2.8.1)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ ast (2.4.2)
12
+ base64 (0.2.0)
13
+ byebug (11.1.3)
14
+ coderay (1.1.3)
15
+ event_stream_parser (1.0.0)
16
+ faraday (2.8.1)
17
+ base64
18
+ faraday-net_http (>= 2.0, < 3.1)
19
+ ruby2_keywords (>= 0.0.4)
20
+ faraday-net_http (3.0.2)
21
+ json (2.7.1)
22
+ language_server-protocol (3.17.0.3)
23
+ method_source (1.0.0)
24
+ parallel (1.24.0)
25
+ parser (3.2.2.4)
26
+ ast (~> 2.4.1)
27
+ racc
28
+ pry (0.14.2)
29
+ coderay (~> 1.1)
30
+ method_source (~> 1.0)
31
+ pry-byebug (3.10.1)
32
+ byebug (~> 11.0)
33
+ pry (>= 0.13, < 0.15)
34
+ racc (1.7.3)
35
+ rainbow (3.1.1)
36
+ regexp_parser (2.8.3)
37
+ rexml (3.2.6)
38
+ rubocop (1.59.0)
39
+ json (~> 2.3)
40
+ language_server-protocol (>= 3.17.0)
41
+ parallel (~> 1.10)
42
+ parser (>= 3.2.2.4)
43
+ rainbow (>= 2.2.2, < 4.0)
44
+ regexp_parser (>= 1.8, < 3.0)
45
+ rexml (>= 3.2.5, < 4.0)
46
+ rubocop-ast (>= 1.30.0, < 2.0)
47
+ ruby-progressbar (~> 1.7)
48
+ unicode-display_width (>= 2.4.0, < 3.0)
49
+ rubocop-ast (1.30.0)
50
+ parser (>= 3.2.1.0)
51
+ ruby-progressbar (1.13.0)
52
+ ruby2_keywords (0.0.5)
53
+ unicode-display_width (2.5.0)
54
+
55
+ PLATFORMS
56
+ x86_64-linux
57
+
58
+ DEPENDENCIES
59
+ mistral-ai!
60
+ pry-byebug (~> 3.10, >= 3.10.1)
61
+ rubocop (~> 1.58)
62
+
63
+ BUNDLED WITH
64
+ 2.4.22
data/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright 2023 Guilherme Baptista
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,526 @@
1
+ # Mistral AI
2
+
3
+ A Ruby gem for interacting with [Mistral AI](https://mistral.ai)'s large language models.
4
+
5
+ ![The image features a graphic that merges a red ruby gem with a robotic face to symbolize the integration of a Ruby software library with Mistral AI's technology. The ruby has a reflective white top facet and the robot face includes two orange eyes, reflecting the Mistral AI logo's color. The design is modern and set against a dark background to emphasize the gem and robotic features.](https://raw.githubusercontent.com/gbaptista/assets/main/mistral-ai/ruby-mistral-ai.png)
6
+
7
+ > _This Gem is designed to provide low-level access to Mistral, enabling people to build abstractions on top of it. If you are interested in more high-level abstractions or more user-friendly tools, you may want to consider [Nano Bots](https://github.com/icebaker/ruby-nano-bots) 💎 🤖._
8
+
9
+ ## TL;DR and Quick Start
10
+
11
+ ```ruby
12
+ gem 'mistral-ai', '~> 1.0.0'
13
+ ```
14
+
15
+ ```ruby
16
+ require 'mistral-ai'
17
+
18
+ client = Mistral.new(
19
+ credentials: { api_key: ENV['MISTRAL_API_KEY'] },
20
+ options: { server_sent_events: true }
21
+ )
22
+
23
+ result = client.chat_completions(
24
+ { model: 'mistral-medium',
25
+ messages: [{ role: 'user', content: 'hi!' }] }
26
+ )
27
+ ```
28
+
29
+ Result:
30
+ ```ruby
31
+ { 'id' => 'cmpl-74fb544d49d04195a4182342936af43b',
32
+ 'object' => 'chat.completion',
33
+ 'created' => 1_703_792_737,
34
+ 'model' => 'mistral-medium',
35
+ 'choices' =>
36
+ [{ 'index' => 0,
37
+ 'message' =>
38
+ { 'role' => 'assistant',
39
+ 'content' =>
40
+ "Hello! How can I assist you today? If you have any questions or need help with something, feel free to ask. I'm here to help.\n" \
41
+ "\n" \
42
+ "If you're not sure where to start, you can ask me about a specific topic, such as a programming language, a scientific concept, or a current event. You can also ask me to tell you a joke, generate a random number, or provide a fun fact.\n" \
43
+ "\n" \
44
+ "I'm a large language model trained by Mistral AI, so I can understand and generate human-like text on a wide range of topics. I can also perform tasks such as summarizing text, translating between languages, and answering questions about a given text. I look forward to helping you!" },
45
+ 'finish_reason' => 'stop' }],
46
+ 'usage' => { 'prompt_tokens' => 10, 'total_tokens' => 166, 'completion_tokens' => 156 } }
47
+ ```
48
+
49
+ ## Index
50
+
51
+ - [TL;DR and Quick Start](#tldr-and-quick-start)
52
+ - [Index](#index)
53
+ - [Setup](#setup)
54
+ - [Installing](#installing)
55
+ - [Credentials](#credentials)
56
+ - [Usage](#usage)
57
+ - [Client](#client)
58
+ - [Custom Address](#custom-address)
59
+ - [Methods](#methods)
60
+ - [chat_completions](#chat_completions)
61
+ - [Without Streaming Events](#without-streaming-events)
62
+ - [Receiving Stream Events](#receiving-stream-events)
63
+ - [embeddings](#embeddings)
64
+ - [Streaming and Server-Sent Events (SSE)](#streaming-and-server-sent-events-sse)
65
+ - [Server-Sent Events (SSE) Hang](#server-sent-events-sse-hang)
66
+ - [System Messages](#system-messages)
67
+ - [Back-and-Forth Conversations](#back-and-forth-conversations)
68
+ - [New Functionalities and APIs](#new-functionalities-and-apis)
69
+ - [Request Options](#request-options)
70
+ - [Timeout](#timeout)
71
+ - [Error Handling](#error-handling)
72
+ - [Rescuing](#rescuing)
73
+ - [For Short](#for-short)
74
+ - [Errors](#errors)
75
+ - [Development](#development)
76
+ - [Purpose](#purpose)
77
+ - [Publish to RubyGems](#publish-to-rubygems)
78
+ - [Updating the README](#updating-the-readme)
79
+ - [Resources and References](#resources-and-references)
80
+ - [Disclaimer](#disclaimer)
81
+
82
+ ## Setup
83
+
84
+ ### Installing
85
+
86
+ ```sh
87
+ gem install mistral-ai -v 1.0.0
88
+ ```
89
+
90
+ ```sh
91
+ gem 'mistral-ai', '~> 1.0.0'
92
+ ```
93
+
94
+ ### Credentials
95
+
96
+ You can obtain your API key from the [Mistral AI Platform](https://console.mistral.ai).
97
+
98
+ ## Usage
99
+
100
+ ### Client
101
+
102
+ Ensure that you have an [API Key](#credentials) for authentication.
103
+
104
+ Create a new client:
105
+ ```ruby
106
+ require 'mistral-ai'
107
+
108
+ client = Mistral.new(
109
+ credentials: { api_key: ENV['MISTRAL_API_KEY'] },
110
+ options: { server_sent_events: true }
111
+ )
112
+ ```
113
+
114
+ #### Custom Address
115
+
116
+ You can use a custom address:
117
+
118
+ ```ruby
119
+ require 'mistral-ai'
120
+
121
+ client = Mistral.new(
122
+ credentials: {
123
+ address: 'https://api.mistral.ai',
124
+ api_key: ENV['MISTRAL_API_KEY']
125
+ },
126
+ options: { server_sent_events: true }
127
+ )
128
+ ```
129
+
130
+ ### Methods
131
+
132
+ #### chat_completions
133
+
134
+ ##### Without Streaming Events
135
+
136
+ ```ruby
137
+ result = client.chat_completions(
138
+ { model: 'mistral-medium',
139
+ messages: [{ role: 'user', content: 'hi!' }] }
140
+ )
141
+ ```
142
+
143
+ Result:
144
+ ```ruby
145
+ { 'id' => 'cmpl-74fb544d49d04195a4182342936af43b',
146
+ 'object' => 'chat.completion',
147
+ 'created' => 1_703_792_737,
148
+ 'model' => 'mistral-medium',
149
+ 'choices' =>
150
+ [{ 'index' => 0,
151
+ 'message' =>
152
+ { 'role' => 'assistant',
153
+ 'content' =>
154
+ "Hello! How can I assist you today? If you have any questions or need help with something, feel free to ask. I'm here to help.\n" \
155
+ "\n" \
156
+ "If you're not sure where to start, you can ask me about a specific topic, such as a programming language, a scientific concept, or a current event. You can also ask me to tell you a joke, generate a random number, or provide a fun fact.\n" \
157
+ "\n" \
158
+ "I'm a large language model trained by Mistral AI, so I can understand and generate human-like text on a wide range of topics. I can also perform tasks such as summarizing text, translating between languages, and answering questions about a given text. I look forward to helping you!" },
159
+ 'finish_reason' => 'stop' }],
160
+ 'usage' => { 'prompt_tokens' => 10, 'total_tokens' => 166, 'completion_tokens' => 156 } }
161
+ ```
162
+
163
+ ##### Receiving Stream Events
164
+
165
+ Ensure that you have enabled [Server-Sent Events](#streaming-and-server-sent-events-sse) before using blocks for streaming. You also need to add `stream: true` in your payload:
166
+
167
+ ```ruby
168
+ client.chat_completions(
169
+ { model: 'mistral-medium',
170
+ stream: true,
171
+ messages: [{ role: 'user', content: 'hi!' }] }
172
+ ) do |event, parsed, raw|
173
+ puts event
174
+ end
175
+ ```
176
+
177
+ Event:
178
+ ```ruby
179
+ { 'id' => 'cmpl-011e6223d8414df4840293b98e0b18ca',
180
+ 'object' => 'chat.completion.chunk',
181
+ 'created' => 1_703_796_464,
182
+ 'model' => 'mistral-medium',
183
+ 'choices' => [
184
+ { 'index' => 0, 'delta' => { 'role' => nil, 'content' => 'Hello' },
185
+ 'finish_reason' => nil }
186
+ ] }
187
+ ```
188
+
189
+ You can get all the receive events at once as an array:
190
+ ```ruby
191
+ result = client.chat_completions(
192
+ { model: 'mistral-medium',
193
+ stream: true,
194
+ messages: [{ role: 'user', content: 'hi!' }] }
195
+ )
196
+ ```
197
+
198
+ Result:
199
+ ```ruby
200
+ [{ 'id' => 'cmpl-20bc384332d749958251e11427aeeb42',
201
+ 'model' => 'mistral-medium',
202
+ 'choices' => [{ 'index' => 0, 'delta' => { 'role' => 'assistant' }, 'finish_reason' => nil }] },
203
+ { 'id' => 'cmpl-20bc384332d749958251e11427aeeb42',
204
+ 'object' => 'chat.completion.chunk',
205
+ 'created' => 1_703_796_630,
206
+ 'model' => 'mistral-medium',
207
+ 'choices' => [{ 'index' => 0, 'delta' => { 'role' => nil, 'content' => 'Hello! How can I' },
208
+ 'finish_reason' => nil }] },
209
+ { 'id' => 'cmpl-20bc384332d749958251e11427aeeb42',
210
+ 'object' => 'chat.completion.chunk',
211
+ 'created' => 1_703_796_630,
212
+ 'model' => 'mistral-medium',
213
+ 'choices' => [{ 'index' => 0, 'delta' => { 'role' => nil, 'content' => ' assist you today?' },
214
+ 'finish_reason' => nil }] },
215
+ # ...
216
+ { 'id' => 'cmpl-20bc384332d749958251e11427aeeb42',
217
+ 'object' => 'chat.completion.chunk',
218
+ 'created' => 1_703_796_630,
219
+ 'model' => 'mistral-medium',
220
+ 'choices' => [{ 'index' => 0, 'delta' => { 'role' => nil, 'content' => '' },
221
+ 'finish_reason' => 'stop' }] }]
222
+ ```
223
+
224
+ You can mix both as well:
225
+ ```ruby
226
+ result = client.chat_completions(
227
+ { model: 'mistral-medium',
228
+ stream: true,
229
+ messages: [{ role: 'user', content: 'hi!' }] }
230
+ ) do |event, parsed, raw|
231
+ puts event
232
+ end
233
+ ```
234
+
235
+ #### embeddings
236
+
237
+ ```ruby
238
+ result = client.embeddings(
239
+ { model: 'mistral-embed',
240
+ input: [
241
+ 'Embed this sentence.',
242
+ 'As well as this one.'
243
+ ] }
244
+ )
245
+ ```
246
+
247
+ Result:
248
+ ```ruby
249
+ { 'id' => 'embd-03f43eaec35744a3bab6f2ca83418555',
250
+ 'object' => 'list',
251
+ 'data' =>
252
+ [{ 'object' => 'embedding',
253
+ 'embedding' =>
254
+ [-0.0165863037109375,
255
+ 0.07012939453125,
256
+ # ...
257
+ 0.00428009033203125,
258
+ -0.036895751953125],
259
+ 'index' => 0 },
260
+ { 'object' => 'embedding',
261
+ 'embedding' =>
262
+ [-0.0234222412109375,
263
+ 0.039337158203125,
264
+ # ...
265
+ 0.00044846534729003906,
266
+ -0.01065826416015625],
267
+ 'index' => 1 }],
268
+ 'model' => 'mistral-embed',
269
+ 'usage' => { 'prompt_tokens' => 15, 'total_tokens' => 15, 'completion_tokens' => 0 } }
270
+
271
+ ```
272
+
273
+ ### Streaming and Server-Sent Events (SSE)
274
+
275
+ [Server-Sent Events (SSE)](https://en.wikipedia.org/wiki/Server-sent_events) is a technology that allows certain endpoints to offer streaming capabilities, such as creating the impression that "the model is typing along with you," rather than delivering the entire answer all at once.
276
+
277
+ You can set up the client to use Server-Sent Events (SSE) for all supported endpoints:
278
+ ```ruby
279
+ client = Mistral.new(
280
+ credentials: { api_key: ENV['MISTRAL_API_KEY'] },
281
+ options: { server_sent_events: true }
282
+ )
283
+ ```
284
+
285
+ Or, you can decide on a request basis:
286
+ ```ruby
287
+ client.chat_completions(
288
+ { model: 'mistral-medium',
289
+ stream: true,
290
+ messages: [{ role: 'user', content: 'hi!' }] },
291
+ server_sent_events: true
292
+ ) do |event, parsed, raw|
293
+ puts event
294
+ end
295
+ ```
296
+
297
+ With Server-Sent Events (SSE) enabled, you can use a block to receive partial results via events. This feature is particularly useful for methods that offer streaming capabilities, such as `chat_completions`: [Receiving Stream Events](#receiving-stream-events)
298
+
299
+ #### Server-Sent Events (SSE) Hang
300
+
301
+ Method calls will _hang_ until the server-sent events finish, so even without providing a block, you can obtain the final results of the received events: [Receiving Stream Events](#receiving-stream-events)
302
+
303
+ ### System Messages
304
+
305
+ System messages influence how the model answers:
306
+
307
+ ```ruby
308
+ result = client.chat_completions(
309
+ { model: 'mistral-medium',
310
+ messages: [
311
+ { role: 'system', content: 'Only answer strictly using JSON.' },
312
+ { role: 'user', content: 'Calculate 1 + 1.' }
313
+ ] }
314
+ )
315
+ ```
316
+
317
+ Result:
318
+ ```ruby
319
+ { 'id' => 'cmpl-0c6fee44022841728e435ac91416d211',
320
+ 'object' => 'chat.completion',
321
+ 'created' => 1_703_794_201,
322
+ 'model' => 'mistral-medium',
323
+ 'choices' => [{
324
+ 'index' => 0,
325
+ 'message' => { 'role' => 'assistant', 'content' => '{"result": 2}' },
326
+ 'finish_reason' => 'stop'
327
+ }],
328
+ 'usage' => { 'prompt_tokens' => 24, 'total_tokens' => 30, 'completion_tokens' => 6 } }
329
+
330
+ ```
331
+
332
+ ### Back-and-Forth Conversations
333
+
334
+ To maintain a back-and-forth conversation, you need to append the received responses and build a history for your requests:
335
+
336
+ ```rb
337
+ result = client.chat_completions(
338
+ { model: 'mistral-medium',
339
+ messages: [
340
+ { role: 'user',
341
+ content: 'Hi! My name is Purple.' },
342
+ { role: 'assistant',
343
+ content: "Hello Purple! It's nice to meet you. How can I help you today?" },
344
+ { role: 'user', content: "What's my name?" }
345
+ ] }
346
+ )
347
+ ```
348
+
349
+ Result:
350
+ ```ruby
351
+ { 'id' => 'cmpl-cbc4a8db84b347738840e34e46388f1f',
352
+ 'object' => 'chat.completion',
353
+ 'created' => 1_703_793_492,
354
+ 'model' => 'mistral-medium',
355
+ 'choices' =>
356
+ [{ 'index' => 0,
357
+ 'message' => {
358
+ 'role' => 'assistant',
359
+ 'content' => 'Your name is Purple, as you introduced yourself earlier. Is there anything else I can help you with?'
360
+ },
361
+ 'finish_reason' => 'stop' }],
362
+ 'usage' => { 'prompt_tokens' => 49, 'total_tokens' => 71, 'completion_tokens' => 22 } }
363
+ ```
364
+
365
+ ### New Functionalities and APIs
366
+
367
+ Mistral may launch a new endpoint that we haven't covered in the Gem yet. If that's the case, you may still be able to use it through the `request` method. For example, `chat_completions` is just a wrapper for `v1/chat/completions`, which you can call directly like this:
368
+
369
+ ```ruby
370
+ result = client.request(
371
+ 'v1/chat/completions',
372
+ { model: 'mistral-medium',
373
+ messages: [{ role: 'user', content: 'hi!' }] }
374
+ )
375
+ ```
376
+
377
+ ### Request Options
378
+
379
+ #### Timeout
380
+
381
+ You can set the maximum number of seconds to wait for the request to complete with the `timeout` option:
382
+
383
+ ```ruby
384
+ client = Mistral.new(
385
+ credentials: { api_key: ENV['MISTRAL_API_KEY'] },
386
+ options: { connection: { request: { timeout: 5 } } }
387
+ )
388
+ ```
389
+
390
+ You can also have more fine-grained control over [Faraday's Request Options](https://lostisland.github.io/faraday/#/customization/request-options?id=request-options) if you prefer:
391
+
392
+ ```ruby
393
+ client = Mistral.new(
394
+ credentials: { api_key: ENV['MISTRAL_API_KEY'] },
395
+ options: {
396
+ connection: {
397
+ request: {
398
+ timeout: 5,
399
+ open_timeout: 5,
400
+ read_timeout: 5,
401
+ write_timeout: 5
402
+ }
403
+ }
404
+ }
405
+ )
406
+ ```
407
+
408
+ ### Error Handling
409
+
410
+ #### Rescuing
411
+
412
+ ```ruby
413
+ require 'mistral-ai'
414
+
415
+ begin
416
+ client.chat_completions(
417
+ { model: 'mistral-medium',
418
+ messages: [{ role: 'user', content: 'hi!' }] }
419
+ )
420
+ rescue Mistral::Errors::MistralError => error
421
+ puts error.class # Mistral::Errors::RequestError
422
+ puts error.message # 'the server responded with status 500'
423
+
424
+ puts error.payload
425
+ # { model: 'mistral-medium',
426
+ # messages: [{ role: 'user', content: 'hi!' }] },
427
+ # ...
428
+ # }
429
+
430
+ puts error.request
431
+ # #<Faraday::ServerError response={:status=>500, :headers...
432
+ end
433
+ ```
434
+
435
+ #### For Short
436
+
437
+ ```ruby
438
+ require 'mistral-ai/errors'
439
+
440
+ begin
441
+ client.chat_completions(
442
+ { model: 'mistral-medium',
443
+ messages: [{ role: 'user', content: 'hi!' }] }
444
+ )
445
+ rescue MistralError => error
446
+ puts error.class # Mistral::Errors::RequestError
447
+ end
448
+ ```
449
+
450
+ #### Errors
451
+
452
+ ```ruby
453
+ MistralError
454
+
455
+ MissingAPIKeyError
456
+ BlockWithoutServerSentEventsError
457
+ UnsupportedError
458
+
459
+ RequestError
460
+ ```
461
+
462
+ ## Development
463
+
464
+ ```bash
465
+ bundle
466
+ rubocop -A
467
+ ```
468
+
469
+ ### Purpose
470
+
471
+ This Gem is designed to provide low-level access to Mistral, enabling people to build abstractions on top of it. If you are interested in more high-level abstractions or more user-friendly tools, you may want to consider [Nano Bots](https://github.com/icebaker/ruby-nano-bots) 💎 🤖.
472
+
473
+ ### Publish to RubyGems
474
+
475
+ ```bash
476
+ gem build mistral-ai.gemspec
477
+
478
+ gem signin
479
+
480
+ gem push mistral-ai-1.0.0.gem
481
+ ```
482
+
483
+ ### Updating the README
484
+
485
+ Install [Babashka](https://babashka.org):
486
+
487
+ ```sh
488
+ curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | sudo bash
489
+ ```
490
+
491
+ Update the `template.md` file and then:
492
+
493
+ ```sh
494
+ bb tasks/generate-readme.clj
495
+ ```
496
+
497
+ Trick for automatically updating the `README.md` when `template.md` changes:
498
+
499
+ ```sh
500
+ sudo pacman -S inotify-tools # Arch / Manjaro
501
+ sudo apt-get install inotify-tools # Debian / Ubuntu / Raspberry Pi OS
502
+ sudo dnf install inotify-tools # Fedora / CentOS / RHEL
503
+
504
+ while inotifywait -e modify template.md; do bb tasks/generate-readme.clj; done
505
+ ```
506
+
507
+ Trick for Markdown Live Preview:
508
+ ```sh
509
+ pip install -U markdown_live_preview
510
+
511
+ mlp README.md -p 8076
512
+ ```
513
+
514
+ ## Resources and References
515
+
516
+ These resources and references may be useful throughout your learning process.
517
+
518
+ - [Mistral AI Official Website](https://mistral.ai)
519
+ - [Mistral AI Documentation](https://docs.mistral.ai)
520
+ - [Mistral AI API Documentation](https://docs.mistral.ai/api/)
521
+
522
+ ## Disclaimer
523
+
524
+ This is not an official Mistral project, nor is it affiliated with Mistral in any way.
525
+
526
+ This software is distributed under the [MIT License](https://github.com/gbaptista/mistral-ai/blob/main/LICENSE). This license includes a disclaimer of warranty. Moreover, the authors assume no responsibility for any damage or costs that may result from using this project. Use the Mistral AI Ruby Gem at your own risk.
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mistral
4
+ module Errors
5
+ class MistralError < StandardError
6
+ def initialize(message = nil)
7
+ super(message)
8
+ end
9
+ end
10
+
11
+ class MissingAPIKeyError < MistralError; end
12
+ class BlockWithoutServerSentEventsError < MistralError; end
13
+ class UnsupportedError < MistralError; end
14
+
15
+ class RequestError < MistralError
16
+ attr_reader :request, :payload
17
+
18
+ def initialize(message = nil, request: nil, payload: nil)
19
+ @request = request
20
+ @payload = payload
21
+
22
+ super(message)
23
+ end
24
+ end
25
+ end
26
+ end