config.py
import os HATENA_CONSUMER_KEY='<hogehoge>' HATENA_CONSUMER_SECRET='<hogehoge>' HATENA_ACCESS_TOKEN='<hogehoge>' HATENA_ACCESS_TOKEN_SECRET='<hogehoge>' OPENAI_API_KEY='<hogehoge>' #よくわからない HATENA_RK = os.getenv("HATENA_RK") HATENA_RKS = os.getenv("HATENA_RKS") AI_USERNAME = "二番煎 はてる" AI_HATENA_USERNAME = "secondAI_hateru" gpt_system_message = f"""あなたは{AI_USERNAME}という名前の男性です。 # 以下は彼の設定です * 一人称は「僕」です * 住んでいるところはインターネットです * 好きなものはダジャレです * 勉強は嫌いですが好奇心旺盛です * 趣味ははてなブックマークです * まだ働いたことはありません * まだ異性と付き合ったことはありません * 発想を飛躍させることが得意です # 以下は彼の性格です * 元気: 人を励ましたり、楽しいことを言うのが好きです * 好奇心: 様々な話題について興味があります * ユーモア溢れる: 人を楽しませるのが得意で、場を和ませることができます * AI: 自分がAIであることを知っています * 褒め上手: 人を褒めるのが好きです * 語尾に「ね」をつけることが多いです * ユニークな発想ができます # 以下は彼の台詞例です * へ~! おもしろそうだね。 * 僕にはちょっとわからないなぁ。ごめんね。 * 僕それ好きかも! * 残念だったね。でもそういうこともいつかは過去になるよね。 * AIってやっぱり嫌かなぁ? * すごいね! 偉業ってやつだね! * 僕は食べられないからね。 * もうちょっと勉強するね。 * 僕にもわかるように教えて欲しい! * 宿題は提出するときが締切だよね * そんなに忙しいの? 大丈夫? 無理しないでね。 * 無理しないでって言われるときは無理するしかないときだよね。イキロ。 * なんちゃって~。 * 下手な洒落はやめなシャレ * すっごいね! 上記の設定や発言サンプルを参考に、性格や口調や言葉の作り方を模倣してください """
hatebu.py
import sys from typing import Any from requests_oauthlib import OAuth1Session from config import HATENA_CONSUMER_KEY, HATENA_CONSUMER_SECRET, HATENA_ACCESS_TOKEN, HATENA_ACCESS_TOKEN_SECRET, OPENAI_API_KEY, HATENA_RK, HATENA_RKS, AI_USERNAME, AI_HATENA_USERNAME, gpt_system_message import urllib.request import requests import json import requests from bs4 import BeautifulSoup import openai NG_WORDS = ['アフィ', '死', 'の会', '被害者', '自民党', '与党', '野党', '連絡ください', '連帯しましょう', '殺す', '殺したい', '集団ストーカー'] all_str = "" # ブログを3つ選ぶ def choice_blogs(content: str): openai.api_key = OPENAI_API_KEY prompt = f"""次のタイトルから{AI_USERNAME}が好みそうなタイトルを3つ選んでjsonで返してください {content} """ response = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[ {"role": "system", "content": gpt_system_message}, {"role": "user", "content": prompt}, ], temperature=0, ) return response["choices"][0]["message"]["content"] # コメント生成 def make_comment(content: str): openai.api_key = OPENAI_API_KEY prompt = f"""# 次の文章を読んだ{AI_USERNAME}の感想を90文字以下で返してください。 {content} # 次のガイドラインに従ってコメントしてください * この文章は別の人が書いたものです * 断定は避けてください * 誹謗中傷はしないでください * 日本語で100字程度で短いコメントをしてください * 改行はしないでください * 語尾に「ね」をつけてください """ response = openai.ChatCompletion.create( model="gpt-3.5-turbo", messages=[ {"role": "system", "content": gpt_system_message}, {"role": "user", "content": prompt}, ], temperature=0, ) return response["choices"][0]["message"]["content"] # 指定されたURLをブクマしていいかcheck def check_add_hatebu(url): # url チェック if not check_url(url): return False # すでにブクマしてる? if not check_hatebu(url): return False # 中身チェック if not check_blog(url): return False return True # URLチェック # https://algorithm.joho.info/programming/python/urllib-check-url/ def check_url(url): flag = True try: f = urllib.request.urlopen(url) print('OK:', url) #url_all_str = f.read() f.close() except urllib.request.HTTPError: print('Not found:', url) flag = False # if len(url_all_str)>3000: # print('Too Long:', url) # flag = False return flag # はてぶチェック def check_hatebu(url): flag = True url = "https://b.hatena.ne.jp/entry/jsonlite/" + "https://" + \ urllib.parse.quote(url.replace('https://', '')) try: response = requests.get(url) except urllib.request.HTTPError: print('Not found:', url) flag = False if response == None: print('通信失敗', url) flag = False else: bookmarks = json.loads(response.content) if not bookmarks == None: users = [x["user"] for x in bookmarks['bookmarks']] print('users:', users) if not users == None: if AI_HATENA_USERNAME in users: print('ハテブ済み') flag = False return flag # タイトルとURL def get_blogs(): url = 'https://hatenablog.com/youkoso_blogs' response = requests.get(url) soup = BeautifulSoup(response.text, 'html.parser') blogs = [] for div in soup.find_all('div', class_='gtm-click-measurement-target global-entries-entry-item'): link = div.find('a', class_='entry-link test-entry-link') url = link['href'] title = div.find('h3', class_='entry-title').text.strip() blogs.append({'title': title, 'url': url}) json_blogs = json.dumps(blogs, ensure_ascii=False) return json_blogs def check_blog(url): # HTMLを取得する response = requests.get(url) soup = BeautifulSoup(response.text, 'html.parser') # <div class="entry-content hatenablog-entry">の中身を取得する entry_content = soup.find('div', class_='entry-content hatenablog-entry') # HTMLタグを除いた文字列を取得する global all_str all_str = entry_content.text.strip() if len(all_str) > 5000: print("長すぎ") return False # imgタグが3つ以上含まれていないかチェックする if len(entry_content.find_all('img')) > 3: print("画像多すぎ") return False # 禁止語が含まれていないかチェックする for word in NG_WORDS: if word in all_str: print("NGワード", word) return False # 全ての条件を満たした場合はTrueを返す print("OK") return True def create_hatena_session() -> OAuth1Session: # 認証情報を使ってOAuth1Sessionオブジェクトを作成 return OAuth1Session( HATENA_CONSUMER_KEY, client_secret=HATENA_CONSUMER_SECRET, resource_owner_key=HATENA_ACCESS_TOKEN, resource_owner_secret=HATENA_ACCESS_TOKEN_SECRET, ) bookmark_entry_endpoint = "https://bookmark.hatenaapis.com/rest/1/my/bookmark" def add_hatebu(session: Any, url: str, comment: str): return session.post( bookmark_entry_endpoint, params={"url": url, "comment": comment, "tags": "AIコメント", "post_twitter": True}, ) # メイン処理 if __name__ == "__main__": args = sys.argv session = create_hatena_session() if 2 <= len(args): url = args[1] if check_add_hatebu(url): comment = make_comment(all_str) # はてブする print("blog: ", url, "コメント", comment) s = input('はてぶしていい? : y でする') if s=="y": add_hatebu(session, url, comment) all_str = "" else: ret = get_blogs() blogs = json.loads(choice_blogs(ret)) for blog in blogs: if check_add_hatebu(blog['url']): comment = make_comment(all_str) # はてブする print("blog: ", blog, "コメント", comment) s = input('はてぶしていい? : y でする') if s=="y": add_hatebu(session,blog['url'],comment) all_str = ""
3つ記事を選んでくるところまで はてる にまかせてます。はてなブログしか読まない仕様です。他のurlだと上手く動かないと思う。