llm_conductor 0.1.1 → 1.0.0
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/.rubocop.yml +16 -12
- data/README.md +10 -32
- data/lib/llm_conductor/prompts.rb +112 -96
- data/lib/llm_conductor/version.rb +1 -1
- data/lib/llm_conductor.rb +4 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c692236c5d26b598a2275a3a6591022312aec4e4a4d4ee57a186abc774bc39ce
|
4
|
+
data.tar.gz: 3c20edc85442b8e5227fb6896d3899f08495fa1296306042c07c8bc62a883941
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ed23461382c3a8ee2fddea05fdaef5c72111bac8e4b820e4310a40105a8b0bd78b8f1c36c9176f9ac7ddf8c7b4300e9208b45711a129ab0531dd579f9a52964
|
7
|
+
data.tar.gz: d446efb23252acee7ea453361d402089b87c56450e20ed7e45b1aab2cd0381bff442ed51ea7e2a52a544c39f3117795ad17ac2208dc12514f211d12ba150bb2c
|
data/.rubocop.yml
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
plugins:
|
3
3
|
- rubocop-performance
|
4
4
|
- rubocop-rake
|
5
|
-
|
6
|
-
require:
|
7
5
|
- rubocop-capybara
|
8
6
|
- rubocop-factory_bot
|
9
7
|
- rubocop-rspec
|
@@ -27,21 +25,14 @@ Style/StringLiteralsInInterpolation:
|
|
27
25
|
|
28
26
|
Style/HashSyntax:
|
29
27
|
EnforcedShorthandSyntax: always
|
30
|
-
# This is not rails application.
|
31
|
-
# Rails/Blank:
|
32
|
-
# Enabled: false
|
33
|
-
|
34
|
-
# Rails/Present:
|
35
|
-
# Enabled: false
|
36
|
-
|
37
|
-
# Rails/TimeZone:
|
38
|
-
# Enabled: false
|
39
28
|
|
40
29
|
Lint/ConstantDefinitionInBlock:
|
41
30
|
Enabled: false
|
42
31
|
|
43
32
|
Metrics/MethodLength:
|
44
33
|
Max: 15
|
34
|
+
Exclude:
|
35
|
+
- 'lib/llm_conductor/prompts.rb'
|
45
36
|
|
46
37
|
RSpec/ExampleLength:
|
47
38
|
Enabled: false
|
@@ -67,7 +58,7 @@ RSpec/MultipleDescribes:
|
|
67
58
|
RSpec/SpecFilePathFormat:
|
68
59
|
Enabled: false
|
69
60
|
|
70
|
-
RSpec/
|
61
|
+
RSpec/SpecFilePathSuffix:
|
71
62
|
Enabled: false
|
72
63
|
|
73
64
|
RSpec/UnspecifiedException:
|
@@ -94,6 +85,19 @@ Metrics/BlockLength:
|
|
94
85
|
Exclude:
|
95
86
|
- '*.gemspec'
|
96
87
|
|
88
|
+
# Prompt template methods naturally have high complexity due to conditional string building
|
89
|
+
Metrics/AbcSize:
|
90
|
+
Exclude:
|
91
|
+
- 'lib/llm_conductor/prompts.rb'
|
92
|
+
|
93
|
+
Metrics/CyclomaticComplexity:
|
94
|
+
Exclude:
|
95
|
+
- 'lib/llm_conductor/prompts.rb'
|
96
|
+
|
97
|
+
Metrics/PerceivedComplexity:
|
98
|
+
Exclude:
|
99
|
+
- 'lib/llm_conductor/prompts.rb'
|
100
|
+
|
97
101
|
Layout/LineLength:
|
98
102
|
Max: 120
|
99
103
|
|
data/README.md
CHANGED
@@ -52,14 +52,18 @@ puts response.estimated_cost # Cost in USD
|
|
52
52
|
### 2. Template-Based Generation
|
53
53
|
|
54
54
|
```ruby
|
55
|
-
# Use built-in
|
55
|
+
# Use built-in text summarization template
|
56
56
|
response = LlmConductor.generate(
|
57
57
|
model: 'gpt-5-mini',
|
58
|
-
type: :
|
58
|
+
type: :summarize_text,
|
59
59
|
data: {
|
60
|
-
|
61
|
-
|
62
|
-
|
60
|
+
text: 'Ekohe (ee-koh-hee) means "boundless possibility." Our way is to make AI practical, achievable, and most importantly, useful for you — and we prove it every day. With almost 16 years of wins under our belt, a market-leading 24-hr design & development cycle, and 5 offices in the most vibrant cities in the world, we surf the seas of innovation. We create efficient, elegant, and scalable digital products — delivering the right interactive solutions to achieve your audience and business goals. We help you transform. We break new ground across the globe — from AI and ML automation that drives the enterprise, to innovative customer experiences and mobile apps for startups. Our special sauce is the care, curiosity, and dedication we offer to solve for your needs. We focus on your success and deliver the most impactful experiences in the most efficient manner. Our clients tell us we partner with them in a trusted and capable way, driving the right design and technical choices.',
|
61
|
+
max_length: '20 words',
|
62
|
+
style: 'professional and engaging',
|
63
|
+
focus_areas: ['core business', 'expertise', 'target market'],
|
64
|
+
audience: 'potential investors',
|
65
|
+
include_key_points: true,
|
66
|
+
output_format: 'paragraph'
|
63
67
|
}
|
64
68
|
)
|
65
69
|
|
@@ -67,7 +71,7 @@ response = LlmConductor.generate(
|
|
67
71
|
if response.success?
|
68
72
|
puts "Generated: #{response.output}"
|
69
73
|
puts "Tokens: #{response.total_tokens}"
|
70
|
-
puts "Cost: $#{response.estimated_cost}"
|
74
|
+
puts "Cost: $#{response.estimated_cost || 'N/A (free model)'}"
|
71
75
|
else
|
72
76
|
puts "Error: #{response.metadata[:error]}"
|
73
77
|
end
|
@@ -143,20 +147,6 @@ response = LlmConductor.generate(
|
|
143
147
|
)
|
144
148
|
```
|
145
149
|
|
146
|
-
**Supported Claude Models:**
|
147
|
-
- `claude-3-5-sonnet-20241022` (Latest Claude 3.5 Sonnet)
|
148
|
-
- `claude-3-5-haiku-20241022` (Claude 3.5 Haiku)
|
149
|
-
- `claude-3-opus-20240229` (Claude 3 Opus)
|
150
|
-
- `claude-3-sonnet-20240229` (Claude 3 Sonnet)
|
151
|
-
- `claude-3-haiku-20240307` (Claude 3 Haiku)
|
152
|
-
|
153
|
-
**Why Choose Claude?**
|
154
|
-
- **Superior Reasoning**: Excellent for complex analysis and problem-solving
|
155
|
-
- **Code Generation**: Outstanding performance for programming tasks
|
156
|
-
- **Long Context**: Support for large documents and conversations
|
157
|
-
- **Safety**: Built with safety and helpfulness in mind
|
158
|
-
- **Cost Effective**: Competitive pricing for high-quality outputs
|
159
|
-
|
160
150
|
### Google Gemini (Automatic for Gemini models)
|
161
151
|
```ruby
|
162
152
|
response = LlmConductor.generate(
|
@@ -172,18 +162,6 @@ response = LlmConductor.generate(
|
|
172
162
|
)
|
173
163
|
```
|
174
164
|
|
175
|
-
**Supported Gemini Models:**
|
176
|
-
- `gemini-2.5-flash` (Latest Gemini 2.5 Flash)
|
177
|
-
- `gemini-2.5-flash` (Gemini 2.5 Flash)
|
178
|
-
- `gemini-2.0-flash` (Gemini 2.0 Flash)
|
179
|
-
|
180
|
-
**Why Choose Gemini?**
|
181
|
-
- **Multimodal**: Native support for text, images, and other modalities
|
182
|
-
- **Long Context**: Massive context windows for large documents
|
183
|
-
- **Fast Performance**: Optimized for speed and efficiency
|
184
|
-
- **Google Integration**: Seamless integration with Google services
|
185
|
-
- **Competitive Pricing**: Cost-effective for high-volume usage
|
186
|
-
|
187
165
|
### Ollama (Default for non-GPT/Claude/Gemini models)
|
188
166
|
```ruby
|
189
167
|
response = LlmConductor.generate(
|
@@ -1,124 +1,140 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module LlmConductor
|
4
|
-
# Collection of
|
5
|
-
# content analysis, link extraction, and data summarization.
|
4
|
+
# Collection of general-purpose prompt templates for common LLM tasks
|
6
5
|
module Prompts
|
7
|
-
|
6
|
+
# General prompt for extracting links from HTML content
|
7
|
+
# More flexible and applicable to various use cases
|
8
|
+
def prompt_extract_links(data)
|
9
|
+
criteria = data[:criteria] || 'relevant and useful'
|
10
|
+
max_links = data[:max_links] || 10
|
11
|
+
link_types = data[:link_types] || %w[navigation content footer]
|
12
|
+
|
8
13
|
<<~PROMPT
|
9
|
-
|
14
|
+
Analyze the provided HTML content and extract links based on the specified criteria.
|
15
|
+
|
16
|
+
HTML Content:
|
17
|
+
#{data[:html_content] || data[:htmls]}
|
18
|
+
|
19
|
+
Extraction Criteria: #{criteria}
|
20
|
+
Maximum Links: #{max_links}
|
21
|
+
Link Types to Consider: #{link_types.join(', ')}
|
10
22
|
|
11
|
-
|
12
|
-
<page_html>
|
13
|
-
#{data[:htmls]}
|
14
|
-
</page_html>
|
23
|
+
#{"Domain Filter: Only include links from domain #{data[:domain_filter]}" if data[:domain_filter]}
|
15
24
|
|
16
|
-
|
25
|
+
Instructions:
|
26
|
+
1. Parse the HTML content and identify all hyperlinks
|
27
|
+
2. Filter links based on the provided criteria
|
28
|
+
3. Prioritize links from specified areas: #{link_types.join(', ')}
|
29
|
+
4. Return up to #{max_links} most relevant links
|
30
|
+
#{if data[:format] == :json
|
31
|
+
'5. Format output as a JSON array of URLs'
|
32
|
+
else
|
33
|
+
'5. Format output as a newline-separated list of URLs'
|
34
|
+
end}
|
17
35
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
c. Include social media profile links (e.g., LinkedIn, Instagram, Twitter, Facebook) if available.
|
22
|
-
d. Exclude links to login pages, search pages, or other utility pages.
|
36
|
+
Provide only the links without additional commentary.
|
37
|
+
PROMPT
|
38
|
+
end
|
23
39
|
|
24
|
-
|
40
|
+
# General prompt for content analysis and data extraction
|
41
|
+
# Flexible template for various content analysis tasks
|
42
|
+
def prompt_analyze_content(data)
|
43
|
+
content_type = data[:content_type] || 'webpage content'
|
44
|
+
analysis_fields = data[:fields] || %w[summary key_points entities]
|
45
|
+
output_format = data[:output_format] || 'structured text'
|
25
46
|
|
26
|
-
|
27
|
-
|
28
|
-
["https://example.com/about-us", "https://example.com/products", "https://example.com/services"]
|
29
|
-
</output_format>
|
47
|
+
<<~PROMPT
|
48
|
+
Analyze the provided #{content_type} and extract the requested information.
|
30
49
|
|
31
|
-
|
32
|
-
|
33
|
-
#{data[:current_url]}
|
34
|
-
</domain>
|
50
|
+
Content:
|
51
|
+
#{data[:content] || data[:htmls] || data[:text]}
|
35
52
|
|
36
|
-
|
53
|
+
Analysis Fields:
|
54
|
+
#{analysis_fields.map { |field| "- #{field}" }.join("\n")}
|
37
55
|
|
38
|
-
|
56
|
+
#{"Additional Instructions:\n#{data[:instructions]}" if data[:instructions]}
|
39
57
|
|
40
|
-
|
58
|
+
#{if output_format == 'json'
|
59
|
+
json_structure = analysis_fields.map { |field| " \"#{field}\": \"value or array\"" }.join(",\n")
|
60
|
+
"Output Format: JSON with the following structure:\n{\n#{json_structure}\n}"
|
61
|
+
else
|
62
|
+
"Output Format: #{output_format}"
|
63
|
+
end}
|
64
|
+
|
65
|
+
#{"Constraints:\n#{data[:constraints]}" if data[:constraints]}
|
66
|
+
|
67
|
+
Provide a comprehensive analysis focusing on the requested fields.
|
41
68
|
PROMPT
|
42
69
|
end
|
43
70
|
|
44
|
-
|
71
|
+
# General prompt for text summarization
|
72
|
+
# Applicable to various types of text content
|
73
|
+
def prompt_summarize_text(data)
|
74
|
+
max_length = data[:max_length] || '200 words'
|
75
|
+
focus_areas = data[:focus_areas] || []
|
76
|
+
style = data[:style] || 'concise and informative'
|
77
|
+
|
45
78
|
<<~PROMPT
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
#{
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
- Product description(product_description): A brief overview of the company's main product(s) or service(s)
|
67
|
-
- Product features(product_features): Key features or capabilities of the product(s) or service(s)
|
68
|
-
- Customers and partners(field customers_and_partners): Notable clients or business partners
|
69
|
-
- Development stage(field development_stage): The current phase of the company (e.g., startup, growth, established)
|
70
|
-
- Social media links(field social_media_links): URLs to the company's social media profiles
|
71
|
-
- instagram_url
|
72
|
-
- linkedin_url
|
73
|
-
- twitter_url
|
74
|
-
|
75
|
-
If any of the above information is not available in the webpage content, use "Not available" as the value for that field.
|
76
|
-
|
77
|
-
Present your findings in a JSON format. Here's an example of the expected structure:
|
78
|
-
|
79
|
-
<output_format>
|
80
|
-
{
|
81
|
-
"name": "AI-powered customer service",
|
82
|
-
"domain_name": "example.com",
|
83
|
-
"description": "XYZ Company develops AI chatbots that help businesses automate customer support...",
|
84
|
-
"founding_on": 2018,
|
85
|
-
"country": "United States",
|
86
|
-
"Region": "SA",
|
87
|
-
"Location": "SFO",
|
88
|
-
"business_model": "SaaS subscription",
|
89
|
-
"product_description": "AI-powered chatbot platform for customer service automation",
|
90
|
-
"product_features": ["Natural language processing", "Multi-language support", "Integration with CRM systems"],
|
91
|
-
"customers_and_partners": ["ABC Corp", "123 Industries", "Big Tech Co."],
|
92
|
-
"development_stage": "Growth",
|
93
|
-
"social_media_links": {
|
94
|
-
"linkedin_url": "https://www.linkedin.com/company/xyzcompany",
|
95
|
-
"twitter_url": "https://twitter.com/xyzcompany",
|
96
|
-
"instagram_url": "https://www.instagram.com/xyzcompany"
|
97
|
-
}
|
98
|
-
}
|
99
|
-
</output_format>
|
100
|
-
|
101
|
-
Remember to use only the information provided in the webpage content. Do not include any external information or make assumptions beyond what is explicitly stated or strongly implied in the given content.
|
102
|
-
|
103
|
-
Present your final output in JSON format, enclosed within <json_output> tags.
|
79
|
+
Summarize the following text content.
|
80
|
+
|
81
|
+
Text:
|
82
|
+
#{data[:text] || data[:content] || data[:description]}
|
83
|
+
|
84
|
+
Summary Requirements:
|
85
|
+
- Maximum Length: #{max_length}
|
86
|
+
- Style: #{style}
|
87
|
+
#{"- Focus Areas: #{focus_areas.join(', ')}" if focus_areas.any?}
|
88
|
+
#{"- Target Audience: #{data[:audience]}" if data[:audience]}
|
89
|
+
|
90
|
+
#{'Include key points and main themes.' if data[:include_key_points]}
|
91
|
+
|
92
|
+
#{if data[:output_format] == 'bullet_points'
|
93
|
+
'Format as bullet points.'
|
94
|
+
elsif data[:output_format] == 'paragraph'
|
95
|
+
'Format as a single paragraph.'
|
96
|
+
end}
|
97
|
+
|
98
|
+
Provide a clear and accurate summary.
|
104
99
|
PROMPT
|
105
100
|
end
|
106
101
|
|
107
|
-
|
102
|
+
# General prompt for data classification and categorization
|
103
|
+
# Useful for various classification tasks
|
104
|
+
def prompt_classify_content(data)
|
105
|
+
categories = data[:categories] || []
|
106
|
+
classification_type = data[:classification_type] || 'content'
|
107
|
+
confidence_scores = data[:include_confidence] || false
|
108
|
+
|
108
109
|
<<~PROMPT
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
110
|
+
Classify the provided #{classification_type} into the most appropriate category.
|
111
|
+
|
112
|
+
Content to Classify:
|
113
|
+
#{data[:content] || data[:text] || data[:description]}
|
114
|
+
|
115
|
+
Available Categories:
|
116
|
+
#{categories.map.with_index(1) { |cat, i| "#{i}. #{cat}" }.join("\n")}
|
117
|
+
|
118
|
+
#{"Classification Criteria:\n#{data[:classification_criteria]}" if data[:classification_criteria]}
|
119
|
+
|
120
|
+
#{if confidence_scores
|
121
|
+
'Output Format: JSON with category and confidence score (0-1)'
|
122
|
+
else
|
123
|
+
'Output Format: Return the most appropriate category name'
|
124
|
+
end}
|
125
|
+
|
126
|
+
#{if data[:multiple_categories]
|
127
|
+
"Note: Multiple categories may apply - select up to #{data[:max_categories] || 3} most relevant."
|
128
|
+
else
|
129
|
+
'Note: Select only the single most appropriate category.'
|
130
|
+
end}
|
131
|
+
|
132
|
+
Provide your classification based on the content analysis.
|
119
133
|
PROMPT
|
120
134
|
end
|
121
135
|
|
136
|
+
# Flexible custom prompt template
|
137
|
+
# Allows for dynamic prompt creation with variable substitution
|
122
138
|
def prompt_custom(data)
|
123
139
|
template = data.fetch(:template)
|
124
140
|
template % data
|
data/lib/llm_conductor.rb
CHANGED
@@ -74,9 +74,10 @@ module LlmConductor
|
|
74
74
|
|
75
75
|
# List of supported prompt types
|
76
76
|
SUPPORTED_PROMPT_TYPES = %i[
|
77
|
-
|
78
|
-
|
79
|
-
|
77
|
+
extract_links
|
78
|
+
analyze_content
|
79
|
+
summarize_text
|
80
|
+
classify_content
|
80
81
|
custom
|
81
82
|
].freeze
|
82
83
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: llm_conductor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Zheng
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-09-
|
10
|
+
date: 2025-09-26 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: activesupport
|