ad-agent_architecture 0.0.3 → 0.0.5

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.
data/docs/requirements.md CHANGED
@@ -1,99 +1,643 @@
1
- ### Analysis and Clarification of Workflow Documents
2
1
 
3
- The provided documents outline structured workflows for creating YouTube scripts and Medium articles using AI tools and human input. Here’s a detailed analysis based on the initial documents and the additional information provided:
2
+ ## Schema for AI Agents
4
3
 
5
- ### Key Insights from Both Documents
4
+ ### Entity Relationship Diagram
6
5
 
7
- 1. **Human-AI Collaboration**:
8
- - The YouTube script workflow is a complete list of steps performed primarily by AI (ChatGPT), with minimal human input, passed through various prompts to generate the output.
9
- - The Medium article workflow is similar but not fully documented, indicating the same concept for generating content from a transcript.
10
- - These workflows are common in agent automation frameworks, where AI performs most tasks, with humans providing quality assurance.
6
+ ![Schema](./erd.svg)
11
7
 
12
- 2. **Parameter Collection**:
13
- - Parameters are collected and built over time, starting with a simple project title (simple_title) for YouTube and a transcript for Medium articles.
14
- - Static input parameters like brand and target audience are crucial for defining the content's direction.
8
+ ### Static Workflow Definition
15
9
 
16
- 3. **Workflow Phases**:
17
- - Both workflows consist of distinct phases: research and script/article writing.
18
- - The research phase involves gathering information and generating potential content elements (titles, factsheets, topics).
19
- - The writing phase focuses on drafting, revising, and finalizing the content.
10
+ Static workflow definition defines the structure of a workflow, including its sections, steps, attributes, and their relationships.
20
11
 
21
- 4. **Input Parameters**:
22
- - Parameters range from simple (single values) to complex (arrays of values).
23
- - Initial parameters are relatively simple but grow in complexity as the workflow progresses.
12
+ ![Static Workflow Definition](./images/sample-workflow.png)
24
13
 
25
- 5. **Prompts and Outputs**:
26
- - Prompts are human-written text files with input parameter placeholders.
27
- - Outputs can be simple (text) or complex (arrays of values such as engaging_titles[], keywords[], topics[]).
28
- - Complex outputs generate new parameters for further steps.
14
+ ### Static Workflow Entities
29
15
 
30
- 6. **Human Decision Points**:
31
- - Certain steps require human decisions, such as selecting the focus_video_type from multiple generated topics.
32
- - Human input is crucial for quality assurance and final content selection.
16
+ #### Table: workflows
33
17
 
34
- 7. **Iterative and Parallel Processes**:
35
- - Workflows often involve iterative steps, refining outputs until satisfactory results are achieved.
36
- - Parallel workflows can be initiated to explore multiple options simultaneously, using the same initial parameters but diverging paths.
18
+ This table stores the basic information about each workflow, including its unique identifier, name, and description.
37
19
 
38
- ### Detailed Analysis Document
20
+ | Field | Type | Description |
21
+ |-------------|--------|-------------------------------------|
22
+ | id | string | Unique identifier for the workflow |
23
+ | name | string | The name of the workflow |
24
+ | description | string | A brief description of the workflow |
39
25
 
40
- #### Document 1: YouTube Script Creation Workflow
26
+ #### Table: sections
27
+ This table stores the sections that belong to a workflow. Each section has an order within its workflow.
41
28
 
42
- - **Parameters**:
43
- - Initial: simple_title (e.g., "Fotor AI tool")
44
- - Dynamic: Built over time (basic_factsheet, video_types[], focus_video_type, expanded_factsheet, topics[], keywords[], engaging_titles[], basic_script, basic_transcript, transcript_qa)
29
+ | Field | Type | Description |
30
+ |-------------|---------|----------------------------------------|
31
+ | id | string | Unique identifier for the section |
32
+ | workflow_id | string | Foreign key referencing workflows |
33
+ | name | string | The name of the section |
34
+ | description | string | A brief description of the section |
35
+ | order | integer | The order of the section in the workflow|
45
36
 
46
- - **Phases**:
47
- - **Research Phase**:
48
- 1. Generate potential titles using YouTube search.
49
- 2. Create a detailed factsheet using web search and AI tools.
50
- 3. Identify video types based on factsheet.
51
- 4. Expand factsheet with focus video type.
52
- 5. Generate engaging titles, keywords, and topics.
53
- - **Script Writing Phase**:
54
- 1. Create basic script.
55
- 2. Clean and revise transcript.
56
- 3. Fact-check and finalize transcript.
37
+ #### Table: steps
57
38
 
58
- - **Human Involvement**:
59
- - Decision on focus_video_type.
60
- - Final review and quality assurance.
39
+ This table stores the steps that belong to a section. Each step has an order within its section and an associated prompt.
61
40
 
62
- #### Document 2: Medium Article Creation Workflow
41
+ Example workflows include "YouTube Video Script", "YouTube Title Creator" and "YouTube Transcription to Medium Article".
63
42
 
64
- - **Parameters**:
65
- - Initial: transcript (YouTube transcript)
66
- - Dynamic: article_recomendations, target_audience, outline, article_first_draft, outline_first_draft, introductions[], outline_first_draft_updated_with_intro
43
+ | Field | Type | Description |
44
+ |-------------|---------|-------------------------------------|
45
+ | id | string | Unique identifier for the step |
46
+ | section_id | string | Foreign key referencing sections |
47
+ | name | string | The name of the step |
48
+ | action | string | The action to be performed by the step, default ('gpt') |
49
+ | description | string | A brief description of the step |
50
+ | order | integer | The order of the step in the section|
51
+ | prompt | string | The template string for the prompt |
67
52
 
68
- - **Phases**:
69
- - **Research Phase**:
70
- 1. Generate article recommendations from transcript.
71
- 2. Draft the article based on target audience and recommendations.
72
- 3. Create preliminary outline from transcript.
73
- - **Writing Phase**:
74
- 1. Write the first draft following the outline.
75
- 2. Generate and critique various introductions.
76
- 3. Revise and update outline with selected introduction.
53
+ #### Table: attributes
77
54
 
78
- - **Human Involvement**:
79
- - Selection of introduction.
80
- - Final review and quality assurance.
55
+ This table stores the attributes associated with a workflow. Each attribute can be a simple value or an array.
81
56
 
82
- ### Additional Insights
57
+ Example attributes include "simple_title", "basic_factsheet" and "working_title".
83
58
 
84
- 1. **Parameter Complexity**:
85
- - Parameters evolve from simple inputs to complex structures, incorporating arrays of values that influence subsequent steps.
59
+ | Field | Type | Description |
60
+ |-------------|---------|---------------------------------------------|
61
+ | id | string | Unique identifier for the attribute |
62
+ | workflow_id | string | Foreign key referencing workflows |
63
+ | name | string | The name of the attribute |
64
+ | type | string | The type of the attribute (e.g., string) |
65
+ | is_array | boolean | Indicates whether the attribute is an array |
86
66
 
87
- 2. **Iterative Processes**:
88
- - Both workflows benefit from iterative refinement, ensuring high-quality outputs before moving to the next phase.
67
+ #### Table: input_attributes
89
68
 
90
- 3. **Parallel Workflows**:
91
- - Exploring multiple options simultaneously (e.g., different video types) can provide richer content and better decision-making.
69
+ This table maps input attributes to steps. This becomes the input parameters for the AI agent.
92
70
 
93
- 4. **Independent Subtasks**:
94
- - Certain elements (like generating introductions for Medium articles) can operate independently but feed back into the main workflow, enhancing flexibility and adaptability.
71
+ | Field | Type | Description |
72
+ |-------------|---------|------------------------------------|
73
+ | step_id | string | Foreign key referencing steps |
74
+ | attribute_id| string | Foreign key referencing attributes |
75
+ | required | boolean | Indicates whether the attribute is required |
95
76
 
96
- 5. **Cyclic Steps**:
97
- - Iterative cycles help refine outputs continuously until optimal results are achieved, demonstrating a robust approach to content creation.
77
+ #### Table: output_attributes
98
78
 
99
- This structured approach to content creation leverages AI for efficiency while ensuring human oversight for quality, making it a highly effective workflow for producing engaging YouTube scripts and Medium articles.
79
+ This table maps output attributes to steps. This becomes a result of the AI agent.
80
+
81
+ | Field | Type | Description |
82
+ |-------------|---------|------------------------------------|
83
+ | step_id | string | Foreign key referencing steps |
84
+ | attribute_id| string | Foreign key referencing attributes |
85
+
86
+ ### Dynamic Workflow Execution
87
+
88
+ Dynamic workflow execution captures the actual execution of a workflow, including the workflow runs, section runs, step runs, and attribute values.
89
+
90
+ ### Dynamic Workflow Entities
91
+
92
+ #### Table: workflow_runs
93
+
94
+ This table stores instances of workflow executions.
95
+
96
+ | Field | Type | Description |
97
+ |-------------|--------|---------------------------------------|
98
+ | id | string | Unique identifier for the workflow run|
99
+ | workflow_id | string | Foreign key referencing workflows |
100
+
101
+ #### Table: section_runs
102
+ This table stores instances of section executions within a workflow run.
103
+
104
+ | Field | Type | Description |
105
+ |-----------------|--------|----------------------------------------|
106
+ | id | string | Unique identifier for the section run |
107
+ | section_id | string | Foreign key referencing sections |
108
+ | workflow_run_id | string | Foreign key referencing workflow_runs |
109
+
110
+ #### Table: step_runs
111
+ This table stores instances of step executions within a section run. Each step run can have multiple branches.
112
+
113
+ | Field | Type | Description |
114
+ |------------------|---------|---------------------------------------------------------------------|
115
+ | id | string | Unique identifier for the step run |
116
+ | section_run_id | string | Foreign key referencing section_runs |
117
+ | step_id | string | Foreign key referencing steps |
118
+ | branch_number | integer | Branch number to distinguish different instances (branches) of the same step |
119
+
120
+ #### Table: attribute_values
121
+ This table stores the values of attributes during step executions.
122
+
123
+ | Field | Type | Description |
124
+ |---------------|--------|-----------------------------------------|
125
+ | id | string | Unique identifier for the attribute value|
126
+ | attribute_id | string | Foreign key referencing attributes |
127
+ | step_run_id | string | Foreign key referencing step_runs |
128
+ | value | text | The actual value of the attribute during the step execution |
129
+
130
+ ## Gemfile
131
+
132
+ ```ruby
133
+
134
+ # Gemfile
135
+
136
+ source 'https://rubygems.org'
137
+
138
+ gem 'sequel'
139
+ gem 'sqlite3'
140
+ ```
141
+
142
+ ## Database Setup
143
+
144
+
145
+ ```ruby
146
+ # db_setup.rb
147
+
148
+ require 'sequel'
149
+
150
+ DB = Sequel.sqlite('workflow.db') # Creates an SQLite database called workflow.db
151
+
152
+ # Create the tables for static workflow definition
153
+ DB.create_table :workflows do
154
+ primary_key :id
155
+ String :name, null: false
156
+ String :description
157
+ end
158
+
159
+ DB.create_table :sections do
160
+ primary_key :id
161
+ String :name, null: false
162
+ String :description
163
+ Integer :order
164
+ foreign_key :workflow_id, :workflows
165
+ end
166
+
167
+ DB.create_table :steps do
168
+ primary_key :id
169
+ String :name, null: false
170
+ String :description
171
+ Integer :order
172
+ foreign_key :section_id, :sections
173
+ String :prompt
174
+ end
175
+
176
+ DB.create_table :attributes do
177
+ primary_key :id
178
+ String :name, null: false
179
+ String :type
180
+ Boolean :is_array
181
+ foreign_key :workflow_id, :workflows
182
+ end
183
+
184
+ DB.create_table :input_attributes do
185
+ foreign_key :step_id, :steps
186
+ foreign_key :attribute_id, :attributes
187
+ end
188
+
189
+ DB.create_table :output_attributes do
190
+ foreign_key :step_id, :steps
191
+ foreign_key :attribute_id, :attributes
192
+ end
193
+
194
+ # Create the tables for dynamic workflow execution
195
+ DB.create_table :workflow_runs do
196
+ primary_key :id
197
+ foreign_key :workflow_id, :workflows
198
+ end
199
+
200
+ DB.create_table :section_runs do
201
+ primary_key :id
202
+ foreign_key :workflow_run_id, :workflow_runs
203
+ foreign_key :section_id, :sections
204
+ end
205
+
206
+ DB.create_table :step_runs do
207
+ primary_key :id
208
+ foreign_key :section_run_id, :section_runs
209
+ foreign_key :step_id, :steps
210
+ Integer :branch_number
211
+ end
212
+
213
+ DB.create_table :attribute_values do
214
+ primary_key :id
215
+ foreign_key :attribute_id, :attributes
216
+ foreign_key :step_run_id, :step_runs
217
+ String :value
218
+ end
219
+ ```
220
+
221
+ ## Models
222
+
223
+ ```ruby
224
+ # models.rb
225
+
226
+ require 'sequel'
227
+
228
+ DB = Sequel.sqlite('workflow.db') # Connect to the SQLite database
229
+
230
+ # Static Workflow Definition
231
+
232
+ class Workflow < Sequel::Model
233
+ one_to_many :sections
234
+ one_to_many :attributes
235
+ one_to_many :workflow_runs
236
+ end
237
+
238
+ class Section < Sequel::Model
239
+ many_to_one :workflow
240
+ one_to_many :steps
241
+ one_to_many :section_runs
242
+ end
243
+
244
+ class Step < Sequel::Model
245
+ many_to_one :section
246
+ one_to_many :input_attributes, class: :StepInputAttribute
247
+ one_to_many :output_attributes, class: :StepOutputAttribute
248
+ one_to_many :step_runs
249
+ end
250
+
251
+ class Attribute < Sequel::Model
252
+ many_to_one :workflow
253
+ one_to_many :input_attributes, class: :StepInputAttribute
254
+ one_to_many :output_attributes, class: :StepOutputAttribute
255
+ end
256
+
257
+ class StepInputAttribute < Sequel::Model
258
+ many_to_one :step
259
+ many_to_one :attribute
260
+ end
261
+
262
+ class StepOutputAttribute < Sequel::Model
263
+ many_to_one :step
264
+ many_to_one :attribute
265
+ end
266
+
267
+ # Dynamic Workflow Execution
268
+
269
+ class WorkflowRun < Sequel::Model
270
+ many_to_one :workflow
271
+ one_to_many :section_runs
272
+ end
273
+
274
+ class SectionRun < Sequel::Model
275
+ many_to_one :workflow_run
276
+ many_to_one :section
277
+ one_to_many :step_runs
278
+ end
279
+
280
+ class StepRun < Sequel::Model
281
+ many_to_one :section_run
282
+ many_to_one :step
283
+ one_to_many :attribute_values
284
+ end
285
+
286
+ class AttributeValue < Sequel::Model
287
+ many_to_one :attribute
288
+ many_to_one :step_run
289
+ end
290
+
291
+ ```
292
+
293
+ ## Usage via Models
294
+
295
+ ```ruby
296
+ # example_usage.rb
297
+
298
+ require_relative 'models'
299
+
300
+ # Create a new workflow
301
+ workflow = Workflow.create(name: "YouTube Video Script", description: "Workflow for creating a YouTube video script")
302
+
303
+ # Create sections for the workflow
304
+ section1 = Section.create(name: "Research", description: "Research phase", order: 1, workflow: workflow)
305
+ section2 = Section.create(name: "Script Writing", description: "Script writing phase", order: 2, workflow: workflow)
306
+
307
+ # Create steps for the sections
308
+ step1 = Step.create(name: "01-1-basic-meta", description: "Basic metadata for Fotor AI tool", order: 1, section: section1, prompt: "Generate 5 titles to get started")
309
+ step2 = Step.create(name: "01-2-basic-factsheet", description: "Detailed factsheet about Fotor AI Tool", order: 2, section: section1, prompt: "Generate detailed factsheet")
310
+
311
+ # Create attributes
312
+ attribute1 = Attribute.create(name: "simple_title", type: "string", is_array: false, workflow: workflow)
313
+ attribute2 = Attribute.create(name: "basic_factsheet", type: "string", is_array: false, workflow: workflow)
314
+
315
+ # Associate input and output attributes with steps
316
+ StepInputAttribute.create(step: step1, attribute: attribute1)
317
+ StepOutputAttribute.create(step: step1, attribute: attribute2)
318
+
319
+ # Create a workflow run
320
+ workflow_run = WorkflowRun.create(workflow: workflow)
321
+
322
+ # Create section runs
323
+ section_run1 = SectionRun.create(workflow_run: workflow_run, section: section1)
324
+ section_run2 = SectionRun.create(workflow_run: workflow_run, section: section2)
325
+
326
+ # Create step runs
327
+ step_run1 = StepRun.create(section_run: section_run1, step: step1, branch_number: 1)
328
+ step_run2 = StepRun.create(section_run: section_run1, step: step2, branch_number: 1)
329
+
330
+ # Add attribute values to step runs
331
+ AttributeValue.create(attribute: attribute1, step_run: step_run1, value: "Fotor AI tool")
332
+ AttributeValue.create(attribute: attribute2, step_run: step_run2, value: "Detailed factsheet about Fotor AI Tool")
333
+ ```
334
+
335
+ ## Exporting to JSON
336
+
337
+ ```ruby
338
+ # export_to_json.rb
339
+
340
+ require 'json'
341
+ require_relative 'models'
342
+
343
+ # Export all workflows to JSON files
344
+ Workflow.all.each do |workflow|
345
+ workflow_data = {
346
+ id: workflow.id,
347
+ name: workflow.name,
348
+ description: workflow.description,
349
+ sections: workflow.sections.map do |section|
350
+ {
351
+ id: section.id,
352
+ name: section.name,
353
+ description: section.description,
354
+ order: section.order,
355
+ steps: section.steps.map do |step|
356
+ {
357
+ id: step.id,
358
+ name: step.name,
359
+ description: step.description,
360
+ order: step.order,
361
+ prompt: step.prompt,
362
+ input_attributes: step.input_attributes.map { |ia| { id: ia.attribute.id, name: ia.attribute.name } },
363
+ output_attributes: step.output_attributes.map { |oa| { id: oa.attribute.id, name: oa.attribute.name } }
364
+ }
365
+ end
366
+ }
367
+ end,
368
+ attributes: workflow.attributes.map { |attr| { id: attr.id, name: attr.name, type: attr.type, is_array: attr.is_array } }
369
+ }
370
+
371
+ File.write("workflow_#{workflow.id}.json", JSON.pretty_generate(workflow_data))
372
+ end
373
+
374
+ # Export all workflow runs to JSON files
375
+ WorkflowRun.all.each do |workflow_run|
376
+ workflow_run_data = {
377
+ id: workflow_run.id,
378
+ workflow_id: workflow_run.workflow_id,
379
+ section_runs: workflow_run.section_runs.map do |section_run|
380
+ {
381
+ id: section_run.id,
382
+ section_id: section_run.section_id,
383
+ step_runs: section_run.step_runs.map do |step_run|
384
+ {
385
+ id: step_run.id,
386
+ step_id: step_run.step_id,
387
+ branch_number: step_run.branch_number,
388
+ attribute_values: step_run.attribute_values.map { |av| { id: av.attribute.id, name: av.attribute.name, value: av.value } }
389
+ }
390
+ end
391
+ }
392
+ end
393
+ }
394
+
395
+ File.write("workflow_run_#{workflow_run.id}.json", JSON.pretty_generate(workflow_run_data))
396
+ end
397
+ ```
398
+
399
+ ## Importing from JSON
400
+
401
+ ```ruby
402
+ # import_from_json.rb
403
+
404
+ require 'json'
405
+ require_relative 'models'
406
+
407
+ # Helper function to find or create an attribute
408
+ def find_or_create_attribute(attr_data, workflow)
409
+ Attribute.find_or_create(name: attr_data['name'], workflow: workflow) do |attribute|
410
+ attribute.type = attr_data['type']
411
+ attribute.is_array = attr_data['is_array']
412
+ end
413
+ end
414
+
415
+ # Restore workflows from JSON files
416
+ Dir.glob('workflow_*.json').each do |file|
417
+ data = JSON.parse(File.read(file))
418
+
419
+ workflow = Workflow.find_or_create(id: data['id']) do |w|
420
+ w.name = data['name']
421
+ w.description = data['description']
422
+ end
423
+
424
+ data['sections'].each do |section_data|
425
+ section = Section.find_or_create(id: section_data['id'], workflow: workflow) do |s|
426
+ s.name = section_data['name']
427
+ s.description = section_data['description']
428
+ s.order = section_data['order']
429
+ end
430
+
431
+ section_data['steps'].each do |step_data|
432
+ step = Step.find_or_create(id: step_data['id'], section: section) do |s|
433
+ s.name = step_data['name']
434
+ s.description = step_data['description']
435
+ s.order = step_data['order']
436
+ s.prompt = step_data['prompt']
437
+ end
438
+
439
+ step_data['input_attributes'].each do |attr_data|
440
+ attribute = find_or_create_attribute(attr_data, workflow)
441
+ StepInputAttribute.find_or_create(step: step, attribute: attribute)
442
+ end
443
+
444
+ step_data['output_attributes'].each do |attr_data|
445
+ attribute = find_or_create_attribute(attr_data, workflow)
446
+ StepOutputAttribute.find_or_create(step: step, attribute: attribute)
447
+ end
448
+ end
449
+ end
450
+
451
+ data['attributes'].each do |attr_data|
452
+ find_or_create_attribute(attr_data, workflow)
453
+ end
454
+ end
455
+
456
+ # Restore workflow runs from JSON files
457
+ Dir.glob('workflow_run_*.json').each do |file|
458
+ data = JSON.parse(File.read(file))
459
+
460
+ workflow_run = WorkflowRun.find_or_create(id: data['id'], workflow_id: data['workflow_id'])
461
+
462
+ data['section_runs'].each do |section_run_data|
463
+ section_run = SectionRun.find_or_create(id: section_run_data['id'], workflow_run: workflow_run, section_id: section_run_data['section_id'])
464
+
465
+ section_run_data['step_runs'].each do |step_run_data|
466
+ step_run = StepRun.find_or_create(id: step_run_data['id'], section_run: section_run, step_id: step_run_data['step_id'], branch_number: step_run_data['branch_number'])
467
+
468
+ step_run_data['attribute_values'].each do |attr_value_data|
469
+ attribute = Attribute.find(id: attr_value_data['id'])
470
+ AttributeValue.find_or_create(attribute: attribute, step_run: step_run) do |av|
471
+ av.value = attr_value_data['value']
472
+ end
473
+ end
474
+ end
475
+ end
476
+ end
477
+ ```
478
+
479
+ ## Sample Implementation of Workflow Builder (DSL)
480
+
481
+ ```ruby
482
+ require 'yaml'
483
+ require 'sequel'
484
+
485
+ # Assuming the database and models are already set up
486
+ DB = Sequel.sqlite('workflow.db')
487
+
488
+ # Models
489
+ class Workflow < Sequel::Model
490
+ one_to_many :sections
491
+ one_to_many :attributes
492
+ one_to_many :workflow_runs
493
+ end
494
+
495
+ class Section < Sequel::Model
496
+ many_to_one :workflow
497
+ one_to_many :steps
498
+ one_to_many :section_runs
499
+ end
500
+
501
+ class Step < Sequel::Model
502
+ many_to_one :section
503
+ one_to_many :input_attributes, class: :StepInputAttribute
504
+ one_to_many :output_attributes, class: :StepOutputAttribute
505
+ one_to_many :step_runs
506
+ end
507
+
508
+ class Attribute < Sequel::Model
509
+ many_to_one :workflow
510
+ one_to_many :input_attributes, class: :StepInputAttribute
511
+ one_to_many :output_attributes, class: :StepOutputAttribute
512
+ end
513
+
514
+ class StepInputAttribute < Sequel::Model
515
+ many_to_one :step
516
+ many_to_one :attribute
517
+ end
518
+
519
+ class StepOutputAttribute < Sequel::Model
520
+ many_to_one :step
521
+ many_to_one :attribute
522
+ end
523
+
524
+ # WorkflowBuilder
525
+ class WorkflowBuilder
526
+ def initialize(name:, description: nil)
527
+ @workflow = Workflow.new(name: name, description: description)
528
+ @current_section_order = 1
529
+ end
530
+
531
+ def description(desc)
532
+ @workflow.description = desc
533
+ end
534
+
535
+ def section(name:, &block)
536
+ @current_step_order = 1
537
+ @current_section = Section.new(name: name, order: @current_section_order)
538
+ @current_section_order += 1
539
+ instance_eval(&block) if block_given?
540
+ @workflow.add_section(@current_section)
541
+ end
542
+
543
+ def step(name:, &block)
544
+ step = Step.new(name: name, order: @current_step_order)
545
+ @current_step_order += 1
546
+ instance_eval(&block) if block_given?
547
+ @current_section.add_step(step)
548
+ end
549
+
550
+ def prompt(prompt)
551
+ @current_section.steps.last.prompt = prompt
552
+ end
553
+
554
+ def save
555
+ @workflow.save
556
+ end
557
+
558
+ def to_yaml
559
+ workflow_data = {
560
+ id: @workflow.id,
561
+ name: @workflow.name,
562
+ description: @workflow.description,
563
+ sections: @workflow.sections.map do |section|
564
+ {
565
+ id: section.id,
566
+ name: section.name,
567
+ description: section.description,
568
+ order: section.order,
569
+ steps: section.steps.map do |step|
570
+ {
571
+ id: step.id,
572
+ name: step.name,
573
+ description: step.description,
574
+ order: step.order,
575
+ prompt: step.prompt
576
+ }
577
+ end
578
+ }
579
+ end
580
+ }
581
+ workflow_data.to_yaml
582
+ end
583
+ end
584
+
585
+ ```
586
+
587
+ ## Usage via DSL
588
+
589
+ ```ruby
590
+ builder = WorkflowBuilder.new(name: 'YouTube Video Script')
591
+
592
+ builder.section(name: 'Research') do
593
+ step(name: '01-1-basic-meta') do
594
+ prompt 'Generate 5 titles to get started'
595
+ end
596
+
597
+ step(name: '01-2-basic-factsheet') do
598
+ prompt 'Generate detailed factsheet'
599
+ end
600
+ end
601
+
602
+ builder.section(name: 'Script Writing') do
603
+ step(name: '02-1-create-script') do
604
+ prompt 'Generate basic script'
605
+ end
606
+ end
607
+
608
+ puts builder.to_yaml
609
+
610
+ # Save to the database
611
+ builder.save
612
+
613
+
614
+ builder = WorkflowBuilder.new(name: 'YouTube Title Creator')
615
+
616
+ builder.section(name: 'Research') do
617
+ step(name: '01-1-working-title') do
618
+ prompt 'Come up with a simple working title for the YouTube video.'
619
+ end
620
+
621
+ step(name: '01-2-keyword-research') do
622
+ prompt 'Perform basic keyword research to identify relevant keywords.'
623
+ end
624
+
625
+ step(name: '01-3-topic-research') do
626
+ prompt 'Conduct basic topic research to gather information on the subject.'
627
+ end
628
+
629
+ step(name: '01-4-powerful-titles') do
630
+ prompt 'Ask GPT for 10 powerful titles based on the research.'
631
+ end
632
+
633
+ step(name: '01-5-title-rules') do
634
+ prompt 'Follow specific rules for title creation to ensure effectiveness.'
635
+ end
636
+ end
637
+
638
+ puts builder.to_yaml
639
+
640
+ # Save to the database
641
+ builder.save
642
+
643
+ ```