vibe_if 0.1.2
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +78 -0
- data/lib/vibe_if/configuration.rb +23 -0
- data/lib/vibe_if/evaluator.rb +118 -0
- data/lib/vibe_if/version.rb +3 -0
- data/lib/vibe_if.rb +85 -0
- metadata +66 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5fdd14e739691bac5fe7835d8a9fbd5c408e78dec3cdca5105747b964938df06
|
4
|
+
data.tar.gz: 9ed1e59682dfd53a5d4ff57b750ab41f442cb3cb8f6bf3fd195eecf0f3606c01
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a812c63278cacfb65fb9388da8a311678f033397353d59aca46e16a9fbae12bd3259171050045b867786061fe2ff53e2055657881e706e022b0061feaf0b9387
|
7
|
+
data.tar.gz: fc0663882a1ab0d2447e4f746a9bf3aef38069c13e0cce900708c6024d6f25c78edcfaa689b2ad27c068d8147364353ccebd34288665a1ac1240b38f67fb51d9
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 VibeIf
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
# VibeIf
|
2
|
+
|
3
|
+
A Ruby gem that uses OpenAI to evaluate your instance variables and conditionally execute code blocks based on natural language descriptions.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'vibe_if'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
```bash
|
15
|
+
$ bundle install
|
16
|
+
```
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
```bash
|
20
|
+
$ gem install vibe_if
|
21
|
+
```
|
22
|
+
|
23
|
+
## Setup
|
24
|
+
|
25
|
+
Create an initializer (e.g., `config/initializers/vibe_if.rb` for Rails) or configure at the top of your script:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
require 'vibe_if'
|
29
|
+
|
30
|
+
VibeIf.configure do |config|
|
31
|
+
config.openai_api_key = ENV['OPENAI_API_KEY'] # or your API key
|
32
|
+
config.model = 'gpt-3.5-turbo' # optional, defaults to gpt-3.5-turbo
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
## Usage
|
37
|
+
|
38
|
+
Use the `vibe_if` method on any object to conditionally execute code based on natural language conditions:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
class User
|
42
|
+
def initialize(name, age, status)
|
43
|
+
@name = name
|
44
|
+
@age = age
|
45
|
+
@status = status
|
46
|
+
end
|
47
|
+
|
48
|
+
def check_eligibility
|
49
|
+
vibe_if "user is an adult and active" do
|
50
|
+
puts "#{@name} is eligible!"
|
51
|
+
end
|
52
|
+
|
53
|
+
vibe_if "user seems unhappy or inactive" do
|
54
|
+
puts "Reaching out to #{@name}..."
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
user = User.new("Alice", 25, "active")
|
60
|
+
user.check_eligibility
|
61
|
+
```
|
62
|
+
|
63
|
+
The gem will send your instance variables to OpenAI, which evaluates the condition and returns true/false to determine whether the block should execute.
|
64
|
+
|
65
|
+
## Environment Variables
|
66
|
+
|
67
|
+
Set your OpenAI API key:
|
68
|
+
```bash
|
69
|
+
export OPENAI_API_KEY="your-openai-api-key-here"
|
70
|
+
```
|
71
|
+
|
72
|
+
## Inspiration
|
73
|
+
|
74
|
+
This gem was inspired by [vibesort](https://github.com/abyesilyurt/vibesort), a Python library that uses GPT for AI-powered array sorting.
|
75
|
+
|
76
|
+
## License
|
77
|
+
|
78
|
+
The gem is available as open source under the [MIT License](LICENSE).
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module VibeIf
|
2
|
+
# Configuration class for VibeIf settings.
|
3
|
+
# Manages OpenAI API credentials and model parameters.
|
4
|
+
class Configuration
|
5
|
+
# @!attribute [rw] openai_api_key
|
6
|
+
# @return [String, nil] the OpenAI API key for authentication
|
7
|
+
# @!attribute [rw] model
|
8
|
+
# @return [String] the OpenAI model to use for evaluation (default: "gpt-3.5-turbo")
|
9
|
+
# @!attribute [rw] max_tokens
|
10
|
+
# @return [Integer] maximum tokens for the AI response (default: 10)
|
11
|
+
# @!attribute [rw] temperature
|
12
|
+
# @return [Float] temperature setting for AI responses, lower values are more deterministic (default: 0.1)
|
13
|
+
attr_accessor :openai_api_key, :model, :max_tokens, :temperature
|
14
|
+
|
15
|
+
# Initializes a new Configuration with default values.
|
16
|
+
def initialize
|
17
|
+
@openai_api_key = nil
|
18
|
+
@model = "gpt-3.5-turbo"
|
19
|
+
@max_tokens = 50
|
20
|
+
@temperature = 0.1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'openai'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module VibeIf
|
5
|
+
# Evaluator handles the AI-powered evaluation of natural language conditions.
|
6
|
+
# It extracts context from objects and uses OpenAI to determine condition truthiness.
|
7
|
+
class Evaluator
|
8
|
+
# Initializes the evaluator with a context object.
|
9
|
+
#
|
10
|
+
# @param context_object [Object] the object whose state will be evaluated
|
11
|
+
# @raise [RuntimeError] if OpenAI API key is not configured
|
12
|
+
def initialize(context_object)
|
13
|
+
@context_object = context_object
|
14
|
+
@config = VibeIf.configuration
|
15
|
+
validate_configuration
|
16
|
+
end
|
17
|
+
|
18
|
+
# Evaluates a natural language condition against the context object.
|
19
|
+
#
|
20
|
+
# @param condition_description [String] the condition to evaluate in natural language
|
21
|
+
# @return [Boolean] true if the condition is met, false otherwise
|
22
|
+
# @raise [RuntimeError] if evaluation fails due to API errors or other issues
|
23
|
+
#
|
24
|
+
# @example Nuanced writing quality assessment
|
25
|
+
# essay = StudentEssay.new(
|
26
|
+
# text: "Technology has revolutionized our lives. It helps us connect with people. But also creates problems like addiction and privacy issues.",
|
27
|
+
# grade_level: "high_school",
|
28
|
+
# word_count: 1200,
|
29
|
+
# assignment: "argumentative_essay"
|
30
|
+
# )
|
31
|
+
# evaluator = VibeIf::Evaluator.new(essay)
|
32
|
+
# evaluator.evaluate("this essay demonstrates sophisticated critical thinking and analysis")
|
33
|
+
# # => false (LLM detects simplistic reasoning despite meeting word count)
|
34
|
+
#
|
35
|
+
# @example Intent detection from ambiguous text
|
36
|
+
# message = CustomerMessage.new(
|
37
|
+
# text: "I guess the product is fine for what it is",
|
38
|
+
# context: "post_purchase_survey",
|
39
|
+
# customer_history: "previous_complaints",
|
40
|
+
# product_category: "premium"
|
41
|
+
# )
|
42
|
+
# evaluator = VibeIf::Evaluator.new(message)
|
43
|
+
# evaluator.evaluate("this customer is expressing subtle dissatisfaction")
|
44
|
+
# # => true (LLM detects lukewarm sentiment and contextual disappointment)
|
45
|
+
def evaluate(condition_description)
|
46
|
+
variables = extract_variables
|
47
|
+
prompt = build_prompt(condition_description, variables)
|
48
|
+
|
49
|
+
response = openai_client.chat.completions.create(
|
50
|
+
model: @config.model,
|
51
|
+
messages: [{ role: "user", content: prompt }],
|
52
|
+
max_tokens: @config.max_tokens,
|
53
|
+
temperature: @config.temperature
|
54
|
+
)
|
55
|
+
|
56
|
+
parse_response(response)
|
57
|
+
rescue => e
|
58
|
+
raise "VibeIf evaluation failed: #{e.message}"
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def validate_configuration
|
64
|
+
return if @config.openai_api_key
|
65
|
+
|
66
|
+
raise "OpenAI API key not configured. Use VibeIf.configure to set it."
|
67
|
+
end
|
68
|
+
|
69
|
+
def openai_client
|
70
|
+
@openai_client ||= OpenAI::Client.new(api_key: @config.openai_api_key)
|
71
|
+
end
|
72
|
+
|
73
|
+
def extract_variables
|
74
|
+
variables = {}
|
75
|
+
|
76
|
+
@context_object.instance_variables.each do |var|
|
77
|
+
name = var.to_s.delete('@')
|
78
|
+
value = @context_object.instance_variable_get(var)
|
79
|
+
variables[name] = serialize_value(value)
|
80
|
+
end
|
81
|
+
|
82
|
+
variables
|
83
|
+
end
|
84
|
+
|
85
|
+
def serialize_value(value)
|
86
|
+
case value
|
87
|
+
when String, Numeric, TrueClass, FalseClass, NilClass
|
88
|
+
value
|
89
|
+
when Array, Hash
|
90
|
+
value.inspect
|
91
|
+
else
|
92
|
+
value.to_s
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def build_prompt(condition_description, variables)
|
97
|
+
variables_text = variables.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
|
98
|
+
|
99
|
+
<<~PROMPT
|
100
|
+
You are evaluating whether a condition is true based on the given data.
|
101
|
+
|
102
|
+
Object data:
|
103
|
+
#{variables_text}
|
104
|
+
|
105
|
+
Condition to evaluate: "#{condition_description}"
|
106
|
+
|
107
|
+
Consider the context and meaning carefully. For content quality, look for evidence-based information, credible sources, and reasonable claims. For sentiment, consider tone and subtext beyond surface words.
|
108
|
+
|
109
|
+
Respond with exactly "true" or "false" (no quotes, no explanation).
|
110
|
+
PROMPT
|
111
|
+
end
|
112
|
+
|
113
|
+
def parse_response(response)
|
114
|
+
result = response.choices.first.message.content&.strip&.downcase
|
115
|
+
result == "true"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/vibe_if.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require "vibe_if/version"
|
2
|
+
require "vibe_if/configuration"
|
3
|
+
require "vibe_if/evaluator"
|
4
|
+
|
5
|
+
# VibeIf provides natural language conditional evaluation using AI.
|
6
|
+
# It allows you to write conditions in plain English that are evaluated
|
7
|
+
# based on the current object's state.
|
8
|
+
module VibeIf
|
9
|
+
class << self
|
10
|
+
# Returns the current configuration instance.
|
11
|
+
#
|
12
|
+
# @return [VibeIf::Configuration] the configuration object
|
13
|
+
def configuration
|
14
|
+
@configuration ||= Configuration.new
|
15
|
+
end
|
16
|
+
|
17
|
+
# Configures VibeIf by yielding the configuration object to a block.
|
18
|
+
#
|
19
|
+
# @yield [config] the configuration object to modify
|
20
|
+
# @yieldparam config [VibeIf::Configuration] the configuration instance
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# VibeIf.configure do |config|
|
24
|
+
# config.openai_api_key = "your-api-key"
|
25
|
+
# config.model = "gpt-4"
|
26
|
+
# end
|
27
|
+
def configure
|
28
|
+
yield(configuration)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Object
|
34
|
+
# Evaluates a natural language condition against the current object's state.
|
35
|
+
# Uses AI to determine if the condition is true or false based on instance variables.
|
36
|
+
#
|
37
|
+
# @param condition_description [String] the condition to evaluate in natural language
|
38
|
+
# @yield optional block to execute if condition is true
|
39
|
+
# @return [Boolean] true if condition evaluates to true, false otherwise
|
40
|
+
#
|
41
|
+
# @example Sentiment-based content promotion
|
42
|
+
# review = Review.new(
|
43
|
+
# text: "The food was okay but the service was incredibly rude and slow",
|
44
|
+
# rating: 3,
|
45
|
+
# restaurant_tier: "premium"
|
46
|
+
# )
|
47
|
+
# review.vibe_if("this review expresses genuine disappointment despite the neutral rating") do
|
48
|
+
# review.escalate_to_management!
|
49
|
+
# end
|
50
|
+
# # => true (LLM detects negative sentiment despite 3-star rating)
|
51
|
+
#
|
52
|
+
# @example Context-aware content quality assessment
|
53
|
+
# article = BlogPost.new(
|
54
|
+
# title: "10 Ways to Lose Weight Fast",
|
55
|
+
# content: "Drink this magic tea and lose 20 pounds in 3 days!",
|
56
|
+
# author_credentials: "fitness_blogger",
|
57
|
+
# word_count: 500
|
58
|
+
# )
|
59
|
+
# unless article.vibe_if("this content provides valuable, evidence-based information")
|
60
|
+
# article.demote_in_search!
|
61
|
+
# end
|
62
|
+
# # => false (LLM detects questionable health claims)
|
63
|
+
#
|
64
|
+
# @example Intelligent customer support routing
|
65
|
+
# ticket = SupportTicket.new(
|
66
|
+
# subject: "My order never arrived",
|
67
|
+
# message: "I'm really frustrated, this is the third time this happened",
|
68
|
+
# customer_tier: "vip",
|
69
|
+
# previous_issues: 2
|
70
|
+
# )
|
71
|
+
# ticket.vibe_if("this customer seems genuinely upset and needs immediate attention") do
|
72
|
+
# ticket.assign_to_senior_agent!
|
73
|
+
# end
|
74
|
+
# # => true (LLM detects frustration and escalation patterns)
|
75
|
+
def vibe_if(condition_description, &block)
|
76
|
+
evaluator = VibeIf::Evaluator.new(self)
|
77
|
+
|
78
|
+
if evaluator.evaluate(condition_description)
|
79
|
+
yield if block_given?
|
80
|
+
true
|
81
|
+
else
|
82
|
+
false
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vibe_if
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- CuddlyBunion341
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-09-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: openai
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.19'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.19'
|
27
|
+
description: A Ruby gem that uses OpenAI to evaluate instance variables and local
|
28
|
+
variables, returning true/false to conditionally execute code blocks. Inspired by
|
29
|
+
vibesort (https://github.com/abyesilyurt/vibesort).
|
30
|
+
email:
|
31
|
+
- daniel.bengl@renuo.ch
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- LICENSE
|
37
|
+
- README.md
|
38
|
+
- lib/vibe_if.rb
|
39
|
+
- lib/vibe_if/configuration.rb
|
40
|
+
- lib/vibe_if/evaluator.rb
|
41
|
+
- lib/vibe_if/version.rb
|
42
|
+
homepage: https://github.com/CuddlyBunion341/vibe_if
|
43
|
+
licenses:
|
44
|
+
- MIT
|
45
|
+
metadata:
|
46
|
+
source_code_uri: https://github.com/CuddlyBunion341/vibe_if
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 2.7.0
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
requirements: []
|
62
|
+
rubygems_version: 3.4.10
|
63
|
+
signing_key:
|
64
|
+
specification_version: 4
|
65
|
+
summary: GPT-powered conditional execution based on variable values
|
66
|
+
test_files: []
|