your_ai_insight 1.0.10 → 1.0.11
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c400f6bb1a051f84900f4ca7c4d229e6f7193aff9bf27b1c6e13772b36935dc6
|
|
4
|
+
data.tar.gz: a05ff0274c36660ed5a0e0dfde6ec242e8c293384dc835fd1b02ba0c471e10bd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e0893b4723fc2827ea30eabc856f9a48820bc377a286b017be3d78e486ffa218e5930c6f4dfb1fca77fc5616e87038912bd11fee75304638c25b6ebdb9a9d879
|
|
7
|
+
data.tar.gz: cc045b166a9f36f017d1f2a90f02412eb213c3d54ee0a739a7958e9a9dd47ec87779a25ac2362c9c460d99178a14cba294a84084efbccd1cc7cd6505f9490dd6
|
|
@@ -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,24 @@ module YourAiInsight
|
|
|
32
31
|
PROMPT
|
|
33
32
|
|
|
34
33
|
def initialize
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
@
|
|
34
|
+
cfg = YourAiInsight.config
|
|
35
|
+
@provider = (cfg.ai_provider || :claude).to_sym
|
|
36
|
+
@max_tokens = cfg.max_tokens
|
|
37
|
+
|
|
38
|
+
case @provider
|
|
39
|
+
when :openrouter
|
|
40
|
+
@api_key = cfg.openrouter_api_key ||
|
|
41
|
+
ENV["OPENROUTER_API_KEY"] ||
|
|
42
|
+
raise(ConfigurationError, "Set config.openrouter_api_key or ENV['OPENROUTER_API_KEY']")
|
|
43
|
+
@model = cfg.openrouter_model
|
|
44
|
+
@site_url = cfg.openrouter_site_url
|
|
45
|
+
@site_name = cfg.openrouter_site_name
|
|
46
|
+
else
|
|
47
|
+
@api_key = cfg.anthropic_api_key ||
|
|
48
|
+
ENV["ANTHROPIC_API_KEY"] ||
|
|
49
|
+
raise(ConfigurationError, "Set config.anthropic_api_key or ENV['ANTHROPIC_API_KEY']")
|
|
50
|
+
@model = cfg.claude_model
|
|
51
|
+
end
|
|
40
52
|
end
|
|
41
53
|
|
|
42
54
|
# Free-form chat with optional live data context injected
|
|
@@ -57,8 +69,12 @@ module YourAiInsight
|
|
|
57
69
|
private
|
|
58
70
|
|
|
59
71
|
def call_api(messages)
|
|
72
|
+
@provider == :openrouter ? call_openrouter(messages) : call_claude(messages)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def call_claude(messages)
|
|
60
76
|
response = self.class.post(
|
|
61
|
-
"/v1/messages",
|
|
77
|
+
"https://api.anthropic.com/v1/messages",
|
|
62
78
|
headers: {
|
|
63
79
|
"x-api-key" => @api_key,
|
|
64
80
|
"anthropic-version" => "2023-06-01",
|
|
@@ -74,7 +90,6 @@ module YourAiInsight
|
|
|
74
90
|
)
|
|
75
91
|
|
|
76
92
|
body = JSON.parse(response.body)
|
|
77
|
-
|
|
78
93
|
unless response.success?
|
|
79
94
|
raise ApiError, "Claude API error (HTTP #{response.code}): #{body.dig('error', 'message')}"
|
|
80
95
|
end
|
|
@@ -86,6 +101,40 @@ module YourAiInsight
|
|
|
86
101
|
raise ApiError, "Network error reaching Claude API: #{e.message}"
|
|
87
102
|
end
|
|
88
103
|
|
|
104
|
+
def call_openrouter(messages)
|
|
105
|
+
headers = {
|
|
106
|
+
"Authorization" => "Bearer #{@api_key}",
|
|
107
|
+
"Content-Type" => "application/json"
|
|
108
|
+
}
|
|
109
|
+
headers["HTTP-Referer"] = @site_url if @site_url.present?
|
|
110
|
+
headers["X-Title"] = @site_name if @site_name.present?
|
|
111
|
+
|
|
112
|
+
# Prepend system prompt as a system message (OpenAI-compatible format)
|
|
113
|
+
full_messages = [{ role: "system", content: SYSTEM_PROMPT }] + messages
|
|
114
|
+
|
|
115
|
+
response = self.class.post(
|
|
116
|
+
"https://openrouter.ai/api/v1/chat/completions",
|
|
117
|
+
headers: headers,
|
|
118
|
+
body: {
|
|
119
|
+
model: @model,
|
|
120
|
+
max_tokens: @max_tokens,
|
|
121
|
+
messages: full_messages
|
|
122
|
+
}.to_json,
|
|
123
|
+
timeout: 90
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
body = JSON.parse(response.body)
|
|
127
|
+
unless response.success?
|
|
128
|
+
raise ApiError, "OpenRouter API error (HTTP #{response.code}): #{body.dig('error', 'message')}"
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
body.dig("choices", 0, "message", "content").presence ||
|
|
132
|
+
raise(ApiError, "Empty response from OpenRouter API")
|
|
133
|
+
|
|
134
|
+
rescue HTTParty::Error, Timeout::Error => e
|
|
135
|
+
raise ApiError, "Network error reaching OpenRouter API: #{e.message}"
|
|
136
|
+
end
|
|
137
|
+
|
|
89
138
|
# Injects a live snapshot into the chat prompt
|
|
90
139
|
def context_block(ctx)
|
|
91
140
|
return nil if ctx.blank?
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
module YourAiInsight
|
|
2
2
|
class Configuration
|
|
3
|
-
# ──
|
|
4
|
-
|
|
3
|
+
# ── AI Provider ───────────────────────────────────────────────────────────
|
|
4
|
+
# :claude (default) or :openrouter
|
|
5
|
+
attr_accessor :ai_provider
|
|
5
6
|
|
|
6
|
-
# ──
|
|
7
|
-
attr_accessor :
|
|
7
|
+
# ── Claude / Anthropic settings ───────────────────────────────────────────
|
|
8
|
+
attr_accessor :anthropic_api_key
|
|
9
|
+
attr_accessor :claude_model # default: claude-opus-4-5
|
|
8
10
|
attr_accessor :max_tokens # default: 2048
|
|
9
11
|
|
|
12
|
+
# ── OpenRouter settings ───────────────────────────────────────────────────
|
|
13
|
+
attr_accessor :openrouter_api_key
|
|
14
|
+
# default: meta-llama/llama-3.3-70b-instruct:free (free, no billing needed)
|
|
15
|
+
attr_accessor :openrouter_model
|
|
16
|
+
attr_accessor :openrouter_site_url # optional — sent as HTTP-Referer
|
|
17
|
+
attr_accessor :openrouter_site_name # optional — sent as X-Title
|
|
18
|
+
|
|
10
19
|
# ── Multi-tenancy: scope data to current user's locations/customers ───────
|
|
11
20
|
# Proc receives current_user and returns an Array of location_ids, or nil for all.
|
|
12
21
|
# Example: config.location_scope = ->(user) { user.locations.pluck(:id) }
|
|
@@ -87,9 +96,14 @@ module YourAiInsight
|
|
|
87
96
|
attr_accessor :sub_contractors_table # "sub_contractors"
|
|
88
97
|
|
|
89
98
|
def initialize
|
|
90
|
-
@
|
|
99
|
+
@ai_provider = :claude
|
|
100
|
+
@claude_model = "claude-opus-4-5"
|
|
91
101
|
@max_tokens = 2048
|
|
92
102
|
@company_name = "AllPro IFM"
|
|
103
|
+
|
|
104
|
+
@openrouter_model = "meta-llama/llama-3.3-70b-instruct:free"
|
|
105
|
+
@openrouter_site_url = nil
|
|
106
|
+
@openrouter_site_name = nil
|
|
93
107
|
@logo_url = nil
|
|
94
108
|
@default_recipients = []
|
|
95
109
|
|