nblog_duo 111.119.999 → 111.120.002
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 +4 -4
- data/lib/nblog_duo.rb +374 -209
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 92d60eb5158a9850b865e0f0610181c13e6a90968e27e8ab32667a3bcbcd51ae
|
4
|
+
data.tar.gz: 68ca780336905933aeb6584b78944eb437524209d48fa65508fe0e966f599981
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 654a707ff0466ecdd152c4983dbcc8a31e2ad073fe1839b2a8d89574161b2189676f8908fda768bb667d87fe814734851ed03be1bfd0589d5abdba8eb72d738f
|
7
|
+
data.tar.gz: 9a539dfd8d82121f8eb79c313be8d1d5f54ffc86cc436fbcc26f420aaf955d532e555c095d8dcb55cd8dc68e721764b67da959ef4f67c459b0b9c9907e3cfd4a
|
data/lib/nblog_duo.rb
CHANGED
@@ -24,13 +24,14 @@ using Rainbow
|
|
24
24
|
include Glimmer
|
25
25
|
|
26
26
|
class Chat
|
27
|
-
def initialize(api_key, gpt_keyword_prompt)
|
27
|
+
def initialize(api_key, gpt_keyword_prompt, model)
|
28
28
|
@api_key = api_key
|
29
29
|
@gpt_keyword_prompt = gpt_keyword_prompt
|
30
|
+
@model = model # 모델을 인자로 받도록 수정
|
30
31
|
end
|
31
32
|
|
32
33
|
def message(keyword)
|
33
|
-
puts 'Sending request to GPT...(키워드 기반 글 생성 중...)'
|
34
|
+
puts 'Sending request to GPT...(키워드 기반 글 생성 중...)'.cyan
|
34
35
|
|
35
36
|
# "키워드 기반 글 생성 중..." 메시지 출력 스레드
|
36
37
|
thread = Thread.new do
|
@@ -54,7 +55,7 @@ class Chat
|
|
54
55
|
|
55
56
|
# 요청 데이터 설정
|
56
57
|
data = {
|
57
|
-
'model' =>
|
58
|
+
'model' => @model,
|
58
59
|
'messages' => [
|
59
60
|
{
|
60
61
|
"role" => "assistant",
|
@@ -64,9 +65,10 @@ class Chat
|
|
64
65
|
'max_tokens' => max_response_tokens # 최대 응답 토큰 설정
|
65
66
|
}
|
66
67
|
|
67
|
-
|
68
|
-
|
69
68
|
answer = ''
|
69
|
+
retry_count = 0
|
70
|
+
max_retries = 5 # 최대 재시도 횟수
|
71
|
+
|
70
72
|
begin
|
71
73
|
req = HTTP.headers(headers).post(url, :json => data)
|
72
74
|
|
@@ -77,7 +79,6 @@ class Chat
|
|
77
79
|
|
78
80
|
# 응답 내용 출력 (디버깅용)
|
79
81
|
response = JSON.parse(req.to_s)
|
80
|
-
|
81
82
|
|
82
83
|
# 응답 데이터에서 안전하게 값 추출
|
83
84
|
if response['choices'] && response['choices'][0] && response['choices'][0]['message']
|
@@ -88,14 +89,21 @@ class Chat
|
|
88
89
|
rescue => e
|
89
90
|
# 오류 메시지 출력
|
90
91
|
puts "Error occurred: #{e.message}"
|
91
|
-
|
92
|
+
if e.message.include?('502') && retry_count < max_retries
|
93
|
+
retry_count += 1
|
94
|
+
puts "Retrying... Attempt ##{retry_count}"
|
95
|
+
sleep(5) # 잠시 대기 후 재시도
|
96
|
+
retry
|
97
|
+
else
|
98
|
+
answer = "오류가 발생했습니다."
|
99
|
+
end
|
92
100
|
end
|
93
101
|
|
94
102
|
# "생성 중..." 메시지 출력 종료
|
95
103
|
thread.kill
|
96
104
|
|
97
105
|
# 결과 로그 출력
|
98
|
-
puts "Final API response ==> #{answer}"
|
106
|
+
puts "Final API response ==> #{answer}".cyan
|
99
107
|
return answer
|
100
108
|
end
|
101
109
|
|
@@ -108,16 +116,16 @@ end
|
|
108
116
|
|
109
117
|
|
110
118
|
|
111
|
-
|
112
|
-
|
113
119
|
class Chat_title
|
114
|
-
def initialize(api_key, gpt_title_prompt)
|
120
|
+
def initialize(api_key, gpt_title_prompt, model)
|
115
121
|
@api_key = api_key
|
116
122
|
@gpt_title_prompt = gpt_title_prompt
|
123
|
+
@model = model # 모델을 인자로 받도록 수정
|
117
124
|
end
|
118
125
|
|
119
126
|
def message(title)
|
120
|
-
puts 'Sending request to GPT...(제목 생성 중...)'
|
127
|
+
puts 'Sending request to GPT...(제목 생성 중...)'.cyan
|
128
|
+
|
121
129
|
# "키워드 기반 글 생성 중..." 메시지를 별도 스레드로 처리
|
122
130
|
thread = Thread.new do
|
123
131
|
while true
|
@@ -125,13 +133,15 @@ class Chat_title
|
|
125
133
|
sleep(3)
|
126
134
|
end
|
127
135
|
end
|
136
|
+
|
128
137
|
url = 'https://api.openai.com/v1/chat/completions'
|
129
138
|
headers = {
|
130
139
|
'Content-Type' => 'application/json',
|
131
140
|
'Authorization' => 'Bearer ' + @api_key
|
132
141
|
}
|
142
|
+
|
133
143
|
data = {
|
134
|
-
'model' =>
|
144
|
+
'model' => @model,
|
135
145
|
'messages' => [{
|
136
146
|
"role" => "system",
|
137
147
|
"content" => "너는 매우 친절하고 성의 있게 답변하는 AI 어시스턴트야."
|
@@ -142,11 +152,14 @@ class Chat_title
|
|
142
152
|
}]
|
143
153
|
}
|
144
154
|
|
155
|
+
answer = ''
|
156
|
+
retry_count = 0
|
157
|
+
max_retries = 5 # 최대 재시도 횟수
|
158
|
+
|
145
159
|
begin
|
146
160
|
req = HTTP.headers(headers).post(url, json: data)
|
147
161
|
|
148
162
|
response = JSON.parse(req.body.to_s)
|
149
|
-
|
150
163
|
|
151
164
|
if req.status == 429
|
152
165
|
return "API 요청 제한을 초과했습니다. 플랜 및 할당량을 확인하세요."
|
@@ -161,28 +174,37 @@ class Chat_title
|
|
161
174
|
answer ||= title # 응답이 없을 경우 기본 메시지 설정
|
162
175
|
rescue => e
|
163
176
|
puts "Error: #{e.message}"
|
164
|
-
|
177
|
+
if e.message.include?('502') && retry_count < max_retries
|
178
|
+
retry_count += 1
|
179
|
+
puts "Retrying... Attempt ##{retry_count}"
|
180
|
+
sleep(5) # 잠시 대기 후 재시도
|
181
|
+
retry
|
182
|
+
else
|
183
|
+
answer = "오류가 발생했습니다."
|
184
|
+
end
|
165
185
|
end
|
166
186
|
|
167
187
|
# "생성 중..." 메시지 출력 종료
|
168
188
|
thread.kill
|
169
189
|
|
170
|
-
puts 'API return ==> '
|
171
|
-
puts answer
|
190
|
+
puts 'API return ==> '.cyan
|
191
|
+
puts answer.cyan
|
172
192
|
answer
|
173
193
|
end
|
174
194
|
end
|
175
195
|
|
176
196
|
|
177
197
|
class Chat_content
|
178
|
-
def initialize(api_key, gpt_content_prompt)
|
198
|
+
def initialize(api_key, gpt_content_prompt, model)
|
179
199
|
@api_key = api_key
|
180
200
|
@gpt_content_prompt = gpt_content_prompt
|
201
|
+
@model = model # 모델을 인자로 받도록 수정
|
181
202
|
end
|
182
203
|
|
183
204
|
def message(content)
|
184
|
-
puts '주의:GPT 특성상 원고 길이가 공백 포함 4천자를 넘기면 오류가 발생할 수 있습니다.'
|
185
|
-
puts 'Sending request to GPT...(내용 변형 중...)'
|
205
|
+
puts '주의:GPT 특성상 원고 길이가 공백 포함 4천자를 넘기면 오류가 발생할 수 있습니다.'.cyan
|
206
|
+
puts 'Sending request to GPT...(내용 변형 중...)'.cyan
|
207
|
+
|
186
208
|
# "키워드 기반 글 생성 중..." 메시지를 별도 스레드로 처리
|
187
209
|
thread = Thread.new do
|
188
210
|
while true
|
@@ -190,14 +212,15 @@ class Chat_content
|
|
190
212
|
sleep(3)
|
191
213
|
end
|
192
214
|
end
|
193
|
-
|
215
|
+
|
194
216
|
url = 'https://api.openai.com/v1/chat/completions'
|
195
217
|
headers = {
|
196
218
|
'Content-Type' => 'application/json',
|
197
219
|
'Authorization' => 'Bearer ' + @api_key
|
198
220
|
}
|
221
|
+
|
199
222
|
data = {
|
200
|
-
'model' =>
|
223
|
+
'model' => @model,
|
201
224
|
'messages' => [{
|
202
225
|
"role" => "system",
|
203
226
|
"content" => "너는 매우 친절하고 성의 있게 답변하는 AI 어시스턴트야."
|
@@ -205,16 +228,18 @@ class Chat_content
|
|
205
228
|
{
|
206
229
|
"role" => "user",
|
207
230
|
"content" => "#{@gpt_content_prompt}\n#{content}"
|
208
|
-
|
209
231
|
}]
|
210
232
|
}
|
211
233
|
|
234
|
+
answer = ''
|
235
|
+
retry_count = 0
|
236
|
+
max_retries = 5 # 최대 재시도 횟수
|
237
|
+
|
212
238
|
begin
|
213
239
|
req = HTTP.headers(headers).post(url, json: data)
|
214
240
|
|
215
241
|
response = JSON.parse(req.body.to_s)
|
216
|
-
|
217
|
-
|
242
|
+
|
218
243
|
if req.status == 429
|
219
244
|
return "API 요청 제한을 초과했습니다. 플랜 및 할당량을 확인하세요."
|
220
245
|
end
|
@@ -224,20 +249,28 @@ class Chat_content
|
|
224
249
|
answer ||= (content) # 응답이 없을 경우 기본 메시지 설정
|
225
250
|
rescue => e
|
226
251
|
puts "Error: #{e.message}"
|
227
|
-
|
252
|
+
if e.message.include?('502') && retry_count < max_retries
|
253
|
+
retry_count += 1
|
254
|
+
puts "Retrying... Attempt ##{retry_count}"
|
255
|
+
sleep(5) # 잠시 대기 후 재시도
|
256
|
+
retry
|
257
|
+
else
|
258
|
+
answer = "오류가 발생했습니다."
|
259
|
+
end
|
228
260
|
end
|
229
261
|
|
230
262
|
# "생성 중..." 메시지 출력 종료
|
231
263
|
thread.kill
|
232
264
|
|
233
|
-
puts 'API return ==> '
|
234
|
-
puts answer
|
265
|
+
puts 'API return ==> '.cyan
|
266
|
+
puts answer.cyan
|
235
267
|
answer
|
236
268
|
end
|
237
269
|
end
|
238
270
|
|
239
271
|
|
240
272
|
|
273
|
+
|
241
274
|
#############################################gpt############################################
|
242
275
|
|
243
276
|
class Naver
|
@@ -2279,83 +2312,111 @@ class Wordpress
|
|
2279
2312
|
return @data2
|
2280
2313
|
end
|
2281
2314
|
|
2282
|
-
|
2283
|
-
|
2284
|
-
|
2285
|
-
|
2286
|
-
client = HTTPClient.new
|
2287
|
-
client.default_header = {
|
2288
|
-
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '\
|
2289
|
-
'(KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
|
2290
|
-
'Accept' => 'application/json, text/javascript, */*; q=0.01',
|
2291
|
-
'Accept-Language' => 'en-US,en;q=0.9',
|
2292
|
-
'Referer' => "https://unsplash.com/s/photos/#{URI.encode_www_form_component(keyword)}",
|
2293
|
-
'X-Requested-With' => 'XMLHttpRequest'
|
2294
|
-
}
|
2315
|
+
def crop_image_height_under_width(path, min_crop_ratio = 0.625)
|
2316
|
+
img = Magick::Image.read(path).first
|
2317
|
+
width = img.columns
|
2318
|
+
height = img.rows
|
2295
2319
|
|
2296
|
-
retry_count = 0
|
2297
|
-
max_retries = 10
|
2298
|
-
results = []
|
2299
2320
|
|
2300
|
-
begin
|
2301
|
-
page = rand(1..15)
|
2302
|
-
url = "https://unsplash.com/napi/search/photos?query=#{URI.encode_www_form_component(keyword)}&page=#{page}&per_page=20"
|
2303
|
-
puts "Request URL: #{url}"
|
2304
|
-
res = client.get(url)
|
2305
|
-
|
2306
|
-
unless res.status == 200
|
2307
|
-
puts "HTTP Error: #{res.status}"
|
2308
|
-
raise "HTTP Error"
|
2309
|
-
end
|
2310
2321
|
|
2311
|
-
|
2312
|
-
|
2313
|
-
|
2322
|
+
if height > width
|
2323
|
+
min_height = (width * min_crop_ratio).to_i
|
2324
|
+
new_height = rand(min_height..width)
|
2325
|
+
crop_top = ((height - new_height) / 2.0).round
|
2314
2326
|
|
2315
|
-
|
2316
|
-
|
2317
|
-
regular_url = photo.dig('urls', 'regular').to_s
|
2327
|
+
cropped = img.crop(0, crop_top, width, new_height, true)
|
2328
|
+
cropped.write(path)
|
2318
2329
|
|
2319
|
-
|
2320
|
-
|
2321
|
-
|
2322
|
-
|
2323
|
-
|
2330
|
+
|
2331
|
+
else
|
2332
|
+
|
2333
|
+
end
|
2334
|
+
end
|
2324
2335
|
|
2325
|
-
|
2326
|
-
|
2327
|
-
|
2336
|
+
def auto_image(keyword = nil)
|
2337
|
+
# auto_image 내부에서만 crop 호출
|
2338
|
+
keyword ||= @keyword
|
2339
|
+
puts "키워드: #{keyword}"
|
2340
|
+
|
2341
|
+
client = HTTPClient.new
|
2342
|
+
client.default_header = {
|
2343
|
+
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '\
|
2344
|
+
'(KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
|
2345
|
+
'Accept' => 'application/json, text/javascript, */*; q=0.01',
|
2346
|
+
'Accept-Language' => 'en-US,en;q=0.9',
|
2347
|
+
'Referer' => "https://unsplash.com/s/photos/#{URI.encode_www_form_component(keyword)}",
|
2348
|
+
'X-Requested-With' => 'XMLHttpRequest'
|
2349
|
+
}
|
2350
|
+
|
2351
|
+
retry_count = 0
|
2352
|
+
max_retries = 10
|
2353
|
+
results = []
|
2354
|
+
|
2355
|
+
begin
|
2356
|
+
page = rand(1..15)
|
2357
|
+
url = "https://unsplash.com/napi/search/photos?query=#{URI.encode_www_form_component(keyword)}&page=#{page}&per_page=20"
|
2358
|
+
puts "Request URL: #{url}"
|
2359
|
+
res = client.get(url)
|
2360
|
+
|
2361
|
+
unless res.status == 200
|
2362
|
+
puts "HTTP Error: #{res.status}"
|
2363
|
+
raise "HTTP Error"
|
2364
|
+
end
|
2328
2365
|
|
2329
|
-
|
2330
|
-
|
2331
|
-
|
2366
|
+
json = JSON.parse(res.body)
|
2367
|
+
results = json['results']
|
2368
|
+
mm = []
|
2332
2369
|
|
2333
|
-
|
2334
|
-
|
2335
|
-
|
2336
|
-
|
2337
|
-
|
2338
|
-
|
2339
|
-
|
2340
|
-
|
2341
|
-
|
2342
|
-
|
2343
|
-
|
2344
|
-
|
2345
|
-
|
2346
|
-
|
2347
|
-
|
2348
|
-
|
2349
|
-
|
2350
|
-
|
2351
|
-
|
2370
|
+
results.each do |photo|
|
2371
|
+
full_url = photo.dig('urls', 'full').to_s
|
2372
|
+
regular_url = photo.dig('urls', 'regular').to_s
|
2373
|
+
|
2374
|
+
if full_url.start_with?("https://images.unsplash.com/photo-") &&
|
2375
|
+
regular_url.include?("1080")
|
2376
|
+
mm << full_url
|
2377
|
+
end
|
2378
|
+
end
|
2379
|
+
|
2380
|
+
if mm.empty?
|
2381
|
+
raise "No matching image"
|
2382
|
+
end
|
2383
|
+
|
2384
|
+
selected_url = mm.sample
|
2385
|
+
destination_path = "./image/memory.png"
|
2386
|
+
Down.download(selected_url, destination: destination_path)
|
2387
|
+
puts "이미지 다운로드 완료: #{selected_url}"
|
2388
|
+
|
2389
|
+
# 오직 auto_image에서만 자르기 호출
|
2390
|
+
crop_image_height_under_width(destination_path)
|
2391
|
+
|
2392
|
+
rescue => e
|
2393
|
+
retry_count += 1
|
2394
|
+
puts "auto_image 에러: #{e.message} (재시도 #{retry_count}/#{max_retries})"
|
2395
|
+
sleep(3)
|
2396
|
+
if retry_count < max_retries
|
2397
|
+
retry
|
2398
|
+
else
|
2399
|
+
puts "최대 재시도 초과. 조건 무시하고 랜덤 이미지 다운로드 시도..."
|
2400
|
+
|
2401
|
+
if results && !results.empty?
|
2402
|
+
random_photo = results.sample
|
2403
|
+
fallback_url = random_photo.dig('urls', 'full')
|
2404
|
+
if fallback_url
|
2405
|
+
Down.download(fallback_url, destination: "./image/memory.png")
|
2406
|
+
puts "랜덤 이미지 다운로드 완료: #{fallback_url}"
|
2407
|
+
crop_image_height_under_width("./image/memory.png")
|
2352
2408
|
else
|
2353
|
-
|
2354
|
-
|
2355
|
-
end
|
2409
|
+
puts "랜덤 이미지 URL을 찾을 수 없습니다. 단색 배경 이미지 생성합니다."
|
2410
|
+
color_image
|
2356
2411
|
end
|
2412
|
+
else
|
2413
|
+
puts "이미지 결과가 없어 다운로드할 수 없습니다. 단색 배경 이미지 생성합니다."
|
2414
|
+
color_image
|
2415
|
+
end
|
2357
2416
|
end
|
2358
2417
|
end
|
2418
|
+
end
|
2419
|
+
|
2359
2420
|
|
2360
2421
|
def color_image
|
2361
2422
|
color = File.open('./color.ini', 'r', :encoding => 'utf-8').read().split("\n")
|
@@ -2449,56 +2510,103 @@ class Wordpress
|
|
2449
2510
|
end
|
2450
2511
|
|
2451
2512
|
|
2452
|
-
|
2513
|
+
def image_text(text1, text2)
|
2514
|
+
begin
|
2515
|
+
color = File.open('./color.ini', 'r', encoding: 'utf-8').read.split("\n").map(&:strip).reject(&:empty?)
|
2516
|
+
font_files = Dir.entries('./fonts').select { |f| f.downcase.end_with?('.ttf') }
|
2517
|
+
font2 = './fonts/' + font_files.sample
|
2518
|
+
|
2519
|
+
# 랜덤 글자색 선택
|
2520
|
+
color2 = color.sample
|
2521
|
+
|
2522
|
+
# 헬퍼 함수: 색상 문자열 '#RRGGBB' -> [R,G,B] 배열로 변환
|
2523
|
+
def hex_to_rgb(hex)
|
2524
|
+
hex = hex.delete('#')
|
2525
|
+
[hex[0..1], hex[2..3], hex[4..5]].map { |c| c.to_i(16) }
|
2526
|
+
end
|
2527
|
+
|
2528
|
+
# 헬퍼 함수: 두 RGB 색상의 차이 계산 (간단한 유클리드 거리)
|
2529
|
+
def color_distance(c1, c2)
|
2530
|
+
Math.sqrt(
|
2531
|
+
(c1[0] - c2[0])**2 +
|
2532
|
+
(c1[1] - c2[1])**2 +
|
2533
|
+
(c1[2] - c2[2])**2
|
2534
|
+
)
|
2535
|
+
end
|
2536
|
+
|
2537
|
+
# 대비가 충분히 되는 테두리 색상 선택
|
2538
|
+
max_attempts = 10
|
2539
|
+
stroke_color = nil
|
2540
|
+
base_rgb = hex_to_rgb(color2)
|
2541
|
+
|
2542
|
+
max_attempts.times do
|
2543
|
+
candidate = color.sample
|
2544
|
+
candidate_rgb = hex_to_rgb(candidate)
|
2545
|
+
dist = color_distance(base_rgb, candidate_rgb)
|
2546
|
+
|
2547
|
+
# 거리(차이) 임계값 100 (0~441 범위) — 필요시 조절 가능
|
2548
|
+
if dist > 100
|
2549
|
+
stroke_color = candidate
|
2550
|
+
break
|
2551
|
+
end
|
2552
|
+
end
|
2553
|
+
stroke_color ||= '#000000' # 만약 충분히 다른 색 없으면 검정색 기본값
|
2554
|
+
|
2555
|
+
img = Magick::Image.read('./image/memory.png').first
|
2556
|
+
draw = Magick::Draw.new
|
2557
|
+
|
2558
|
+
raw_message = "#{text1}\n#{text2}".strip
|
2559
|
+
max_width = img.columns * 0.85
|
2560
|
+
max_height = img.rows * 0.6
|
2561
|
+
|
2453
2562
|
begin
|
2454
|
-
|
2455
|
-
font_files = Dir.entries('./fonts').select { |f| f.downcase.end_with?('.ttf') }
|
2456
|
-
font2 = './fonts/' + font_files.sample
|
2457
|
-
color2 = color.sample
|
2458
|
-
|
2459
|
-
img = Magick::Image.read('./image/memory.png').first
|
2460
|
-
draw = Magick::Draw.new
|
2461
|
-
|
2462
|
-
raw_message = "#{text1}\n#{text2}".strip
|
2463
|
-
max_width = img.columns * 0.85
|
2464
|
-
max_height = img.rows * 0.6
|
2465
|
-
|
2466
|
-
begin
|
2467
|
-
size = rand(@data['이미지설정']['이미지글자1크기1'].text.to_i..@data['이미지설정']['이미지글자1크기2'].text.to_i)
|
2468
|
-
rescue
|
2469
|
-
size = 30
|
2470
|
-
end
|
2471
|
-
|
2472
|
-
wrapped_message, adjusted_size = wrap_text_to_fit(draw, raw_message, max_width, max_height, font2, size)
|
2473
|
-
|
2474
|
-
if @data['이미지설정']['글자그림자'].checked?
|
2475
|
-
img.annotate(draw, 0, 0, 2, 2, wrapped_message) do
|
2476
|
-
draw.gravity = Magick::CenterGravity
|
2477
|
-
draw.pointsize = adjusted_size
|
2478
|
-
draw.fill = '#000000'
|
2479
|
-
draw.font = font2
|
2480
|
-
end
|
2481
|
-
end
|
2482
|
-
|
2483
|
-
draw2 = Magick::Draw.new
|
2484
|
-
img.annotate(draw2, 0, 0, 0, 0, wrapped_message) do
|
2485
|
-
draw2.gravity = Magick::CenterGravity
|
2486
|
-
draw2.pointsize = adjusted_size
|
2487
|
-
draw2.fill = color2
|
2488
|
-
draw2.font = font2
|
2489
|
-
if @data['이미지설정']['글자테두리'].checked?
|
2490
|
-
draw2.stroke_width = 2
|
2491
|
-
draw2.stroke = '#000000'
|
2492
|
-
end
|
2493
|
-
end
|
2494
|
-
|
2495
|
-
img.write('./image/memory.png')
|
2563
|
+
size = rand(@data['이미지설정']['이미지글자1크기1'].text.to_i..@data['이미지설정']['이미지글자1크기2'].text.to_i)
|
2496
2564
|
rescue
|
2497
|
-
|
2498
|
-
|
2499
|
-
|
2565
|
+
size = 30
|
2566
|
+
end
|
2567
|
+
|
2568
|
+
wrapped_message, adjusted_size = wrap_text_to_fit(draw, raw_message, max_width, max_height, font2, size)
|
2569
|
+
|
2570
|
+
if @data['이미지설정']['글자그림자'].checked?
|
2571
|
+
img.annotate(draw, 0, 0, 2, 2, wrapped_message) do
|
2572
|
+
draw.gravity = Magick::CenterGravity
|
2573
|
+
draw.pointsize = adjusted_size
|
2574
|
+
draw.fill = '#000000'
|
2575
|
+
draw.font = font2
|
2576
|
+
end
|
2577
|
+
end
|
2578
|
+
|
2579
|
+
if @data['이미지설정']['글자테두리'].checked?
|
2580
|
+
draw_stroke = Magick::Draw.new
|
2581
|
+
img.annotate(draw_stroke, 0, 0, 0, 0, wrapped_message) do
|
2582
|
+
draw_stroke.gravity = Magick::CenterGravity
|
2583
|
+
draw_stroke.pointsize = adjusted_size
|
2584
|
+
draw_stroke.fill = 'none'
|
2585
|
+
draw_stroke.stroke = stroke_color
|
2586
|
+
draw_stroke.stroke_width = rand(5..10)
|
2587
|
+
draw_stroke.font = font2
|
2588
|
+
end
|
2589
|
+
end
|
2590
|
+
|
2591
|
+
draw2 = Magick::Draw.new
|
2592
|
+
img.annotate(draw2, 0, 0, 0, 0, wrapped_message) do
|
2593
|
+
draw2.gravity = Magick::CenterGravity
|
2594
|
+
draw2.pointsize = adjusted_size
|
2595
|
+
draw2.fill = color2
|
2596
|
+
draw2.stroke = 'none'
|
2597
|
+
draw2.font = font2
|
2500
2598
|
end
|
2599
|
+
|
2600
|
+
img.write('./image/memory.png')
|
2601
|
+
|
2602
|
+
rescue => e
|
2603
|
+
puts "이미지 폰트 불러오기 오류 재시도... (#{e.message})"
|
2604
|
+
sleep(3)
|
2605
|
+
retry
|
2501
2606
|
end
|
2607
|
+
end
|
2608
|
+
|
2609
|
+
|
2502
2610
|
|
2503
2611
|
def border()
|
2504
2612
|
color = File.open('./color.ini', 'r',:encoding => 'utf-8').read().split("\n")
|
@@ -2556,33 +2664,33 @@ class Wordpress
|
|
2556
2664
|
|
2557
2665
|
if @data['이미지설정']['글자삽입1'].checked?
|
2558
2666
|
if @data['이미지설정']['이미지글자1'].length == 0
|
2559
|
-
|
2667
|
+
image_text_path1 = ''
|
2560
2668
|
else
|
2561
|
-
|
2562
|
-
|
2563
|
-
|
2564
|
-
|
2565
|
-
|
2566
|
-
|
2567
|
-
|
2568
|
-
|
2569
|
-
|
2669
|
+
if @data['이미지설정']['글자랜덤'].checked?
|
2670
|
+
image_text_path1 = @data['이미지설정']['이미지글자1'].sample
|
2671
|
+
else
|
2672
|
+
image_text_path1 = @data['이미지설정']['이미지글자1'][@image_text_soon1]
|
2673
|
+
@image_text_soon1 += 1
|
2674
|
+
if @image_text_soon1 > @data['이미지설정']['이미지글자1'].length - 1
|
2675
|
+
@image_text_soon1 = 0
|
2676
|
+
end
|
2677
|
+
end
|
2570
2678
|
end
|
2571
2679
|
end
|
2572
2680
|
|
2573
2681
|
if @data['이미지설정']['글자삽입2'].checked?
|
2574
2682
|
if @data['이미지설정']['이미지글자2'].length == 0
|
2575
|
-
|
2576
|
-
else
|
2577
|
-
if @data['이미지설정']['글자랜덤'].checked?
|
2578
|
-
image_text_path2 = @data['이미지설정']['이미지글자2'].sample
|
2683
|
+
image_text_path2 = ''
|
2579
2684
|
else
|
2580
|
-
|
2581
|
-
|
2582
|
-
|
2583
|
-
|
2584
|
-
|
2585
|
-
|
2685
|
+
if @data['이미지설정']['글자랜덤'].checked?
|
2686
|
+
image_text_path2 = @data['이미지설정']['이미지글자2'].sample
|
2687
|
+
else
|
2688
|
+
image_text_path2 = @data['이미지설정']['이미지글자2'][@image_text_soon2]
|
2689
|
+
@image_text_soon2 += 1
|
2690
|
+
if @image_text_soon2 > @data['이미지설정']['이미지글자2'].length - 1
|
2691
|
+
@image_text_soon2 = 0
|
2692
|
+
end
|
2693
|
+
end
|
2586
2694
|
end
|
2587
2695
|
end
|
2588
2696
|
|
@@ -2796,6 +2904,19 @@ class Wordpress
|
|
2796
2904
|
end
|
2797
2905
|
end
|
2798
2906
|
|
2907
|
+
if @data['포스트설정']['gpt35'].checked? || @data['포스트설정']['gpt4turbo'].checked? || @data['포스트설정']['gpt4'].checked?
|
2908
|
+
gpt_model = if @data['포스트설정']['gpt35'].checked?
|
2909
|
+
'gpt-3.5-turbo'
|
2910
|
+
elsif @data['포스트설정']['gpt4turbo'].checked?
|
2911
|
+
'gpt-4-turbo'
|
2912
|
+
elsif @data['포스트설정']['gpt4'].checked?
|
2913
|
+
'gpt-4'
|
2914
|
+
end
|
2915
|
+
puts "선택 된 GPT model: #{gpt_model}".green
|
2916
|
+
else
|
2917
|
+
|
2918
|
+
end
|
2919
|
+
|
2799
2920
|
if @data['포스트설정']['gpt제목'].checked?
|
2800
2921
|
gpt_title_prompt = @data['포스트설정']['gpt제목_프롬프트'].text.to_s.force_encoding('utf-8')
|
2801
2922
|
|
@@ -2803,7 +2924,7 @@ class Wordpress
|
|
2803
2924
|
gpt_title_prompt_sample = gpt_title_prompt.strip.empty? ? "프롬프트: 문장을 비슷한 길이로 ChatGPT의 멘트는 빼고 표현을 더 추가해서 하나만 만들어줘." : gpt_title_prompt
|
2804
2925
|
|
2805
2926
|
# gpt_title_prompt_sample을 Chat_title 객체에 전달
|
2806
|
-
chat = Chat_title.new(@data['포스트설정']['api_key'].text.to_s.force_encoding('utf-8'), gpt_title_prompt_sample)
|
2927
|
+
chat = Chat_title.new(@data['포스트설정']['api_key'].text.to_s.force_encoding('utf-8'), gpt_title_prompt_sample, gpt_model)
|
2807
2928
|
|
2808
2929
|
# 메시지 요청 후 title에 저장
|
2809
2930
|
gpt_text1 = chat.message(title)
|
@@ -2859,7 +2980,7 @@ class Wordpress
|
|
2859
2980
|
gpt_content_prompt_sample = gpt_content_prompt.strip.empty? ? "프롬프트:ChatGPT의 멘트는 빼고 위 전체적인 내용의 형식을 똑같이 표현을 더 추가하고 유사어로 변경하여 하나 만들어줘! 전화번호,연락처,가격,홈페이지안내 ,상담안내 관련 문구는 유지해야해" : gpt_content_prompt
|
2860
2981
|
|
2861
2982
|
# Chat_content 객체 생성 시 api_key와 gpt_content_prompt_sample을 두 개의 인자로 전달
|
2862
|
-
chat = Chat_content.new(api_key, gpt_content_prompt_sample)
|
2983
|
+
chat = Chat_content.new(api_key, gpt_content_prompt_sample, gpt_model)
|
2863
2984
|
|
2864
2985
|
# 메시지 요청 후 content에 저장
|
2865
2986
|
gpt_text3 = chat.message(content)
|
@@ -3007,7 +3128,7 @@ class Wordpress
|
|
3007
3128
|
if @data['포스트설정']['gpt키워드'].checked?
|
3008
3129
|
gpt_keyword_prompt = @data['포스트설정']['gpt키워드_프롬프트'].text.to_s.force_encoding('utf-8')
|
3009
3130
|
gpt_keyword_prompt_sample = gpt_keyword_prompt.strip.empty? ? "프롬프트: 관련된 글을 1500자에서 2500자 사이로 만들어줘" : gpt_keyword_prompt
|
3010
|
-
chat = Chat.new(@data['포스트설정']['api_key'].text.to_s.force_encoding('utf-8'), gpt_keyword_prompt)
|
3131
|
+
chat = Chat.new(@data['포스트설정']['api_key'].text.to_s.force_encoding('utf-8'), gpt_keyword_prompt, gpt_model)
|
3011
3132
|
gpt_text = chat.message(keyword)
|
3012
3133
|
#content = content.to_s + "\n(자동생성글)\n" + gpt_text.to_s
|
3013
3134
|
content = content.to_s + "(자동생성글)" + gpt_text.to_s
|
@@ -4969,7 +5090,11 @@ class Wordpress
|
|
4969
5090
|
vertical_box{
|
4970
5091
|
horizontal_box{
|
4971
5092
|
stretchy false
|
4972
|
-
|
5093
|
+
grid{
|
5094
|
+
stretchy false
|
5095
|
+
@data['image_type'][0] = checkbox('저장 사진 사용 '){
|
5096
|
+
top 0
|
5097
|
+
left 0
|
4973
5098
|
on_toggled{
|
4974
5099
|
if @data['image_type'][0].checked?
|
4975
5100
|
@data['image_type'][1].checked = false
|
@@ -4977,7 +5102,9 @@ class Wordpress
|
|
4977
5102
|
end
|
4978
5103
|
}
|
4979
5104
|
}
|
4980
|
-
@data['image_type'][1] = checkbox('색상 사진 사용'){
|
5105
|
+
@data['image_type'][1] = checkbox('색상 사진 사용 '){
|
5106
|
+
top 0
|
5107
|
+
left 1
|
4981
5108
|
on_toggled{
|
4982
5109
|
if @data['image_type'][1].checked?
|
4983
5110
|
@data['image_type'][0].checked = false
|
@@ -4986,6 +5113,8 @@ class Wordpress
|
|
4986
5113
|
}
|
4987
5114
|
}
|
4988
5115
|
@data['image_type'][2] = checkbox('자동 다운로드 사진 사용'){
|
5116
|
+
top 0
|
5117
|
+
left 2
|
4989
5118
|
on_toggled{
|
4990
5119
|
if @data['image_type'][2].checked?
|
4991
5120
|
@data['image_type'][1].checked = false
|
@@ -4994,7 +5123,7 @@ class Wordpress
|
|
4994
5123
|
}
|
4995
5124
|
}
|
4996
5125
|
}
|
4997
|
-
|
5126
|
+
}
|
4998
5127
|
grid{
|
4999
5128
|
stretchy false
|
5000
5129
|
@data['이미지설정']['글자삽입1'] = checkbox('글자 삽입1'){
|
@@ -5072,8 +5201,12 @@ class Wordpress
|
|
5072
5201
|
top 1
|
5073
5202
|
left 6
|
5074
5203
|
}
|
5075
|
-
|
5076
|
-
|
5204
|
+
}
|
5205
|
+
|
5206
|
+
grid{
|
5207
|
+
stretchy false
|
5208
|
+
@data['이미지설정']['글자순서'] = checkbox('글자 리스트 순서 사용 '){
|
5209
|
+
top 1
|
5077
5210
|
left 0
|
5078
5211
|
on_toggled{
|
5079
5212
|
if @data['이미지설정']['글자순서'].checked?
|
@@ -5082,8 +5215,8 @@ class Wordpress
|
|
5082
5215
|
}
|
5083
5216
|
}
|
5084
5217
|
|
5085
|
-
@data['이미지설정']['글자랜덤'] = checkbox('글자 리스트
|
5086
|
-
top
|
5218
|
+
@data['이미지설정']['글자랜덤'] = checkbox('글자 리스트 랜덤 사용'){
|
5219
|
+
top 1
|
5087
5220
|
left 1
|
5088
5221
|
on_toggled{
|
5089
5222
|
if @data['이미지설정']['글자랜덤'].checked?
|
@@ -5091,32 +5224,38 @@ class Wordpress
|
|
5091
5224
|
end
|
5092
5225
|
}
|
5093
5226
|
}
|
5227
|
+
}
|
5094
5228
|
|
5095
5229
|
|
5096
|
-
|
5097
|
-
|
5098
|
-
|
5230
|
+
grid{
|
5231
|
+
stretchy false
|
5232
|
+
@data['이미지설정']['필터사용'] = checkbox('사진 필터 사용 [흑백,흐림,가우시안,,,등 랜덤] (※색상 사진 사용시 적용 불가)'){
|
5233
|
+
top 0
|
5234
|
+
left 0
|
5099
5235
|
}
|
5100
|
-
|
5101
|
-
|
5236
|
+
}
|
5237
|
+
grid{
|
5238
|
+
stretchy false
|
5239
|
+
@data['이미지설정']['테두리사용'] = checkbox('사진 테두리 적용하기 '){
|
5240
|
+
top 1
|
5102
5241
|
left 0
|
5103
5242
|
}
|
5104
5243
|
@data['이미지설정']['테두리크기1'] = entry{
|
5105
|
-
top
|
5244
|
+
top 1
|
5106
5245
|
left 2
|
5107
5246
|
text 'ex) 1'
|
5108
5247
|
}
|
5109
|
-
label('
|
5110
|
-
top
|
5248
|
+
label('px'){
|
5249
|
+
top 1
|
5111
5250
|
left 3
|
5112
5251
|
}
|
5113
5252
|
@data['이미지설정']['테두리크기2'] = entry{
|
5114
|
-
top
|
5253
|
+
top 1
|
5115
5254
|
left 4
|
5116
5255
|
text 'ex) 33'
|
5117
5256
|
}
|
5118
|
-
label('
|
5119
|
-
top
|
5257
|
+
label('px'){
|
5258
|
+
top 1
|
5120
5259
|
left 5
|
5121
5260
|
}
|
5122
5261
|
|
@@ -5275,7 +5414,7 @@ class Wordpress
|
|
5275
5414
|
stretchy false
|
5276
5415
|
grid{
|
5277
5416
|
stretchy false
|
5278
|
-
@data['포스트설정']['제목키워드변경'] = checkbox('제목에 특정 단어를
|
5417
|
+
@data['포스트설정']['제목키워드변경'] = checkbox('제목에 특정 단어를 키워드로 변경'){
|
5279
5418
|
top 0
|
5280
5419
|
left 0
|
5281
5420
|
|
@@ -5318,13 +5457,10 @@ class Wordpress
|
|
5318
5457
|
left 3
|
5319
5458
|
text '최대수량'
|
5320
5459
|
}
|
5321
|
-
|
5322
|
-
|
5323
|
-
left 2
|
5324
|
-
}
|
5325
|
-
@data['포스트설정']['제목앞'] = checkbox('제목에 키워드 삽입 제목 앞'){
|
5460
|
+
|
5461
|
+
@data['포스트설정']['제목앞'] = checkbox('제목에 키워드 삽입시 제목 앞에 붙이기'){
|
5326
5462
|
top 3
|
5327
|
-
left
|
5463
|
+
left 0
|
5328
5464
|
enabled false # 기본적으로 비활성화
|
5329
5465
|
on_toggled{
|
5330
5466
|
if @data['포스트설정']['제목앞'].checked? == true
|
@@ -5334,13 +5470,10 @@ class Wordpress
|
|
5334
5470
|
end
|
5335
5471
|
}
|
5336
5472
|
}
|
5337
|
-
|
5338
|
-
|
5339
|
-
|
5340
|
-
|
5341
|
-
@data['포스트설정']['제목뒤'] = checkbox('제목에 키워드 삽입 제목 뒤'){
|
5342
|
-
top 4
|
5343
|
-
left 3
|
5473
|
+
|
5474
|
+
@data['포스트설정']['제목뒤'] = checkbox('제목에 키워드시 삽입 제목 뒤에 붙이기'){
|
5475
|
+
top 3
|
5476
|
+
left 1
|
5344
5477
|
enabled false # 기본적으로 비활성화
|
5345
5478
|
on_toggled{
|
5346
5479
|
if @data['포스트설정']['제목뒤'].checked? == true
|
@@ -5554,34 +5687,65 @@ class Wordpress
|
|
5554
5687
|
text 'URL'
|
5555
5688
|
}
|
5556
5689
|
|
5557
|
-
@data['포스트설정']['ChatGPT사용'] = checkbox('Chat GPT 사용하기'){
|
5558
|
-
top 15+ aa1
|
5559
|
-
left 0
|
5560
|
-
}
|
5561
|
-
|
5562
|
-
@data['포스트설정']['api_key'] = entry(){
|
5563
|
-
top 15+ aa1
|
5564
|
-
left 1
|
5565
|
-
text 'api key 입력 필수!!'
|
5566
|
-
}
|
5567
|
-
|
5568
5690
|
@data['포스트설정']['클립적용'] = checkbox('클립 내용에 넣기'){
|
5569
|
-
top
|
5691
|
+
top 15+ aa1
|
5570
5692
|
left 0
|
5571
5693
|
}
|
5572
5694
|
|
5573
5695
|
@data['포스트설정']['클립단어'] = entry(){
|
5574
|
-
top
|
5696
|
+
top 15+ aa1
|
5575
5697
|
left 1
|
5576
5698
|
text '특정단어'
|
5577
5699
|
}
|
5578
5700
|
@data['포스트설정']['클립넘버'] = entry(){
|
5579
|
-
top
|
5701
|
+
top 15+ aa1
|
5580
5702
|
left 3
|
5581
5703
|
text '클립넘버 ex)1,2,3'
|
5582
5704
|
}
|
5583
|
-
|
5584
5705
|
}
|
5706
|
+
grid{
|
5707
|
+
stretchy false
|
5708
|
+
@data['포스트설정']['ChatGPT사용'] = checkbox('Chat GPT 사용하기 '){
|
5709
|
+
top 1
|
5710
|
+
left 0
|
5711
|
+
}
|
5712
|
+
|
5713
|
+
@data['포스트설정']['api_key'] = entry(){
|
5714
|
+
top 1
|
5715
|
+
left 1
|
5716
|
+
text 'api key 입력'
|
5717
|
+
}
|
5718
|
+
@data['포스트설정']['gpt35'] = checkbox('GPT 3.5-turbo'){
|
5719
|
+
top 1
|
5720
|
+
left 2
|
5721
|
+
on_toggled {
|
5722
|
+
if @data['포스트설정']['gpt35'].checked?
|
5723
|
+
@data['포스트설정']['gpt4'].checked = false
|
5724
|
+
@data['포스트설정']['gpt4turbo'].checked = false
|
5725
|
+
end
|
5726
|
+
}
|
5727
|
+
}
|
5728
|
+
@data['포스트설정']['gpt4'] = checkbox('GPT 4'){
|
5729
|
+
top 1
|
5730
|
+
left 3
|
5731
|
+
on_toggled {
|
5732
|
+
if @data['포스트설정']['gpt4'].checked?
|
5733
|
+
@data['포스트설정']['gpt35'].checked = false
|
5734
|
+
@data['포스트설정']['gpt4turbo'].checked = false
|
5735
|
+
end
|
5736
|
+
}
|
5737
|
+
}
|
5738
|
+
@data['포스트설정']['gpt4turbo'] = checkbox('GPT 4-turbo'){
|
5739
|
+
top 1
|
5740
|
+
left 4
|
5741
|
+
on_toggled {
|
5742
|
+
if @data['포스트설정']['gpt4turbo'].checked?
|
5743
|
+
@data['포스트설정']['gpt35'].checked = false
|
5744
|
+
@data['포스트설정']['gpt4'].checked = false
|
5745
|
+
end
|
5746
|
+
}
|
5747
|
+
}
|
5748
|
+
}
|
5585
5749
|
}
|
5586
5750
|
|
5587
5751
|
vertical_separator{
|
@@ -6121,6 +6285,7 @@ class Wordpress
|
|
6121
6285
|
@data['포스트설정']['발행기능'].checked = true
|
6122
6286
|
@data['포스트설정']['인용구랜덤'].checked = true
|
6123
6287
|
@data['이미지설정']['글자순서'].checked = true
|
6288
|
+
@data['포스트설정']['gpt35'].checked = true
|
6124
6289
|
}.show
|
6125
6290
|
end
|
6126
6291
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nblog_duo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 111.
|
4
|
+
version: 111.120.002
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- zon
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-06-
|
10
|
+
date: 2025-06-26 00:00:00.000000000 Z
|
11
11
|
dependencies: []
|
12
12
|
description: File to Clipboard gem
|
13
13
|
email: mymin26@naver.com
|