lex-azure-ai 0.1.4 → 0.1.6
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/CHANGELOG.md +12 -0
- data/CLAUDE.md +102 -18
- data/README.md +137 -31
- data/lib/legion/extensions/azure_ai/client.rb +2 -0
- data/lib/legion/extensions/azure_ai/helpers/client.rb +9 -0
- data/lib/legion/extensions/azure_ai/identity.rb +44 -0
- data/lib/legion/extensions/azure_ai/runners/content_safety.rb +39 -0
- data/lib/legion/extensions/azure_ai/version.rb +1 -1
- data/lib/legion/extensions/azure_ai.rb +2 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0b999c09cc1e7d260fd320f576ffe0bac0c7404e6d74ef210f83e216ab42fdf4
|
|
4
|
+
data.tar.gz: 73e5d2ac265f6b70a96bfbcbb754b44e96eeb202f84021999ce3d80e8ecd90e3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 94d33edca3f7af18a63c8ac353c0e7636715c6493ab2722e74e93c3cde068ccdf2e3bc9f6650deaf99bd18b452ccdb8fc9b815b864932c3319ac36fff2948726
|
|
7
|
+
data.tar.gz: 91886385ce36acaf98edada221dac55654ca58ae968b4869b7a3ab41ac67934c254a852db22400848ff57df56a5b0c9c36bda18b0fde062acf1af82552b1a7c4
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.1.6] - 2026-04-17
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Content Safety runner with `check_text` method for Azure AI Content Safety `text:analyze` API (#4)
|
|
7
|
+
- `content_safety_client` factory method in `Helpers::Client` for Cognitive Services endpoint
|
|
8
|
+
- Configurable severity threshold (default 2, range 0-6) with normalized blocked/reasons response
|
|
9
|
+
|
|
10
|
+
## [0.1.5] - 2026-04-06
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Credential-only identity module for Phase 8 Broker integration (`Identity` module with `provide_token`)
|
|
14
|
+
|
|
3
15
|
## [0.1.4] - 2026-03-31
|
|
4
16
|
|
|
5
17
|
### Added
|
data/CLAUDE.md
CHANGED
|
@@ -6,53 +6,137 @@
|
|
|
6
6
|
|
|
7
7
|
## Purpose
|
|
8
8
|
|
|
9
|
-
Legion Extension that connects LegionIO to Azure AI Services
|
|
9
|
+
Legion Extension that connects LegionIO to Azure AI Services. Provides runners for chat completions, embeddings, model listing (via Azure OpenAI), and content safety moderation (via Azure AI Content Safety).
|
|
10
10
|
|
|
11
11
|
**GitHub**: https://github.com/LegionIO/lex-azure-ai
|
|
12
12
|
**License**: MIT
|
|
13
|
-
**Version**: 0.1.
|
|
14
|
-
**Specs**:
|
|
13
|
+
**Version**: 0.1.6
|
|
14
|
+
**Specs**: 45 examples (5 spec files)
|
|
15
15
|
|
|
16
16
|
## Architecture
|
|
17
17
|
|
|
18
18
|
```
|
|
19
19
|
Legion::Extensions::AzureAi
|
|
20
20
|
├── Runners/
|
|
21
|
-
│ ├── Chat
|
|
22
|
-
│ ├── Embeddings
|
|
23
|
-
│
|
|
21
|
+
│ ├── Chat # create(deployment:, messages:, api_key:, endpoint:, api_version:, ...)
|
|
22
|
+
│ ├── Embeddings # create(deployment:, input:, api_key:, endpoint:, api_version:, ...)
|
|
23
|
+
│ ├── Models # list(api_key:, endpoint:, api_version:, ...)
|
|
24
|
+
│ └── ContentSafety # check_text(content:, endpoint:, api_key:, severity_threshold:, ...)
|
|
24
25
|
├── Helpers/
|
|
25
|
-
│ └── Client
|
|
26
|
-
|
|
26
|
+
│ └── Client # Faraday-based client factory (two methods: client + content_safety_client)
|
|
27
|
+
├── Client # Standalone client class (includes all runners, holds @config)
|
|
28
|
+
└── Identity # Credential-only identity module for Broker integration
|
|
27
29
|
```
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
### Two Azure Services, Two Clients
|
|
30
32
|
|
|
31
|
-
`Client`
|
|
33
|
+
`Helpers::Client` is a **module** with two factory methods:
|
|
34
|
+
|
|
35
|
+
| Factory Method | Base URL | Auth Header | Used By |
|
|
36
|
+
|----------------|----------|-------------|---------|
|
|
37
|
+
| `client(api_key:, endpoint:, ...)` | `https://#{endpoint}.openai.azure.com` | `api-key` | Chat, Embeddings, Models |
|
|
38
|
+
| `content_safety_client(api_key:, endpoint:, ...)` | `https://#{endpoint}.cognitiveservices.azure.com` | `Ocp-Apim-Subscription-Key` | ContentSafety |
|
|
39
|
+
|
|
40
|
+
Both build a Faraday connection with JSON request/response middleware. Runner modules `extend` `Helpers::Client` to gain these as module-level methods.
|
|
41
|
+
|
|
42
|
+
`Client` (class) provides a standalone instantiable wrapper. It holds `@config` and delegates through `Helpers::Client`. It includes all four runner modules.
|
|
43
|
+
|
|
44
|
+
## Runner Reference
|
|
45
|
+
|
|
46
|
+
### Chat — `Runners::Chat`
|
|
47
|
+
|
|
48
|
+
```ruby
|
|
49
|
+
create(deployment:, messages:, api_key:, endpoint:, api_version: '2024-10-21', max_tokens: nil, temperature: nil, **)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- POST `/openai/deployments/#{deployment}/chat/completions?api-version=#{api_version}`
|
|
53
|
+
- Returns `{ result: response.body, usage: { input_tokens:, output_tokens:, cache_read_tokens:, cache_write_tokens: } }`
|
|
54
|
+
|
|
55
|
+
### Embeddings — `Runners::Embeddings`
|
|
56
|
+
|
|
57
|
+
```ruby
|
|
58
|
+
create(deployment:, input:, api_key:, endpoint:, api_version: '2024-10-21', **)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- POST `/openai/deployments/#{deployment}/embeddings?api-version=#{api_version}`
|
|
62
|
+
- Returns `{ result: response.body, usage: { input_tokens:, output_tokens:, cache_read_tokens:, cache_write_tokens: } }`
|
|
63
|
+
|
|
64
|
+
### Models — `Runners::Models`
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
list(api_key:, endpoint:, api_version: '2024-10-21', **)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- GET `/openai/models?api-version=#{api_version}`
|
|
71
|
+
- Returns `{ models: response.body }` (note: `models` key, not `result`)
|
|
72
|
+
|
|
73
|
+
### ContentSafety — `Runners::ContentSafety`
|
|
74
|
+
|
|
75
|
+
```ruby
|
|
76
|
+
check_text(content:, endpoint:, api_key:, severity_threshold: 2, categories: nil, api_version: '2024-09-01', **)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- POST `/contentsafety/text:analyze?api-version=#{api_version}`
|
|
80
|
+
- Request body: `{ text: content }` (plus `categories:` if provided)
|
|
81
|
+
- Response parsing: reads `categoriesAnalysis` array, filters by `severity >= severity_threshold`
|
|
82
|
+
- Returns `{ result: { blocked:, reasons:, categories:, raw: } }`
|
|
83
|
+
- Categories: Hate, Violence, SelfHarm, Sexual — severity range 0–6
|
|
84
|
+
- Default `api_version` is `'2024-09-01'` (differs from OpenAI runners which default to `'2024-10-21'`)
|
|
85
|
+
- No `usage` key — Content Safety API doesn't return token counts
|
|
32
86
|
|
|
33
87
|
## Key Design Decisions
|
|
34
88
|
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
- `
|
|
39
|
-
- `
|
|
89
|
+
- **Azure OpenAI auth** uses the `api-key` header (not `Authorization: Bearer`). Differs from lex-openai which uses Bearer.
|
|
90
|
+
- **Content Safety auth** uses `Ocp-Apim-Subscription-Key` header. Different Azure service, different auth mechanism.
|
|
91
|
+
- **API base URLs** are constructed from the `endpoint` param. The endpoint is typically the Azure resource name (e.g., `my-resource`).
|
|
92
|
+
- **Two default `api_version` values**: `'2024-10-21'` for OpenAI runners, `'2024-09-01'` for Content Safety. All runners accept `api_version:` as an override.
|
|
93
|
+
- **Return key conventions**: Chat and Embeddings return `{ result: ... }`, Models returns `{ models: ... }`, ContentSafety returns `{ result: { blocked:, reasons:, categories:, raw: } }`.
|
|
94
|
+
- `include Legion::Extensions::Helpers::Lex` is guarded with `const_defined?` pattern in all runner modules.
|
|
95
|
+
- **Identity module** is credential-only (`provider_type: :credential`). Resolves API key from `Legion::Settings.dig(:llm, :providers, :azure, :api_key)`.
|
|
96
|
+
|
|
97
|
+
## File Map
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
lib/legion/extensions/azure_ai.rb # Entry point, requires all modules
|
|
101
|
+
lib/legion/extensions/azure_ai/version.rb # VERSION constant
|
|
102
|
+
lib/legion/extensions/azure_ai/helpers/client.rb # Faraday factory methods (client + content_safety_client)
|
|
103
|
+
lib/legion/extensions/azure_ai/runners/chat.rb # Chat completions runner
|
|
104
|
+
lib/legion/extensions/azure_ai/runners/embeddings.rb # Embeddings runner
|
|
105
|
+
lib/legion/extensions/azure_ai/runners/models.rb # Model listing runner
|
|
106
|
+
lib/legion/extensions/azure_ai/runners/content_safety.rb # Content Safety text analysis runner
|
|
107
|
+
lib/legion/extensions/azure_ai/client.rb # Standalone Client class
|
|
108
|
+
lib/legion/extensions/azure_ai/identity.rb # Broker identity integration
|
|
109
|
+
|
|
110
|
+
spec/legion/extensions/azure_ai/runners/chat_spec.rb # 9 examples
|
|
111
|
+
spec/legion/extensions/azure_ai/runners/embeddings_spec.rb # 9 examples
|
|
112
|
+
spec/legion/extensions/azure_ai/runners/models_spec.rb # 4 examples
|
|
113
|
+
spec/legion/extensions/azure_ai/runners/content_safety_spec.rb # 10 examples
|
|
114
|
+
spec/legion/extensions/azure_ai/identity_spec.rb # 8 examples
|
|
115
|
+
spec/client_spec.rb # 5 examples
|
|
116
|
+
```
|
|
40
117
|
|
|
41
118
|
## Dependencies
|
|
42
119
|
|
|
43
120
|
| Gem | Purpose |
|
|
44
121
|
|-----|---------|
|
|
45
|
-
| `faraday` >= 2.0 | HTTP client for Azure OpenAI
|
|
122
|
+
| `faraday` >= 2.0 | HTTP client for Azure OpenAI and Content Safety APIs |
|
|
46
123
|
| `multi_json` | JSON parser abstraction |
|
|
124
|
+
| `legion-cache`, `legion-crypt`, `legion-data`, `legion-json`, `legion-logging`, `legion-settings`, `legion-transport` | LegionIO core |
|
|
47
125
|
|
|
48
126
|
## Testing
|
|
49
127
|
|
|
50
128
|
```bash
|
|
51
129
|
bundle install
|
|
52
|
-
bundle exec rspec #
|
|
53
|
-
bundle exec rubocop
|
|
130
|
+
bundle exec rspec # 45 examples
|
|
131
|
+
bundle exec rubocop # 0 offenses expected
|
|
54
132
|
```
|
|
55
133
|
|
|
134
|
+
All specs use Faraday instance doubles — no network calls. The test pattern is:
|
|
135
|
+
1. Create an anonymous class that `extend`s the runner module
|
|
136
|
+
2. Stub `Faraday.new` to return an instance double
|
|
137
|
+
3. Assert on paths, request bodies, and parsed response structures
|
|
138
|
+
|
|
56
139
|
---
|
|
57
140
|
|
|
58
141
|
**Maintained By**: Matthew Iverson (@Esity)
|
|
142
|
+
**Last Updated**: 2026-04-17
|
data/README.md
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# lex-azure-ai
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://rubygems.org/gems/lex-azure-ai)
|
|
4
|
+
[](https://www.ruby-lang.org)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
Legion Extension that connects LegionIO to Azure AI Services — Azure OpenAI and Azure AI Content Safety.
|
|
4
8
|
|
|
5
9
|
## Purpose
|
|
6
10
|
|
|
7
|
-
Wraps the Azure
|
|
11
|
+
Wraps the Azure AI REST APIs as named runners consumable by any LegionIO task chain. Provides chat completions, embeddings, model listing, and content safety moderation. Use this extension when you need direct access to the Azure AI API surface within the LEX runner/actor lifecycle. For simple chat/embed workflows, consider `legion-llm` instead.
|
|
8
12
|
|
|
9
13
|
## Installation
|
|
10
14
|
|
|
@@ -14,62 +18,164 @@ Add to your Gemfile:
|
|
|
14
18
|
gem 'lex-azure-ai'
|
|
15
19
|
```
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
Then run:
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
```bash
|
|
24
|
+
bundle install
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
20
28
|
|
|
21
29
|
```ruby
|
|
22
30
|
require 'legion/extensions/azure_ai'
|
|
23
31
|
|
|
24
32
|
client = Legion::Extensions::AzureAi::Client.new(
|
|
25
|
-
api_key:
|
|
26
|
-
endpoint: 'my-resource'
|
|
27
|
-
api_version: '2024-10-21'
|
|
33
|
+
api_key: 'your-azure-api-key',
|
|
34
|
+
endpoint: 'my-resource'
|
|
28
35
|
)
|
|
29
36
|
|
|
30
|
-
|
|
37
|
+
# Chat completion
|
|
38
|
+
chat = client.create(
|
|
31
39
|
deployment: 'gpt-4o',
|
|
32
|
-
messages:
|
|
40
|
+
messages: [{ role: 'user', content: 'Hello!' }]
|
|
33
41
|
)
|
|
42
|
+
puts chat[:result]['choices'].first['message']['content']
|
|
43
|
+
|
|
44
|
+
# Content safety check
|
|
45
|
+
safety = client.check_text(
|
|
46
|
+
content: 'some user-generated text',
|
|
47
|
+
endpoint: 'my-content-safety-resource',
|
|
48
|
+
api_key: 'your-content-safety-key'
|
|
49
|
+
)
|
|
50
|
+
puts "Blocked: #{safety[:result][:blocked]}"
|
|
34
51
|
```
|
|
35
52
|
|
|
36
|
-
|
|
53
|
+
## API Coverage
|
|
54
|
+
|
|
55
|
+
| Runner | Method | Azure API | Auth Header |
|
|
56
|
+
|--------|--------|-----------|-------------|
|
|
57
|
+
| `Chat` | `create` | Azure OpenAI — Chat Completions | `api-key` |
|
|
58
|
+
| `Embeddings` | `create` | Azure OpenAI — Embeddings | `api-key` |
|
|
59
|
+
| `Models` | `list` | Azure OpenAI — Models | `api-key` |
|
|
60
|
+
| `ContentSafety` | `check_text` | Azure AI Content Safety — `text:analyze` | `Ocp-Apim-Subscription-Key` |
|
|
61
|
+
|
|
62
|
+
## Usage
|
|
63
|
+
|
|
64
|
+
### Chat Completions
|
|
37
65
|
|
|
38
66
|
```ruby
|
|
39
|
-
Legion::Extensions::AzureAi::Runners::Chat.create(
|
|
40
|
-
deployment:
|
|
41
|
-
messages:
|
|
42
|
-
api_key:
|
|
43
|
-
endpoint:
|
|
67
|
+
result = Legion::Extensions::AzureAi::Runners::Chat.create(
|
|
68
|
+
deployment: 'gpt-4o',
|
|
69
|
+
messages: [{ role: 'user', content: 'Hello!' }],
|
|
70
|
+
api_key: 'your-key',
|
|
71
|
+
endpoint: 'my-resource',
|
|
72
|
+
temperature: 0.7, # optional
|
|
73
|
+
max_tokens: 1000 # optional
|
|
44
74
|
)
|
|
75
|
+
# => { result: { 'choices' => [...], 'usage' => {...} },
|
|
76
|
+
# usage: { input_tokens: 10, output_tokens: 20, ... } }
|
|
77
|
+
```
|
|
45
78
|
|
|
46
|
-
|
|
79
|
+
### Embeddings
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
result = Legion::Extensions::AzureAi::Runners::Embeddings.create(
|
|
47
83
|
deployment: 'text-embedding-ada-002',
|
|
48
|
-
input:
|
|
49
|
-
api_key:
|
|
50
|
-
endpoint:
|
|
84
|
+
input: 'Hello world',
|
|
85
|
+
api_key: 'your-key',
|
|
86
|
+
endpoint: 'my-resource'
|
|
51
87
|
)
|
|
88
|
+
# => { result: { 'data' => [{ 'embedding' => [...] }] },
|
|
89
|
+
# usage: { input_tokens: 2, output_tokens: 0, ... } }
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Models
|
|
52
93
|
|
|
53
|
-
|
|
54
|
-
|
|
94
|
+
```ruby
|
|
95
|
+
result = Legion::Extensions::AzureAi::Runners::Models.list(
|
|
96
|
+
api_key: 'your-key',
|
|
55
97
|
endpoint: 'my-resource'
|
|
56
98
|
)
|
|
99
|
+
# => { models: { 'data' => [{ 'id' => 'gpt-4o' }, ...] } }
|
|
57
100
|
```
|
|
58
101
|
|
|
59
|
-
|
|
102
|
+
### Content Safety
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
result = Legion::Extensions::AzureAi::Runners::ContentSafety.check_text(
|
|
106
|
+
content: 'text to analyze',
|
|
107
|
+
api_key: 'your-content-safety-key',
|
|
108
|
+
endpoint: 'my-content-safety-resource',
|
|
109
|
+
severity_threshold: 2, # default 2, range 0-6
|
|
110
|
+
categories: %w[Hate Violence], # optional filter; defaults to all four
|
|
111
|
+
api_version: '2024-09-01' # default
|
|
112
|
+
)
|
|
113
|
+
# => { result: {
|
|
114
|
+
# blocked: false,
|
|
115
|
+
# reasons: [],
|
|
116
|
+
# categories: [
|
|
117
|
+
# { 'category' => 'Hate', 'severity' => 0 },
|
|
118
|
+
# { 'category' => 'Violence', 'severity' => 0 }, ...
|
|
119
|
+
# ],
|
|
120
|
+
# raw: { ... }
|
|
121
|
+
# } }
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Categories:** Hate, Violence, SelfHarm, Sexual — severity range 0–6. Any category at or above `severity_threshold` triggers `blocked: true`.
|
|
125
|
+
|
|
126
|
+
### Standalone Client
|
|
127
|
+
|
|
128
|
+
The `Client` class includes all runners and stores credentials so you don't repeat them:
|
|
129
|
+
|
|
130
|
+
```ruby
|
|
131
|
+
client = Legion::Extensions::AzureAi::Client.new(
|
|
132
|
+
api_key: 'your-key',
|
|
133
|
+
endpoint: 'my-resource',
|
|
134
|
+
api_version: '2024-10-21' # default
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
client.create(deployment: 'gpt-4o', messages: [...])
|
|
138
|
+
client.list
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
> **Note:** `check_text` requires `endpoint:` and `api_key:` as explicit arguments because Content Safety uses a different Azure resource and auth mechanism than OpenAI.
|
|
60
142
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
|
143
|
+
## Azure Service Endpoints
|
|
144
|
+
|
|
145
|
+
This gem talks to two distinct Azure services with different base URLs and authentication:
|
|
146
|
+
|
|
147
|
+
| Service | Base URL | Auth Header |
|
|
148
|
+
|---------|----------|-------------|
|
|
149
|
+
| Azure OpenAI | `https://{endpoint}.openai.azure.com` | `api-key` |
|
|
150
|
+
| Azure AI Content Safety | `https://{endpoint}.cognitiveservices.azure.com` | `Ocp-Apim-Subscription-Key` |
|
|
151
|
+
|
|
152
|
+
The `endpoint` parameter is typically the Azure resource name (e.g., `my-resource`).
|
|
153
|
+
|
|
154
|
+
## Identity
|
|
155
|
+
|
|
156
|
+
The `Identity` module provides credential-only integration with the LegionIO Broker identity system:
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
Legion::Extensions::AzureAi::Identity.provide_token
|
|
160
|
+
# => Legion::Identity::Lease (or nil if no key configured)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
API keys are resolved from `Legion::Settings` at `:llm → :providers → :azure → :api_key`.
|
|
164
|
+
|
|
165
|
+
## Development
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
bundle install
|
|
169
|
+
bundle exec rspec # 45 examples, 5 spec files
|
|
170
|
+
bundle exec rubocop # 0 offenses expected
|
|
171
|
+
```
|
|
66
172
|
|
|
67
173
|
## Related
|
|
68
174
|
|
|
69
|
-
- `lex-foundry` — Azure AI Foundry management API (model catalog, deployments, connections)
|
|
70
|
-
- `legion-llm` — High-level LLM interface across all providers including Azure OpenAI
|
|
71
|
-
- `extensions-ai/CLAUDE.md` — Architecture patterns shared across all AI extensions
|
|
175
|
+
- [`lex-foundry`](https://github.com/LegionIO/lex-foundry) — Azure AI Foundry management API (model catalog, deployments, connections)
|
|
176
|
+
- [`legion-llm`](https://github.com/LegionIO/legion-llm) — High-level LLM interface across all providers including Azure OpenAI
|
|
177
|
+
- [`extensions-ai/CLAUDE.md`](../CLAUDE.md) — Architecture patterns shared across all AI extensions
|
|
72
178
|
|
|
73
179
|
## License
|
|
74
180
|
|
|
75
|
-
MIT
|
|
181
|
+
MIT — see [LICENSE](LICENSE) for details.
|
|
@@ -4,6 +4,7 @@ require 'legion/extensions/azure_ai/helpers/client'
|
|
|
4
4
|
require 'legion/extensions/azure_ai/runners/chat'
|
|
5
5
|
require 'legion/extensions/azure_ai/runners/embeddings'
|
|
6
6
|
require 'legion/extensions/azure_ai/runners/models'
|
|
7
|
+
require 'legion/extensions/azure_ai/runners/content_safety'
|
|
7
8
|
|
|
8
9
|
module Legion
|
|
9
10
|
module Extensions
|
|
@@ -12,6 +13,7 @@ module Legion
|
|
|
12
13
|
include Legion::Extensions::AzureAi::Runners::Chat
|
|
13
14
|
include Legion::Extensions::AzureAi::Runners::Embeddings
|
|
14
15
|
include Legion::Extensions::AzureAi::Runners::Models
|
|
16
|
+
include Legion::Extensions::AzureAi::Runners::ContentSafety
|
|
15
17
|
|
|
16
18
|
attr_reader :config
|
|
17
19
|
|
|
@@ -18,6 +18,15 @@ module Legion
|
|
|
18
18
|
conn.headers['Content-Type'] = 'application/json'
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
|
+
|
|
22
|
+
def content_safety_client(api_key:, endpoint:, **)
|
|
23
|
+
Faraday.new(url: "https://#{endpoint}.cognitiveservices.azure.com") do |conn|
|
|
24
|
+
conn.request :json
|
|
25
|
+
conn.response :json, content_type: /\bjson$/
|
|
26
|
+
conn.headers['Ocp-Apim-Subscription-Key'] = api_key
|
|
27
|
+
conn.headers['Content-Type'] = 'application/json'
|
|
28
|
+
end
|
|
29
|
+
end
|
|
21
30
|
end
|
|
22
31
|
end
|
|
23
32
|
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module AzureAi
|
|
6
|
+
module Identity
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def provider_name = :azure
|
|
10
|
+
def provider_type = :credential
|
|
11
|
+
def facing = nil
|
|
12
|
+
def capabilities = %i[credentials]
|
|
13
|
+
|
|
14
|
+
def resolve(canonical_name: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
15
|
+
nil
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def provide_token
|
|
19
|
+
api_key = resolve_api_key
|
|
20
|
+
return nil unless api_key
|
|
21
|
+
|
|
22
|
+
Legion::Identity::Lease.new(
|
|
23
|
+
provider: :azure,
|
|
24
|
+
credential: api_key,
|
|
25
|
+
expires_at: nil,
|
|
26
|
+
renewable: false,
|
|
27
|
+
issued_at: Time.now,
|
|
28
|
+
metadata: { credential_type: :api_key }
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def resolve_api_key
|
|
33
|
+
return nil unless defined?(Legion::Settings)
|
|
34
|
+
|
|
35
|
+
value = Legion::Settings.dig(:llm, :providers, :azure, :api_key)
|
|
36
|
+
value = value.find { |v| v && !v.empty? } if value.is_a?(Array)
|
|
37
|
+
value unless value.nil? || (value.is_a?(String) && (value.empty? || value.start_with?('env://')))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private_class_method :resolve_api_key
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/azure_ai/helpers/client'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module AzureAi
|
|
8
|
+
module Runners
|
|
9
|
+
module ContentSafety
|
|
10
|
+
extend Legion::Extensions::AzureAi::Helpers::Client
|
|
11
|
+
|
|
12
|
+
def check_text(content:, endpoint:, api_key:, severity_threshold: 2,
|
|
13
|
+
categories: nil, api_version: '2024-09-01', **)
|
|
14
|
+
body = { text: content }
|
|
15
|
+
body[:categories] = categories if categories
|
|
16
|
+
|
|
17
|
+
path = "/contentsafety/text:analyze?api-version=#{api_version}"
|
|
18
|
+
response = content_safety_client(api_key: api_key, endpoint: endpoint).post(path, body)
|
|
19
|
+
|
|
20
|
+
categories_analysis = response.body['categoriesAnalysis'] || []
|
|
21
|
+
blocked_categories = categories_analysis.select { |c| c['severity'] >= severity_threshold }
|
|
22
|
+
|
|
23
|
+
{
|
|
24
|
+
result: {
|
|
25
|
+
blocked: !blocked_categories.empty?,
|
|
26
|
+
reasons: blocked_categories.map { |c| c['category'] },
|
|
27
|
+
categories: categories_analysis,
|
|
28
|
+
raw: response.body
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
|
|
34
|
+
Legion::Extensions::Helpers.const_defined?(:Lex, false)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -5,7 +5,9 @@ require 'legion/extensions/azure_ai/helpers/client'
|
|
|
5
5
|
require 'legion/extensions/azure_ai/runners/chat'
|
|
6
6
|
require 'legion/extensions/azure_ai/runners/embeddings'
|
|
7
7
|
require 'legion/extensions/azure_ai/runners/models'
|
|
8
|
+
require 'legion/extensions/azure_ai/runners/content_safety'
|
|
8
9
|
require 'legion/extensions/azure_ai/client'
|
|
10
|
+
require 'legion/extensions/azure_ai/identity'
|
|
9
11
|
|
|
10
12
|
module Legion
|
|
11
13
|
module Extensions
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lex-azure-ai
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -157,7 +157,9 @@ files:
|
|
|
157
157
|
- lib/legion/extensions/azure_ai.rb
|
|
158
158
|
- lib/legion/extensions/azure_ai/client.rb
|
|
159
159
|
- lib/legion/extensions/azure_ai/helpers/client.rb
|
|
160
|
+
- lib/legion/extensions/azure_ai/identity.rb
|
|
160
161
|
- lib/legion/extensions/azure_ai/runners/chat.rb
|
|
162
|
+
- lib/legion/extensions/azure_ai/runners/content_safety.rb
|
|
161
163
|
- lib/legion/extensions/azure_ai/runners/embeddings.rb
|
|
162
164
|
- lib/legion/extensions/azure_ai/runners/models.rb
|
|
163
165
|
- lib/legion/extensions/azure_ai/version.rb
|