exa-ai 0.9.0 → 0.10.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 +4 -4
- data/exe/exa-ai-search +40 -4
- data/lib/exa/cli/search_parser.rb +49 -1
- data/lib/exa/resources/search_result.rb +2 -1
- data/lib/exa/services/parameter_converter.rb +27 -2
- data/lib/exa/services/search.rb +3 -2
- data/lib/exa/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ffa1108ddff0ff951dc18d12eeef57f74020a4c0425916a394fac95e4699fef5
|
|
4
|
+
data.tar.gz: 43c40cc61a7bee139dc3c179fe9d11c40b04dd506d53c22f88e312705ae9dfe3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5745df2cf4664fff7b8a507fb82662cd1e448a51dba7a0a0ac30485d624ac1bb3624e85b6086a6bd511a9485636b0d5a9804c561e9476106679a7458572fcf62
|
|
7
|
+
data.tar.gz: 637d5150a3b0d192b1c68288c83c4e0ad13827d4d60ac9deb4a974397ab9b0c2ab86dd9281f33bc11dc5e1fd7ba06b22daa4c8d0f80c8927c108946e4c8ffe46
|
data/exe/exa-ai-search
CHANGED
|
@@ -15,7 +15,8 @@ def print_help
|
|
|
15
15
|
|
|
16
16
|
Options:
|
|
17
17
|
--num-results N Number of results to return (default: 10)
|
|
18
|
-
--type TYPE Search type: fast, deep,
|
|
18
|
+
--type TYPE Search type: auto, neural, fast, deep, deep-reasoning,
|
|
19
|
+
or instant (default: auto)
|
|
19
20
|
--category CAT Focus on specific data category
|
|
20
21
|
Options: "company", "research paper", "news", "pdf",
|
|
21
22
|
"github", "tweet", "personal site", "financial report",
|
|
@@ -42,6 +43,19 @@ def print_help
|
|
|
42
43
|
--subpage-target PHRASE Subpage target phrases (repeatable)
|
|
43
44
|
--links N Number of links to extract per result
|
|
44
45
|
--image-links N Number of image links to extract
|
|
46
|
+
--highlights Include text highlights in results
|
|
47
|
+
--highlights-max-characters N Max characters per highlight
|
|
48
|
+
--highlights-num-sentences N Number of sentences per highlight
|
|
49
|
+
--highlights-per-url N Number of highlights per URL
|
|
50
|
+
--highlights-query QUERY Custom query for highlight extraction
|
|
51
|
+
--livecrawl MODE Livecrawl mode: always, fallback, never, auto, or preferred
|
|
52
|
+
--livecrawl-timeout N Livecrawl timeout in milliseconds
|
|
53
|
+
--max-age-hours N Maximum age of results in hours
|
|
54
|
+
|
|
55
|
+
Search Options:
|
|
56
|
+
--additional-queries QUERY Additional search queries (repeatable)
|
|
57
|
+
--output-schema JSON JSON schema for output structure (@file syntax)
|
|
58
|
+
--user-location CODE User location (ISO country code)
|
|
45
59
|
|
|
46
60
|
General Options:
|
|
47
61
|
--api-key KEY Exa API key (or set EXA_API_KEY env var)
|
|
@@ -105,6 +119,25 @@ def build_contents(args)
|
|
|
105
119
|
contents[:extras][:image_links] = args[:image_links] if args[:image_links]
|
|
106
120
|
end
|
|
107
121
|
|
|
122
|
+
# Highlights options
|
|
123
|
+
if args[:highlights]
|
|
124
|
+
highlight_opts = %i[highlights_max_characters highlights_num_sentences highlights_per_url highlights_query]
|
|
125
|
+
if highlight_opts.any? { |k| args[k] }
|
|
126
|
+
contents[:highlights] = {}
|
|
127
|
+
contents[:highlights][:max_characters] = args[:highlights_max_characters] if args[:highlights_max_characters]
|
|
128
|
+
contents[:highlights][:num_sentences] = args[:highlights_num_sentences] if args[:highlights_num_sentences]
|
|
129
|
+
contents[:highlights][:highlights_per_url] = args[:highlights_per_url] if args[:highlights_per_url]
|
|
130
|
+
contents[:highlights][:query] = args[:highlights_query] if args[:highlights_query]
|
|
131
|
+
else
|
|
132
|
+
contents[:highlights] = true
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Livecrawl options
|
|
137
|
+
contents[:livecrawl] = args[:livecrawl] if args[:livecrawl]
|
|
138
|
+
contents[:livecrawl_timeout] = args[:livecrawl_timeout] if args[:livecrawl_timeout]
|
|
139
|
+
contents[:max_age_hours] = args[:max_age_hours] if args[:max_age_hours]
|
|
140
|
+
|
|
108
141
|
contents.empty? ? nil : contents
|
|
109
142
|
end
|
|
110
143
|
|
|
@@ -130,17 +163,20 @@ begin
|
|
|
130
163
|
|
|
131
164
|
# Prepare search parameters
|
|
132
165
|
search_params = {}
|
|
133
|
-
search_params[:
|
|
166
|
+
search_params[:num_results] = args[:num_results] if args[:num_results]
|
|
134
167
|
search_params[:type] = args[:type] if args[:type]
|
|
135
168
|
search_params[:category] = args[:category] if args[:category]
|
|
136
|
-
search_params[:
|
|
137
|
-
search_params[:
|
|
169
|
+
search_params[:include_domains] = args[:include_domains] if args[:include_domains]
|
|
170
|
+
search_params[:exclude_domains] = args[:exclude_domains] if args[:exclude_domains]
|
|
138
171
|
search_params[:start_published_date] = args[:start_published_date] if args[:start_published_date]
|
|
139
172
|
search_params[:end_published_date] = args[:end_published_date] if args[:end_published_date]
|
|
140
173
|
search_params[:start_crawl_date] = args[:start_crawl_date] if args[:start_crawl_date]
|
|
141
174
|
search_params[:end_crawl_date] = args[:end_crawl_date] if args[:end_crawl_date]
|
|
142
175
|
search_params[:include_text] = args[:include_text] if args[:include_text]
|
|
143
176
|
search_params[:exclude_text] = args[:exclude_text] if args[:exclude_text]
|
|
177
|
+
search_params[:additional_queries] = args[:additional_queries] if args[:additional_queries]
|
|
178
|
+
search_params[:output_schema] = args[:output_schema] if args[:output_schema]
|
|
179
|
+
search_params[:user_location] = args[:user_location] if args[:user_location]
|
|
144
180
|
contents = build_contents(args)
|
|
145
181
|
search_params.merge!(contents) if contents
|
|
146
182
|
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
module Exa
|
|
4
4
|
module CLI
|
|
5
5
|
class SearchParser
|
|
6
|
-
VALID_SEARCH_TYPES = ["fast", "deep", "
|
|
6
|
+
VALID_SEARCH_TYPES = ["auto", "neural", "fast", "deep", "deep-reasoning", "instant"].freeze
|
|
7
|
+
VALID_LIVECRAWL_MODES = ["always", "fallback", "never", "auto", "preferred"].freeze
|
|
7
8
|
VALID_CATEGORIES = [
|
|
8
9
|
"company", "research paper", "news", "pdf", "github",
|
|
9
10
|
"tweet", "personal site", "financial report", "people"
|
|
@@ -123,6 +124,47 @@ module Exa
|
|
|
123
124
|
when "--image-links"
|
|
124
125
|
@args[:image_links] = @argv[i + 1].to_i
|
|
125
126
|
i += 2
|
|
127
|
+
when "--highlights"
|
|
128
|
+
@args[:highlights] = true
|
|
129
|
+
i += 1
|
|
130
|
+
when "--highlights-max-characters"
|
|
131
|
+
@args[:highlights_max_characters] = @argv[i + 1].to_i
|
|
132
|
+
i += 2
|
|
133
|
+
when "--highlights-num-sentences"
|
|
134
|
+
@args[:highlights_num_sentences] = @argv[i + 1].to_i
|
|
135
|
+
i += 2
|
|
136
|
+
when "--highlights-per-url"
|
|
137
|
+
@args[:highlights_per_url] = @argv[i + 1].to_i
|
|
138
|
+
i += 2
|
|
139
|
+
when "--highlights-query"
|
|
140
|
+
@args[:highlights_query] = @argv[i + 1]
|
|
141
|
+
i += 2
|
|
142
|
+
when "--livecrawl"
|
|
143
|
+
livecrawl = @argv[i + 1]
|
|
144
|
+
validate_livecrawl(livecrawl)
|
|
145
|
+
@args[:livecrawl] = livecrawl
|
|
146
|
+
i += 2
|
|
147
|
+
when "--livecrawl-timeout"
|
|
148
|
+
@args[:livecrawl_timeout] = @argv[i + 1].to_i
|
|
149
|
+
i += 2
|
|
150
|
+
when "--max-age-hours"
|
|
151
|
+
@args[:max_age_hours] = @argv[i + 1].to_i
|
|
152
|
+
i += 2
|
|
153
|
+
when "--additional-queries"
|
|
154
|
+
@args[:additional_queries] ||= []
|
|
155
|
+
@args[:additional_queries] << @argv[i + 1]
|
|
156
|
+
i += 2
|
|
157
|
+
when "--output-schema"
|
|
158
|
+
schema_arg = @argv[i + 1]
|
|
159
|
+
@args[:output_schema] = if schema_arg.start_with?("@")
|
|
160
|
+
JSON.parse(File.read(schema_arg[1..]))
|
|
161
|
+
else
|
|
162
|
+
JSON.parse(schema_arg)
|
|
163
|
+
end
|
|
164
|
+
i += 2
|
|
165
|
+
when "--user-location"
|
|
166
|
+
@args[:user_location] = @argv[i + 1]
|
|
167
|
+
i += 2
|
|
126
168
|
else
|
|
127
169
|
query_parts << arg
|
|
128
170
|
i += 1
|
|
@@ -142,6 +184,12 @@ module Exa
|
|
|
142
184
|
raise ArgumentError, "Search type must be one of: #{VALID_SEARCH_TYPES.join(', ')}"
|
|
143
185
|
end
|
|
144
186
|
|
|
187
|
+
def validate_livecrawl(mode)
|
|
188
|
+
return if VALID_LIVECRAWL_MODES.include?(mode)
|
|
189
|
+
|
|
190
|
+
raise ArgumentError, "Livecrawl mode must be one of: #{VALID_LIVECRAWL_MODES.join(', ')}"
|
|
191
|
+
end
|
|
192
|
+
|
|
145
193
|
def validate_category(category)
|
|
146
194
|
return if VALID_CATEGORIES.include?(category)
|
|
147
195
|
|
|
@@ -11,9 +11,10 @@ module Exa
|
|
|
11
11
|
:search_type,
|
|
12
12
|
:context,
|
|
13
13
|
:cost_dollars,
|
|
14
|
+
:output,
|
|
14
15
|
keyword_init: true
|
|
15
16
|
)
|
|
16
|
-
def initialize(results:, request_id: nil, resolved_search_type: nil, search_type: nil, context: nil, cost_dollars: nil)
|
|
17
|
+
def initialize(results:, request_id: nil, resolved_search_type: nil, search_type: nil, context: nil, cost_dollars: nil, output: nil)
|
|
17
18
|
super
|
|
18
19
|
freeze
|
|
19
20
|
end
|
|
@@ -36,18 +36,26 @@ module Exa
|
|
|
36
36
|
when :include_text then :includeText
|
|
37
37
|
when :exclude_text then :excludeText
|
|
38
38
|
when :external_id then :externalId
|
|
39
|
+
when :additional_queries then :additionalQueries
|
|
40
|
+
when :output_schema then :outputSchema
|
|
41
|
+
when :user_location then :userLocation
|
|
42
|
+
when :num_results then :numResults
|
|
43
|
+
when :include_domains then :includeDomains
|
|
44
|
+
when :exclude_domains then :excludeDomains
|
|
39
45
|
else
|
|
40
46
|
key
|
|
41
47
|
end
|
|
42
48
|
end
|
|
43
49
|
|
|
44
50
|
def content_key?(key)
|
|
45
|
-
%i[text summary context subpages subpage_target extras].include?(key)
|
|
51
|
+
%i[text summary context subpages subpage_target extras highlights livecrawl livecrawl_timeout max_age_hours].include?(key)
|
|
46
52
|
end
|
|
47
53
|
|
|
48
54
|
def convert_content_key(key)
|
|
49
55
|
case key
|
|
50
56
|
when :subpage_target then :subpageTarget
|
|
57
|
+
when :livecrawl_timeout then :livecrawlTimeout
|
|
58
|
+
when :max_age_hours then :maxAgeHours
|
|
51
59
|
else
|
|
52
60
|
key
|
|
53
61
|
end
|
|
@@ -79,6 +87,12 @@ module Exa
|
|
|
79
87
|
else
|
|
80
88
|
value
|
|
81
89
|
end
|
|
90
|
+
when :highlights
|
|
91
|
+
if value.is_a?(Hash)
|
|
92
|
+
convert_hash_value(value, highlights_hash_mappings)
|
|
93
|
+
else
|
|
94
|
+
value
|
|
95
|
+
end
|
|
82
96
|
else
|
|
83
97
|
value
|
|
84
98
|
end
|
|
@@ -96,7 +110,9 @@ module Exa
|
|
|
96
110
|
def text_hash_mappings
|
|
97
111
|
{
|
|
98
112
|
max_characters: :maxCharacters,
|
|
99
|
-
include_html_tags: :includeHtmlTags
|
|
113
|
+
include_html_tags: :includeHtmlTags,
|
|
114
|
+
include_sections: :includeSections,
|
|
115
|
+
exclude_sections: :excludeSections
|
|
100
116
|
}
|
|
101
117
|
end
|
|
102
118
|
|
|
@@ -118,6 +134,15 @@ module Exa
|
|
|
118
134
|
image_links: :imageLinks
|
|
119
135
|
}
|
|
120
136
|
end
|
|
137
|
+
|
|
138
|
+
def highlights_hash_mappings
|
|
139
|
+
{
|
|
140
|
+
max_characters: :maxCharacters,
|
|
141
|
+
num_sentences: :numSentences,
|
|
142
|
+
highlights_per_url: :highlightsPerUrl,
|
|
143
|
+
query: :query
|
|
144
|
+
}
|
|
145
|
+
end
|
|
121
146
|
end
|
|
122
147
|
end
|
|
123
148
|
end
|
data/lib/exa/services/search.rb
CHANGED
|
@@ -5,7 +5,7 @@ require_relative "parameter_converter"
|
|
|
5
5
|
module Exa
|
|
6
6
|
module Services
|
|
7
7
|
class Search
|
|
8
|
-
VALID_SEARCH_TYPES = ["fast", "deep", "
|
|
8
|
+
VALID_SEARCH_TYPES = ["auto", "neural", "fast", "deep", "deep-reasoning", "instant"].freeze
|
|
9
9
|
DEFAULT_SEARCH_TYPE = "auto"
|
|
10
10
|
|
|
11
11
|
def initialize(connection, **params)
|
|
@@ -24,7 +24,8 @@ module Exa
|
|
|
24
24
|
resolved_search_type: body["resolvedSearchType"],
|
|
25
25
|
search_type: body["searchType"],
|
|
26
26
|
context: body["context"],
|
|
27
|
-
cost_dollars: body["costDollars"]
|
|
27
|
+
cost_dollars: body["costDollars"],
|
|
28
|
+
output: body["output"]
|
|
28
29
|
)
|
|
29
30
|
end
|
|
30
31
|
|
data/lib/exa/version.rb
CHANGED