ai_screen_analyzer 0.1.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +26 -0
- data/LICENSE.txt +21 -0
- data/README.md +242 -0
- data/app/controllers/ai_screen_analyzer/ai_analyzer_controller.rb +91 -0
- data/app/helpers/ai_screen_analyzer/ai_screen_analyzer_helper.rb +15 -0
- data/app/views/ai_screen_analyzer/shared/_ai_screen_analyzer.html.erb +374 -0
- data/config/routes.rb +3 -0
- data/lib/ai_screen_analyzer/engine.rb +38 -0
- data/lib/ai_screen_analyzer/version.rb +3 -0
- data/lib/ai_screen_analyzer.rb +24 -0
- data/lib/generators/ai_screen_analyzer/install_generator.rb +81 -0
- metadata +131 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: a6bf3e8162eb1f6bf74dbc3c95014e2dc85eac5b366ab8250c37565b3a2a3cd8
|
|
4
|
+
data.tar.gz: 6cc3545842cf2c2a3590c97a1303a4551e85c59f54ca5c4eb24547035608e6db
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 18c631bb87ef6ec91e4b730202dd4ad330c8cb54c711e8a2332624417bac0d07df127da950244c016651a8496608825e19303abe4ccc352036bd3a23ff0705da
|
|
7
|
+
data.tar.gz: b776e0d6e50be723bce6632a709715a63a448cdee294273d878237fa1ae7e865197eb21c592f9e8e44c8f1d75c45bdf53b1f3cd544f28a43761bea65d153f927
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2024-12-10
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Initial release of AI Screen Analyzer gem
|
|
12
|
+
- `ai_screen_analyzer` helper to add AI screen analysis to any page
|
|
13
|
+
- Customizable floating button
|
|
14
|
+
- Elegant sidebar to display results
|
|
15
|
+
- Support for customizable prompts
|
|
16
|
+
- Controller to process analysis requests
|
|
17
|
+
- Integration with OpenAI GPT-4V API
|
|
18
|
+
- Installation generator
|
|
19
|
+
- Complete documentation
|
|
20
|
+
|
|
21
|
+
### Features
|
|
22
|
+
- Screenshot capture using html2canvas
|
|
23
|
+
- Image upload for AI analysis
|
|
24
|
+
- Real-time results display
|
|
25
|
+
- Support for customizing colors and texts
|
|
26
|
+
- Responsive for mobile devices
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 AI Screen Analyzer Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# AI Screen Analyzer
|
|
2
|
+
|
|
3
|
+
A Rails gem that adds AI-powered screen analysis to any application. With a simple helper, you can capture the visual content of any page, send it for analysis with GPT-4V, and display the result in an interactive sidebar.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Customizable Floating Button:** A sleek button that appears on any page.
|
|
10
|
+
- **Automatic Screenshot Capture:** Uses `html2canvas` to capture the visual content of the page.
|
|
11
|
+
- **AI Analysis:** Integration with OpenAI's GPT-4V for intelligent analysis.
|
|
12
|
+
- **Responsive Sidebar:** Displays results in an elegant, non-intrusive sidebar.
|
|
13
|
+
- **Customizable Prompts:** Configure different prompts for different use cases.
|
|
14
|
+
- **Easy Integration:** Just add one line of code to your layout.
|
|
15
|
+
- **No External Dependencies:** Uses only standard Rails libraries.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
Add the gem to your `Gemfile`:
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
gem 'ai_screen_analyzer'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Run bundler:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
bundle install
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Run the installation generator:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
rails generate ai_screen_analyzer:install
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Routes
|
|
38
|
+
|
|
39
|
+
The generator automatically mounts the engine in your host application. After installation, these routes are available by default:
|
|
40
|
+
|
|
41
|
+
- Engine mounted at: `/ai_screen_analyzer`
|
|
42
|
+
- Analysis endpoint: `POST /ai_screen_analyzer/analyze-screen`
|
|
43
|
+
|
|
44
|
+
If you need to mount manually (or customize the path), add this to your app's `config/routes.rb`:
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
# Mount the AiScreenAnalyzer engine, exposing its routes under /ai_screen_analyzer
|
|
48
|
+
mount AiScreenAnalyzer::Engine => '/ai_screen_analyzer', as: 'ai_screen_analyzer_engine'
|
|
49
|
+
|
|
50
|
+
# (Optional) Direct alias for compatibility with existing calls
|
|
51
|
+
post '/ai_screen_analyzer/analyze-screen', to: 'ai_screen_analyzer/ai_analyzer#analyze_screen'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Notes:
|
|
55
|
+
- The gem's view uses route helpers to resolve the endpoint dynamically according to the mounted path, avoiding 404s when you customize the path.
|
|
56
|
+
- If you change the mount path, you don't need to change anything in the view; the helper will point to the new path.
|
|
57
|
+
|
|
58
|
+
## Configuration
|
|
59
|
+
|
|
60
|
+
### 1. OpenAI API Key
|
|
61
|
+
|
|
62
|
+
Set your OpenAI API key as an environment variable:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
export OPENAI_API_KEY='your_secret_key_here'
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Or configure it in `config/initializers/ai_screen_analyzer.rb`:
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
AiScreenAnalyzer.configure do |config|
|
|
72
|
+
config.api_key = ENV['OPENAI_API_KEY']
|
|
73
|
+
config.model = 'gpt-4-turbo'
|
|
74
|
+
end
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 2. Add the Helper to the Layout
|
|
78
|
+
|
|
79
|
+
Open your main layout (`app/views/layouts/application.html.erb`) and add:
|
|
80
|
+
|
|
81
|
+
```erb
|
|
82
|
+
<body>
|
|
83
|
+
<%= yield %>
|
|
84
|
+
|
|
85
|
+
<%= ai_screen_analyzer %>
|
|
86
|
+
</body>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Usage
|
|
90
|
+
|
|
91
|
+
### Basic Usage
|
|
92
|
+
|
|
93
|
+
```erb
|
|
94
|
+
<%= ai_screen_analyzer %>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### With Customizations
|
|
98
|
+
|
|
99
|
+
```erb
|
|
100
|
+
<%= ai_screen_analyzer(
|
|
101
|
+
prompt: "You are a UX expert. Analyze this interface and provide feedback.",
|
|
102
|
+
button_text: "Review Design",
|
|
103
|
+
sidebar_title: "UX Feedback"
|
|
104
|
+
) %>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Options
|
|
108
|
+
|
|
109
|
+
| Option | Description | Default |
|
|
110
|
+
|-------|-----------|--------|
|
|
111
|
+
| `prompt` | The prompt text sent to the AI along with the image | "Analyze the visible content on this screen..." |
|
|
112
|
+
| `button_text` | Text displayed on the floating button | "Analyze with AI" |
|
|
113
|
+
| `sidebar_title` | Title of the results sidebar | "AI Analysis" |
|
|
114
|
+
|
|
115
|
+
## Usage Examples
|
|
116
|
+
|
|
117
|
+
### UX/UI Analysis
|
|
118
|
+
|
|
119
|
+
```erb
|
|
120
|
+
<%= ai_screen_analyzer(
|
|
121
|
+
prompt: "You are a UX/UI expert. Analyze this interface and provide feedback on: 1) Visual hierarchy, 2) Accessibility, 3) Design consistency, 4) Improvement suggestions.",
|
|
122
|
+
button_text: "Review Design",
|
|
123
|
+
sidebar_title: "UX/UI Feedback"
|
|
124
|
+
) %>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Accessibility Analysis
|
|
128
|
+
|
|
129
|
+
```erb
|
|
130
|
+
<%= ai_screen_analyzer(
|
|
131
|
+
prompt: "You are a web accessibility (WCAG) specialist. Analyze this page and identify potential accessibility issues.",
|
|
132
|
+
button_text: "Check Accessibility",
|
|
133
|
+
sidebar_title: "Accessibility Analysis"
|
|
134
|
+
) %>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Content Analysis
|
|
138
|
+
|
|
139
|
+
```erb
|
|
140
|
+
<%= ai_screen_analyzer(
|
|
141
|
+
prompt: "Analyze the textual content of this page. Evaluate: 1) Clarity of message, 2) Writing quality, 3) Tone appropriateness.",
|
|
142
|
+
button_text: "Analyze Content",
|
|
143
|
+
sidebar_title: "Content Analysis"
|
|
144
|
+
) %>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## How It Works
|
|
148
|
+
|
|
149
|
+
1. The user clicks the "Analyze with AI" button.
|
|
150
|
+
2. The `html2canvas` JavaScript library captures an image of the page body.
|
|
151
|
+
3. The image is converted to base64 and sent to the Rails backend.
|
|
152
|
+
4. The controller processes the image and sends it to the GPT-4V API.
|
|
153
|
+
5. The AI analyzes the image according to the provided prompt.
|
|
154
|
+
6. The result is returned and displayed in the sidebar.
|
|
155
|
+
|
|
156
|
+
## Gem Structure
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
ai_screen_analyzer/
|
|
160
|
+
├── app/
|
|
161
|
+
│ ├── controllers/
|
|
162
|
+
│ │ └── ai_screen_analyzer/
|
|
163
|
+
│ │ └── ai_analyzer_controller.rb
|
|
164
|
+
│ ├── helpers/
|
|
165
|
+
│ │ └── ai_screen_analyzer/
|
|
166
|
+
│ │ └── ai_screen_analyzer_helper.rb
|
|
167
|
+
│ └── views/
|
|
168
|
+
│ └── ai_screen_analyzer/
|
|
169
|
+
│ └── shared/
|
|
170
|
+
│ └── _ai_screen_analyzer.html.erb
|
|
171
|
+
├── config/
|
|
172
|
+
│ └── routes.rb
|
|
173
|
+
├── lib/
|
|
174
|
+
│ ├── ai_screen_analyzer.rb
|
|
175
|
+
│ ├── ai_screen_analyzer/
|
|
176
|
+
│ │ ├── engine.rb
|
|
177
|
+
│ │ └── version.rb
|
|
178
|
+
│ └── generators/
|
|
179
|
+
│ └── ai_screen_analyzer/
|
|
180
|
+
│ └── install_generator.rb
|
|
181
|
+
├── ai_screen_analyzer.gemspec
|
|
182
|
+
├── Rakefile
|
|
183
|
+
├── README.md
|
|
184
|
+
├── LICENSE.txt
|
|
185
|
+
└── CHANGELOG.md
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Requirements
|
|
189
|
+
|
|
190
|
+
- Rails 6.0 or higher
|
|
191
|
+
- Ruby 2.7.0 or higher
|
|
192
|
+
- Valid OpenAI API key (with access to the gpt-4-turbo model)
|
|
193
|
+
|
|
194
|
+
## Troubleshooting
|
|
195
|
+
|
|
196
|
+
### The button does not appear
|
|
197
|
+
|
|
198
|
+
Make sure the helper is being called correctly in your layout and there are no errors in the browser console.
|
|
199
|
+
|
|
200
|
+
### Analysis is not working
|
|
201
|
+
|
|
202
|
+
Ensure that:
|
|
203
|
+
- The OpenAI API key is configured correctly
|
|
204
|
+
- You have sufficient credits in your OpenAI account
|
|
205
|
+
- The route is registered correctly
|
|
206
|
+
|
|
207
|
+
### 404 error when calling analyze-screen
|
|
208
|
+
|
|
209
|
+
- Ensure the engine is mounted in the host app. By default, the generator already adds this line to your `config/routes.rb`:
|
|
210
|
+
|
|
211
|
+
```ruby
|
|
212
|
+
mount AiScreenAnalyzer::Engine => '/ai_screen_analyzer', as: 'ai_screen_analyzer_engine'
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
- If you removed the automatic mount, add it manually as above.
|
|
216
|
+
- Restart the server after changing routes.
|
|
217
|
+
- Run `bin/rails routes | grep ai_screen_analyzer` to confirm the presence of the `analyze-screen` endpoint.
|
|
218
|
+
|
|
219
|
+
### CORS error
|
|
220
|
+
|
|
221
|
+
If you receive CORS errors when capturing the screen, ensure that all external resources are using HTTPS.
|
|
222
|
+
|
|
223
|
+
## Contributing
|
|
224
|
+
|
|
225
|
+
Contributions are welcome! Please open an issue or submit a pull request.
|
|
226
|
+
|
|
227
|
+
## License
|
|
228
|
+
|
|
229
|
+
This gem is licensed under the MIT License. See LICENSE.txt for details.
|
|
230
|
+
|
|
231
|
+
## Support
|
|
232
|
+
|
|
233
|
+
For support, open an issue in the GitHub repository or contact the maintainers.
|
|
234
|
+
|
|
235
|
+
## Changelog
|
|
236
|
+
|
|
237
|
+
See the CHANGELOG.md file for a list of all changes.
|
|
238
|
+
|
|
239
|
+
## Roadmap
|
|
240
|
+
|
|
241
|
+
- Support for other AI models (Claude, Gemini, etc.)
|
|
242
|
+
- Cache of recent analyses
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
require 'base64'
|
|
2
|
+
require 'net/http'
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
5
|
+
module AiScreenAnalyzer
|
|
6
|
+
class AiAnalyzerController < ActionController::Base
|
|
7
|
+
skip_before_action :verify_authenticity_token, only: [:analyze_screen]
|
|
8
|
+
|
|
9
|
+
def analyze_screen
|
|
10
|
+
begin
|
|
11
|
+
image_data = params[:image]
|
|
12
|
+
prompt = params[:prompt]
|
|
13
|
+
|
|
14
|
+
# Validar parâmetros
|
|
15
|
+
return render_error('Imagem não fornecida') if image_data.blank?
|
|
16
|
+
return render_error('Prompt não fornecido') if prompt.blank?
|
|
17
|
+
|
|
18
|
+
# Remover data URI prefix se presente
|
|
19
|
+
image_data = image_data.sub(/^data:image\/\w+;base64,/, '')
|
|
20
|
+
|
|
21
|
+
# Chamar API do GPT-4V
|
|
22
|
+
analysis = analyze_with_gpt4v(image_data, prompt)
|
|
23
|
+
|
|
24
|
+
render json: {
|
|
25
|
+
success: true,
|
|
26
|
+
analysis: analysis
|
|
27
|
+
}
|
|
28
|
+
rescue StandardError => e
|
|
29
|
+
render_error(e.message)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def analyze_with_gpt4v(image_data, prompt)
|
|
36
|
+
api_key = ENV['OPENAI_API_KEY'] || AiScreenAnalyzer.api_key
|
|
37
|
+
return 'Chave de API não configurada' if api_key.blank?
|
|
38
|
+
|
|
39
|
+
uri = URI('https://api.openai.com/v1/chat/completions')
|
|
40
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
41
|
+
http.use_ssl = true
|
|
42
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
43
|
+
|
|
44
|
+
request = Net::HTTP::Post.new(uri.path)
|
|
45
|
+
request['Content-Type'] = 'application/json'
|
|
46
|
+
request['Authorization'] = "Bearer #{api_key}"
|
|
47
|
+
|
|
48
|
+
model = AiScreenAnalyzer.model || 'gpt-4-turbo'
|
|
49
|
+
|
|
50
|
+
body = {
|
|
51
|
+
model: model,
|
|
52
|
+
messages: [
|
|
53
|
+
{
|
|
54
|
+
role: 'user',
|
|
55
|
+
content: [
|
|
56
|
+
{
|
|
57
|
+
type: 'text',
|
|
58
|
+
text: prompt
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
type: 'image_url',
|
|
62
|
+
image_url: {
|
|
63
|
+
url: "data:image/jpeg;base64,#{image_data}"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
],
|
|
69
|
+
max_tokens: 1024
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
request.body = body.to_json
|
|
73
|
+
|
|
74
|
+
response = http.request(request)
|
|
75
|
+
result = JSON.parse(response.body)
|
|
76
|
+
|
|
77
|
+
if response.code.to_i == 200
|
|
78
|
+
result['choices'][0]['message']['content']
|
|
79
|
+
else
|
|
80
|
+
raise "Erro da API: #{result['error']['message']}"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def render_error(message)
|
|
85
|
+
render json: {
|
|
86
|
+
success: false,
|
|
87
|
+
error: message
|
|
88
|
+
}, status: :unprocessable_entity
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module AiScreenAnalyzer
|
|
2
|
+
module AiScreenAnalyzerHelper
|
|
3
|
+
def ai_screen_analyzer(options = {})
|
|
4
|
+
prompt = options[:prompt] || AiScreenAnalyzer.default_prompt
|
|
5
|
+
button_text = options[:button_text] || AiScreenAnalyzer.default_button_text
|
|
6
|
+
sidebar_title = options[:sidebar_title] || AiScreenAnalyzer.default_sidebar_title
|
|
7
|
+
|
|
8
|
+
render 'ai_screen_analyzer/shared/ai_screen_analyzer', {
|
|
9
|
+
prompt: prompt,
|
|
10
|
+
button_text: button_text,
|
|
11
|
+
sidebar_title: sidebar_title
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
<% # AI Screen Analyzer Component %>
|
|
2
|
+
|
|
3
|
+
<div>
|
|
4
|
+
<%# Resolve dinamicamente o endpoint respeitando o path de montagem definido no app host %>
|
|
5
|
+
<% endpoint_path = (analyze_screen_path rescue '/ai_screen_analyzer/analyze-screen') %>
|
|
6
|
+
<!-- Botão flutuante para ativar análise -->
|
|
7
|
+
<button
|
|
8
|
+
class="button"
|
|
9
|
+
id="ai-analyzer-trigger"
|
|
10
|
+
title="Clique para analisar a tela com IA"
|
|
11
|
+
>
|
|
12
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
13
|
+
<circle cx="12" cy="12" r="1"></circle>
|
|
14
|
+
<path d="M12 1v6m0 6v6"></path>
|
|
15
|
+
<path d="M4.22 4.22l4.24 4.24m5.08 5.08l4.24 4.24"></path>
|
|
16
|
+
<path d="M1 12h6m6 0h6"></path>
|
|
17
|
+
<path d="M4.22 19.78l4.24-4.24m5.08-5.08l4.24-4.24"></path>
|
|
18
|
+
</svg>
|
|
19
|
+
<%= button_text %>
|
|
20
|
+
</button>
|
|
21
|
+
|
|
22
|
+
<!-- Barra lateral com resultado da análise -->
|
|
23
|
+
<div class="ai-analyzer-sidebar" id="ai-analyzer-sidebar">
|
|
24
|
+
<div class="ai-analyzer-header">
|
|
25
|
+
<h3><%= sidebar_title %></h3>
|
|
26
|
+
<button class="ai-analyzer-close" id="ai-analyzer-close">
|
|
27
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
28
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
29
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
30
|
+
</svg>
|
|
31
|
+
</button>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<div class="ai-analyzer-content" id="ai-analyzer-content">
|
|
35
|
+
<div class="ai-analyzer-loading" id="ai-analyzer-loading" style="display: none;">
|
|
36
|
+
<div class="spinner"></div>
|
|
37
|
+
<p>Analisando tela com IA...</p>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="ai-analyzer-result" id="ai-analyzer-result" style="display: none;"></div>
|
|
40
|
+
<div class="ai-analyzer-error" id="ai-analyzer-error" style="display: none;"></div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<!-- Overlay para fechar sidebar -->
|
|
45
|
+
<div class="ai-analyzer-overlay" id="ai-analyzer-overlay"></div>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<style>
|
|
49
|
+
.ai-screen-analyzer-container {
|
|
50
|
+
position: fixed;
|
|
51
|
+
z-index: 9998;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Botão flutuante */
|
|
55
|
+
.ai-analyzer-button {
|
|
56
|
+
position: fixed;
|
|
57
|
+
bottom: 20px;
|
|
58
|
+
right: 20px;
|
|
59
|
+
z-index: 9999;
|
|
60
|
+
width: 56px;
|
|
61
|
+
height: 56px;
|
|
62
|
+
border-radius: 50%;
|
|
63
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
64
|
+
color: white;
|
|
65
|
+
border: none;
|
|
66
|
+
cursor: pointer;
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
justify-content: center;
|
|
70
|
+
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
|
71
|
+
transition: all 0.3s ease;
|
|
72
|
+
font-size: 0;
|
|
73
|
+
padding: 0;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.ai-analyzer-button:hover {
|
|
77
|
+
transform: scale(1.1);
|
|
78
|
+
box-shadow: 0 6px 16px rgba(102, 126, 234, 0.6);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.ai-analyzer-button:active {
|
|
82
|
+
transform: scale(0.95);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.ai-analyzer-button svg {
|
|
86
|
+
width: 24px;
|
|
87
|
+
height: 24px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Overlay */
|
|
91
|
+
.ai-analyzer-overlay {
|
|
92
|
+
position: fixed;
|
|
93
|
+
top: 0;
|
|
94
|
+
left: 0;
|
|
95
|
+
width: 100%;
|
|
96
|
+
height: 100%;
|
|
97
|
+
background: rgba(0, 0, 0, 0.5);
|
|
98
|
+
z-index: 9997;
|
|
99
|
+
opacity: 0;
|
|
100
|
+
pointer-events: none;
|
|
101
|
+
transition: opacity 0.3s ease;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.ai-analyzer-overlay.active {
|
|
105
|
+
opacity: 1;
|
|
106
|
+
pointer-events: auto;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Barra lateral */
|
|
110
|
+
.ai-analyzer-sidebar {
|
|
111
|
+
position: fixed;
|
|
112
|
+
right: 0;
|
|
113
|
+
top: 0;
|
|
114
|
+
width: 400px;
|
|
115
|
+
height: 100vh;
|
|
116
|
+
background: white;
|
|
117
|
+
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.15);
|
|
118
|
+
z-index: 9999;
|
|
119
|
+
display: flex;
|
|
120
|
+
flex-direction: column;
|
|
121
|
+
transform: translateX(100%);
|
|
122
|
+
transition: transform 0.3s ease;
|
|
123
|
+
overflow: hidden;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.ai-analyzer-sidebar.active {
|
|
127
|
+
transform: translateX(0);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@media (max-width: 768px) {
|
|
131
|
+
.ai-analyzer-sidebar {
|
|
132
|
+
width: 100%;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* Header da sidebar */
|
|
137
|
+
.ai-analyzer-header {
|
|
138
|
+
padding: 20px;
|
|
139
|
+
border-bottom: 1px solid #e5e7eb;
|
|
140
|
+
display: flex;
|
|
141
|
+
justify-content: space-between;
|
|
142
|
+
align-items: center;
|
|
143
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
144
|
+
color: white;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.ai-analyzer-header h3 {
|
|
148
|
+
margin: 0;
|
|
149
|
+
font-size: 18px;
|
|
150
|
+
font-weight: 600;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.ai-analyzer-close {
|
|
154
|
+
background: none;
|
|
155
|
+
border: none;
|
|
156
|
+
color: white;
|
|
157
|
+
cursor: pointer;
|
|
158
|
+
padding: 4px;
|
|
159
|
+
display: flex;
|
|
160
|
+
align-items: center;
|
|
161
|
+
justify-content: center;
|
|
162
|
+
transition: opacity 0.2s ease;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.ai-analyzer-close:hover {
|
|
166
|
+
opacity: 0.8;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/* Conteúdo da sidebar */
|
|
170
|
+
.ai-analyzer-content {
|
|
171
|
+
flex: 1;
|
|
172
|
+
overflow-y: auto;
|
|
173
|
+
padding: 20px;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/* Loading spinner */
|
|
177
|
+
.ai-analyzer-loading {
|
|
178
|
+
display: flex;
|
|
179
|
+
flex-direction: column;
|
|
180
|
+
align-items: center;
|
|
181
|
+
justify-content: center;
|
|
182
|
+
height: 100%;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.spinner {
|
|
186
|
+
width: 40px;
|
|
187
|
+
height: 40px;
|
|
188
|
+
border: 4px solid #e5e7eb;
|
|
189
|
+
border-top-color: #667eea;
|
|
190
|
+
border-radius: 50%;
|
|
191
|
+
animation: spin 0.8s linear infinite;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
@keyframes spin {
|
|
195
|
+
to { transform: rotate(360deg); }
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.ai-analyzer-loading p {
|
|
199
|
+
margin-top: 16px;
|
|
200
|
+
color: #6b7280;
|
|
201
|
+
font-size: 14px;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* Resultado */
|
|
205
|
+
.ai-analyzer-result {
|
|
206
|
+
color: #374151;
|
|
207
|
+
font-size: 14px;
|
|
208
|
+
line-height: 1.6;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.ai-analyzer-result h4 {
|
|
212
|
+
color: #667eea;
|
|
213
|
+
margin-top: 16px;
|
|
214
|
+
margin-bottom: 8px;
|
|
215
|
+
font-size: 14px;
|
|
216
|
+
font-weight: 600;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.ai-analyzer-result p {
|
|
220
|
+
margin: 0 0 12px 0;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.ai-analyzer-result ul,
|
|
224
|
+
.ai-analyzer-result ol {
|
|
225
|
+
margin: 8px 0 12px 20px;
|
|
226
|
+
padding: 0;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.ai-analyzer-result li {
|
|
230
|
+
margin-bottom: 6px;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/* Erro */
|
|
234
|
+
.ai-analyzer-error {
|
|
235
|
+
background: #fee2e2;
|
|
236
|
+
border: 1px solid #fecaca;
|
|
237
|
+
border-radius: 6px;
|
|
238
|
+
padding: 12px;
|
|
239
|
+
color: #991b1b;
|
|
240
|
+
font-size: 14px;
|
|
241
|
+
line-height: 1.5;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* Scrollbar customizado */
|
|
245
|
+
.ai-analyzer-content::-webkit-scrollbar {
|
|
246
|
+
width: 6px;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.ai-analyzer-content::-webkit-scrollbar-track {
|
|
250
|
+
background: #f3f4f6;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.ai-analyzer-content::-webkit-scrollbar-thumb {
|
|
254
|
+
background: #d1d5db;
|
|
255
|
+
border-radius: 3px;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.ai-analyzer-content::-webkit-scrollbar-thumb:hover {
|
|
259
|
+
background: #9ca3af;
|
|
260
|
+
}
|
|
261
|
+
</style>
|
|
262
|
+
|
|
263
|
+
<script>
|
|
264
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
265
|
+
const triggerButton = document.getElementById('ai-analyzer-trigger');
|
|
266
|
+
const sidebar = document.getElementById('ai-analyzer-sidebar');
|
|
267
|
+
const closeButton = document.getElementById('ai-analyzer-close');
|
|
268
|
+
const overlay = document.getElementById('ai-analyzer-overlay');
|
|
269
|
+
const loadingEl = document.getElementById('ai-analyzer-loading');
|
|
270
|
+
const resultEl = document.getElementById('ai-analyzer-result');
|
|
271
|
+
const errorEl = document.getElementById('ai-analyzer-error');
|
|
272
|
+
|
|
273
|
+
const prompt = '<%= prompt %>';
|
|
274
|
+
const endpoint = '<%= endpoint_path %>';
|
|
275
|
+
|
|
276
|
+
function openSidebar() {
|
|
277
|
+
sidebar.classList.add('active');
|
|
278
|
+
overlay.classList.add('active');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function closeSidebar() {
|
|
282
|
+
sidebar.classList.remove('active');
|
|
283
|
+
overlay.classList.remove('active');
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function showLoading() {
|
|
287
|
+
loadingEl.style.display = 'flex';
|
|
288
|
+
resultEl.style.display = 'none';
|
|
289
|
+
errorEl.style.display = 'none';
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function showResult(html) {
|
|
293
|
+
loadingEl.style.display = 'none';
|
|
294
|
+
resultEl.style.display = 'block';
|
|
295
|
+
errorEl.style.display = 'none';
|
|
296
|
+
resultEl.innerHTML = html;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function showError(message) {
|
|
300
|
+
loadingEl.style.display = 'none';
|
|
301
|
+
resultEl.style.display = 'none';
|
|
302
|
+
errorEl.style.display = 'block';
|
|
303
|
+
errorEl.innerHTML = `<strong>Erro:</strong> ${message}`;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
async function captureAndAnalyzeScreen() {
|
|
307
|
+
openSidebar();
|
|
308
|
+
showLoading();
|
|
309
|
+
|
|
310
|
+
try {
|
|
311
|
+
// Carregar html2canvas dinamicamente
|
|
312
|
+
const script = document.createElement('script');
|
|
313
|
+
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js';
|
|
314
|
+
|
|
315
|
+
script.onload = async function() {
|
|
316
|
+
try {
|
|
317
|
+
const canvas = await html2canvas(document.body, {
|
|
318
|
+
allowTaint: true,
|
|
319
|
+
useCORS: true,
|
|
320
|
+
scale: 1,
|
|
321
|
+
backgroundColor: '#ffffff'
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
const imageData = canvas.toDataURL('image/jpeg', 0.8);
|
|
325
|
+
|
|
326
|
+
// Enviar para backend
|
|
327
|
+
const response = await fetch(endpoint, {
|
|
328
|
+
method: 'POST',
|
|
329
|
+
headers: {
|
|
330
|
+
'Content-Type': 'application/json',
|
|
331
|
+
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
|
|
332
|
+
},
|
|
333
|
+
body: JSON.stringify({
|
|
334
|
+
image: imageData,
|
|
335
|
+
prompt: prompt
|
|
336
|
+
})
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
if (!response.ok) {
|
|
340
|
+
throw new Error(`Erro ${response.status}: ${response.statusText}`);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const data = await response.json();
|
|
344
|
+
|
|
345
|
+
if (data.success) {
|
|
346
|
+
// Converter markdown para HTML simples
|
|
347
|
+
const html = data.analysis
|
|
348
|
+
.replace(/\n\n/g, '</p><p>')
|
|
349
|
+
.replace(/\n/g, '<br>')
|
|
350
|
+
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
|
351
|
+
.replace(/\*(.*?)\*/g, '<em>$1</em>')
|
|
352
|
+
.replace(/^- (.*?)$/gm, '<li>$1</li>')
|
|
353
|
+
.replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>');
|
|
354
|
+
|
|
355
|
+
showResult(`<p>${html}</p>`);
|
|
356
|
+
} else {
|
|
357
|
+
showError(data.error || 'Erro ao analisar a tela');
|
|
358
|
+
}
|
|
359
|
+
} catch (error) {
|
|
360
|
+
showError(error.message || 'Erro ao capturar a tela');
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
document.head.appendChild(script);
|
|
365
|
+
} catch (error) {
|
|
366
|
+
showError(error.message || 'Erro desconhecido');
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
triggerButton.addEventListener('click', captureAndAnalyzeScreen);
|
|
371
|
+
closeButton.addEventListener('click', closeSidebar);
|
|
372
|
+
overlay.addEventListener('click', closeSidebar);
|
|
373
|
+
});
|
|
374
|
+
</script>
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module AiScreenAnalyzer
|
|
2
|
+
class Engine < ::Rails::Engine
|
|
3
|
+
isolate_namespace AiScreenAnalyzer
|
|
4
|
+
|
|
5
|
+
# Garantir que helpers do engine sejam autocarregados/eager carregados
|
|
6
|
+
config.autoload_paths << config.root.join('app/helpers')
|
|
7
|
+
config.eager_load_paths << config.root.join('app/helpers')
|
|
8
|
+
config.eager_load_namespaces << AiScreenAnalyzer
|
|
9
|
+
|
|
10
|
+
initializer "ai_screen_analyzer.helpers" do
|
|
11
|
+
# Certifica-se de que a constante do helper exista antes de qualquer constantize do Rails
|
|
12
|
+
helper_path = AiScreenAnalyzer::Engine.root.join('app/helpers/ai_screen_analyzer/ai_screen_analyzer_helper.rb').to_s
|
|
13
|
+
ActiveSupport::Dependencies.autoload_paths << File.dirname(helper_path) unless ActiveSupport::Dependencies.autoload_paths.include?(File.dirname(helper_path))
|
|
14
|
+
|
|
15
|
+
ActiveSupport.on_load(:action_view) do
|
|
16
|
+
require_dependency helper_path
|
|
17
|
+
include AiScreenAnalyzer::AiScreenAnalyzerHelper
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
ActiveSupport.on_load(:action_controller) do
|
|
21
|
+
require_dependency helper_path
|
|
22
|
+
helper AiScreenAnalyzer::AiScreenAnalyzerHelper
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
config.to_prepare do
|
|
27
|
+
# Recarrega o helper em modo desenvolvimento para refletir mudanças
|
|
28
|
+
helper_path = AiScreenAnalyzer::Engine.root.join('app/helpers/ai_screen_analyzer/ai_screen_analyzer_helper.rb').to_s
|
|
29
|
+
begin
|
|
30
|
+
require_dependency helper_path
|
|
31
|
+
ActionView::Base.include AiScreenAnalyzer::AiScreenAnalyzerHelper
|
|
32
|
+
rescue LoadError, NameError
|
|
33
|
+
# Em ambientes onde o helper não é necessário, apenas ignore
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'active_support'
|
|
2
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
|
3
|
+
require "ai_screen_analyzer/version"
|
|
4
|
+
require "ai_screen_analyzer/engine" if defined?(Rails)
|
|
5
|
+
|
|
6
|
+
module AiScreenAnalyzer
|
|
7
|
+
class Error < StandardError; end
|
|
8
|
+
|
|
9
|
+
# Configuração padrão
|
|
10
|
+
mattr_accessor :api_key
|
|
11
|
+
mattr_accessor :model
|
|
12
|
+
mattr_accessor :default_prompt
|
|
13
|
+
mattr_accessor :default_button_text
|
|
14
|
+
mattr_accessor :default_sidebar_title
|
|
15
|
+
|
|
16
|
+
self.model = "gpt-4-turbo"
|
|
17
|
+
self.default_prompt = "Analise o conteúdo visível nesta tela e descreva: 1) O que você vê, 2) Elementos principais, 3) Possíveis melhorias de UX/UI"
|
|
18
|
+
self.default_button_text = "Analisar com IA"
|
|
19
|
+
self.default_sidebar_title = "Análise da IA"
|
|
20
|
+
|
|
21
|
+
def self.configure
|
|
22
|
+
yield self if block_given?
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module AiScreenAnalyzer
|
|
2
|
+
module Generators
|
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
|
4
|
+
source_root File.expand_path('templates', __dir__)
|
|
5
|
+
|
|
6
|
+
desc "Instala o AI Screen Analyzer e cria um arquivo de configuração"
|
|
7
|
+
|
|
8
|
+
def create_initializer
|
|
9
|
+
create_file "config/initializers/ai_screen_analyzer.rb", <<~RUBY
|
|
10
|
+
# AI Screen Analyzer Configuration
|
|
11
|
+
# Configure a gem AI Screen Analyzer aqui
|
|
12
|
+
|
|
13
|
+
AiScreenAnalyzer.configure do |config|
|
|
14
|
+
# Defina sua chave de API da OpenAI
|
|
15
|
+
# config.api_key = ENV['OPENAI_API_KEY']
|
|
16
|
+
|
|
17
|
+
# Modelo de IA a ser usado (padrão: gpt-4-turbo)
|
|
18
|
+
# config.model = 'gpt-4-turbo'
|
|
19
|
+
|
|
20
|
+
# Prompt padrão para análise
|
|
21
|
+
# config.default_prompt = "Analise o conteúdo visível nesta tela..."
|
|
22
|
+
|
|
23
|
+
# Texto do botão
|
|
24
|
+
# config.default_button_text = "Analisar com IA"
|
|
25
|
+
|
|
26
|
+
# Título da sidebar
|
|
27
|
+
# config.default_sidebar_title = "Análise da IA"
|
|
28
|
+
end
|
|
29
|
+
RUBY
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def mount_engine_routes
|
|
33
|
+
routes_path = "config/routes.rb"
|
|
34
|
+
|
|
35
|
+
if File.exist?(routes_path)
|
|
36
|
+
content = File.read(routes_path)
|
|
37
|
+
already_mounted = content.include?("AiScreenAnalyzer::Engine")
|
|
38
|
+
|
|
39
|
+
unless already_mounted
|
|
40
|
+
say_status :route, "Montando AiScreenAnalyzer::Engine em /ai_screen_analyzer", :green
|
|
41
|
+
route "mount AiScreenAnalyzer::Engine => '/ai_screen_analyzer', as: 'ai_screen_analyzer_engine'"
|
|
42
|
+
else
|
|
43
|
+
say_status :route, "AiScreenAnalyzer::Engine já está montado (nenhuma alteração)", :blue
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
say_status :warning, "Arquivo config/routes.rb não encontrado. Adicione manualmente: mount AiScreenAnalyzer::Engine => '/ai_screen_analyzer', as: 'ai_screen_analyzer_engine'", :yellow
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def display_readme
|
|
51
|
+
puts <<~TEXT
|
|
52
|
+
|
|
53
|
+
╔════════════════════════════════════════════════════════════════╗
|
|
54
|
+
║ AI Screen Analyzer instalado com sucesso! ║
|
|
55
|
+
╚════════════════════════════════════════════════════════════════╝
|
|
56
|
+
|
|
57
|
+
Próximos passos:
|
|
58
|
+
|
|
59
|
+
1. Rotas montadas automaticamente:
|
|
60
|
+
- O engine foi montado em /ai_screen_analyzer
|
|
61
|
+
- Endpoint de análise: POST /ai_screen_analyzer/analyze-screen
|
|
62
|
+
- Se desejar mudar o path de montagem, ajuste em config/routes.rb e veja a seção "Rotas" do README.
|
|
63
|
+
|
|
64
|
+
2. Configure sua chave de API da OpenAI:
|
|
65
|
+
- Abra config/initializers/ai_screen_analyzer.rb
|
|
66
|
+
- Descomente e configure as opções desejadas
|
|
67
|
+
|
|
68
|
+
3. Adicione o helper em seu layout principal:
|
|
69
|
+
<%= ai_screen_analyzer %>
|
|
70
|
+
|
|
71
|
+
4. Certifique-se de que a variável de ambiente está definida:
|
|
72
|
+
export OPENAI_API_KEY='sua_chave_aqui'
|
|
73
|
+
|
|
74
|
+
Para mais informações, visite:
|
|
75
|
+
https://github.com/seu-usuario/ai_screen_analyzer
|
|
76
|
+
|
|
77
|
+
TEXT
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ai_screen_analyzer
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- José Lopes Neto
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2025-12-12 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rails
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '6.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '6.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: bundler
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '2.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '2.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rake
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '13.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '13.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rspec-rails
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '5.0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '5.0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rubocop
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '1.0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '1.0'
|
|
83
|
+
description: AI Screen Analyzer é uma gem Rails que adiciona um botão flutuante em
|
|
84
|
+
qualquer página para capturar a tela, enviar para análise com GPT-4V e exibir o
|
|
85
|
+
resultado em uma barra lateral elegante.
|
|
86
|
+
email:
|
|
87
|
+
- jlneto@mcfox.com.br
|
|
88
|
+
executables: []
|
|
89
|
+
extensions: []
|
|
90
|
+
extra_rdoc_files: []
|
|
91
|
+
files:
|
|
92
|
+
- CHANGELOG.md
|
|
93
|
+
- LICENSE.txt
|
|
94
|
+
- README.md
|
|
95
|
+
- app/controllers/ai_screen_analyzer/ai_analyzer_controller.rb
|
|
96
|
+
- app/helpers/ai_screen_analyzer/ai_screen_analyzer_helper.rb
|
|
97
|
+
- app/views/ai_screen_analyzer/shared/_ai_screen_analyzer.html.erb
|
|
98
|
+
- config/routes.rb
|
|
99
|
+
- lib/ai_screen_analyzer.rb
|
|
100
|
+
- lib/ai_screen_analyzer/engine.rb
|
|
101
|
+
- lib/ai_screen_analyzer/version.rb
|
|
102
|
+
- lib/generators/ai_screen_analyzer/install_generator.rb
|
|
103
|
+
homepage: https://github.com/mcfox/ai_screen_analyzer
|
|
104
|
+
licenses:
|
|
105
|
+
- MIT
|
|
106
|
+
metadata:
|
|
107
|
+
allowed_push_host: https://rubygems.org
|
|
108
|
+
homepage_uri: https://github.com/mcfox/ai_screen_analyzer
|
|
109
|
+
source_code_uri: https://github.com/mcfox/ai_screen_analyzer
|
|
110
|
+
bug_tracker_uri: https://github.com/mcfox/ai_screen_analyzer/issues
|
|
111
|
+
changelog_uri: https://github.com/mcfox/ai_screen_analyzer/releases
|
|
112
|
+
post_install_message:
|
|
113
|
+
rdoc_options: []
|
|
114
|
+
require_paths:
|
|
115
|
+
- lib
|
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
117
|
+
requirements:
|
|
118
|
+
- - ">="
|
|
119
|
+
- !ruby/object:Gem::Version
|
|
120
|
+
version: 2.7.0
|
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
|
+
requirements:
|
|
123
|
+
- - ">="
|
|
124
|
+
- !ruby/object:Gem::Version
|
|
125
|
+
version: '0'
|
|
126
|
+
requirements: []
|
|
127
|
+
rubygems_version: 3.5.9
|
|
128
|
+
signing_key:
|
|
129
|
+
specification_version: 4
|
|
130
|
+
summary: Rails helper gem para analisar telas com IA usando GPT-4V
|
|
131
|
+
test_files: []
|