cohere-ai 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,765 @@
1
+ # Cohere AI
2
+
3
+ A Ruby gem for interacting with [Cohere AI](https://cohere.com).
4
+
5
+ ![The logo depicts a ruby with a liquid-like interior on a peach background. The gem has a flowing lava appearance, with swirls of red and pink suggesting movement, resembling molten rock. Darker red edges and a circular dark border frame this vibrant, fluid core.](https://raw.githubusercontent.com/gbaptista/assets/main/cohere-ai/cohere-ai-canvas.png)
6
+
7
+ > _This Gem is designed to provide low-level access to Cohere AI, 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 'cohere-ai', '~> 1.0.0'
13
+ ```
14
+
15
+ ```ruby
16
+ require 'cohere-ai'
17
+
18
+ client = Cohere.new(
19
+ credentials: { api_key: ENV['COHERE_API_KEY'] },
20
+ options: { server_sent_events: true }
21
+ )
22
+
23
+ result = client.chat(
24
+ { model: 'command', message: 'Hi!' }
25
+ )
26
+ ```
27
+
28
+ Result:
29
+ ```ruby
30
+ { 'response_id' => '59aac3ec-74c8-4b65-a80c-d4c1916d2511',
31
+ 'text' =>
32
+ "Hi there! I'm Coral, an AI-assistant chatbot ready to help you with whatever you need. Is there anything I can assist you with today? \n" \
33
+ "\n" \
34
+ "If you'd like, I can also provide you with a list of some common topics that I can help with if you're looking for ideas. \n" \
35
+ "\n" \
36
+ "Just let me know if there's anything I can do to help make your day easier!",
37
+ 'generation_id' => '8a72b85c-ed29-4258-bd52-82b81be2353b',
38
+ 'token_count' => { 'prompt_tokens' => 64, 'response_tokens' => 82, 'total_tokens' => 146, 'billed_tokens' => 135 },
39
+ 'meta' => { 'api_version' => { 'version' => '1' },
40
+ 'billed_units' => { 'input_tokens' => 53, 'output_tokens' => 82 } },
41
+ 'tool_inputs' => nil }
42
+ ```
43
+
44
+ ## Index
45
+
46
+ - [TL;DR and Quick Start](#tldr-and-quick-start)
47
+ - [Index](#index)
48
+ - [Setup](#setup)
49
+ - [Installing](#installing)
50
+ - [Credentials](#credentials)
51
+ - [Usage](#usage)
52
+ - [Client](#client)
53
+ - [Custom Address](#custom-address)
54
+ - [Methods](#methods)
55
+ - [chat](#chat)
56
+ - [Without Streaming Events](#without-streaming-events)
57
+ - [Receiving Stream Events](#receiving-stream-events)
58
+ - [generate](#generate)
59
+ - [embed](#embed)
60
+ - [rerank](#rerank)
61
+ - [classify](#classify)
62
+ - [detect_language](#detect_language)
63
+ - [summarize](#summarize)
64
+ - [tokenize](#tokenize)
65
+ - [detokenize](#detokenize)
66
+ - [Datasets](#datasets)
67
+ - [Connectors](#connectors)
68
+ - [Streaming and Server-Sent Events (SSE)](#streaming-and-server-sent-events-sse)
69
+ - [Server-Sent Events (SSE) Hang](#server-sent-events-sse-hang)
70
+ - [Back-and-Forth Conversations](#back-and-forth-conversations)
71
+ - [New Functionalities and APIs](#new-functionalities-and-apis)
72
+ - [Request Options](#request-options)
73
+ - [Timeout](#timeout)
74
+ - [Error Handling](#error-handling)
75
+ - [Rescuing](#rescuing)
76
+ - [For Short](#for-short)
77
+ - [Errors](#errors)
78
+ - [Development](#development)
79
+ - [Purpose](#purpose)
80
+ - [Publish to RubyGems](#publish-to-rubygems)
81
+ - [Updating the README](#updating-the-readme)
82
+ - [Resources and References](#resources-and-references)
83
+ - [Disclaimer](#disclaimer)
84
+
85
+ ## Setup
86
+
87
+ ### Installing
88
+
89
+ ```sh
90
+ gem install cohere-ai -v 1.0.0
91
+ ```
92
+
93
+ ```sh
94
+ gem 'cohere-ai', '~> 1.0.0'
95
+ ```
96
+
97
+ ### Credentials
98
+
99
+ You can obtain your API key from the [Cohere AI Platform](https://dashboard.cohere.com).
100
+
101
+ ## Usage
102
+
103
+ ### Client
104
+
105
+ Ensure that you have an [API Key](#credentials) for authentication.
106
+
107
+ Create a new client:
108
+ ```ruby
109
+ require 'cohere-ai'
110
+
111
+ client = Cohere.new(
112
+ credentials: { api_key: ENV['COHERE_API_KEY'] },
113
+ options: { server_sent_events: true }
114
+ )
115
+ ```
116
+
117
+ #### Custom Address
118
+
119
+ You can use a custom address:
120
+
121
+ ```ruby
122
+ require 'cohere-ai'
123
+
124
+ client = Cohere.new(
125
+ credentials: {
126
+ address: 'https://api.cohere.ai',
127
+ api_key: ENV['COHERE_API_KEY']
128
+ },
129
+ options: { server_sent_events: true }
130
+ )
131
+ ```
132
+
133
+ ### Methods
134
+
135
+ #### chat
136
+
137
+ Documentation: https://docs.cohere.com/reference/chat
138
+
139
+ ##### Without Streaming Events
140
+
141
+ ```ruby
142
+ result = client.chat(
143
+ { model: 'command', message: 'Hi!' }
144
+ )
145
+ ```
146
+
147
+ Result:
148
+ ```ruby
149
+ { 'response_id' => '59aac3ec-74c8-4b65-a80c-d4c1916d2511',
150
+ 'text' =>
151
+ "Hi there! I'm Coral, an AI-assistant chatbot ready to help you with whatever you need. Is there anything I can assist you with today? \n" \
152
+ "\n" \
153
+ "If you'd like, I can also provide you with a list of some common topics that I can help with if you're looking for ideas. \n" \
154
+ "\n" \
155
+ "Just let me know if there's anything I can do to help make your day easier!",
156
+ 'generation_id' => '8a72b85c-ed29-4258-bd52-82b81be2353b',
157
+ 'token_count' => { 'prompt_tokens' => 64, 'response_tokens' => 82, 'total_tokens' => 146, 'billed_tokens' => 135 },
158
+ 'meta' => { 'api_version' => { 'version' => '1' },
159
+ 'billed_units' => { 'input_tokens' => 53, 'output_tokens' => 82 } },
160
+ 'tool_inputs' => nil }
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(
169
+ { model: 'command', stream: true, message: 'Hi!' }
170
+ ) do |event, raw|
171
+ puts event
172
+ end
173
+ ```
174
+
175
+ Event:
176
+ ```ruby
177
+ { 'is_finished' => false,
178
+ 'event_type' => 'stream-start',
179
+ 'generation_id' => '0672df6f-736e-4536-8ad1-36bc808a114d' }
180
+ ```
181
+
182
+ ```ruby
183
+ { 'is_finished' => false,
184
+ 'event_type' => 'text-generation',
185
+ 'text' => 'Hi' }
186
+ ```
187
+
188
+ ```ruby
189
+ { 'is_finished' => true,
190
+ 'event_type' => 'stream-end',
191
+ 'response' => {
192
+ 'response_id' => '7dca6bf9-8a21-4f81-9e4e-2c5b8eb8c767',
193
+ 'text' => "Hi there! How can I help you today? I'm glad to assist you with any questions or tasks you have in mind, and I'm always happy to have a friendly conversation too. Go ahead and let me know how I can make your day better!",
194
+ 'generation_id' => '0672df6f-736e-4536-8ad1-36bc808a114d',
195
+ 'token_count' => {
196
+ 'prompt_tokens' => 64, 'response_tokens' => 52, 'total_tokens' => 116, 'billed_tokens' => 105
197
+ },
198
+ 'tool_inputs' => nil
199
+ },
200
+ 'finish_reason' => 'COMPLETE' }
201
+ ```
202
+
203
+ You can get all the receive events at once as an array:
204
+ ```ruby
205
+ result = client.chat(
206
+ { model: 'command', stream: true, message: 'Hi!' }
207
+ )
208
+ ```
209
+
210
+ Result:
211
+ ```ruby
212
+ [{ 'is_finished' => false, 'event_type' => 'stream-start', 'generation_id' => '7f0349ef-a823-4779-801a-6e0a56c016a9' },
213
+ { 'is_finished' => false, 'event_type' => 'text-generation', 'text' => 'Hi' },
214
+ # ...
215
+ { 'is_finished' => false, 'event_type' => 'text-generation', 'text' => '?' },
216
+ { 'is_finished' => true,
217
+ 'event_type' => 'stream-end',
218
+ 'response' =>
219
+ { 'response_id' => 'f4135de4-3631-4f7c-98be-deb50b7f986b',
220
+ 'text' =>
221
+ "Hi there! How can I assist you today? I'm programmed to provide helpful, fact-based responses and engage in conversations on a wide range of topics. Feel free to ask me anything, and we'll see how I can help you out! \n" \
222
+ "\n" \
223
+ 'Do you have any requests or questions that I can help with?',
224
+ 'generation_id' => '7f0349ef-a823-4779-801a-6e0a56c016a9',
225
+ 'token_count' => { 'prompt_tokens' => 64, 'response_tokens' => 65, 'total_tokens' => 129, 'billed_tokens' => 118 },
226
+ 'tool_inputs' => nil },
227
+ 'finish_reason' => 'COMPLETE' }]
228
+ ```
229
+
230
+ You can mix both as well:
231
+ ```ruby
232
+ result = client.chat(
233
+ { model: 'command', stream: true, message: 'Hi!' }
234
+ ) do |event, raw|
235
+ puts event
236
+ end
237
+ ```
238
+
239
+ #### generate
240
+
241
+ Documentation: https://docs.cohere.com/reference/generate
242
+
243
+ ```ruby
244
+ client.generate(
245
+ { stream: true,
246
+ truncate: 'END',
247
+ return_likelihoods: 'NONE',
248
+ prompt: 'Please explain to me how LLMs work' }
249
+ ) do |event, raw|
250
+ puts event
251
+ end
252
+ ```
253
+
254
+ ```ruby
255
+ result = client.generate(
256
+ { truncate: 'END',
257
+ return_likelihoods: 'NONE',
258
+ prompt: 'Please explain to me how LLMs work' }
259
+ )
260
+ ```
261
+
262
+ Result:
263
+ ```ruby
264
+ { 'id' => '9caef8a6-07fb-465c-a003-5fd7c7bbccbd',
265
+ 'generations' =>
266
+ [{ 'id' => '11b043ab-6d9c-415f-90b0-6a802a3807f7',
267
+ 'text' =>
268
+ " LLMs, or Large Language Models, are a type of neural network architecture designed to understand and generate human-like language. They are trained by feeding them massive amounts of text data and adjusting their internal parameters to predict the next word in a sequence accurately, given the words that came before it. This process is known as language modeling.\n" \
269
+ "\n" \
270
+ "There are two main types of LLMs: autoregressive and generative models. Autoregressive models, such as the long short-term memory (LSTM) network and the gated recurrent unit (GRU), predict the next word in a sequence by relying solely on the past context. On the other hand, generative models, such as the variational autoencoder (VAE) and the generative adversarial network (GAN), can generate new data similar to the training data.\n" \
271
+ "\n" \
272
+ "One of the key features of LLMs is their ability to capture long-range dependencies in text, which means they can understand and generate sentences that rely on information from words far away in the sequence. This is particularly useful for tasks like language translation, summarization, and question-answering, where understanding the context is crucial.\n" \
273
+ "\n" \
274
+ "To improve the accuracy and performance of LLMs, researchers and engineers often use techniques like pre-training and transfer learning. During pre-training, the LLM is trained on a large and diverse dataset, such as books, articles, and websites, to learn general language patterns and relationships. Once the LLM is pre-trained, it can be fine-tuned on specific tasks with smaller datasets related to the task, such as medical texts or legal documents. This way, the LLM can leverage its knowledge of language understanding while adapting to the specific domain or task at hand.\n" \
275
+ "\n" \
276
+ "Overall, LLMs have had a significant impact on the field of natural language processing, allowing researchers to build more sophisticated models that can understand and generate language in ways that were previously impossible. However, it is important to note that LLMs are sophisticated tools that require large amounts of data, computational power, and careful tuning to achieve their full potential. Moreover, they can also inherit the biases present in the training data, highlighting the importance of data diversity and responsible LLM development and usage. \n" \
277
+ "\n" \
278
+ 'Would you like me to go into more detail about any specific aspect of LLM functionality? ',
279
+ 'finish_reason' => 'COMPLETE' }],
280
+ 'prompt' => 'Please explain to me how LLMs work',
281
+ 'meta' => { 'api_version' => { 'version' => '1' },
282
+ 'billed_units' => { 'input_tokens' => 8, 'output_tokens' => 476 } } }
283
+ ```
284
+
285
+ #### embed
286
+
287
+ Documentation: https://docs.cohere.com/reference/embed
288
+
289
+ ```ruby
290
+ result = client.embed(
291
+ { texts: ['hello', 'goodbye'],
292
+ model: 'embed-english-v3.0',
293
+ input_type: 'classification' }
294
+ )
295
+ ```
296
+
297
+ Result:
298
+ ```ruby
299
+ { 'id' => '5d77f09a-3518-44d3-bac3-f868b3e036bc',
300
+ 'texts' => ['hello', 'goodbye'],
301
+ 'embeddings' =>
302
+ [[0.016296387,
303
+ -0.008354187,
304
+ # ...
305
+ -0.01802063,
306
+ 0.009765625],
307
+ [0.04663086,
308
+ -0.023239136,
309
+ # ...
310
+ 0.0023212433,
311
+ 0.0052719116]],
312
+ 'meta' =>
313
+ { 'api_version' => { 'version' => '1' }, 'billed_units' => { 'input_tokens' => 2 } },
314
+ 'response_type' => 'embeddings_floats' }
315
+ ```
316
+
317
+ #### rerank
318
+
319
+ Documentation: https://docs.cohere.com/reference/rerank
320
+
321
+ ```ruby
322
+ result = client.rerank(
323
+ { return_documents: false,
324
+ max_chunks_per_doc: 10,
325
+ model: 'rerank-english-v2.0',
326
+ query: 'What is the capital of the United States?',
327
+ documents: [
328
+ 'Carson City is the capital city of the American state of Nevada.',
329
+ 'The Commonwealth of the Northern Mariana Islands is a group of islands in the Pacific Ocean. Its capital is Saipan.',
330
+ 'Washington, D.C. (also known as simply Washington or D.C., and officially as the District of Columbia) is the capital of the United States. It is a federal district.',
331
+ 'Capital punishment (the death penalty) has existed in the United States since beforethe United States was a country. As of 2017, capital punishment is legal in 30 of the 50 states.'
332
+ ] }
333
+ )
334
+ ```
335
+
336
+ Result:
337
+ ```ruby
338
+ { 'id' => 'ba2100fe-69d2-41d6-8680-810948af872d',
339
+ 'results' =>
340
+ [{ 'index' => 2, 'relevance_score' => 0.98005307 },
341
+ { 'index' => 3, 'relevance_score' => 0.27904198 },
342
+ { 'index' => 0, 'relevance_score' => 0.10194652 },
343
+ { 'index' => 1, 'relevance_score' => 0.0721122 }],
344
+ 'meta' =>
345
+ { 'api_version' => { 'version' => '1' }, 'billed_units' => { 'search_units' => 1 } } }
346
+ ```
347
+
348
+ #### classify
349
+
350
+ Documentation: https://docs.cohere.com/reference/classify
351
+
352
+ ```ruby
353
+ result = client.classify(
354
+ {
355
+ truncate: 'END',
356
+ inputs: [
357
+ 'Confirm your email address',
358
+ 'hey i need u to send some $'
359
+ ],
360
+ examples: [
361
+ {
362
+ text: "Dermatologists don't like her!",
363
+ label: 'Spam'
364
+ },
365
+ {
366
+ text: 'Hello, open to this?',
367
+ label: 'Spam'
368
+ },
369
+ {
370
+ text: 'I need help please wire me $1000 right now',
371
+ label: 'Spam'
372
+ },
373
+ {
374
+ text: 'Nice to know you ;)',
375
+ label: 'Spam'
376
+ },
377
+ {
378
+ text: 'Please help me?',
379
+ label: 'Spam'
380
+ },
381
+ {
382
+ text: 'Your parcel will be delivered today',
383
+ label: 'Not spam'
384
+ },
385
+ {
386
+ text: 'Review changes to our Terms and Conditions',
387
+ label: 'Not spam'
388
+ },
389
+ {
390
+ text: 'Weekly sync notes',
391
+ label: 'Not spam'
392
+ },
393
+ {
394
+ text: 'Re: Follow up from today’s meeting',
395
+ label: 'Not spam'
396
+ },
397
+ {
398
+ text: 'Pre-read for tomorrow',
399
+ label: 'Not spam'
400
+ }
401
+ ]
402
+ }
403
+ )
404
+ ```
405
+
406
+ Result:
407
+ ```ruby
408
+ { 'id' => '1d0c322e-9ab7-4a80-b601-720e7592dde5',
409
+ 'classifications' =>
410
+ [{ 'classification_type' => 'single-label',
411
+ 'confidence' => 0.8082329,
412
+ 'confidences' => [0.8082329],
413
+ 'id' => '44b2e358-83f1-4b9b-a6f1-e8d9c823f0ba',
414
+ 'input' => 'Confirm your email address',
415
+ 'labels' =>
416
+ { 'Not spam' => { 'confidence' => 0.8082329 },
417
+ 'Spam' => { 'confidence' => 0.19176713 } },
418
+ 'prediction' => 'Not spam',
419
+ 'predictions' => ['Not spam'] },
420
+ { 'classification_type' => 'single-label',
421
+ 'confidence' => 0.9893421,
422
+ 'confidences' => [0.9893421],
423
+ 'id' => '53ad6d6e-872f-4185-b3d6-6d03fe55f4c4',
424
+ 'input' => 'hey i need u to send some $',
425
+ 'labels' =>
426
+ { 'Not spam' => { 'confidence' => 0.01065793 },
427
+ 'Spam' => { 'confidence' => 0.9893421 } },
428
+ 'prediction' => 'Spam',
429
+ 'predictions' => ['Spam'] }],
430
+ 'meta' =>
431
+ { 'api_version' => { 'version' => '1' }, 'billed_units' => { 'classifications' => 2 } } }
432
+ ```
433
+
434
+ #### detect_language
435
+
436
+ Documentation: https://docs.cohere.com/reference/detect-language
437
+
438
+ ```ruby
439
+ result = client.detect_language(
440
+ { texts: ['Hello world', "'Здравствуй, Мир'"] }
441
+ )
442
+ ```
443
+
444
+ Result:
445
+ ```ruby
446
+ { 'id' => '82b111d4-ba6d-4f60-9536-883b42f3d86d',
447
+ 'results' =>
448
+ [{ 'language_code' => 'en', 'language_name' => 'English' },
449
+ { 'language_code' => 'ru', 'language_name' => 'Russian' }],
450
+ 'meta' => { 'api_version' => { 'version' => '1' } } }
451
+ ```
452
+
453
+ #### summarize
454
+
455
+ Documentation: https://docs.cohere.com/reference/summarize
456
+
457
+ ```ruby
458
+ result = client.summarize(
459
+ { text: "Ice cream is a sweetened frozen food typically eaten as a snack or dessert. It may be made from milk or cream and is flavoured with a sweetener, either sugar or an alternative, and a spice, such as cocoa or vanilla, or with fruit such as strawberries or peaches. It can also be made by whisking a flavored cream base and liquid nitrogen together. Food coloring is sometimes added, in addition to stabilizers. The mixture is cooled below the freezing point of water and stirred to incorporate air spaces and to prevent detectable ice crystals from forming. The result is a smooth, semi-solid foam that is solid at very low temperatures (below 2 °C or 35 °F). It becomes more malleable as its temperature increases.\n\nThe meaning of the name \"ice cream\" varies from one country to another. In some countries, such as the United States, \"ice cream\" applies only to a specific variety, and most governments regulate the commercial use of the various terms according to the relative quantities of the main ingredients, notably the amount of cream. Products that do not meet the criteria to be called ice cream are sometimes labelled \"frozen dairy dessert\" instead. In other countries, such as Italy and Argentina, one word is used fo\r all variants. Analogues made from dairy alternatives, such as goat's or sheep's milk, or milk substitutes (e.g., soy, cashew, coconut, almond milk or tofu), are available for those who are lactose intolerant, allergic to dairy protein or vegan." }
460
+ )
461
+ ```
462
+
463
+ Result:
464
+ ```ruby
465
+ { 'id' => '5189bed8-2d12-47d8-8ae7-cf60788cf507',
466
+ 'summary' =>
467
+ 'Ice cream is a popular frozen dessert made from milk or cream, sweeteners, and spices like vanilla or cocoa, or fruit like strawberries. It is cooled below the freezing point of water and stirred to incorporate air spaces, resulting in a smooth semi-solid foam. While the name applies to just one variety in some countries, like the US, it refers to all variants in others, like Italy. Additionally, there are dairy alternatives available for those who are lactose intolerant or vegan. Ice cream is regulated by governments based on the quantities of its main ingredients.',
468
+ 'meta' =>
469
+ { 'api_version' => { 'version' => '1' },
470
+ 'billed_units' => { 'input_tokens' => 321, 'output_tokens' => 111 } } }
471
+ ```
472
+
473
+ #### tokenize
474
+
475
+ Documentation: https://docs.cohere.com/reference/tokenize
476
+
477
+ ```ruby
478
+ result = client.tokenize(
479
+ { text: 'tokenize me! :D', model: 'command' }
480
+ )
481
+ ```
482
+
483
+ Result:
484
+ ```ruby
485
+ { 'tokens' => [10_002, 2261, 2012, 8, 2792, 43],
486
+ 'token_strings' => ['token', 'ize', ' me', '!', ' :', 'D'],
487
+ 'meta' => { 'api_version' => { 'version' => '1' } } }
488
+ ```
489
+
490
+ #### detokenize
491
+
492
+ Documentation: https://docs.cohere.com/reference/detokenize
493
+
494
+ ```ruby
495
+ result = client.detokenize(
496
+ { tokens: [10_104, 12_221, 1315, 34, 1420, 69], model: 'command' }
497
+ )
498
+ ```
499
+
500
+ Result:
501
+ ```ruby
502
+ { 'text' => ' Anton Mun🟣;🥭^', 'meta' => { 'api_version' => { 'version' => '1' } } }
503
+ ```
504
+
505
+ ### Datasets
506
+
507
+ Documentation: https://docs.cohere.com/reference/create-dataset
508
+
509
+ ```ruby
510
+ result = client.request(
511
+ 'v1/dataset',
512
+ request_method: 'GET', server_sent_events: false
513
+ )
514
+ ```
515
+
516
+ ```ruby
517
+ result = client.request(
518
+ 'v1/dataset',
519
+ { name: 'prompt-completion-dataset',
520
+ data: File.read('./prompt-completion.jsonl'),
521
+ dataset_type: 'prompt-completion-finetune-input' },
522
+ request_method: 'POST', server_sent_events: false
523
+ )
524
+ ```
525
+
526
+ ### Connectors
527
+
528
+ Documentation: https://docs.cohere.com/reference/list-connectors
529
+
530
+ ```ruby
531
+ result = client.request(
532
+ 'v1/connectors',
533
+ request_method: 'GET', server_sent_events: false
534
+ )
535
+ ```
536
+
537
+ ```ruby
538
+ result = client.request(
539
+ 'v1/connectors',
540
+ { name: 'test-connector',
541
+ url: 'https://example.com/search',
542
+ description: 'A test connector' },
543
+ request_method: 'POST', server_sent_events: false
544
+ )
545
+ ```
546
+
547
+ ### Streaming and Server-Sent Events (SSE)
548
+
549
+ [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.
550
+
551
+ You can set up the client to use Server-Sent Events (SSE) for all supported endpoints:
552
+ ```ruby
553
+ client = Cohere.new(
554
+ credentials: { api_key: ENV['COHERE_API_KEY'] },
555
+ options: { server_sent_events: true }
556
+ )
557
+ ```
558
+
559
+ Or, you can decide on a request basis:
560
+ ```ruby
561
+ client.chat(
562
+ { model: 'command', stream: true, message: 'Hi!' }
563
+ server_sent_events: true
564
+ ) do |event, raw|
565
+ puts event
566
+ end
567
+ ```
568
+
569
+ 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`: [Receiving Stream Events](#receiving-stream-events)
570
+
571
+ #### Server-Sent Events (SSE) Hang
572
+
573
+ 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)
574
+
575
+
576
+ ### Back-and-Forth Conversations
577
+
578
+ To maintain a back-and-forth conversation, you need to append the received responses and build a history for your requests:
579
+
580
+ ```rb
581
+ result = client.chat(
582
+ { model: 'command',
583
+ chat_history: [
584
+ { role: 'USER', message: 'Hi, my name is Purple.' },
585
+ { role: 'CHATBOT', message: "Hi Purple! It's nice to meet you." }
586
+ ],
587
+ message: "What's my name?" }
588
+ )
589
+ ```
590
+
591
+ Result:
592
+ ```ruby
593
+ { 'response_id' => 'a2009c24-fee3-465e-9945-a85edcdcb3cf',
594
+ 'text' =>
595
+ "Your name is Purple. Isn't it an enchanting name? \n" \
596
+ "\n" \
597
+ "Would you like me to help you with anything else? If you have any questions or need assistance with a particular task, feel free to let me know. I'm here to help!",
598
+ 'generation_id' => 'e1630c10-f773-4ced-8760-19199004653a',
599
+ 'token_count' => { 'prompt_tokens' => 91, 'response_tokens' => 51, 'total_tokens' => 142, 'billed_tokens' => 124 },
600
+ 'meta' => { 'api_version' => { 'version' => '1' },
601
+ 'billed_units' => { 'input_tokens' => 73, 'output_tokens' => 51 } },
602
+ 'tool_inputs' => nil }
603
+
604
+ ```
605
+
606
+ ### New Functionalities and APIs
607
+
608
+ Cohere 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` is just a wrapper for `v1/chat`, which you can call directly like this:
609
+
610
+ ```ruby
611
+ result = client.request(
612
+ 'v1/chat',
613
+ { model: 'command', message: 'Hi!' },
614
+ request_method: 'POST', server_sent_events: true
615
+ )
616
+ ```
617
+
618
+ ### Request Options
619
+
620
+ #### Timeout
621
+
622
+ You can set the maximum number of seconds to wait for the request to complete with the `timeout` option:
623
+
624
+ ```ruby
625
+ client = Cohere.new(
626
+ credentials: { api_key: ENV['COHERE_API_KEY'] },
627
+ options: { connection: { request: { timeout: 5 } } }
628
+ )
629
+ ```
630
+
631
+ 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:
632
+
633
+ ```ruby
634
+ client = Cohere.new(
635
+ credentials: { api_key: ENV['COHERE_API_KEY'] },
636
+ options: {
637
+ connection: {
638
+ request: {
639
+ timeout: 5,
640
+ open_timeout: 5,
641
+ read_timeout: 5,
642
+ write_timeout: 5
643
+ }
644
+ }
645
+ }
646
+ )
647
+ ```
648
+
649
+ ### Error Handling
650
+
651
+ #### Rescuing
652
+
653
+ ```ruby
654
+ require 'cohere-ai'
655
+
656
+ begin
657
+ client.chat(
658
+ { model: 'command', message: 'Hi!' }
659
+ )
660
+ rescue Cohere::Errors::CohereError => error
661
+ puts error.class # Cohere::Errors::RequestError
662
+ puts error.message # 'the server responded with status 500'
663
+
664
+ puts error.payload
665
+ # { model: 'command',
666
+ # message: 'Hi!'
667
+ # ...
668
+ # }
669
+
670
+ puts error.request
671
+ # #<Faraday::ServerError response={:status=>500, :headers...
672
+ end
673
+ ```
674
+
675
+ #### For Short
676
+
677
+ ```ruby
678
+ require 'cohere-ai/errors'
679
+
680
+ begin
681
+ client.chat(
682
+ { model: 'command',
683
+ messages: [{ role: 'user', content: 'hi!' }] }
684
+ )
685
+ rescue CohereError => error
686
+ puts error.class # Cohere::Errors::RequestError
687
+ end
688
+ ```
689
+
690
+ #### Errors
691
+
692
+ ```ruby
693
+ CohereError
694
+
695
+ MissingAPIKeyError
696
+ BlockWithoutServerSentEventsError
697
+
698
+ RequestError
699
+ ```
700
+
701
+ ## Development
702
+
703
+ ```bash
704
+ bundle
705
+ rubocop -A
706
+ ```
707
+
708
+ ### Purpose
709
+
710
+ This Gem is designed to provide low-level access to Cohere, 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) 💎 🤖.
711
+
712
+ ### Publish to RubyGems
713
+
714
+ ```bash
715
+ gem build cohere-ai.gemspec
716
+
717
+ gem signin
718
+
719
+ gem push cohere-ai-1.0.0.gem
720
+ ```
721
+
722
+ ### Updating the README
723
+
724
+ Install [Babashka](https://babashka.org):
725
+
726
+ ```sh
727
+ curl -s https://raw.githubusercontent.com/babashka/babashka/master/install | sudo bash
728
+ ```
729
+
730
+ Update the `template.md` file and then:
731
+
732
+ ```sh
733
+ bb tasks/generate-readme.clj
734
+ ```
735
+
736
+ Trick for automatically updating the `README.md` when `template.md` changes:
737
+
738
+ ```sh
739
+ sudo pacman -S inotify-tools # Arch / Manjaro
740
+ sudo apt-get install inotify-tools # Debian / Ubuntu / Raspberry Pi OS
741
+ sudo dnf install inotify-tools # Fedora / CentOS / RHEL
742
+
743
+ while inotifywait -e modify template.md; do bb tasks/generate-readme.clj; done
744
+ ```
745
+
746
+ Trick for Markdown Live Preview:
747
+ ```sh
748
+ pip install -U markdown_live_preview
749
+
750
+ mlp README.md -p 8076
751
+ ```
752
+
753
+ ## Resources and References
754
+
755
+ These resources and references may be useful throughout your learning process.
756
+
757
+ - [Cohere AI Official Website](https://cohere.com)
758
+ - [Cohere AI Documentation](https://docs.cohere.com/docs)
759
+ - [Cohere AI API Reference](https://docs.cohere.com/reference/about)
760
+
761
+ ## Disclaimer
762
+
763
+ This is not an official Cohere project, nor is it affiliated with Cohere in any way.
764
+
765
+ This software is distributed under the [MIT License](https://github.com/gbaptista/cohere-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 Cohere AI Ruby Gem at your own risk.