nblog_duo 0.0.79 → 0.0.93
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 +276 -14
- 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: db31678c1e8c72469d43b2ec52267cc966218dafe7e31259fb181e9bf83f4137
|
4
|
+
data.tar.gz: ef8000e946326e95eda34866c239804ee164c3fe5b773a122d1d6ac856b73e85
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d84296cb6debacafe2f68eedd3578b97ca58f5fd57f18f9845a12625aef9d428d32e38d44ac150b5a1336bed3f1249a3a5c4d2faae984400df80bb5f2eb05de1
|
7
|
+
data.tar.gz: 6c87a7b19110136b8cc9def03d9c3871c5932920d0c88acae5f345f9633ed7774bc6c379a219dc1c165a5ffcb0f6296686b8db13ab3a7b8f412178e1c88d7315
|
data/lib/nblog_duo.rb
CHANGED
@@ -236,6 +236,246 @@ end
|
|
236
236
|
|
237
237
|
|
238
238
|
|
239
|
+
#############################################gpt############################################
|
240
|
+
|
241
|
+
require 'glimmer-dsl-libui'
|
242
|
+
require 'selenium-webdriver'
|
243
|
+
# require 'webdrivers'
|
244
|
+
require 'iconv'
|
245
|
+
require 'nokogiri'
|
246
|
+
require 'http'
|
247
|
+
require 'json'
|
248
|
+
require 'down'
|
249
|
+
require 'rmagick'
|
250
|
+
require 'fileutils'
|
251
|
+
require 'rest-client'
|
252
|
+
require 'open3'
|
253
|
+
require 'clipboard'
|
254
|
+
require 'crack'
|
255
|
+
require 'uri'
|
256
|
+
require 'cgi'
|
257
|
+
require 'digest'
|
258
|
+
require 'auto_click'
|
259
|
+
require 'rainbow/refinement'
|
260
|
+
include AutoClickMethods
|
261
|
+
using Rainbow
|
262
|
+
include Glimmer
|
263
|
+
|
264
|
+
class Chat
|
265
|
+
def initialize(api_key, gpt_keyword_prompt)
|
266
|
+
@api_key = api_key
|
267
|
+
@gpt_keyword_prompt = gpt_keyword_prompt
|
268
|
+
end
|
269
|
+
|
270
|
+
def message(keyword)
|
271
|
+
puts 'Sending request to GPT...(키워드 기반 글 생성 중...)'
|
272
|
+
|
273
|
+
# "키워드 기반 글 생성 중..." 메시지 출력 스레드
|
274
|
+
thread = Thread.new do
|
275
|
+
while true
|
276
|
+
print "▶"
|
277
|
+
sleep 3
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
url = 'https://api.openai.com/v1/chat/completions'
|
282
|
+
headers = {
|
283
|
+
'Content-Type' => 'application/json',
|
284
|
+
'Authorization' => 'Bearer ' + @api_key
|
285
|
+
}
|
286
|
+
|
287
|
+
# 사용자로부터 받은 입력과 GPT 프롬프트의 토큰 수 계산
|
288
|
+
message_tokens = calculate_tokens(keyword) + calculate_tokens(@gpt_keyword_prompt)
|
289
|
+
|
290
|
+
# 8,192 토큰을 초과하지 않도록 최대 토큰 수를 설정
|
291
|
+
max_response_tokens = [8192 - message_tokens, 4000].min # 8,192 - 입력된 토큰 수, 4,000 이하로 설정
|
292
|
+
|
293
|
+
# 요청 데이터 설정
|
294
|
+
data = {
|
295
|
+
'model' => 'gpt-4',
|
296
|
+
'messages' => [
|
297
|
+
{
|
298
|
+
"role" => "assistant",
|
299
|
+
"content" => "#{keyword}\n#{@gpt_keyword_prompt}"
|
300
|
+
}
|
301
|
+
],
|
302
|
+
'max_tokens' => max_response_tokens # 최대 응답 토큰 설정
|
303
|
+
}
|
304
|
+
|
305
|
+
|
306
|
+
|
307
|
+
answer = ''
|
308
|
+
begin
|
309
|
+
req = HTTP.headers(headers).post(url, :json => data)
|
310
|
+
|
311
|
+
# 상태 코드 확인
|
312
|
+
if req.status != 200
|
313
|
+
raise "HTTP Error: #{req.status}, Response Body: #{req.body.to_s}"
|
314
|
+
end
|
315
|
+
|
316
|
+
# 응답 내용 출력 (디버깅용)
|
317
|
+
response = JSON.parse(req.to_s)
|
318
|
+
|
319
|
+
|
320
|
+
# 응답 데이터에서 안전하게 값 추출
|
321
|
+
if response['choices'] && response['choices'][0] && response['choices'][0]['message']
|
322
|
+
answer = response['choices'][0]['message']['content']
|
323
|
+
else
|
324
|
+
raise "Invalid API response format"
|
325
|
+
end
|
326
|
+
rescue => e
|
327
|
+
# 오류 메시지 출력
|
328
|
+
puts "Error occurred: #{e.message}"
|
329
|
+
answer = "오류가 발생했습니다."
|
330
|
+
end
|
331
|
+
|
332
|
+
# "생성 중..." 메시지 출력 종료
|
333
|
+
thread.kill
|
334
|
+
|
335
|
+
# 결과 로그 출력
|
336
|
+
puts "Final API response ==> #{answer}"
|
337
|
+
return answer
|
338
|
+
end
|
339
|
+
|
340
|
+
def calculate_tokens(text)
|
341
|
+
# 간단한 방식으로 텍스트의 토큰 수 계산 (정확도는 다를 수 있음)
|
342
|
+
# OpenAI API는 1토큰이 대략 4글자 정도임
|
343
|
+
text.split(/\s+/).length # 간단한 단어 수로 계산
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
|
348
|
+
|
349
|
+
|
350
|
+
|
351
|
+
class Chat_title
|
352
|
+
def initialize(api_key, gpt_title_prompt)
|
353
|
+
@api_key = api_key
|
354
|
+
@gpt_title_prompt = gpt_title_prompt
|
355
|
+
end
|
356
|
+
|
357
|
+
def message(title)
|
358
|
+
puts 'Sending request to GPT...(제목 생성 중...)'
|
359
|
+
# "키워드 기반 글 생성 중..." 메시지를 별도 스레드로 처리
|
360
|
+
thread = Thread.new do
|
361
|
+
while true
|
362
|
+
print "▶"
|
363
|
+
sleep(3)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
url = 'https://api.openai.com/v1/chat/completions'
|
367
|
+
headers = {
|
368
|
+
'Content-Type' => 'application/json',
|
369
|
+
'Authorization' => 'Bearer ' + @api_key
|
370
|
+
}
|
371
|
+
data = {
|
372
|
+
'model' => 'gpt-4',
|
373
|
+
'messages' => [{
|
374
|
+
"role" => "system",
|
375
|
+
"content" => "너는 매우 친절하고 성의 있게 답변하는 AI 어시스턴트야."
|
376
|
+
},
|
377
|
+
{
|
378
|
+
"role" => "user",
|
379
|
+
"content" => "#{@gpt_title_prompt}\n#{title}"
|
380
|
+
}]
|
381
|
+
}
|
382
|
+
|
383
|
+
begin
|
384
|
+
req = HTTP.headers(headers).post(url, json: data)
|
385
|
+
|
386
|
+
response = JSON.parse(req.body.to_s)
|
387
|
+
|
388
|
+
|
389
|
+
if req.status == 429
|
390
|
+
return "API 요청 제한을 초과했습니다. 플랜 및 할당량을 확인하세요."
|
391
|
+
end
|
392
|
+
|
393
|
+
# 응답 데이터에서 안전하게 값 추출
|
394
|
+
answer = response.dig('choices', 0, 'message', 'content')
|
395
|
+
|
396
|
+
# 따옴표 제거
|
397
|
+
answer = answer.gsub('"', '') if answer
|
398
|
+
|
399
|
+
answer ||= title # 응답이 없을 경우 기본 메시지 설정
|
400
|
+
rescue => e
|
401
|
+
puts "Error: #{e.message}"
|
402
|
+
answer = "오류가 발생했습니다."
|
403
|
+
end
|
404
|
+
|
405
|
+
# "생성 중..." 메시지 출력 종료
|
406
|
+
thread.kill
|
407
|
+
|
408
|
+
puts 'API return ==> '
|
409
|
+
puts answer
|
410
|
+
answer
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
|
415
|
+
class Chat_content
|
416
|
+
def initialize(api_key, gpt_content_prompt)
|
417
|
+
@api_key = api_key
|
418
|
+
@gpt_content_prompt = gpt_content_prompt
|
419
|
+
end
|
420
|
+
|
421
|
+
def message(content)
|
422
|
+
puts '주의:GPT 특성상 원고 길이가 공백 포함 4천자를 넘기면 오류가 발생할 수 있습니다.'
|
423
|
+
puts 'Sending request to GPT...(내용 변형 중...)'
|
424
|
+
# "키워드 기반 글 생성 중..." 메시지를 별도 스레드로 처리
|
425
|
+
thread = Thread.new do
|
426
|
+
while true
|
427
|
+
print "▶"
|
428
|
+
sleep(3)
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
url = 'https://api.openai.com/v1/chat/completions'
|
433
|
+
headers = {
|
434
|
+
'Content-Type' => 'application/json',
|
435
|
+
'Authorization' => 'Bearer ' + @api_key
|
436
|
+
}
|
437
|
+
data = {
|
438
|
+
'model' => 'gpt-4',
|
439
|
+
'messages' => [{
|
440
|
+
"role" => "system",
|
441
|
+
"content" => "너는 매우 친절하고 성의 있게 답변하는 AI 어시스턴트야."
|
442
|
+
},
|
443
|
+
{
|
444
|
+
"role" => "user",
|
445
|
+
"content" => "#{@gpt_content_prompt}\n#{content}"
|
446
|
+
|
447
|
+
}]
|
448
|
+
}
|
449
|
+
|
450
|
+
begin
|
451
|
+
req = HTTP.headers(headers).post(url, json: data)
|
452
|
+
|
453
|
+
response = JSON.parse(req.body.to_s)
|
454
|
+
|
455
|
+
|
456
|
+
if req.status == 429
|
457
|
+
return "API 요청 제한을 초과했습니다. 플랜 및 할당량을 확인하세요."
|
458
|
+
end
|
459
|
+
|
460
|
+
# 응답 데이터에서 안전하게 값 추출
|
461
|
+
answer = response.dig('choices', 0, 'message', 'content')
|
462
|
+
answer ||= (content) # 응답이 없을 경우 기본 메시지 설정
|
463
|
+
rescue => e
|
464
|
+
puts "Error: #{e.message}"
|
465
|
+
answer = "오류가 발생했습니다."
|
466
|
+
end
|
467
|
+
|
468
|
+
# "생성 중..." 메시지 출력 종료
|
469
|
+
thread.kill
|
470
|
+
|
471
|
+
puts 'API return ==> '
|
472
|
+
puts answer
|
473
|
+
answer
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
|
478
|
+
|
239
479
|
#############################################gpt############################################
|
240
480
|
|
241
481
|
class Naver
|
@@ -246,9 +486,13 @@ class Naver
|
|
246
486
|
naver_cookie_dir = "C:/naver_cookie"
|
247
487
|
FileUtils.mkdir_p(naver_cookie_dir) unless File.exist?(naver_cookie_dir)
|
248
488
|
if proxy == ''
|
249
|
-
|
489
|
+
|
490
|
+
system(%{"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" https://naver.com/ --remote-debugging-port=9222 --user-data-dir=C:/naver_cookie/#{user_id} --no-first-run --no-default-browser-check --disable-sync})
|
491
|
+
|
250
492
|
else
|
251
|
-
|
493
|
+
|
494
|
+
system(%{"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" https://naver.com/ --remote-debugging-port=9222 --user-data-dir=C:/naver_cookie/#{user_id} --proxy-server=#{proxy.to_s.force_encoding('utf-8').to_s} --no-first-run --no-default-browser-check --disable-sync})
|
495
|
+
|
252
496
|
end
|
253
497
|
end
|
254
498
|
def chrome_start(proxy, user_id)
|
@@ -260,6 +504,9 @@ class Naver
|
|
260
504
|
options = Selenium::WebDriver::Chrome::Options.new
|
261
505
|
options.add_argument('--no-first-run') # 자동 실행 시 나타나는 "첫 실행" 화면 방지
|
262
506
|
options.add_argument('--disable-extensions') # 확장 프로그램 초기화 화면 방지
|
507
|
+
options.add_argument('--disable-sync') # Chrome 동기화 비활성화
|
508
|
+
options.add_argument('--disable-popup-blocking') # 팝업 방지 (로그인 창이 뜨는 경우 대비)
|
509
|
+
options.add_argument('--no-default-browser-check')
|
263
510
|
options.page_load_strategy = :normal
|
264
511
|
options.timeouts = {page_load: 20_000}
|
265
512
|
options.page_load_strategy = 'none'
|
@@ -285,6 +532,9 @@ class Naver
|
|
285
532
|
options = Selenium::WebDriver::Chrome::Options.new
|
286
533
|
options.add_argument('--no-first-run') # 자동 실행 시 나타나는 "첫 실행" 화면 방지
|
287
534
|
options.add_argument('--disable-extensions') # 확장 프로그램 초기화 화면 방지
|
535
|
+
options.add_argument('--disable-sync') # Chrome 동기화 비활성화
|
536
|
+
options.add_argument('--disable-popup-blocking') # 팝업 방지 (로그인 창이 뜨는 경우 대비)
|
537
|
+
options.add_argument('--no-default-browser-check')
|
288
538
|
options.add_argument '--proxy-server='+proxy.to_s.force_encoding('utf-8').to_s
|
289
539
|
options.page_load_strategy = :normal
|
290
540
|
options.timeouts = {page_load: 20_000}
|
@@ -309,6 +559,9 @@ class Naver
|
|
309
559
|
options = Selenium::WebDriver::Chrome::Options.new
|
310
560
|
options.add_argument('--no-first-run') # 자동 실행 시 나타나는 "첫 실행" 화면 방지
|
311
561
|
options.add_argument('--disable-extensions') # 확장 프로그램 초기화 화면 방지
|
562
|
+
options.add_argument('--disable-sync') # Chrome 동기화 비활성화
|
563
|
+
options.add_argument('--disable-popup-blocking') # 팝업 방지 (로그인 창이 뜨는 경우 대비)
|
564
|
+
options.add_argument('--no-default-browser-check')
|
312
565
|
options.page_load_strategy = :normal
|
313
566
|
options.timeouts = {page_load: 20_000}
|
314
567
|
options.page_load_strategy = 'none'
|
@@ -373,13 +626,20 @@ class Naver
|
|
373
626
|
puts'[Step.02] 계정 세션 확인!! 로그인 skip.......'.yellow
|
374
627
|
sleep(2.5)
|
375
628
|
rescue
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
629
|
+
begin
|
630
|
+
wait = Selenium::WebDriver::Wait.new(:timeout => 7)
|
631
|
+
# 요소가 나타날 때까지 기다립니다.
|
632
|
+
wait.until { @driver.find_element(:xpath, '//*[@class="MyView-module__link_login___HpHMW"]') }
|
633
|
+
sleep(1.5)
|
634
|
+
|
635
|
+
# 요소가 있으면 클릭
|
636
|
+
@driver.find_element(:xpath, '//*[@class="MyView-module__link_login___HpHMW"]').click
|
637
|
+
check_cookie_login = 0
|
638
|
+
sleep(1)
|
639
|
+
rescue
|
640
|
+
@driver.quit
|
641
|
+
return 0
|
642
|
+
end
|
383
643
|
end
|
384
644
|
|
385
645
|
if check_cookie_login == 0
|
@@ -414,8 +674,8 @@ class Naver
|
|
414
674
|
puts "Failed to close tab: #{e.message}"
|
415
675
|
end
|
416
676
|
end
|
417
|
-
return 0
|
418
677
|
@driver.quit
|
678
|
+
return 0
|
419
679
|
end
|
420
680
|
|
421
681
|
else
|
@@ -438,9 +698,9 @@ class Naver
|
|
438
698
|
puts "Failed to close tab: #{e.message}"
|
439
699
|
end
|
440
700
|
end
|
441
|
-
return 0
|
442
701
|
@driver.quit
|
443
|
-
|
702
|
+
return 0
|
703
|
+
end
|
444
704
|
end
|
445
705
|
|
446
706
|
def create_id
|
@@ -756,8 +1016,9 @@ class Naver
|
|
756
1016
|
puts "Failed to close tab: #{e.message}"
|
757
1017
|
end
|
758
1018
|
end
|
759
|
-
return 0
|
760
1019
|
@driver.quit
|
1020
|
+
return 0
|
1021
|
+
|
761
1022
|
end
|
762
1023
|
|
763
1024
|
ele = @driver.find_element(:xpath, '//*[@draggable="false"]')
|
@@ -1662,8 +1923,9 @@ class Naver
|
|
1662
1923
|
puts "Failed to close tab: #{e.message}"
|
1663
1924
|
end
|
1664
1925
|
end
|
1665
|
-
return 0
|
1666
1926
|
@driver.quit
|
1927
|
+
return 0
|
1928
|
+
|
1667
1929
|
end
|
1668
1930
|
|
1669
1931
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nblog_duo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.93
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- zon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-02-
|
11
|
+
date: 2025-02-17 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: File to Clipboard gem
|
14
14
|
email: mymin26@naver.com
|