perplexity_api 0.2.1 → 0.4.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: e12f67af2fe793c9b3e55bab4bf16bb16ddc01340af2b6ed1ae89e54c0501a63
4
- data.tar.gz: adec45a5e5209bafef27fc2ce2dd8a098654b1c7ef32de6c52bd62629a40a14c
3
+ metadata.gz: 10cccc1a9dad1b047e3bd0e8f23e28fe8a9f3aa1fdc74913508425ac5f0a6a02
4
+ data.tar.gz: 1459050a00ee3ed660ffeda383e57844f070468d4493b514cace04d80e32b7c7
5
5
  SHA512:
6
- metadata.gz: 1823a33101eea983a021a20c225a379193116bc0efbaffc8aff5a49afd45d111fcb096ef6a10da433a5b136c4f8469911c3b74a46744d9873d8a0fc39aa640f3
7
- data.tar.gz: 7d73bbe2a1d1b865bc5c72f440ebf7622df70001b0ac5f453d65432fc3668eaa507b67b6fcd3883baed28a6425d3aa130d3dfcd8f41f011732af71461fc4d7a3
6
+ metadata.gz: fe6ff45b5e5790e4b0677489f9e11d50c1009386756797bd315bbfe93c097f9bc269ef203d3e2b973fc51c4fee19ecde6e99ab084b092c0b84ce58f4b3b5671e
7
+ data.tar.gz: c22d078676a41db9f88e1494910787e0420e83d679eaee7455d53351f9471cf339f90165b8b8090e13b7557a4ff6b09d6ec873c6feaab696291d7752ab81699e
@@ -7,4 +7,6 @@ PERPLEXITY_API_KEY=your_api_key_here
7
7
  # PERPLEXITY_TEMPERATURE=0.7
8
8
  # PERPLEXITY_MAX_TOKENS=1024
9
9
  # PERPLEXITY_TOP_P=0.9
10
- # PERPLEXITY_TOP_K=0
10
+ # PERPLEXITY_TOP_K=0
11
+ # PERPLEXITY_FREQUENCY_PENALTY=0.0
12
+ # PERPLEXITY_PRESENCE_PENALTY=0.0
data/.gitignore CHANGED
@@ -55,3 +55,7 @@ build-iPhoneSimulator/
55
55
 
56
56
  # Used by RuboCop. Remote config files pulled in from inherit_from directive.
57
57
  # .rubocop-https?--*
58
+ /docs/
59
+ .rspec_status
60
+
61
+ test_*
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.4.4
data/CHANGELOG.md ADDED
@@ -0,0 +1,59 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.4.1] - 2025-01-07
6
+
7
+ ### Fixed
8
+ - Corrected homepage and source code URLs in gemspec
9
+
10
+ ## [0.4.0] - 2025-01-07
11
+
12
+ ### Changed
13
+ - **BREAKING**: Minimum Ruby version requirement updated from 2.6.0 to 3.1.0
14
+ - Updated development dependencies:
15
+ - Bundler from ~> 1.17 to ~> 2.0
16
+ - Rake from ~> 10.0 to ~> 13.0
17
+
18
+ ### Tested
19
+ - Verified compatibility with Ruby 3.4.4
20
+ - All 42 tests passing on Ruby 3.1.0+
21
+
22
+ ## [0.3.0] - 2025-01-07
23
+
24
+ ### Added
25
+ - Streaming support via `StreamClient` class for real-time responses
26
+ - Web search capabilities with `search_mode` parameter (web/academic)
27
+ - Domain filtering with `search_domain_filter` (include/exclude domains)
28
+ - Date filtering with `search_after_date_filter` and `search_before_date_filter`
29
+ - Recency filtering with `search_recency_filter` (month/week/day/hour)
30
+ - Location-based search with `web_search_options`
31
+ - Support for new models: sonar-pro, sonar-deep-research
32
+ - Full conversation history support with messages array
33
+ - New parameters: `frequency_penalty` and `presence_penalty`
34
+ - Beta features: `return_images` and `return_related_questions`
35
+ - Model constants in `PerplexityApi::Models`
36
+ - Helper methods: `stream`, `stream_chat`
37
+ - Comprehensive examples directory
38
+
39
+ ### Changed
40
+ - `chat` method now accepts both string and array of messages
41
+ - `chat` method accepts options parameter for per-request configuration
42
+ - Updated default configuration to include new penalty parameters
43
+
44
+ ### Fixed
45
+ - Improved error handling for streaming responses
46
+
47
+ ## [0.2.1] - Previous version
48
+
49
+ ### Fixed
50
+ - Environment variable loading issues
51
+ - Configuration management improvements
52
+
53
+ ## [0.1.0] - Initial release
54
+
55
+ ### Added
56
+ - Basic chat functionality
57
+ - Configuration management
58
+ - Environment variable support
59
+ - Basic parameter support (temperature, max_tokens, top_p, top_k)
data/Gemfile.lock CHANGED
@@ -1,13 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- perplexity_api (0.2.0)
4
+ perplexity_api (0.4.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  diff-lcs (1.6.1)
10
- rake (10.5.0)
10
+ rake (13.3.0)
11
11
  rspec (3.13.0)
12
12
  rspec-core (~> 3.13.0)
13
13
  rspec-expectations (~> 3.13.0)
@@ -26,10 +26,10 @@ PLATFORMS
26
26
  ruby
27
27
 
28
28
  DEPENDENCIES
29
- bundler (~> 1.17)
29
+ bundler (~> 2.0)
30
30
  perplexity_api!
31
- rake (~> 10.0)
31
+ rake (~> 13.0)
32
32
  rspec (~> 3.0)
33
33
 
34
34
  BUNDLED WITH
35
- 1.17.2
35
+ 2.6.9
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # PerplexityApi
2
- [![Gem Version](https://badge.fury.io/rb/perplexity_api.svg)](https://badge.fury.io/rb/perplexity_api)
2
+ [![Gem Version](https://badge.fury.io/rb/perplexity_api.svg?v=0.4.0)](https://badge.fury.io/rb/perplexity_api)
3
3
  [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt)
4
4
 
5
5
  A Ruby wrapper gem for Perplexity AI's API. This gem allows you to easily integrate Perplexity AI's powerful language models into your Ruby applications.
@@ -7,8 +7,13 @@ A Ruby wrapper gem for Perplexity AI's API. This gem allows you to easily integr
7
7
  ## Features
8
8
 
9
9
  - API key can be configured externally
10
- - Ability to select the latest models
10
+ - Support for all latest Perplexity models including sonar-pro and sonar-deep-research
11
11
  - Simple interface to send messages and get results
12
+ - Streaming support for real-time responses
13
+ - Web search capabilities with domain filtering and date filters
14
+ - Conversation history support with full messages array
15
+ - Advanced search features including location-based search
16
+ - Beta features: image results and related questions
12
17
  - Options can be customized or use defaults
13
18
 
14
19
  ## Installation
@@ -85,6 +90,21 @@ response = PerplexityApi.chat("Hello, Perplexity AI!")
85
90
  puts response["choices"][0]["message"]["content"]
86
91
  ```
87
92
 
93
+ ### Conversation History
94
+
95
+ You can maintain conversation context by passing an array of messages:
96
+
97
+ ```ruby
98
+ messages = [
99
+ { role: "system", content: "You are a helpful assistant." },
100
+ { role: "user", content: "What is the capital of France?" },
101
+ { role: "assistant", content: "The capital of France is Paris." },
102
+ { role: "user", content: "What is its population?" }
103
+ ]
104
+
105
+ response = PerplexityApi.chat(messages)
106
+ ```
107
+
88
108
  ### Using a Client Instance
89
109
 
90
110
  For more detailed control, you can create a client instance:
@@ -97,7 +117,10 @@ client = PerplexityApi.new(
97
117
  temperature: 0.5,
98
118
  max_tokens: 2048,
99
119
  top_p: 0.9,
100
- top_k: 0
120
+ top_k: 0,
121
+ frequency_penalty: 0.1,
122
+ presence_penalty: 0.1,
123
+ search_mode: "web"
101
124
  }
102
125
  )
103
126
 
@@ -105,8 +128,106 @@ response = client.chat("Enter your complex question here...")
105
128
  puts response["choices"][0]["message"]["content"]
106
129
  ```
107
130
 
131
+ ### Streaming Responses
132
+
133
+ For real-time streaming responses:
134
+
135
+ ```ruby
136
+ PerplexityApi.stream_chat("Tell me about Ruby programming") do |chunk|
137
+ print chunk["choices"][0]["delta"]["content"] if chunk["choices"][0]["delta"]["content"]
138
+ end
139
+ ```
140
+
141
+ Or with a client instance:
142
+
143
+ ```ruby
144
+ client = PerplexityApi.stream
145
+ client.chat("Explain quantum computing") do |chunk|
146
+ # Process each chunk as it arrives
147
+ end
148
+ ```
149
+
150
+ ### Web Search Features
151
+
152
+ Enable web search with specific filters:
153
+
154
+ ```ruby
155
+ response = PerplexityApi.chat(
156
+ "What are the latest developments in AI?",
157
+ options: {
158
+ search_mode: "web",
159
+ search_domain_filter: ["arxiv.org", "nature.com", "-reddit.com"],
160
+ search_recency_filter: "week"
161
+ }
162
+ )
163
+ ```
164
+
165
+ ### Advanced Search Options
166
+
167
+ Use date filters and location-based search:
168
+
169
+ ```ruby
170
+ response = PerplexityApi.chat(
171
+ "Find research papers on climate change",
172
+ options: {
173
+ search_mode: "academic",
174
+ search_after_date_filter: "01/01/2024",
175
+ search_before_date_filter: "12/31/2024",
176
+ web_search_options: {
177
+ search_context_size: "high",
178
+ user_location: {
179
+ country: "US",
180
+ latitude: 37.7749,
181
+ longitude: -122.4194
182
+ }
183
+ }
184
+ }
185
+ )
186
+ ```
187
+
188
+ ### Beta Features
189
+
190
+ Enable image results and related questions (closed beta):
191
+
192
+ ```ruby
193
+ response = PerplexityApi.chat(
194
+ "Show me images of the Eiffel Tower",
195
+ options: {
196
+ return_images: true,
197
+ return_related_questions: true
198
+ }
199
+ )
200
+
201
+ # Access images if available
202
+ if response["images"]
203
+ response["images"].each do |image|
204
+ puts "Image URL: #{image["url"]}"
205
+ end
206
+ end
207
+
208
+ # Access related questions
209
+ if response["related_questions"]
210
+ puts "Related questions:"
211
+ response["related_questions"].each { |q| puts "- #{q}" }
212
+ end
213
+ ```
214
+
108
215
  ## Models
109
216
 
217
+ The gem includes constants for all available models:
218
+
219
+ ```ruby
220
+ # Current Sonar Models
221
+ PerplexityApi::Models::SONAR # "sonar"
222
+ PerplexityApi::Models::SONAR_PRO # "sonar-pro"
223
+ PerplexityApi::Models::SONAR_DEEP_RESEARCH # "sonar-deep-research"
224
+
225
+ # Other Models
226
+ PerplexityApi::Models::LLAMA_3_1_70B_INSTRUCT # "llama-3.1-70b-instruct"
227
+ PerplexityApi::Models::MISTRAL_7B # "mistral-7b"
228
+ PerplexityApi::Models::CODELLAMA_34B # "codellama-34b"
229
+ ```
230
+
110
231
  For the most up-to-date list of models, refer to the [Perplexity AI official documentation](https://docs.perplexity.ai/guides/model-cards).
111
232
 
112
233
  ## Development
@@ -0,0 +1,25 @@
1
+ require 'perplexity_api'
2
+
3
+ # Basic chat
4
+ puts "=== Basic Chat ==="
5
+ response = PerplexityApi.chat("What is Ruby programming language?")
6
+ puts response["choices"][0]["message"]["content"]
7
+ puts
8
+
9
+ # Chat with options
10
+ puts "=== Chat with Custom Options ==="
11
+ response = PerplexityApi.chat(
12
+ "Tell me about the benefits of Ruby",
13
+ options: {
14
+ temperature: 0.3,
15
+ max_tokens: 500
16
+ }
17
+ )
18
+ puts response["choices"][0]["message"]["content"]
19
+ puts
20
+
21
+ # Using specific model
22
+ puts "=== Using Sonar Pro Model ==="
23
+ client = PerplexityApi.new(model: PerplexityApi::Models::SONAR_PRO)
24
+ response = client.chat("What are the latest features in Ruby 3.3?")
25
+ puts response["choices"][0]["message"]["content"]
@@ -0,0 +1,34 @@
1
+ require 'perplexity_api'
2
+
3
+ # Multi-turn conversation
4
+ puts "=== Multi-turn Conversation ==="
5
+
6
+ messages = [
7
+ { role: "system", content: "You are a helpful Ruby programming expert." },
8
+ { role: "user", content: "What is a Ruby gem?" }
9
+ ]
10
+
11
+ # First response
12
+ response = PerplexityApi.chat(messages)
13
+ assistant_message = response["choices"][0]["message"]["content"]
14
+ puts "User: What is a Ruby gem?"
15
+ puts "Assistant: #{assistant_message}"
16
+ puts
17
+
18
+ # Add assistant response to conversation
19
+ messages << { role: "assistant", content: assistant_message }
20
+ messages << { role: "user", content: "How do I create my own gem?" }
21
+
22
+ # Second response
23
+ response = PerplexityApi.chat(messages)
24
+ puts "User: How do I create my own gem?"
25
+ puts "Assistant: #{response["choices"][0]["message"]["content"]}"
26
+ puts
27
+
28
+ # Continue the conversation
29
+ messages << { role: "assistant", content: response["choices"][0]["message"]["content"] }
30
+ messages << { role: "user", content: "What about publishing it to RubyGems?" }
31
+
32
+ response = PerplexityApi.chat(messages)
33
+ puts "User: What about publishing it to RubyGems?"
34
+ puts "Assistant: #{response["choices"][0]["message"]["content"]}"
@@ -0,0 +1,26 @@
1
+ require 'perplexity_api'
2
+
3
+ # Basic streaming
4
+ puts "=== Basic Streaming ==="
5
+ PerplexityApi.stream_chat("Write a haiku about programming") do |chunk|
6
+ if chunk["choices"] && chunk["choices"][0]["delta"]["content"]
7
+ print chunk["choices"][0]["delta"]["content"]
8
+ end
9
+ end
10
+ puts "\n"
11
+
12
+ # Streaming with web search
13
+ puts "\n=== Streaming with Web Search ==="
14
+ client = PerplexityApi.stream(
15
+ options: {
16
+ search_mode: "web",
17
+ search_recency_filter: "day"
18
+ }
19
+ )
20
+
21
+ client.chat("What happened in tech news today?") do |chunk|
22
+ if chunk["choices"] && chunk["choices"][0]["delta"]["content"]
23
+ print chunk["choices"][0]["delta"]["content"]
24
+ end
25
+ end
26
+ puts "\n"
@@ -0,0 +1,45 @@
1
+ require 'perplexity_api'
2
+
3
+ # Web search with domain filtering
4
+ puts "=== Web Search with Domain Filtering ==="
5
+ response = PerplexityApi.chat(
6
+ "What are the latest AI research papers?",
7
+ options: {
8
+ search_mode: "web",
9
+ search_domain_filter: ["arxiv.org", "openai.com", "-reddit.com"],
10
+ search_recency_filter: "week"
11
+ }
12
+ )
13
+ puts response["choices"][0]["message"]["content"]
14
+ puts
15
+
16
+ # Academic search
17
+ puts "=== Academic Search ==="
18
+ response = PerplexityApi.chat(
19
+ "Find recent studies on climate change mitigation",
20
+ options: {
21
+ search_mode: "academic",
22
+ search_after_date_filter: "01/01/2024",
23
+ search_before_date_filter: "12/31/2024"
24
+ }
25
+ )
26
+ puts response["choices"][0]["message"]["content"]
27
+ puts
28
+
29
+ # Location-based search
30
+ puts "=== Location-based Search ==="
31
+ response = PerplexityApi.chat(
32
+ "What are the best restaurants near me?",
33
+ options: {
34
+ search_mode: "web",
35
+ web_search_options: {
36
+ search_context_size: "high",
37
+ user_location: {
38
+ country: "US",
39
+ latitude: 37.7749,
40
+ longitude: -122.4194
41
+ }
42
+ }
43
+ }
44
+ )
45
+ puts response["choices"][0]["message"]["content"]
@@ -14,9 +14,12 @@ module PerplexityApi
14
14
  end
15
15
 
16
16
  # Method to send a message and get a response
17
- def chat(message)
17
+ def chat(messages, options = {})
18
18
  @config.validate!
19
19
 
20
+ messages = prepare_messages(messages)
21
+ merged_options = @options.merge(options)
22
+
20
23
  uri = URI.parse("#{@config.api_base}/chat/completions")
21
24
  http = Net::HTTP.new(uri.host, uri.port)
22
25
  http.use_ssl = true
@@ -25,14 +28,8 @@ module PerplexityApi
25
28
  request["Content-Type"] = "application/json"
26
29
  request["Authorization"] = "Bearer #{@config.api_key}"
27
30
 
28
- request.body = {
29
- model: @model,
30
- messages: [{ role: "user", content: message }],
31
- temperature: @options[:temperature],
32
- max_tokens: @options[:max_tokens],
33
- top_p: @options[:top_p],
34
- top_k: @options[:top_k]
35
- }.to_json
31
+ request_body = build_request_body(messages, merged_options)
32
+ request.body = request_body.to_json
36
33
 
37
34
  response = http.request(request)
38
35
 
@@ -42,5 +39,56 @@ module PerplexityApi
42
39
  raise Error, "API call failed: #{response.code} #{response.body}"
43
40
  end
44
41
  end
42
+
43
+ private
44
+
45
+ def prepare_messages(messages)
46
+ case messages
47
+ when String
48
+ [{ role: "user", content: messages }]
49
+ when Array
50
+ messages
51
+ else
52
+ raise ArgumentError, "Messages must be a string or array"
53
+ end
54
+ end
55
+
56
+ def build_request_body(messages, options)
57
+ body = {
58
+ model: @model,
59
+ messages: messages
60
+ }
61
+
62
+ # Basic parameters
63
+ body[:temperature] = options[:temperature] if options[:temperature]
64
+ body[:max_tokens] = options[:max_tokens] if options[:max_tokens]
65
+ body[:top_p] = options[:top_p] if options[:top_p]
66
+ body[:top_k] = options[:top_k] if options[:top_k]
67
+ body[:frequency_penalty] = options[:frequency_penalty] if options[:frequency_penalty]
68
+ body[:presence_penalty] = options[:presence_penalty] if options[:presence_penalty]
69
+ body[:stream] = options[:stream] if options.key?(:stream)
70
+
71
+ # Search parameters
72
+ body[:search_mode] = options[:search_mode] if options[:search_mode]
73
+ body[:search_domain_filter] = options[:search_domain_filter] if options[:search_domain_filter]
74
+ body[:search_recency_filter] = options[:search_recency_filter] if options[:search_recency_filter]
75
+ body[:search_after_date_filter] = options[:search_after_date_filter] if options[:search_after_date_filter]
76
+ body[:search_before_date_filter] = options[:search_before_date_filter] if options[:search_before_date_filter]
77
+ body[:last_updated_after_filter] = options[:last_updated_after_filter] if options[:last_updated_after_filter]
78
+ body[:last_updated_before_filter] = options[:last_updated_before_filter] if options[:last_updated_before_filter]
79
+
80
+ # Beta features
81
+ body[:return_images] = options[:return_images] if options[:return_images]
82
+ body[:return_related_questions] = options[:return_related_questions] if options[:return_related_questions]
83
+
84
+ # Advanced features
85
+ body[:reasoning_effort] = options[:reasoning_effort] if options[:reasoning_effort]
86
+
87
+ if options[:web_search_options]
88
+ body[:web_search_options] = options[:web_search_options]
89
+ end
90
+
91
+ body
92
+ end
45
93
  end
46
94
  end
@@ -17,7 +17,9 @@ module PerplexityApi
17
17
  temperature: ENV["PERPLEXITY_TEMPERATURE"] ? ENV["PERPLEXITY_TEMPERATURE"].to_f : 0.7,
18
18
  max_tokens: ENV["PERPLEXITY_MAX_TOKENS"] ? ENV["PERPLEXITY_MAX_TOKENS"].to_i : 1024,
19
19
  top_p: ENV["PERPLEXITY_TOP_P"] ? ENV["PERPLEXITY_TOP_P"].to_f : 0.9,
20
- top_k: ENV["PERPLEXITY_TOP_K"] ? ENV["PERPLEXITY_TOP_K"].to_i : 0
20
+ top_k: ENV["PERPLEXITY_TOP_K"] ? ENV["PERPLEXITY_TOP_K"].to_i : 0,
21
+ frequency_penalty: ENV["PERPLEXITY_FREQUENCY_PENALTY"] ? ENV["PERPLEXITY_FREQUENCY_PENALTY"].to_f : 0.0,
22
+ presence_penalty: ENV["PERPLEXITY_PRESENCE_PENALTY"] ? ENV["PERPLEXITY_PRESENCE_PENALTY"].to_f : 0.0
21
23
  }
22
24
 
23
25
  debug_log "Configuration loaded from environment variables"
@@ -0,0 +1,44 @@
1
+ module PerplexityApi
2
+ module Models
3
+ # Current Sonar Models
4
+ SONAR = "sonar"
5
+ SONAR_PRO = "sonar-pro"
6
+ SONAR_DEEP_RESEARCH = "sonar-deep-research"
7
+
8
+ # Legacy Models
9
+ LLAMA_3_1_SONAR_SMALL_128K_CHAT = "llama-3.1-sonar-small-128k-chat"
10
+ LLAMA_3_1_SONAR_LARGE_128K_CHAT = "llama-3.1-sonar-large-128k-chat"
11
+ LLAMA_3_1_70B_INSTRUCT = "llama-3.1-70b-instruct"
12
+ LLAMA_3_1_8B_INSTRUCT = "llama-3.1-8b-instruct"
13
+ MISTRAL_7B = "mistral-7b"
14
+ CODELLAMA_34B = "codellama-34b"
15
+ LLAMA_2_70B = "llama-2-70b"
16
+
17
+ # Model Groups
18
+ SONAR_MODELS = [SONAR, SONAR_PRO, SONAR_DEEP_RESEARCH].freeze
19
+ LLAMA_MODELS = [
20
+ LLAMA_3_1_SONAR_SMALL_128K_CHAT,
21
+ LLAMA_3_1_SONAR_LARGE_128K_CHAT,
22
+ LLAMA_3_1_70B_INSTRUCT,
23
+ LLAMA_3_1_8B_INSTRUCT,
24
+ LLAMA_2_70B
25
+ ].freeze
26
+
27
+ ALL_MODELS = (SONAR_MODELS + LLAMA_MODELS + [MISTRAL_7B, CODELLAMA_34B]).freeze
28
+
29
+ # Search modes
30
+ SEARCH_MODE_WEB = "web"
31
+ SEARCH_MODE_ACADEMIC = "academic"
32
+
33
+ # Search recency filters
34
+ RECENCY_MONTH = "month"
35
+ RECENCY_WEEK = "week"
36
+ RECENCY_DAY = "day"
37
+ RECENCY_HOUR = "hour"
38
+
39
+ # Search context sizes
40
+ CONTEXT_SIZE_LOW = "low"
41
+ CONTEXT_SIZE_MEDIUM = "medium"
42
+ CONTEXT_SIZE_HIGH = "high"
43
+ end
44
+ end
@@ -0,0 +1,115 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'json'
4
+
5
+ module PerplexityApi
6
+ class StreamClient
7
+ attr_reader :config
8
+
9
+ def initialize(api_key: nil, model: nil, options: {})
10
+ @config = PerplexityApi.configuration.dup
11
+ @config.api_key = api_key if api_key != nil
12
+ @model = model || @config.default_model
13
+ @options = @config.default_options.merge(options)
14
+ end
15
+
16
+ def chat(messages, &block)
17
+ @config.validate!
18
+
19
+ messages = prepare_messages(messages)
20
+
21
+ uri = URI.parse("#{@config.api_base}/chat/completions")
22
+
23
+ Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
24
+ request = Net::HTTP::Post.new(uri.path)
25
+ request["Content-Type"] = "application/json"
26
+ request["Authorization"] = "Bearer #{@config.api_key}"
27
+ request["Accept"] = "text/event-stream"
28
+ request["Cache-Control"] = "no-cache"
29
+
30
+ request_body = build_request_body(messages)
31
+ request_body[:stream] = true
32
+ request.body = request_body.to_json
33
+
34
+ http.request(request) do |response|
35
+ if response.code.to_i != 200
36
+ raise Error, "API call failed: #{response.code} #{response.read_body}"
37
+ end
38
+
39
+ buffer = ""
40
+ response.read_body do |chunk|
41
+ buffer += chunk
42
+
43
+ while (line_end = buffer.index("\n"))
44
+ line = buffer[0...line_end]
45
+ buffer = buffer[(line_end + 1)..-1]
46
+
47
+ next if line.strip.empty?
48
+ next unless line.start_with?("data: ")
49
+
50
+ data = line[6..-1].strip
51
+ next if data == "[DONE]"
52
+
53
+ begin
54
+ parsed = JSON.parse(data)
55
+ block.call(parsed) if block_given?
56
+ rescue JSON::ParserError => e
57
+ # Skip invalid JSON
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def prepare_messages(messages)
68
+ case messages
69
+ when String
70
+ [{ role: "user", content: messages }]
71
+ when Array
72
+ messages
73
+ else
74
+ raise ArgumentError, "Messages must be a string or array"
75
+ end
76
+ end
77
+
78
+ def build_request_body(messages)
79
+ body = {
80
+ model: @model,
81
+ messages: messages
82
+ }
83
+
84
+ # Basic parameters
85
+ body[:temperature] = @options[:temperature] if @options[:temperature]
86
+ body[:max_tokens] = @options[:max_tokens] if @options[:max_tokens]
87
+ body[:top_p] = @options[:top_p] if @options[:top_p]
88
+ body[:top_k] = @options[:top_k] if @options[:top_k]
89
+ body[:frequency_penalty] = @options[:frequency_penalty] if @options[:frequency_penalty]
90
+ body[:presence_penalty] = @options[:presence_penalty] if @options[:presence_penalty]
91
+
92
+ # Search parameters
93
+ body[:search_mode] = @options[:search_mode] if @options[:search_mode]
94
+ body[:search_domain_filter] = @options[:search_domain_filter] if @options[:search_domain_filter]
95
+ body[:search_recency_filter] = @options[:search_recency_filter] if @options[:search_recency_filter]
96
+ body[:search_after_date_filter] = @options[:search_after_date_filter] if @options[:search_after_date_filter]
97
+ body[:search_before_date_filter] = @options[:search_before_date_filter] if @options[:search_before_date_filter]
98
+ body[:last_updated_after_filter] = @options[:last_updated_after_filter] if @options[:last_updated_after_filter]
99
+ body[:last_updated_before_filter] = @options[:last_updated_before_filter] if @options[:last_updated_before_filter]
100
+
101
+ # Beta features
102
+ body[:return_images] = @options[:return_images] if @options[:return_images]
103
+ body[:return_related_questions] = @options[:return_related_questions] if @options[:return_related_questions]
104
+
105
+ # Advanced features
106
+ body[:reasoning_effort] = @options[:reasoning_effort] if @options[:reasoning_effort]
107
+
108
+ if @options[:web_search_options]
109
+ body[:web_search_options] = @options[:web_search_options]
110
+ end
111
+
112
+ body
113
+ end
114
+ end
115
+ end
@@ -1,3 +1,3 @@
1
1
  module PerplexityApi
2
- VERSION = "0.2.1"
2
+ VERSION = "0.4.1"
3
3
  end
@@ -1,6 +1,8 @@
1
1
  require "perplexity_api/version"
2
2
  require "perplexity_api/configuration"
3
+ require "perplexity_api/models"
3
4
  require "perplexity_api/client"
5
+ require "perplexity_api/stream_client"
4
6
 
5
7
  module PerplexityApi
6
8
  class Error < StandardError; end
@@ -11,9 +13,20 @@ module PerplexityApi
11
13
  end
12
14
 
13
15
  # Helper method to directly send a message
14
- def self.chat(message, api_key: nil, model: nil, options: {})
16
+ def self.chat(messages, api_key: nil, model: nil, options: {})
15
17
  client = Client.new(api_key: api_key, model: model, options: options)
16
- client.chat(message)
18
+ client.chat(messages, options)
19
+ end
20
+
21
+ # Helper method to create a stream client instance
22
+ def self.stream(api_key: nil, model: nil, options: {})
23
+ StreamClient.new(api_key: api_key, model: model, options: options)
24
+ end
25
+
26
+ # Helper method to directly stream a message
27
+ def self.stream_chat(messages, api_key: nil, model: nil, options: {}, &block)
28
+ client = StreamClient.new(api_key: api_key, model: model, options: options)
29
+ client.chat(messages, &block)
17
30
  end
18
31
 
19
32
  # Helper method to get available models
@@ -5,12 +5,12 @@ require "perplexity_api/version"
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "perplexity_api"
7
7
  spec.version = PerplexityApi::VERSION
8
- spec.authors = ["Hisafumi Kikkawa"]
8
+ spec.authors = ["Delightech"]
9
9
  spec.email = ["hisafumi.kikkawa@gmail.com"]
10
10
 
11
11
  spec.summary = %q{Ruby wrapper for Perplexity API}
12
12
  spec.description = %q{A Ruby library for easily using Perplexity AI's API. Allows setting API keys, selecting models, and customizing options.}
13
- spec.homepage = "https://github.com/hisafumi-kikkawa/perplexity_api"
13
+ spec.homepage = "https://github.com/delightech/perplexity_api"
14
14
  spec.license = "MIT"
15
15
 
16
16
  # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
20
20
 
21
21
  spec.metadata["homepage_uri"] = spec.homepage
22
- spec.metadata["source_code_uri"] = "https://github.com/hisafumi-kikkawa/perplexity_api"
23
- spec.metadata["changelog_uri"] = "https://github.com/hisafumi-kikkawa/perplexity_api/blob/master/CHANGELOG.md"
22
+ spec.metadata["source_code_uri"] = "https://github.com/delightech/perplexity_api"
23
+ spec.metadata["changelog_uri"] = "https://github.com/delightech/perplexity_api/blob/main/CHANGELOG.md"
24
24
  else
25
25
  raise "RubyGems 2.0 or newer is required to protect against " \
26
26
  "public gem pushes."
@@ -35,9 +35,9 @@ Gem::Specification.new do |spec|
35
35
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
36
36
  spec.require_paths = ["lib"]
37
37
 
38
- spec.add_development_dependency "bundler", "~> 1.17"
39
- spec.add_development_dependency "rake", "~> 10.0"
38
+ spec.add_development_dependency "bundler", "~> 2.0"
39
+ spec.add_development_dependency "rake", "~> 13.0"
40
40
  spec.add_development_dependency "rspec", "~> 3.0"
41
41
 
42
- spec.required_ruby_version = ">= 2.6.0"
42
+ spec.required_ruby_version = ">= 3.1.0"
43
43
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perplexity_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
- - Hisafumi Kikkawa
7
+ - Delightech
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-03-27 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bundler
@@ -15,28 +15,28 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '1.17'
18
+ version: '2.0'
19
19
  type: :development
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: '1.17'
25
+ version: '2.0'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: rake
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '10.0'
32
+ version: '13.0'
33
33
  type: :development
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '10.0'
39
+ version: '13.0'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: rspec
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -59,33 +59,39 @@ executables: []
59
59
  extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
- - ".env.sample"
62
+ - ".env.example"
63
63
  - ".gitignore"
64
64
  - ".rspec"
65
- - ".rspec_status"
65
+ - ".ruby-version"
66
66
  - ".travis.yml"
67
+ - CHANGELOG.md
67
68
  - CODE_OF_CONDUCT.md
68
69
  - Gemfile
69
70
  - Gemfile.lock
70
71
  - LICENSE.txt
71
- - PUBLISHING.md
72
72
  - README.md
73
73
  - Rakefile
74
74
  - bin/console
75
75
  - bin/setup
76
+ - examples/basic_usage.rb
77
+ - examples/conversation.rb
78
+ - examples/streaming.rb
79
+ - examples/web_search.rb
76
80
  - lib/perplexity_api.rb
77
81
  - lib/perplexity_api/client.rb
78
82
  - lib/perplexity_api/configuration.rb
83
+ - lib/perplexity_api/models.rb
84
+ - lib/perplexity_api/stream_client.rb
79
85
  - lib/perplexity_api/version.rb
80
86
  - perplexity_api.gemspec
81
- homepage: https://github.com/hisafumi-kikkawa/perplexity_api
87
+ homepage: https://github.com/delightech/perplexity_api
82
88
  licenses:
83
89
  - MIT
84
90
  metadata:
85
91
  allowed_push_host: https://rubygems.org
86
- homepage_uri: https://github.com/hisafumi-kikkawa/perplexity_api
87
- source_code_uri: https://github.com/hisafumi-kikkawa/perplexity_api
88
- changelog_uri: https://github.com/hisafumi-kikkawa/perplexity_api/blob/master/CHANGELOG.md
92
+ homepage_uri: https://github.com/delightech/perplexity_api
93
+ source_code_uri: https://github.com/delightech/perplexity_api
94
+ changelog_uri: https://github.com/delightech/perplexity_api/blob/main/CHANGELOG.md
89
95
  rdoc_options: []
90
96
  require_paths:
91
97
  - lib
@@ -93,14 +99,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
99
  requirements:
94
100
  - - ">="
95
101
  - !ruby/object:Gem::Version
96
- version: 2.6.0
102
+ version: 3.1.0
97
103
  required_rubygems_version: !ruby/object:Gem::Requirement
98
104
  requirements:
99
105
  - - ">="
100
106
  - !ruby/object:Gem::Version
101
107
  version: '0'
102
108
  requirements: []
103
- rubygems_version: 3.6.2
109
+ rubygems_version: 3.6.7
104
110
  specification_version: 4
105
111
  summary: Ruby wrapper for Perplexity API
106
112
  test_files: []
data/.rspec_status DELETED
@@ -1,24 +0,0 @@
1
- example_id | status | run_time |
2
- ---------------------------------------------------- | ------ | --------------- |
3
- ./spec/perplexity_api/client_spec.rb[1:1:1:1] | passed | 0.0228 seconds |
4
- ./spec/perplexity_api/client_spec.rb[1:1:2:1] | passed | 0.0001 seconds |
5
- ./spec/perplexity_api/client_spec.rb[1:2:1] | passed | 0.00063 seconds |
6
- ./spec/perplexity_api/client_spec.rb[1:2:2] | passed | 0.00161 seconds |
7
- ./spec/perplexity_api/client_spec.rb[1:2:3:1] | passed | 0.0053 seconds |
8
- ./spec/perplexity_api/client_spec.rb[1:2:4:1] | passed | 0.00045 seconds |
9
- ./spec/perplexity_api/configuration_spec.rb[1:1:1:1] | passed | 0.0081 seconds |
10
- ./spec/perplexity_api/configuration_spec.rb[1:1:2:1] | passed | 0.00034 seconds |
11
- ./spec/perplexity_api/configuration_spec.rb[1:1:3:1] | passed | 0.00192 seconds |
12
- ./spec/perplexity_api/configuration_spec.rb[1:2:1] | passed | 0.00362 seconds |
13
- ./spec/perplexity_api/configuration_spec.rb[1:3:1:1] | passed | 0.00084 seconds |
14
- ./spec/perplexity_api/configuration_spec.rb[1:3:2:1] | passed | 0.00007 seconds |
15
- ./spec/perplexity_api/configuration_spec.rb[2:1:1] | passed | 0.00073 seconds |
16
- ./spec/perplexity_api/configuration_spec.rb[2:1:2] | passed | 0.00006 seconds |
17
- ./spec/perplexity_api/configuration_spec.rb[2:2:1] | passed | 0.00739 seconds |
18
- ./spec/perplexity_api/configuration_spec.rb[2:2:2] | passed | 0.0001 seconds |
19
- ./spec/perplexity_api/configuration_spec.rb[2:3:1] | passed | 0.00102 seconds |
20
- ./spec/perplexity_api_spec.rb[1:1] | passed | 0.00011 seconds |
21
- ./spec/perplexity_api_spec.rb[1:2:1] | passed | 0.00011 seconds |
22
- ./spec/perplexity_api_spec.rb[1:3:1] | passed | 0.00017 seconds |
23
- ./spec/perplexity_api_spec.rb[1:3:2] | passed | 0.00013 seconds |
24
- ./spec/perplexity_api_spec.rb[1:4:1:1] | passed | 0.00151 seconds |
data/PUBLISHING.md DELETED
@@ -1,101 +0,0 @@
1
- # Publishing Guide for Perplexity API Gem
2
-
3
- This document explains the steps to publish the Perplexity API Gem to [RubyGems.org](https://rubygems.org).
4
-
5
- ## Prerequisites
6
-
7
- 1. Have a RubyGems account
8
- 2. Have the `gem` command installed
9
- 3. Have git installed
10
-
11
- ## Publishing Steps
12
-
13
- ### 1. Check the gemspec file
14
-
15
- Verify that the `perplexity_api.gemspec` file has the following items correctly set:
16
-
17
- - `spec.authors` - Your name
18
- - `spec.email` - Your email address
19
- - `spec.summary` - A brief description of the gem
20
- - `spec.description` - A detailed description of the gem
21
- - `spec.homepage` - The URL of the gem's homepage (usually a GitHub repository URL)
22
- - `spec.metadata["source_code_uri"]` - The URI of the source code
23
- - `spec.metadata["changelog_uri"]` - The URI of the changelog
24
-
25
- ### 2. Check the version number
26
-
27
- Verify that the version number in `lib/perplexity_api/version.rb` is appropriate.
28
-
29
- ### 3. Run the tests
30
-
31
- Make sure all tests pass:
32
-
33
- ```
34
- $ bundle exec rake spec
35
- ```
36
-
37
- ### 4. Build the gem
38
-
39
- Build the gem:
40
-
41
- ```
42
- $ gem build perplexity_api.gemspec
43
- ```
44
-
45
- This will create a `perplexity_api-x.y.z.gem` file (where x.y.z is the version number).
46
-
47
- ### 5. Test the gem installation (optional)
48
-
49
- Install the built gem locally to verify it works correctly:
50
-
51
- ```
52
- $ gem install ./perplexity_api-x.y.z.gem
53
- ```
54
-
55
- ### 6. Publish to RubyGems
56
-
57
- Publish the gem to RubyGems:
58
-
59
- ```
60
- $ gem push perplexity_api-x.y.z.gem
61
- ```
62
-
63
- If this is your first time, you'll be prompted for your RubyGems username and password.
64
-
65
- ### 7. Verify the publication
66
-
67
- Visit [RubyGems.org](https://rubygems.org) to verify that the gem was published successfully:
68
-
69
- ```
70
- https://rubygems.org/gems/perplexity_api
71
- ```
72
-
73
- ## Version Update Steps
74
-
75
- 1. Make code changes
76
- 2. Add/update tests
77
- 3. Update the version number in `lib/perplexity_api/version.rb`
78
- 4. Update the changelog (if you have a CHANGELOG.md)
79
- 5. Follow steps 3-7 from the "Publishing Steps" section above
80
-
81
- ## Creating Git Tags (Recommended)
82
-
83
- It's recommended to create git tags for each version:
84
-
85
- ```
86
- $ git tag -a v0.1.0 -m "Version 0.1.0"
87
- $ git push origin v0.1.0
88
- ```
89
-
90
- ## Troubleshooting
91
-
92
- ### If publication fails
93
-
94
- - Check that there are no `TODO` items left in the gemspec file
95
- - Verify your RubyGems account information
96
- - Check your network connection
97
-
98
- ### If installation fails
99
-
100
- - Verify that dependencies are correctly set
101
- - Check that the Ruby version requirement is appropriate