your_ai_insight 1.0.10 → 1.0.12

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: 3241c83b9d80f1cffabef64df8128eb4d765b1c31667e256815257040bfb8861
4
- data.tar.gz: 0ebe08ba0157fa78175d2f1188f57d62d97fee0c384fcf627bd20d897eb4e460
3
+ metadata.gz: 7d1204c7328e49de4459471b39022f9d2482ddebc0e72f26774cf889d1feb7fc
4
+ data.tar.gz: c01acdcda667e9bf44ba364d5e9c48138da79ae42375c8a327c65a17c6d1b4c6
5
5
  SHA512:
6
- metadata.gz: 17e3e5509660d296e10855c05f3ac4df938ae9fc64974dc538c023d4b7e85d9d1ba994b7b205e7d157e88736559e6b6ef57e8b1f2fd66ef4580aba1d78fecada
7
- data.tar.gz: 94b4d799978ea42d41354b7d57089972243866ce4e2d2fb0a059dafb1f33159c657fe033d61cdbdbc31588781598ff1c033befa0f91717c4bc45dbf1df8e2c96
6
+ metadata.gz: 53ee1ee3ab937cd1ec3436f44af642a687e223b5c62ba05d7da3d43a0f8f2cc8fbba7c6e577bb9a240f31a19394b3ffa6d78880686d75f0c9d8d5f2c0adca541
7
+ data.tar.gz: 401fba06aff405ab6d07c08aa547b3514ae365fd155add6b61b535d835e22b2254210ff2706e84a8b15abff2a15868274b7035574351f0a04fc801bea8776d1d
@@ -3,7 +3,6 @@ require "httparty"
3
3
  module YourAiInsight
4
4
  class ClaudeService
5
5
  include HTTParty
6
- base_uri "https://api.anthropic.com"
7
6
 
8
7
  SYSTEM_PROMPT = <<~PROMPT.freeze
9
8
  You are an expert facility management analyst for AllPro IFM.
@@ -32,11 +31,14 @@ module YourAiInsight
32
31
  PROMPT
33
32
 
34
33
  def initialize
35
- @api_key = YourAiInsight.config.anthropic_api_key ||
36
- ENV["ANTHROPIC_API_KEY"] ||
37
- raise(ConfigurationError, "Set YourAiInsight.configure { |c| c.anthropic_api_key = ENV['ANTHROPIC_API_KEY'] }")
38
- @model = YourAiInsight.config.claude_model
39
- @max_tokens = YourAiInsight.config.max_tokens
34
+ cfg = YourAiInsight.config
35
+ @api_key = cfg.openrouter_api_key ||
36
+ ENV["OPENROUTER_API_KEY"] ||
37
+ raise(ConfigurationError, "Set config.openrouter_api_key or ENV['OPENROUTER_API_KEY']")
38
+ @model = cfg.openrouter_model
39
+ @max_tokens = cfg.max_tokens
40
+ @site_url = cfg.openrouter_site_url
41
+ @site_name = cfg.openrouter_site_name
40
42
  end
41
43
 
42
44
  # Free-form chat with optional live data context injected
@@ -57,18 +59,22 @@ module YourAiInsight
57
59
  private
58
60
 
59
61
  def call_api(messages)
62
+ headers = {
63
+ "Authorization" => "Bearer #{@api_key}",
64
+ "Content-Type" => "application/json"
65
+ }
66
+ headers["HTTP-Referer"] = @site_url if @site_url.present?
67
+ headers["X-Title"] = @site_name if @site_name.present?
68
+
69
+ full_messages = [{ role: "system", content: SYSTEM_PROMPT }] + messages
70
+
60
71
  response = self.class.post(
61
- "/v1/messages",
62
- headers: {
63
- "x-api-key" => @api_key,
64
- "anthropic-version" => "2023-06-01",
65
- "content-type" => "application/json"
66
- },
72
+ "https://openrouter.ai/api/v1/chat/completions",
73
+ headers: headers,
67
74
  body: {
68
75
  model: @model,
69
76
  max_tokens: @max_tokens,
70
- system: SYSTEM_PROMPT,
71
- messages: messages
77
+ messages: full_messages
72
78
  }.to_json,
73
79
  timeout: 90
74
80
  )
@@ -76,17 +82,16 @@ module YourAiInsight
76
82
  body = JSON.parse(response.body)
77
83
 
78
84
  unless response.success?
79
- raise ApiError, "Claude API error (HTTP #{response.code}): #{body.dig('error', 'message')}"
85
+ raise ApiError, "OpenRouter error (HTTP #{response.code}): #{body.dig('error', 'message')}"
80
86
  end
81
87
 
82
- body.dig("content", 0, "text").presence ||
83
- raise(ApiError, "Empty response from Claude API")
88
+ body.dig("choices", 0, "message", "content").presence ||
89
+ raise(ApiError, "Empty response from OpenRouter")
84
90
 
85
91
  rescue HTTParty::Error, Timeout::Error => e
86
- raise ApiError, "Network error reaching Claude API: #{e.message}"
92
+ raise ApiError, "Network error reaching OpenRouter: #{e.message}"
87
93
  end
88
94
 
89
- # Injects a live snapshot into the chat prompt
90
95
  def context_block(ctx)
91
96
  return nil if ctx.blank?
92
97
  lines = ["## Live Facility Snapshot"]
@@ -1,13 +1,16 @@
1
1
  module YourAiInsight
2
2
  class Configuration
3
- # ── Required ──────────────────────────────────────────────────────────────
4
- attr_accessor :anthropic_api_key
3
+ # ── OpenRouter (required) ──────────────────────────────────────────────────
4
+ attr_accessor :openrouter_api_key
5
+ # See https://openrouter.ai/models?q=free for free models
6
+ attr_accessor :openrouter_model # default: meta-llama/llama-3.3-70b-instruct:free
7
+ attr_accessor :openrouter_site_url # optional — sent as HTTP-Referer
8
+ attr_accessor :openrouter_site_name # optional — sent as X-Title
5
9
 
6
- # ── Model / Claude settings ───────────────────────────────────────────────
7
- attr_accessor :claude_model # default: claude-sonnet-4-20250514
8
- attr_accessor :max_tokens # default: 2048
10
+ # ── Response tuning ────────────────────────────────────────────────────────
11
+ attr_accessor :max_tokens # default: 2048
9
12
 
10
- # ── Multi-tenancy: scope data to current user's locations/customers ───────
13
+ # ── Multi-tenancy: scope data to current user's locations/customers ────────
11
14
  # Proc receives current_user and returns an Array of location_ids, or nil for all.
12
15
  # Example: config.location_scope = ->(user) { user.locations.pluck(:id) }
13
16
  attr_accessor :location_scope
@@ -87,11 +90,13 @@ module YourAiInsight
87
90
  attr_accessor :sub_contractors_table # "sub_contractors"
88
91
 
89
92
  def initialize
90
- @claude_model = "claude-sonnet-4-20250514"
91
- @max_tokens = 2048
92
- @company_name = "AllPro IFM"
93
- @logo_url = nil
94
- @default_recipients = []
93
+ @openrouter_model = "meta-llama/llama-3.3-70b-instruct:free"
94
+ @openrouter_site_url = nil
95
+ @openrouter_site_name = nil
96
+ @max_tokens = 2048
97
+ @company_name = "AllPro IFM"
98
+ @logo_url = nil
99
+ @default_recipients = []
95
100
 
96
101
  # jobs
97
102
  @jobs_table = "jobs"
@@ -122,11 +127,11 @@ module YourAiInsight
122
127
  @bids_task_id_col = "task_id"
123
128
 
124
129
  # expenses
125
- @expenses_table = "expenses"
126
- @expenses_budget_col = "budget"
127
- @expenses_actual_col = "actual"
128
- @expenses_job_id_col = "job_id"
129
- @expenses_task_id_col= "task_id"
130
+ @expenses_table = "expenses"
131
+ @expenses_budget_col = "budget"
132
+ @expenses_actual_col = "actual"
133
+ @expenses_job_id_col = "job_id"
134
+ @expenses_task_id_col = "task_id"
130
135
 
131
136
  # location_budgets
132
137
  @location_budgets_table = "location_budgets"
@@ -1,3 +1,3 @@
1
1
  module YourAiInsight
2
- VERSION = "1.0.10"
2
+ VERSION = "1.0.12"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: your_ai_insight
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.10
4
+ version: 1.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - AllPro IFM