diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 245cdfd..e52605e 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -79,11 +79,16 @@ en:
chatbot_escalate_to_staff_max_history: "(Chat only) number of chat messages included in transcript added to escalation PM"
chatbot_user_fields_collection: "(EXPERIMENTAL) Collect empty user fields from the user as part of the conversation"
chatbot_news_api_token: "News API token for news (if left blank, news will never be searched)Get one at NewsAPI.org"
+ chatbot_news_api_call_token_cost: "The notional token cost used for each call to the News API against users' overall quota."
chatbot_firecrawl_api_token: "Firecrawl API token for crawling remote websites. If left blank, crawling will not be available. Get one at https://www.firecrawl.dev/"
+ chatbot_firecrawl_api_call_token_cost: "The notional token cost used for each call to the Firecrawl API against users' overall quota."
chatbot_jina_api_token: "Jina API token for web crawl and search. Get one at https://jina.ai. Alternative to Firecrawl and Serp. If Firecrawl API token is populated, it will be used in preference to Jina for crawling. Ditto Serp API for Searching."
+ chatbot_jina_api_token_cost_multiplier: "The notional token cost multiplier used for each call to the Jina API against users' overall quota. A Users's cost is the amount of text returned multiplied by this number."
chatbot_function_response_char_limit: "The maximum number of characters taken from the response from web crawl in order to mitigate the risk of a token breach when later including result in LLM call"
chatbot_serp_api_key: "Serp API token for google search (if left blank, google will never be searched). Get one at SerpAPI.com"
+ chatbot_serp_api_call_token_cost: "The notional token cost used for each call to the Serp API against users' overall quota."
chatbot_marketstack_key: "Marketstack API key for stock price information (if left blank, Marketstack will never be queried).Get one at MarketStack.com"
+ chatbot_marketstack_api_call_token_cost: "The notional token cost used for each call to the Marketstack API against users' overall quota."
chatbot_enable_verbose_console_logging: "Enable response retrieval progress logging to console to help debug issues"
chatbot_enable_verbose_rails_logging: "Enable response retrieval progress logging to rails logs to help debug issues. 'api_calls_only' restricts this to just API calls, 'all' logs all progress"
chatbot_verbose_rails_logging_destination_level: "Choose which category of logs to send verbose logs to. 'warn' is useful in Production as 'info' logs are not exposed at /logs."
diff --git a/config/settings.yml b/config/settings.yml
index 1a5a2f9..d5b2e01 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -373,21 +373,36 @@ plugins:
chatbot_news_api_token:
client: false
default: ''
+ chatbot_news_api_call_token_cost:
+ client: false
+ default: 10000
chatbot_firecrawl_api_token:
client: false
default: ''
+ chatbot_firecrawl_api_call_token_cost:
+ client: false
+ default: 10000
chatbot_jina_api_token:
client: false
default: ''
+ chatbot_jina_api_token_cost_multiplier:
+ client: false
+ default: 10000
chatbot_function_response_char_limit:
client: false
default: 350000
chatbot_serp_api_key:
client: false
default: ''
+ chatbot_serp_api_call_token_cost:
+ client: false
+ default: 10000
chatbot_marketstack_key:
client: false
default: ''
+ chatbot_marketstack_api_call_token_cost:
+ client: false
+ default: 10000
chatbot_enable_verbose_console_logging:
client: false
default: false
diff --git a/lib/discourse_chatbot/functions/news_function.rb b/lib/discourse_chatbot/functions/news_function.rb
index 05bd48a..0c54519 100644
--- a/lib/discourse_chatbot/functions/news_function.rb
+++ b/lib/discourse_chatbot/functions/news_function.rb
@@ -4,7 +4,6 @@
module DiscourseChatbot
class NewsFunction < Function
- TOKEN_COST = 10000
def name
'news'
@@ -33,6 +32,7 @@ def process(args)
--------------------------------------
EOS
super(args)
+ token_usage = 0
conn_params = {}
@@ -56,14 +56,15 @@ def process(args)
all_articles.each do |a|
news += "#{a["title"]}. "
end
+ token_usage = SiteSetting.chatbot_news_api_call_token_cost
{
answer: news,
- token_usage: TOKEN_COST
+ token_usage: token_usage
}
rescue
{
answer: I18n.t("chatbot.prompt.function.news.error"),
- token_usage: TOKEN_COST
+ token_usage: token_usage
}
end
end
diff --git a/lib/discourse_chatbot/functions/stock_data_function.rb b/lib/discourse_chatbot/functions/stock_data_function.rb
index c168f71..4304563 100644
--- a/lib/discourse_chatbot/functions/stock_data_function.rb
+++ b/lib/discourse_chatbot/functions/stock_data_function.rb
@@ -9,7 +9,6 @@
module DiscourseChatbot
class StockDataFunction < Function
- TOKEN_COST = 1000
def name
'stock_data'
@@ -33,6 +32,7 @@ def required
def process(args)
begin
super(args)
+ token_usage = 0
params = {
access_key: "#{SiteSetting.chatbot_marketstack_key}",
@@ -57,15 +57,16 @@ def process(args)
api_response = JSON.parse(json)
stock_data = api_response['data'][0]
+ token_usage = SiteSetting.chatbot_marketstack_api_call_token_cost
{
answer: I18n.t("chatbot.prompt.function.stock_data.answer", ticker: stock_data['symbol'], close: stock_data['close'].to_s, date: stock_data['date'].to_s, high: stock_data['high'].to_s, low: stock_data['low'].to_s),
- token_usage: TOKEN_COST
+ token_usage: token_usage
}
rescue
{
answer: I18n.t("chatbot.prompt.function.stock_data.error"),
- token_usage: TOKEN_COST
+ token_usage: token_usage
}
end
end
diff --git a/lib/discourse_chatbot/functions/web_crawler_function.rb b/lib/discourse_chatbot/functions/web_crawler_function.rb
index fe3fe7f..b0f3e39 100644
--- a/lib/discourse_chatbot/functions/web_crawler_function.rb
+++ b/lib/discourse_chatbot/functions/web_crawler_function.rb
@@ -31,6 +31,7 @@ def process(args)
--------------------------------------
EOS
super(args)
+ token_usage = 0
if SiteSetting.chatbot_firecrawl_api_token.blank?
conn = Faraday.new(
url: "https://r.jina.ai/#{args[parameters[0][:name]]}",
@@ -40,6 +41,7 @@ def process(args)
)
response = conn.get
result = response.body
+ token_usage = result.length * SiteSetting.chatbot_jina_api_token_cost_multiplier
else
conn = Faraday.new(
url: 'https://api.firecrawl.dev',
@@ -71,12 +73,14 @@ def process(args)
end
result = response_body["data"][0]["markdown"]
+ token_usage = SiteSetting.chatbot_firecrawl_api_token_cost
end
{
answer: result[0..SiteSetting.chatbot_function_response_char_limit],
token_usage: token_usage
}
- rescue
+ rescue=> e
+ Rails.logger.error("Chatbot: Error in web crawler function: #{e}")
{
answer: I18n.t("chatbot.prompt.function.web_crawler.error"),
token_usage: token_usage
diff --git a/lib/discourse_chatbot/functions/web_search_function.rb b/lib/discourse_chatbot/functions/web_search_function.rb
index 204cbca..e5357e9 100644
--- a/lib/discourse_chatbot/functions/web_search_function.rb
+++ b/lib/discourse_chatbot/functions/web_search_function.rb
@@ -27,6 +27,7 @@ def required
def process(args)
begin
super(args)
+ token_usage = 0
if SiteSetting.chatbot_serp_api_key.blank?
query = URI.encode_www_form_component(args[parameters[0][:name]])
conn = Faraday.new(
@@ -37,6 +38,7 @@ def process(args)
)
response = conn.get
result = response.body
+ token_usage = response.body.length * SiteSetting.chatbot_jina_api_token_cost_multiplier
else
hash_results = ::GoogleSearch.new(q: args[parameters[0][:name]], serp_api_key: SiteSetting.chatbot_serp_api_key)
.get_hash
@@ -44,6 +46,7 @@ def process(args)
result = hash_results.dig(:answer_box, :answer).presence ||
hash_results.dig(:answer_box, :snippet).presence ||
hash_results.dig(:organic_results)
+ token_usage = SiteSetting.chatbot_serp_api_token_cost
end
{
answer: result[0..SiteSetting.chatbot_function_response_char_limit],