ad-agent_architecture 0.0.3 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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
+ ```