openai_101 1.0.0 → 1.2.1

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.builders/_.rb +1 -0
  3. data/.builders/boot.rb +39 -0
  4. data/.builders/generators/01-bootstrap.rb +135 -0
  5. data/.releaserc.json +1 -1
  6. data/.rubocop.yml +7 -24
  7. data/.tool-versions +1 -1
  8. data/CHANGELOG.md +18 -11
  9. data/README.md +41 -65
  10. data/lib/openai101/sample.rb +10 -0
  11. data/lib/{openai_101 → openai101}/version.rb +1 -1
  12. data/lib/openai_101.rb +7 -9
  13. data/package-lock.json +2225 -1386
  14. data/package.json +2 -5
  15. metadata +18 -52
  16. data/bin/automate-chatgpt.js +0 -60
  17. data/bin/automate-midjourney.js +0 -75
  18. data/bin/convert_webp_to_png.rb +0 -86
  19. data/bin/gpt_context_gatherer.rb +0 -63
  20. data/course/course.md +0 -64
  21. data/course/images/beautiful-llm-models.png +0 -0
  22. data/course/images/prompts/beautiful-llm-models.txt +0 -1
  23. data/course/images/prompts/series-2-appydave-gpt-summit.txt +0 -1
  24. data/course/images/series-2-appydave-gpt-summit.png +0 -0
  25. data/gpt-context/openai-documentation.md +0 -498
  26. data/gpt-context/ruby-openai-documenation.md +0 -747
  27. data/gpt-context/theme-prompts.csv +0 -21
  28. data/lib/openai_101/tools/automate-images-chatgpt.js +0 -60
  29. data/lib/openai_101/tools/automate-images-midjourney.js +0 -75
  30. data/lib/openai_101/tools/bulk_image_bot/base_automator.js +0 -53
  31. data/lib/openai_101/tools/bulk_image_bot/chatgpt_automator.js +0 -27
  32. data/lib/openai_101/tools/bulk_image_bot/midjourney_automator.js +0 -49
  33. data/lib/openai_101/tools/clean_ruby_errors.rb +0 -274
  34. data/lib/openai_101/tools/edl_to_chapters.rb +0 -56
  35. data/lib/openai_101/tools/file_content_gatherer.rb +0 -36
  36. data/lib/openai_101/tools/webp_to_png.rb +0 -124
  37. /data/lib/{openai_101 → openai101}/config/openai.rb +0 -0
@@ -1,21 +0,0 @@
1
- Theme,Prompt
2
- "Futuristic Cityscapes", "A bustling futuristic cityscape where AI and humans coexist seamlessly, with drones flying overhead and digital billboards displaying AI-generated art"
3
- "Digital Renaissance", "A digital recreation of a Renaissance scene, where figures interact with AI devices, blending classical beauty with modern technology"
4
- "AI in Nature", "A serene forest where trees and wildlife are monitored and cared for by gentle AI robots, highlighting a balance between technology and natural preservation"
5
- "Cybernetic Organisms", "A close-up of a flower with digital circuit patterns on its petals, symbolizing the fusion of organic life with AI enhancements"
6
- "Virtual Reality Worlds", "An individual wearing a VR headset, transported to a breathtaking AI-created fantasy world, showcasing the limitless possibilities of virtual reality"
7
- "AI as a Companion", "A friendly AI robot walking alongside a human in a park, offering guidance and companionship, symbolizing the supportive role of AI"
8
- "Abstract Data Visualizations", "An abstract representation of a neural network, with flowing streams of data and colorful nodes, visualizing the complexity and beauty of AI algorithms"
9
- "Steampunk AI", "A steampunk-inspired workshop with AI robots made of brass and gears, working alongside humans to invent new technologies"
10
- "Space Exploration", "A robotic AI explorer navigating the rugged terrain of an alien planet, with a distant galaxy shining brightly in the sky above"
11
- "Underwater Discoveries", "AI-powered submarines exploring coral reefs and ancient underwater ruins, illuminating the depths with advanced technology"
12
- "Mythical Integration", "A majestic phoenix with digital wings soaring above a futuristic city, blending mythology with advanced AI technology"
13
- "Digital Nomads", "A group of tech-savvy digital nomads in a remote, exotic location, using AI to work and communicate from anywhere in the world"
14
- "Retro-Futurism", "A scene set in a neon-lit arcade from the 1980s, where gamers are playing AI-developed video games that predict future events"
15
- "AI Guardians", "A powerful AI guardian overseeing the digital safety of a smart city, visualized as a holographic entity projecting from a city's central tower"
16
- "Dystopian vs Utopian AI", "A split scene showing one side as a dystopian world overwhelmed by AI surveillance and control, and the other as a utopian society where AI enhances quality of life"
17
- "Quantum Computing", "An ethereal quantum realm where qubits float in a space-like environment, representing the power and mystery of quantum computing in AI"
18
- "AI in Sports and Fitness", "An athletic training session where an AI coach provides personalized feedback and strategies to an athlete wearing smart wearables"
19
- "Education Through AI", "A futuristic classroom where holographic projections of AI tutors teach students from around the globe in an interactive learning environment"
20
- "AI in Art and Music", "An AI painting a masterpiece while another composes a symphony, showcasing the creative potential of AI in art and music"
21
- "AI as a Time Traveler", "An AI entity interacting with historical figures across different eras, from ancient civilizations to future societies, illustrating the timeless impact of AI"
@@ -1,60 +0,0 @@
1
- const { Command } = require('commander');
2
- const fs = require('fs');
3
- const robot = require("robotjs");
4
-
5
- const program = new Command();
6
-
7
- program
8
- .option('-f, --file <filename>', 'The file to read prompts from', 'prompts.txt')
9
- .option('-o, --completed-file <filename>', 'The file to write completed prompts to', 'completed.txt')
10
- .option('-i, --interval <seconds>', 'The interval in seconds between prompts', 80)
11
- .option('-m, --max-images <number>', 'The maximum number of images to process', 20);
12
-
13
- program.parse(process.argv);
14
-
15
- function read_prompts_from_file(file, maxImages) {
16
- const prompts = fs.readFileSync(file, 'utf-8').split('\n').filter(Boolean);
17
- return prompts.slice(0, maxImages);
18
- }
19
-
20
- function remove_prompt_from_file(file, prompt) {
21
- const prompts = fs.readFileSync(file, 'utf-8').split('\n').filter(Boolean);
22
- const index = prompts.indexOf(prompt);
23
- if (index !== -1) {
24
- prompts.splice(index, 1);
25
- fs.writeFileSync(file, prompts.join('\n'));
26
- }
27
- }
28
-
29
- function append_prompt_to_file(file, prompt) {
30
- fs.appendFileSync(file, `${prompt}\n`);
31
- }
32
-
33
- function wait(ms) {
34
- return new Promise(resolve => setTimeout(resolve, ms));
35
- }
36
-
37
- async function send_prompt_to_chat(prompt) {
38
- const formattedPrompt = `create image: ${prompt}`;
39
- robot.typeString(formattedPrompt);
40
- robot.keyTap('enter');
41
- }
42
-
43
- async function start() {
44
- console.log('Starting Image Creation Automation');
45
- console.log('Please open the ChatGPT interface where you intend to use this script.');
46
- console.log('Automation will begin in 10 seconds.');
47
- await wait(10000);
48
-
49
- const prompts = read_prompts_from_file(program.opts().file, parseInt(program.opts().maxImages));
50
- for (let prompt of prompts) {
51
- console.log(`Sending prompt "${prompt}"...`);
52
- await send_prompt_to_chat(prompt);
53
- await wait(program.opts().interval * 1000);
54
- remove_prompt_from_file(program.opts().file, prompt);
55
- append_prompt_to_file(program.opts().completedFile, prompt);
56
- }
57
- console.log('Automation complete.');
58
- }
59
-
60
- start();
@@ -1,75 +0,0 @@
1
- const { Command } = require('commander');
2
- const fs = require('fs');
3
- const robot = require("robotjs");
4
-
5
- const program = new Command();
6
-
7
- program
8
- .option('-f, --file <filename>', 'The file to read prompts from', 'prompts.txt')
9
- .option('-o, --completed-file <filename>', 'The file to write completed prompts to', 'completed.txt')
10
- .option('-i, --interval <seconds>', 'The interval in seconds between prompts', 4)
11
- .option('-p, --prompts-per-session <prompts>', 'The number of prompts to process in a session', 7)
12
- .option('-w, --wait-between-sessions <seconds>', 'The number of seconds to wait between sessions', 180);
13
-
14
- program.parse(process.argv);
15
-
16
- function read_next_prompt_from_file(file) {
17
- const prompts = fs.readFileSync(file, 'utf-8').split('\n').filter(Boolean);
18
- return prompts.shift();
19
- }
20
-
21
- function remove_prompt_from_file(file, prompt) {
22
- const lockfile = `${file}.lock`;
23
- fs.writeFileSync(lockfile, '', { flag: 'wx' });
24
- const prompts = fs.readFileSync(file, 'utf-8').split('\n').filter(Boolean);
25
- const index = prompts.indexOf(prompt);
26
- prompts.splice(index, 1);
27
- fs.writeFileSync(file, prompts.join('\n'));
28
- fs.unlinkSync(lockfile);
29
- }
30
-
31
- function append_prompt_to_file(file, prompt) {
32
- const lockfile = `${file}.lock`;
33
- fs.writeFileSync(lockfile, '', { flag: 'wx' });
34
- fs.appendFileSync(file, `${prompt}\n`);
35
- fs.unlinkSync(lockfile);
36
- }
37
-
38
- function wait(ms) {
39
- const end = Date.now() + ms;
40
- while (Date.now() < end) {
41
- // Wait
42
- }
43
- }
44
-
45
- function send_prompt_to_discord(prompt) {
46
- const formattedPrompt = `/imagine prompt: ${prompt}`;
47
- robot.typeString(formattedPrompt);
48
- robot.keyTap('enter');
49
- }
50
-
51
- function start() {
52
- console.log('Starting MidJourney Automation');
53
- console.log('Please open Discord and navigate to the MidJourney channel.');
54
- console.log('Automation will begin in 10 seconds.');
55
- wait(10 * 1000);
56
-
57
- let index = 0;
58
- let prompt = read_next_prompt_from_file(program.opts().file);
59
- while (prompt) {
60
- console.log(`Sending prompt "${prompt}"...`);
61
- send_prompt_to_discord(prompt);
62
- wait(program.opts().interval * 1000);
63
- remove_prompt_from_file(program.opts().file, prompt);
64
- append_prompt_to_file(program.opts().completedFile, prompt);
65
- index++;
66
- if (index % program.opts().promptsPerSession === 0) {
67
- console.log(`Pausing for ${program.opts().waitBetweenSessions} seconds.`);
68
- wait(program.opts().waitBetweenSessions * 1000);
69
- }
70
- prompt = read_next_prompt_from_file(program.opts().file);
71
- }
72
- console.log('Automation complete.');
73
- }
74
-
75
- start();
@@ -1,53 +0,0 @@
1
- const fs = require('fs');
2
- const { promisify } = require('util');
3
- const robot = require("robotjs");
4
-
5
- const wait = promisify(setTimeout);
6
-
7
- class BaseAutomator {
8
- constructor({ file, completedFile, interval = 5, maxImages = 20 }) {
9
- this.file = file;
10
- this.completedFile = completedFile;
11
- this.interval = interval;
12
- this.maxImages = maxImages;
13
- }
14
-
15
- async readPromptsFromFile() {
16
- try {
17
- const content = await fs.promises.readFile(this.file, 'utf-8');
18
- return content.split('\n').filter(Boolean).slice(0, this.maxImages);
19
- } catch (error) {
20
- console.error('Error reading prompts from file:', error);
21
- return [];
22
- }
23
- }
24
-
25
- async appendToCompletedFile(prompt) {
26
- try {
27
- await fs.promises.appendFile(this.completedFile, `${prompt}\n`);
28
- } catch (error) {
29
- console.error('Error appending prompt to completed file:', error);
30
- }
31
- }
32
-
33
- async removeFromInputFile(prompt) {
34
- try {
35
- let prompts = await this.readPromptsFromFile();
36
- prompts = prompts.filter(line => line !== prompt);
37
- await fs.promises.writeFile(this.file, prompts.join('\n'));
38
- } catch (error) {
39
- console.error('Error removing prompt from input file:', error);
40
- }
41
- }
42
-
43
- async waitInterval() {
44
- await wait(this.interval * 1000);
45
- }
46
-
47
- async sendKeystrokes(string) {
48
- robot.typeString(string);
49
- robot.keyTap('enter');
50
- }
51
- }
52
-
53
- module.exports = BaseAutomator;
@@ -1,27 +0,0 @@
1
- const BaseAutomator = require('./base_automator');
2
-
3
- class ChatGPTAutomator extends BaseAutomator {
4
- constructor(options) {
5
- super(options);
6
- }
7
-
8
- async sendPromptToChat(prompt) {
9
- const formattedPrompt = `create image: ${prompt}`;
10
- await this.sendKeystrokes(formattedPrompt);
11
- console.log(`Sending prompt "${prompt}" to ChatGPT...`);
12
- }
13
-
14
- async start() {
15
- console.log('Starting ChatGPT Image Creation Automation');
16
- const prompts = await this.readPromptsFromFile();
17
- for (const prompt of prompts) {
18
- await this.sendPromptToChat(prompt);
19
- await this.waitInterval();
20
- await this.removeFromInputPromptFile(prompt);
21
- await this.appendToCompletedPromptFile(prompt);
22
- }
23
- console.log('Automation complete.');
24
- }
25
- }
26
-
27
- module.exports = ChatGPTAutomator;
@@ -1,49 +0,0 @@
1
- const BaseAutomator = require('./base_automator');
2
- const fs = require('fs');
3
- const robot = require("robotjs");
4
-
5
- class MidJourneyAutomator extends BaseAutomator {
6
- constructor(options) {
7
- super(options);
8
- }
9
-
10
- async sendPromptToDiscord(prompt) {
11
- const formattedPrompt = this.formatPrompt(prompt);
12
- this.sendKeystrokes(formattedPrompt);
13
- }
14
-
15
- formatPrompt(prompt) {
16
- return `/imagine prompt: ${prompt}`;
17
- }
18
-
19
- sendKeystrokes(string) {
20
- robot.typeString(string);
21
- robot.keyTap('enter');
22
- }
23
-
24
- async start() {
25
- console.log('Starting MidJourney Automation');
26
- console.log('Please open Discord and navigate to the MidJourney channel.');
27
- console.log('Automation will begin in 10 seconds.');
28
- await this.wait(10 * 1000);
29
-
30
- let index = 0;
31
- let prompt = await this.readNextPromptFromFile();
32
- while (prompt) {
33
- console.log(`Sending prompt "${prompt}"...`);
34
- await this.sendPromptToDiscord(prompt);
35
- await this.wait(this.interval * 1000);
36
- await this.removePromptFromFile(prompt);
37
- await this.appendToCompletedFile(this.completedFile, prompt);
38
- index++;
39
- if (index % this.maxImages === 0) {
40
- console.log(`Pausing for ${this.waitBetweenSessions} seconds.`);
41
- await this.wait(this.waitBetweenSessions * 1000);
42
- }
43
- prompt = await this.readNextPromptFromFile();
44
- }
45
- console.log('Automation complete.');
46
- }
47
- }
48
-
49
- module.exports = MidJourneyAutomator;
@@ -1,274 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Openai101
4
- module Tools
5
- # Clean Ruby Errors
6
- module ReportFormatter
7
- def print_column_names(column_definitions)
8
- headings = column_definitions.map { |_, col| col[:label].ljust(col[:width]) }.join(' | ')
9
- separator_length = column_definitions.sum { |_, col| col[:width] } + ((column_definitions.keys.size - 1) * 3)
10
-
11
- puts '-' * separator_length
12
- puts headings
13
- puts '-' * separator_length
14
- end
15
-
16
- def print_line(column_definitions, **column_key_values)
17
- line = column_definitions.map do |key, col|
18
- value = column_key_values[key] || ''
19
- value.to_s.ljust(col[:width])
20
- end.join(' | ')
21
- puts line
22
- end
23
- end
24
-
25
- # Convert EDL to YouTube description chapters
26
- class CleanRubyErrors
27
- include ReportFormatter
28
-
29
- attr_reader :file
30
- attr_reader :error
31
- attr_reader :errors
32
-
33
- def initialize(file)
34
- @file = file
35
- @errors = []
36
- end
37
-
38
- def parse
39
- capture_code = []
40
- capture_stack = []
41
-
42
- lines.each do |line|
43
- @section = detect_section(line)
44
-
45
- case section
46
- when :new_error
47
- add_stack_to_error(error, capture_stack) if capture_stack.any? && error
48
-
49
- @error = initialize_error(line)
50
- errors << error
51
-
52
- when :failure_error1
53
- error[:error_technique] = '1'
54
- capture_code = []
55
- @section = :capture_failure_error
56
- when :failure_error2
57
- error[:error_technique] = '2'
58
- capture_code = []
59
- @section = :capture_failure_error
60
- when :capture_failure_error
61
- capture_code << line.rstrip
62
- when :actual_error
63
- error[:error_type] = line.strip
64
- error[:code_section] = format_code(capture_code)
65
- capture_stack = []
66
- @section = :capture_stack
67
- when :capture_stack
68
- capture_stack << line.strip
69
- end
70
- end
71
-
72
- add_stack_to_error(error, capture_stack) if capture_stack.any? && error
73
- end
74
-
75
- def print_errors(errors)
76
- column_definitions = {
77
- test_number: { label: '#', width: 5 },
78
- test_technique: { label: 'Style', width: 7 },
79
- error_at: { label: 'Error At', width: 70 },
80
- error_by: { label: 'Error By', width: 80 },
81
- error_type: { label: 'Error Type', width: 20 },
82
- error_message: { label: 'Error Message', width: 180 }
83
- }
84
-
85
- print_column_names(column_definitions)
86
-
87
- errors.each do |error|
88
- print_line(column_definitions,
89
- test_number: error[:test_number],
90
- test_technique: error[:error_technique],
91
- error_at: "#{error[:error_at][:file]}:#{error[:error_at][:line]}",
92
- error_by: "#{error[:error_by][:file]}:#{error[:error_by][:line]}",
93
- error_type: error[:error_type],
94
- error_message: error[:error_message])
95
- end
96
-
97
- print_column_names(column_definitions)
98
- end
99
-
100
- def print_aggregated_error(errors)
101
- aggregated_errors = aggregate_errors(errors)
102
- # puts JSON.pretty_generate(aggregated_errors.first)
103
-
104
- # puts '----------------------'
105
- # puts aggregated_errors.first
106
-
107
- column_definitions = {
108
- error_type: { label: 'Error Type', width: 20 },
109
- error_message: { label: 'Error Message', width: 180 },
110
- error_at_file: { label: 'Error At File', width: 70 },
111
- error_at_lines: { label: 'L#', width: 5 },
112
- error_by_file: { label: 'Error By File', width: 80 },
113
- error_by_lines: { label: 'Lines', width: 30 }
114
- }
115
-
116
- print_column_names(column_definitions)
117
-
118
- aggregated_errors.each do |error|
119
- print_line(column_definitions,
120
- error_type: error[:error_type],
121
- error_message: error[:error_message],
122
- error_at_file: error[:error_at_file],
123
- error_at_lines: error[:error_at_lines].join(', '),
124
- error_by_file: error[:error_by_file],
125
- error_by_lines: error[:error_by_lines].join(', '))
126
- end
127
-
128
- print_column_names(column_definitions)
129
- end
130
-
131
- # # column_definitions = {
132
- # # error_message: { label: "Error Message", width: 180 },
133
- # # }
134
-
135
- # # # Print the report
136
- # # puts "Error Message | Source File(Line Numbers) | Spec File(Line Numbers)"
137
- # # puts "-" * 100
138
-
139
- # # aggregated_errors.each do |(message, source_file, spec_file), lines|
140
- # # source_lines = lines[:source_lines].uniq.sort.join(', ')
141
- # # spec_lines = lines[:spec_lines].uniq.sort.join(', ')
142
- # # puts "#{message} | #{source_file}(#{source_lines}) | #{spec_file}(#{spec_lines})"
143
- # # end
144
- # end
145
-
146
- private
147
-
148
- def lines
149
- @lines ||= File.readlines(file)
150
- end
151
-
152
- def detect_section(line)
153
- return :new_error if line.match?(/^\d+\)/)
154
- return :failure_error2 if line.include?('Failure/Error: ') # Note the space
155
- return :failure_error1 if line.include?('Failure/Error:')
156
- return :actual_error if line.include?('Error:')
157
-
158
- section
159
- end
160
-
161
- def section
162
- @section ||= :start
163
- end
164
-
165
- def initialize_error(line)
166
- {
167
- error_type: '',
168
- error_technique: '',
169
- test_number: extract_error_number(line),
170
- code_section: [],
171
- error_message: '',
172
- error_messages: [],
173
- stack: [],
174
- error_at: { file: '', line: 0 },
175
- error_by: { file: '', line: 0 }
176
- }
177
- end
178
-
179
- def extract_error_number(line)
180
- match = line.match(/^(\d+)\)/)
181
- match ? match[1] : nil
182
- end
183
-
184
- def format_code(code_lines)
185
- return 'Investigate!!!' if code_lines.empty?
186
-
187
- first_line_spaces = code_lines.first[/\A */].size
188
- code_lines.map { |line| line[first_line_spaces..] }.compact
189
- end
190
-
191
- def add_stack_to_error(error, stack_lines)
192
- error_messages, stack_trace = split_strack_from_errors(stack_lines)
193
-
194
- error[:error_message] = error_messages.join(' ')
195
- error[:error_messages] = error_messages
196
- error[:stack] = stack_trace
197
-
198
- error[:error_at] = extract_error_location(stack_trace)
199
- error[:error_by] = extract_test_location(stack_trace)
200
- end
201
-
202
- def split_strack_from_errors(stack_lines)
203
- error_messages, stack_trace = stack_lines.partition { |line| !line.start_with?('#') }
204
-
205
- clean_error_messages = error_messages.reject(&:empty?)
206
- clean_stack_trace = stack_trace.map { |line| line.sub(/^#\s*/, '') }
207
-
208
- [clean_error_messages, clean_stack_trace]
209
- end
210
-
211
- def extract_error_location(stack_trace)
212
- return { file: '', line: 0 } if stack_trace.empty?
213
-
214
- # Matches on file paths ending in .rb followed by a colon and a line number.
215
- # It captures the file path and line number into named groups 'file' and 'line'.
216
- # Example Match: "./app/models/user.rb:13" => file: "./app/models/user.rb", line: "13"
217
- match = stack_trace.first.match(/(?<file>.*\.rb):(?<line>\d+)/)
218
- match ? { file: match[:file], line: match[:line] } : { file: 'XXXXXX1', line: 0 }
219
- end
220
-
221
- def extract_test_location(stack_trace)
222
- stack_trace.reverse_each do |trace_line|
223
- # Searches for file paths that specifically end with _spec.rb (indicating a test file),
224
- # followed by a colon and a line number. It captures the test file path and line number.
225
- # Example Match: "./spec/models/user_spec.rb:26" => file: "./spec/models/user_spec.rb", line: "26"
226
- if (match = trace_line.match(/(?<file>.*_spec\.rb):(?<line>\d+)/))
227
- return { file: match[:file], line: match[:line] }
228
- end
229
- end
230
- { file: 'XXXXXX2', line: 0 } # Return a default value if no test location is found
231
- end
232
-
233
- def aggregate_errors(errors)
234
- # Initialize an empty hash for aggregations
235
- aggregated_errors = {}
236
-
237
- errors.each do |error|
238
- # Create a unique key for each aggregation based on error_message, error_at[:file], and error_by[:file]
239
- key = [
240
- error[:error_message],
241
- error[:error_at][:file],
242
- error[:error_by][:file]
243
- ].join('|')
244
-
245
- # If the aggregation key doesn't exist, initialize it
246
- aggregated_errors[key] ||= {
247
- error_type: error[:error_type],
248
- error_message: error[:error_message],
249
- code_section: error[:code_section], # Assuming code_section is the same for aggregated errors
250
- error_at: { file: error[:error_at][:file], lines: [] },
251
- error_by: { file: error[:error_by][:file], lines: [] }
252
- }
253
-
254
- # Append unique error messages and line numbers for error_at and error_by
255
- aggregated_errors[key][:error_at][:lines] |= [error[:error_at][:line]]
256
- aggregated_errors[key][:error_by][:lines] |= [error[:error_by][:line]]
257
- end
258
-
259
- # Convert the aggregated_errors hash back into an array of values
260
- aggregated_errors.values.map do |error|
261
- {
262
- error_type: error[:error_type],
263
- error_message: error[:error_message],
264
- code_section: error[:code_section].join("\n"),
265
- error_at_file: error[:error_at][:file],
266
- error_at_lines: error[:error_at][:lines],
267
- error_by_file: error[:error_by][:file],
268
- error_by_lines: error[:error_by][:lines]
269
- }
270
- end
271
- end
272
- end
273
- end
274
- end
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Openai101
4
- module Tools
5
- # Convert EDL to YouTube description chapters
6
- class EdlToChapters
7
- attr_reader :content
8
-
9
- def initialize(content: nil, file: nil)
10
- @content = content
11
- @content = File.read(file) if file
12
- end
13
-
14
- def convert
15
- # TITLE: a36
16
- # FCM: NON-DROP FRAME
17
-
18
- # 001 001 V C 00:00:09:16 00:00:09:17 00:00:09:16 00:00:09:17
19
- # |C:ResolveColorBlue |M:Hey Code Voice Commands |D:1
20
-
21
- # 002 001 V C 00:00:53:13 00:00:53:14 00:00:53:13 00:00:53:14
22
- # |C:ResolveColorBlue |M:Keyboard Shortcuts |D:1
23
-
24
- # 003 001 V C 00:01:17:20 00:01:17:21 00:01:17:20 00:01:17:21
25
- # |C:ResolveColorBlue |M:Create code using voice |D:1
26
-
27
- # 004 001 V C 00:02:17:25 00:02:17:26 00:02:17:25 00:02:17:26
28
- # |C:ResolveColorBlue |M:Next steps |D:1
29
-
30
- chapters = []
31
- chapter = nil
32
- content.each_line do |line|
33
- line = line.strip
34
-
35
- if line =~ /^\d{3}/
36
- chapter = build_chapter(line)
37
- chapters << chapter
38
- next
39
- end
40
-
41
- chapter[:description] = line.match(/\|M:(.+?)\|/)[1].strip if chapter && line.match(/\|M:(.+?)\|/) && line.match(/\|M:(.+?)\|/)[1]
42
- end
43
- chapters.map { |item| "#{item[:time]} #{item[:description]}" }.join("\n")
44
- end
45
-
46
- def build_chapter(line)
47
- time_code = line.split(/\s+/)[5] # Extract time code
48
- hours, minutes, seconds, frames = time_code.split(':').map(&:to_i)
49
- total_seconds = (hours * 3600) + (minutes * 60) + seconds + (frames / 30.0)
50
- formatted_time = format('%<hours>02d:%<minutes>02d:%<seconds>02d', hours: total_seconds / 3600, minutes: (total_seconds / 60) % 60, seconds: total_seconds % 60)
51
-
52
- { time: formatted_time }
53
- end
54
- end
55
- end
56
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Openai101
4
- module Tools
5
- # Gather content from files in a directory, used by gpt_context_gatherer.rb
6
- class FileContentGatherer
7
- attr_reader :include_patterns, :exclude_patterns
8
-
9
- def initialize(include_pattern: nil, include_patterns: [], exclude_patterns: [])
10
- @include_patterns = Array(include_pattern) + include_patterns
11
- @exclude_patterns = exclude_patterns
12
- end
13
-
14
- def build
15
- concatenated_content = []
16
-
17
- include_patterns.each do |pattern|
18
- Dir.glob(pattern).each do |file_path|
19
- next if excluded?(file_path) || File.directory?(file_path)
20
-
21
- content = "# file: #{file_path}\n\n#{File.read(file_path)}"
22
- concatenated_content << content
23
- end
24
- end
25
-
26
- concatenated_content.join("\n\n")
27
- end
28
-
29
- private
30
-
31
- def excluded?(file_path)
32
- exclude_patterns.any? { |pattern| File.fnmatch(pattern, file_path) }
33
- end
34
- end
35
- end
36
- end