Class: WritersRoom::Director

Inherits:
Object
  • Object
show all
Defined in:
lib/writers_room/director.rb

Overview

Director orchestrates a scene using the Room pattern.

Instead of manual sleep-polling, the Director:

  • Creates a Room (bus + memory + roster)
  • Loads actors from .md character files
  • Seeds the scene with an opening prompt
  • Lets Room.wait_for_completion handle the event loop
  • Assembles transcript from shared memory

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(scene_file:, character_dir: nil, max_lines: nil) ⇒ Director

Initialize the Director.

Parameters:

  • Path to scene .md file

  • (defaults to: nil)

    Directory containing character files (optional, auto-detected)

  • (defaults to: nil)

    Maximum dialog lines before scene ends



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/writers_room/director.rb', line 29

def initialize(scene_file:, character_dir: nil, max_lines: nil)
  @scene_file = scene_file
  @character_dir = character_dir || detect_character_dir(scene_file)
  @scene_info = load_scene
  @max_lines = max_lines || ENV["MAX_LINES"]&.to_i || 50
  @transcript = []
  @running = false

  # Build shared config via LLMSetup
  @run_config = LLMSetup.build_run_config

  # Create display
  @display = Display.new

  # Create room
  @room = Room.new(
    display:    @display,
    config:     @run_config,
    scene_info: @scene_info
  )

end

Instance Attribute Details

#roomObject (readonly)

Returns the value of attribute room.



22
23
24
# File 'lib/writers_room/director.rb', line 22

def room
  @room
end

#scene_infoObject (readonly)

Returns the value of attribute scene_info.



22
23
24
# File 'lib/writers_room/director.rb', line 22

def scene_info
  @scene_info
end

#transcriptObject (readonly)

Returns the value of attribute transcript.



22
23
24
# File 'lib/writers_room/director.rb', line 22

def transcript
  @transcript
end

Instance Method Details

#action!Object

Start the scene with all actors.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/writers_room/director.rb', line 53

def action!
  @display.scene_header(@scene_info)
  @running = true

  load_actors

  if @room.actors.empty?
    @display.director_note("No actors could be loaded. Cannot direct scene.")
    return
  end

  seed_scene
  @room.wait_for_completion(timeout: scene_timeout, max_lines: @max_lines)

  # Collect transcript from shared memory
  @transcript = @room.assemble_transcript

  shutdown_actors
end

#cut!Object

Stop the scene and all actors.



74
75
76
77
78
# File 'lib/writers_room/director.rb', line 74

def cut!
  @running = false
  @display.director_note("CUT! Scene ended.")
  shutdown_actors
end

#save_transcript(filename = nil) ⇒ Object

Save the transcript to a file.

Parameters:

  • (defaults to: nil)

    Output filename



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/writers_room/director.rb', line 83

def save_transcript(filename = nil)
  unless filename
    transcripts_dir = detect_transcripts_dir(@scene_file)
    FileUtils.mkdir_p(transcripts_dir)
    filename = File.join(transcripts_dir, "transcript_scene_#{@scene_info[:scene_number]}_#{Time.now.to_i}.txt")
  end

  File.open(filename, "w") do |file|
    file.puts "SCENE #{@scene_info[:scene_number]}: #{@scene_info[:scene_name]}"
    file.puts "Location: #{@scene_info[:location]}"
    file.puts "Week: #{@scene_info[:week]}"
    file.puts "\n" + "-" * 60 + "\n"

    @transcript.each do |entry|
      emotion_tag = entry[:emotion] ? " [#{entry[:emotion]}]" : ""
      file.puts "#{entry[:from]}#{emotion_tag}: #{entry[:content]}"
    end
  end

  @display.info("Transcript saved to: #{filename}")
  filename
end

#statisticsObject

Get scene statistics.



107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/writers_room/director.rb', line 107

def statistics
  total_lines = @transcript.length
  lines_by_character = @transcript
    .group_by { |e| e[:from] }
    .transform_values(&:count)

  {
    total_lines: total_lines,
    lines_by_character: lines_by_character,
    scene: @scene_info[:scene_number],
  }
end