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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d62cce58c74c7629813ee041e1170b89b8bf840290e4780df44c498842e74575
4
- data.tar.gz: d7ec97c677ba8c83c3e13fcfacf5e5ac9f3fb34eae518b65d57f21d37e1314e6
3
+ metadata.gz: 0b999c09cc1e7d260fd320f576ffe0bac0c7404e6d74ef210f83e216ab42fdf4
4
+ data.tar.gz: 73e5d2ac265f6b70a96bfbcbb754b44e96eeb202f84021999ce3d80e8ecd90e3
5
5
  SHA512:
6
- metadata.gz: 2658586dd660d0a5dfce414f12932ca82582a7d142ad4605ef7eaf649aaf30368ebb3fd31a48dc6459f3120539622c34c82fd017a68d961e15075a23ae896998
7
- data.tar.gz: dde8723318bf4c19c9c7396d6f2df1f6e25abcbf59f9f24051f1f0fdd1a3f95cc26153955aba57bbf16db34cca825a2a7d0f1c65a556532a70565003b0ab7daf
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 (Azure OpenAI). Provides runners for chat completions, embeddings, and model listing via the Azure OpenAI REST API.
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.2
14
- **Specs**: 22 examples
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 # 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:, ...)
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 # Faraday-based Azure OpenAI client (module, factory method)
26
- └── Client # Standalone client class (includes all runners, holds @config)
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
- `Helpers::Client` is a **module** with a `client(api_key:, endpoint:, ...)` factory method. It builds a Faraday connection to `https://#{endpoint}.openai.azure.com` and sets the `api-key` header. Runner modules `extend` it to gain `client(...)` as a module-level method.
31
+ ### Two Azure Services, Two Clients
30
32
 
31
- `Client` (class) provides a standalone instantiable wrapper. It holds `@config` and delegates through `Helpers::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
- - Authentication uses the `api-key` header (not `Authorization: Bearer`). This is specific to Azure OpenAI — differs from lex-openai which uses Bearer.
36
- - API base URL is constructed from the `endpoint` param: `https://#{endpoint}.openai.azure.com`. The endpoint is typically the Azure resource name (e.g., `my-resource`).
37
- - Default `api_version` is `'2024-10-21'`. All runner methods accept `api_version:` as an override keyword.
38
- - `Models#list` returns `{ models: response.body }` (not `{ result: ... }`). `Chat` and `Embeddings` return `{ result: response.body }`.
39
- - `include Legion::Extensions::Helpers::Lex` is guarded with `const_defined?` pattern.
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 API |
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 # 22 examples
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
- Legion Extension that connects LegionIO to Azure AI Services (Azure OpenAI).
3
+ [![Gem Version](https://img.shields.io/gem/v/lex-azure-ai.svg)](https://rubygems.org/gems/lex-azure-ai)
4
+ [![Ruby](https://img.shields.io/badge/ruby-%3E%3D%203.4-red.svg)](https://www.ruby-lang.org)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](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 OpenAI REST API as named runners consumable by any LegionIO task chain. Provides chat completions, embeddings, and model listing. Use this extension when you need direct access to the Azure OpenAI API surface within the LEX runner/actor lifecycle. For simple chat/embed workflows, consider `legion-llm` instead.
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
- ## Usage
21
+ Then run:
18
22
 
19
- ### Standalone Client
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: 'your-azure-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
- result = client.create(
37
+ # Chat completion
38
+ chat = client.create(
31
39
  deployment: 'gpt-4o',
32
- messages: [{ role: 'user', content: 'Hello!' }]
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
- ### Runners Directly
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: 'gpt-4o',
41
- messages: [{ role: 'user', content: 'Hello!' }],
42
- api_key: 'your-key',
43
- endpoint: 'my-resource'
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
- Legion::Extensions::AzureAi::Runners::Embeddings.create(
79
+ ### Embeddings
80
+
81
+ ```ruby
82
+ result = Legion::Extensions::AzureAi::Runners::Embeddings.create(
47
83
  deployment: 'text-embedding-ada-002',
48
- input: 'Hello world',
49
- api_key: 'your-key',
50
- endpoint: 'my-resource'
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
- Legion::Extensions::AzureAi::Runners::Models.list(
54
- api_key: 'your-key',
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
- ## API Coverage
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
- | Runner | Methods |
62
- |--------|---------|
63
- | `Chat` | `create` |
64
- | `Embeddings` | `create` |
65
- | `Models` | `list` |
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
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module AzureAi
6
- VERSION = '0.1.4'
6
+ VERSION = '0.1.6'
7
7
  end
8
8
  end
9
9
  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
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