Class: Charai::InputTool

Inherits:
Object
  • Object
show all
Defined in:
lib/charai/input_tool.rb

Overview

Hub class for performing actions on the browser Mainly used by AI.

Instance Method Summary collapse

Constructor Details

#initialize(browsing_context, callback: nil) ⇒ InputTool

callback

  • on_assertion_ok(description)
  • on_assertion_fail(description)
  • on_action_start(action, params)


9
10
11
12
# File 'lib/charai/input_tool.rb', line 9

def initialize(browsing_context, callback: nil)
  @browsing_context = browsing_context
  @callback = callback
end

Instance Method Details

#aria_snapshot(root_locator: 'document.body', ref: false) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/charai/input_tool.rb', line 34

def aria_snapshot(root_locator: 'document.body', ref: false)
  trigger_callback(:on_action_start, 'aria_snapshot', { root_locator: root_locator, ref: ref })

  current_url = @browsing_context.url
  snapshot = @browsing_context.default_realm._with_injected_script do |script|
    if ref
      body_handle = script.getprop("document.body", as_handle: true)
      result = script.call(:ariaSnapshot, body_handle, { mode: 'ai' })
      result.split("\n")
    else
      not_found = script.e("!#{root_locator}")
      if not_found
        raise ArgumentError, "Element not found: #{root_locator}"
      end
      result = script.call(:ariaSnapshot, script.h(root_locator), { mode: 'autoexpect' })
      result.split("\n")
    end
  end

  if @message_sender
    message = Agent::Message.new(text: "ARIA snapshot of #{current_url}\n\n#{snapshot}")
    @message_sender.call(message)
  end
end

#assertion_fail(description) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
# File 'lib/charai/input_tool.rb', line 22

def assertion_fail(description)
  trigger_callback(:on_assertion_fail, description)

  if defined?(RSpec::Expectations)
    RSpec::Expectations.fail_with(description)
  elsif defined?(MiniTest::Assertion)
    raise MiniTest::Assertion, description
  else
    raise description
  end
end

#assertion_ok(description) ⇒ Object



18
19
20
# File 'lib/charai/input_tool.rb', line 18

def assertion_ok(description)
  trigger_callback(:on_assertion_ok, description)
end

#capture_screenshotObject



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/charai/input_tool.rb', line 59

def capture_screenshot
  trigger_callback(:on_action_start, 'capture_screenshot', {})

  current_url = @browsing_context.url
  @browsing_context.capture_screenshot(format: { type: 'png' }).tap do |binary|
    if @message_sender
      message = Agent::Message.new(
        text: "Capture of #{current_url}",
        images: [
          { png: Base64.strict_encode64(binary) },
        ],
      )
      @message_sender.call(message)
    end
  end
end

#click(x:, y:, delay: 50) ⇒ Object



76
77
78
79
80
81
82
83
84
85
# File 'lib/charai/input_tool.rb', line 76

def click(x:, y:, delay: 50)
  trigger_callback(:on_action_start, 'click', { x: x, y: y, delay: delay })

  @browsing_context.perform_mouse_actions do |q|
    q.pointer_move(x: x.to_i, y: y.to_i)
    q.pointer_down(button: 0)
    q.pause(duration: delay)
    q.pointer_up(button: 0)
  end
end

#execute_script(script) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/charai/input_tool.rb', line 87

def execute_script(script)
  trigger_callback(:on_action_start, 'execute_script', { script: script })

  begin
    result = @browsing_context.default_realm.script_evaluate(script)
  rescue BrowsingContext::Realm::ScriptEvaluationError => e
    result = e.message
  end

  notify_to_sender(result) unless "#{result}" == ''

  result
end

#execute_script_with_ref(ref, element_function_declaration) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/charai/input_tool.rb', line 101

def execute_script_with_ref(ref, element_function_declaration)
  resolved = resolve_selector_for_ref(ref)
  trigger_callback(:on_action_start, 'execute_script_with_ref', { script: element_function_declaration, ref: ref, selector: resolved[:selector] })

  begin
    result = @browsing_context.default_realm.script_call_function(
      element_function_declaration,
      arguments: [resolved[:element_handle]])
  rescue BrowsingContext::Realm::ScriptEvaluationError => e
    result = e.message
  end

  notify_to_sender(result) unless "#{result}" == ''

  result
end

#on_pressing_key(key, &block) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/charai/input_tool.rb', line 118

def on_pressing_key(key, &block)
  trigger_callback(:on_action_start, 'key_down', { key: key })

  value = convert_key(key)
  @browsing_context.perform_keyboard_actions do |q|
    q.key_down(value: value)
  end

  begin
    block.call
  ensure
    trigger_callback(:on_action_start, 'key_up', { key: key })

    @browsing_context.perform_keyboard_actions do |q|
      q.key_up(value: value)
    end
  end
end

#on_send_message(&block) ⇒ Object



14
15
16
# File 'lib/charai/input_tool.rb', line 14

def on_send_message(&block)
  @message_sender = block
end

#press_key(key, delay: 50) ⇒ Object



137
138
139
140
141
142
143
144
145
146
# File 'lib/charai/input_tool.rb', line 137

def press_key(key, delay: 50)
  trigger_callback(:on_action_start, 'press_key', { key: key, delay: delay })

  value = convert_key(key)
  @browsing_context.perform_keyboard_actions do |q|
    q.key_down(value: value)
    q.pause(duration: delay)
    q.key_up(value: value)
  end
end

#scroll_down(x: 0, y: 0, velocity: 1000) ⇒ Object

velocity: 500 - weak 1000 - normal 2000 - strong

Raises:

  • (ArgumentError)


171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/charai/input_tool.rb', line 171

def scroll_down(x: 0, y: 0, velocity: 1000)
  raise ArgumentError, 'velocity must be positive' if velocity <= 0
  trigger_callback(:on_action_start, 'scroll_down', { x: x, y: y, velocity: velocity })

  @browsing_context.perform_mouse_wheel_actions do |q|
    deceleration = SplineDeceleration.new(velocity)
    loop do
      delta_y = deceleration.calc
      break if delta_y.zero?
      q.scroll(x: x, y: y, delta_y: delta_y, duration: 16)
    end
  end
end

#scroll_up(x: 0, y: 0, velocity: 1000) ⇒ Object

velocity: 500 - weak 1000 - normal 2000 - strong

Raises:

  • (ArgumentError)


189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/charai/input_tool.rb', line 189

def scroll_up(x: 0, y: 0, velocity: 1000)
  raise ArgumentError, 'velocity must be positive' if velocity <= 0
  trigger_callback(:on_action_start, 'scroll_up', { x: x, y: y, velocity: velocity })

  @browsing_context.perform_mouse_wheel_actions do |q|
    deceleration = SplineDeceleration.new(velocity)
    loop do
      delta_y = -deceleration.calc
      break if delta_y.zero?
      q.scroll(x: x, y: y, delta_y: delta_y, duration: 16)
    end
  end
end

#sleep_seconds(seconds) ⇒ Object



148
149
150
151
152
# File 'lib/charai/input_tool.rb', line 148

def sleep_seconds(seconds)
  trigger_callback(:on_action_start, 'sleep_seconds', { seconds: seconds })

  sleep seconds
end

#type_text(text, delay: 50) ⇒ Object



154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/charai/input_tool.rb', line 154

def type_text(text, delay: 50)
  trigger_callback(:on_action_start, 'type_text', { text: text, delay: delay })

  text.each_char do |c|
    @browsing_context.perform_keyboard_actions do |q|
      q.key_down(value: c)
      q.pause(duration: delay / 2)
      q.key_up(value: c)
      q.pause(duration: delay - delay / 2)
    end
  end
end