perplexity_api 0.2.0 → 0.4.0

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: a1fb38e349b1dec664c558b497eb1cfebb13db32a2dfe8b73235c67d1d60a8da
4
- data.tar.gz: 65c6e01e0fc38d3709b74928931804a1cd2894c5c1e2f1229f2efa12347c2a24
3
+ metadata.gz: 4f134dd6fd6ac47f11b94ed74f4a6c361de0859a73b7845c9c642769e4e340b0
4
+ data.tar.gz: b0e6576ed1173b6702d6382d2711f34b8ddae1570b2a793a19a216744b330ec1
5
5
  SHA512:
6
- metadata.gz: cbf92894516bd532e9027e64d100d98559610d14f879d4e6e346998d3adf85ba5f4dbc3c108db9c62773dd8a935ddd95df6c2e1c75fabc3ccd1efe8c85e3fd2d
7
- data.tar.gz: 5cb07fc82fad69e9f4c0b483db88e6f010250360f9aff30ab3e02152dd28eb6d9a08a901f98ae066b3eeddf1aa9c860060fe0cdbfaba00d0263073ec41ce6043
6
+ metadata.gz: f891118c6640903373100e66654c59c15900eb36d4ed3d7c6b428e4c624b81d9930bd6b7569f39d1255753edf58acf664e57adbf80e92efe10bf189449b2586d
7
+ data.tar.gz: '0097f6120b11a3ddde782cd0673bb4442a9c45f7e308f16363821ed9ae11b0a455191712e7c2cf8813498271d6bad826cef22e930cee822d7338c7bb44f11186'
@@ -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/CHANGELOG.md ADDED
@@ -0,0 +1,42 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.3.0] - 2025-01-07
6
+
7
+ ### Added
8
+ - Streaming support via `StreamClient` class for real-time responses
9
+ - Web search capabilities with `search_mode` parameter (web/academic)
10
+ - Domain filtering with `search_domain_filter` (include/exclude domains)
11
+ - Date filtering with `search_after_date_filter` and `search_before_date_filter`
12
+ - Recency filtering with `search_recency_filter` (month/week/day/hour)
13
+ - Location-based search with `web_search_options`
14
+ - Support for new models: sonar-pro, sonar-deep-research
15
+ - Full conversation history support with messages array
16
+ - New parameters: `frequency_penalty` and `presence_penalty`
17
+ - Beta features: `return_images` and `return_related_questions`
18
+ - Model constants in `PerplexityApi::Models`
19
+ - Helper methods: `stream`, `stream_chat`
20
+ - Comprehensive examples directory
21
+
22
+ ### Changed
23
+ - `chat` method now accepts both string and array of messages
24
+ - `chat` method accepts options parameter for per-request configuration
25
+ - Updated default configuration to include new penalty parameters
26
+
27
+ ### Fixed
28
+ - Improved error handling for streaming responses
29
+
30
+ ## [0.2.1] - Previous version
31
+
32
+ ### Fixed
33
+ - Environment variable loading issues
34
+ - Configuration management improvements
35
+
36
+ ## [0.1.0] - Initial release
37
+
38
+ ### Added
39
+ - Basic chat functionality
40
+ - Configuration management
41
+ - Environment variable support
42
+ - Basic parameter support (temperature, max_tokens, top_p, top_k)
data/Gemfile.lock CHANGED
@@ -1,14 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- perplexity_api (0.1.1)
4
+ perplexity_api (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  diff-lcs (1.6.1)
10
- dotenv (2.8.1)
11
- rake (10.5.0)
10
+ rake (13.3.0)
12
11
  rspec (3.13.0)
13
12
  rspec-core (~> 3.13.0)
14
13
  rspec-expectations (~> 3.13.0)
@@ -27,11 +26,10 @@ PLATFORMS
27
26
  ruby
28
27
 
29
28
  DEPENDENCIES
30
- bundler (~> 1.17)
31
- dotenv (~> 2.7)
29
+ bundler (~> 2.0)
32
30
  perplexity_api!
33
- rake (~> 10.0)
31
+ rake (~> 13.0)
34
32
  rspec (~> 3.0)
35
33
 
36
34
  BUNDLED WITH
37
- 1.17.2
35
+ 2.6.9
data/README.md CHANGED
@@ -1,12 +1,19 @@
1
1
  # PerplexityApi
2
+ [![Gem Version](https://badge.fury.io/rb/perplexity_api.svg?v=0.2.1)](https://badge.fury.io/rb/perplexity_api)
3
+ [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt)
2
4
 
3
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.
4
6
 
5
7
  ## Features
6
8
 
7
9
  - API key can be configured externally
8
- - Ability to select the latest models
10
+ - Support for all latest Perplexity models including sonar-pro and sonar-deep-research
9
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
10
17
  - Options can be customized or use defaults
11
18
 
12
19
  ## Installation
@@ -54,13 +61,10 @@ PERPLEXITY_TOP_P=0.9
54
61
  PERPLEXITY_TOP_K=0
55
62
  ```
56
63
 
57
- If you're using the dotenv gem in your application, you can load these variables from a `.env` file:
64
+ You can set these environment variables in your application's environment or use a method of your choice to load them from a `.env` file.
58
65
 
59
66
  ```ruby
60
- require 'dotenv'
61
- Dotenv.load # Load environment variables from .env file
62
-
63
- # Then use the PerplexityApi gem
67
+ # After setting environment variables, use the PerplexityApi gem
64
68
  require 'perplexity_api'
65
69
  ```
66
70
 
@@ -86,6 +90,21 @@ response = PerplexityApi.chat("Hello, Perplexity AI!")
86
90
  puts response["choices"][0]["message"]["content"]
87
91
  ```
88
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
+
89
108
  ### Using a Client Instance
90
109
 
91
110
  For more detailed control, you can create a client instance:
@@ -98,7 +117,10 @@ client = PerplexityApi.new(
98
117
  temperature: 0.5,
99
118
  max_tokens: 2048,
100
119
  top_p: 0.9,
101
- top_k: 0
120
+ top_k: 0,
121
+ frequency_penalty: 0.1,
122
+ presence_penalty: 0.1,
123
+ search_mode: "web"
102
124
  }
103
125
  )
104
126
 
@@ -106,8 +128,106 @@ response = client.chat("Enter your complex question here...")
106
128
  puts response["choices"][0]["message"]["content"]
107
129
  ```
108
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
+
109
215
  ## Models
110
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
+
111
231
  For the most up-to-date list of models, refer to the [Perplexity AI official documentation](https://docs.perplexity.ai/guides/model-cards).
112
232
 
113
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.0"
2
+ VERSION = "0.4.0"
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
@@ -35,10 +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
- spec.add_development_dependency "dotenv", "~> 2.7"
42
41
 
43
- spec.required_ruby_version = ">= 2.6.0"
42
+ spec.required_ruby_version = ">= 3.1.0"
44
43
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perplexity_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hisafumi Kikkawa
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-03-27 00:00:00.000000000 Z
11
+ date: 2025-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.17'
19
+ version: '2.0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.17'
26
+ version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,20 +52,6 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
- - !ruby/object:Gem::Dependency
56
- name: dotenv
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '2.7'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '2.7'
69
55
  description: A Ruby library for easily using Perplexity AI's API. Allows setting API
70
56
  keys, selecting models, and customizing options.
71
57
  email:
@@ -74,11 +60,11 @@ executables: []
74
60
  extensions: []
75
61
  extra_rdoc_files: []
76
62
  files:
77
- - ".env.sample"
63
+ - ".env.example"
78
64
  - ".gitignore"
79
65
  - ".rspec"
80
- - ".rspec_status"
81
66
  - ".travis.yml"
67
+ - CHANGELOG.md
82
68
  - CODE_OF_CONDUCT.md
83
69
  - Gemfile
84
70
  - Gemfile.lock
@@ -88,9 +74,15 @@ files:
88
74
  - Rakefile
89
75
  - bin/console
90
76
  - bin/setup
77
+ - examples/basic_usage.rb
78
+ - examples/conversation.rb
79
+ - examples/streaming.rb
80
+ - examples/web_search.rb
91
81
  - lib/perplexity_api.rb
92
82
  - lib/perplexity_api/client.rb
93
83
  - lib/perplexity_api/configuration.rb
84
+ - lib/perplexity_api/models.rb
85
+ - lib/perplexity_api/stream_client.rb
94
86
  - lib/perplexity_api/version.rb
95
87
  - perplexity_api.gemspec
96
88
  homepage: https://github.com/hisafumi-kikkawa/perplexity_api
@@ -101,7 +93,7 @@ metadata:
101
93
  homepage_uri: https://github.com/hisafumi-kikkawa/perplexity_api
102
94
  source_code_uri: https://github.com/hisafumi-kikkawa/perplexity_api
103
95
  changelog_uri: https://github.com/hisafumi-kikkawa/perplexity_api/blob/master/CHANGELOG.md
104
- post_install_message:
96
+ post_install_message:
105
97
  rdoc_options: []
106
98
  require_paths:
107
99
  - lib
@@ -109,15 +101,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
109
101
  requirements:
110
102
  - - ">="
111
103
  - !ruby/object:Gem::Version
112
- version: 2.6.0
104
+ version: 3.1.0
113
105
  required_rubygems_version: !ruby/object:Gem::Requirement
114
106
  requirements:
115
107
  - - ">="
116
108
  - !ruby/object:Gem::Version
117
109
  version: '0'
118
110
  requirements: []
119
- rubygems_version: 3.0.3.1
120
- signing_key:
111
+ rubygems_version: 3.3.3
112
+ signing_key:
121
113
  specification_version: 4
122
114
  summary: Ruby wrapper for Perplexity API
123
115
  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 |