-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.rb
195 lines (172 loc) · 4.96 KB
/
app.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#!/usr/bin/env ruby -I ../lib -I lib
# frozen_string_literal: true
require "sinatra/base"
require "sinatra/reloader"
require "slim"
require "openai"
require "open-uri"
require "yaml"
require "fileutils"
require "securerandom"
require "byebug"
require 'zip'
Dir.glob("./lib/**/*.rb").each{|f| require f }
Dir.glob("./custom_actions/**/*.rb").each{|f| require f }
CustomActions.class_eval do
DependentActionError = Class.new(StandardError)
end
class App < Sinatra::Base
include Helpers
include OpenAi
include Actions
include CustomActions
configure :development do
register Sinatra::Reloader
end
IP_ADDRESS =
Socket.
ip_address_list.
map{|addr| addr.inspect_sockaddr }.
reject do |addr|
addr.length > 15 ||
addr == "127.0.0.1" ||
addr.count(".") < 3
end.
first
set :bind, IP_ADDRESS
set :port, ENV["PORT"] || 5001
use Rack::Auth::Basic, 'Restricted Area' do |username, password|
username == '' && password == ENV['BASIC_AUTH_PASSWORD'] || ''
end
# Prompts the user for the following information:
#
# - Audio File to Transcribe
# - Number of Prompts/Images to Generate
# - Context (optional/recommended)
# - Style (optional)
# - Open AI Image Model to use
#
get '/' do
App.debug "Loaded index"
@data = {
dalle_models: App.dalle_models
}
slim :index, locals: { data: @data }
end
# Generates all the things based on the form
# data submitted in the prior step.
#
post '/' do
App.debug "Parsing Form Data"
begin
@cache = App.find_or_create_project(params)
if params["audio"]
@cache = App.transcribe(
File.open(params["audio"]["tempfile"], "rb"),
@cache
)
end
unless @cache[:transcription]
raise ArgumentError, 'No transcription'
end
@cache = App.generate_prompts(@cache)
@cache = App.summarize(@cache)
@cache = App.generate_images(@cache)
redirect "/projects/#{@cache[:project_id]}"
rescue StandardError => e
if e.message.include? "OpenAI HTTP Error"
App.debug e.message
next
end
"<h3 style='color: #{App.color_red};'>#{e.message}</h3>"
end
end
# See ./lib/actions.rb for the list of actions. Custom
# actions can be added to the CustomActions module.
#
App.actions.each do |action|
post "/projects/:project_id/#{action.to_s}" do
App.debug "Executing #{action} for #{params['project_id']}"
cache = App.load_cache_for_project(params["project_id"])
App.stash(cache)
App.send(action, cache)
cache[action] = true
App.write_cache(cache)
redirect "/projects/#{cache[:project_id]}"
rescue DependentActionError => e
@cache = cache
@error = e.message
slim :project
end
end
# Displays the project page with all the generated content
# and the available actions to be taken on the images.
#
get "/projects/:project_id/?" do
App.debug "Loading Project #{params["project_id"]}"
@cache = App.load_cache_for_project(params["project_id"])
if @cache
@images = Dir.glob(
App.project_root(params["project_id"]) + "/**/*.png"
)
end
slim :project
end
# Downloads a zip file containing all the images generated
#
get '/projects/:project_id/download' do
@cache = App.load_cache_for_project(params["project_id"])
return redirect(
"/projects/#{params['project_id']}"
) unless @cache
@images = Dir.glob(
App.project_root(params["project_id"]) + "/**/*.png"
)
filename = "#{params["project_id"]}_images.zip"
temp_file = Tempfile.new(filename)
begin
Zip::OutputStream.open(temp_file) { |zos| }
Zip::File.open(temp_file.path, Zip::File::CREATE) do |zip|
zip.add("data.yml",
App.project_root(params["project_id"]) + "/cache.yml"
)
@images.each do |filename|
zip.add(filename.split("/").last, filename)
end
end
content_type 'application/octet-stream'
attachment filename
File.read(temp_file.path)
ensure # important steps below
temp_file.close
temp_file.unlink
end
end
# Serves the images generated for the project.
#
# NOTE: This is probably unsafe and should only be used
# for local experimentation. That goes for the entire
# app, really.
#
get '/projects/:project_id/:image_file_name' do
path = "/#{params["project_id"]}/#{params["image_file_name"]}"
identifier = params["image_file_name"].split("--").first
cache = App.load_cache_for_project(params["project_id"])
if (
cache && cache[:images] &&
cache[:images].any?{|item| item[:path].
include? identifier }
)
App.debug "Sending #{path}"
send_file(
App.project_root(params["project_id"]) +
"/#{params["image_file_name"]}",
:type => :png
)
else
App.debug 'File path not found in cache'
""
end
end
run!
end