Capture The Frog

かえるぴょこぴょこw

MENU

juliusの辞書に言葉を追加

「juliusの辞書に言葉を追加」と調べると、yomi2voca.pl
を使用して。。。これは、perlだからwindowsに環境構築を。。。
みたいな記事がいっぱい出てくる。確かに昔はそうだったのであろう。

だが、2022年12月もうそんなめんどくさい方法は取らなくていいのだ!!(自分が開発したわけでもないのに)




自分は下のダウンロードサイトからjuliusの話し言葉モデルキット (ssr-kit)をダウンロードした。

osdn.net



自分の環境


windows 11

・julius 話し言葉モデルキット (ssr-kit) ver4.5



辞書に追加方法

まず、ダウンロードしたzipファイルを展開し、そこに移動する。

次に、適当なテキストファイル(ここではtest.txtとする)を作成して、下のようにshift-jis
「認識させたい言葉 ひらがなの読み方」を書いていく。
言葉と読み方の間は、tabで空ける。
最後に空改行を入れない。

節約術    せつやくじゅつ
ありよりのあり    ありよりのあり
スタレン    すたれん
リア垢    りああか
告つぶ    のりつぶ
鬼電    おにいなずま
百里ある    ひゃくりある


dictool.exeの実行

作成し終わったら、次に同じディレクトリ内の「dictool.exe」を実行する。
「新しい辞書を指定する」を押す。

適当に名前を入れる。(ここではtest.htkdicとする)
次に、「テキストファイルから読み込む」を押す。

先程作成したテキストファイル(test.txt)を読み込ませる。
*ここで、文字化けしていたらtest.txtがshift-jisではないので、shift-jisに直す。
次に「辞書に書き出す」を押す。

はい。完成!!!

main.jconfの編集

後は、この辞書ファイルを使うように設定していきます。
同じディレクトリ内のmain.jconfを編集することで変えることが出来ます。
main.jconfをエディタで開きます。
下の写真でマーカーが引かれている「-v 」の後が辞書ファイルになります。

なので、ここをdictool.exeで作成したtest.htkdicに変更し、保存します。

実行

run.batを実行することで実際に自身で変更した辞書ファイルを使って認識させることが出来ます。

追記
もとから使われている辞書に追加したい方は、test.htkdicの中身をデフォルトの辞書であるmodels/csj.pdp.htkdicにコピペすることで、
追加することが出来ます。その際は、main.jconfを-v models/csj.pdp.htkdicに戻すことをお忘れなく!!

0ab2aeda90221832167e5127332dd702 の解析レポート

自宅に設置したハニーポッドdionaeaで収集された
0ab2aeda90221832167e5127332dd702(以下 本ファイル)を解析した結果と
その結果から考えられることを記していく。

表層解析

本ソフト内の可読ascii文字列・API・PE情報の取得・分析した。
また、VirusTotal・HYBIRD ANALYSESを利用し、既知の情報についても調査した。

オンラインデータベースへのリンク

  • HYBIRD ANALYSES
  • Virus Total

    ハッシュ値

  • md5sum
    0ab2aeda90221832167e5127332dd702
  • sha256sum
    64bb708b31b4b043018457c1098465ea83da7d6408c7029b2f68c333fc25891c
  • sha1sum
    f370045d8ac3f4ba78acf8bfe4c4d35758d5ea05

    ファイル情報

  • xxd
    00000000: 4d5a 9000 0300 0000 0400 0000 ffff 0000 MZ..............

    MZファイルシグニチャが含まれていることから実行ファイルであることが分かる。

  • file
    0ab2aeda90221832167e5127332dd702: PE32 executable (DLL) (GUI) Intel 80386, for MS Windows

    32ビットの実行ファイルであることが分かる。


    以下のVirusTotalの検索結果では、 63 / 70のアンチウイルスソフトウェアが本ファイルをマルウェアだと検知した。

    docs.google.com

    ファイル情報からwindowsの実行ファイルであり、virusTotalの結果からマルウェアであると考えられる。
    また、virus Totalのresultから本ファイルは、「Ransom.Wannacry」「Trojan.Agent.CZTF」と呼ばれている事がわかった。


    文字列の抽出

    一覧は、スプレッドシート参照のこと
    抜粋

    特徴が現れた文字列

    compiler-stamp,Thu May 11 12:21:37 2017 | UTC

  • パソコンを起動したときに、本ソフトウェアも自動起動する可能性
    GetStartupInfoA

  • 実行環境を読み取る可能性
    GetEnvironmentStrings
    GetExitCodeProcess


  • プロセスの作成・削除が行われる可能性
    GetCurrentProcessId
    GetExitCodeProcess

  • ファイルの作成、移動、削除が行われる可能性
    MoveFileW
    MoveFileExW
    WriteFile
    DeleteFileW

  • このマルウェアは、ドロッパーの可能性
    FindResourceA
    LoadResource
    LockResource

  • shellやコマンドプロンプトが使われる可能性
    GetCommandLineA
    SHELL32.dll

  • ユーザーの意図しないスリープをする可能性
    Sleep

  • バーチャルプロテクトを施している可能性
    VirtualProtect

  • windowsレジストリに影響を与える可能性
    RegCreateKeyW

  • ファイルが暗号化される可能性
    CryptDestroyKey
    CryptDecrypt
    CryptEncrypt
    CryptImportKey
    CryptReleaseContext

  • ランサムウェアの可能性
    CryptDestroyKey
    CryptDecrypt
    CryptEncrypt
    CryptImportKey
    CryptReleaseContext
    Microsoft Security Center (2.0) Service
    Microsoft Base Cryptographic Provider v1.0

  • 関連があると考えられる実行ファイル
    mssecsvc.exe
    tasksche.exe
    WanaCrypt0r

  • 通信していると考えられるIP
    172.16.99.5
    192.168.56.20

    表層解析から分かったこと

    難読化処理が行われている。
    また、本ソフトウェアの文字列からファイルを暗号化する関数や Microsoft Base Cryptographic Provider v1.0」はCryptoapiを呼び出すプロバイダーを確認できたためランサムウェアだと考えられる。
    compiler-stampが2017年となっており、攻撃者が変更していなければこの頃に作られたと考えられる。
    Intel-386より以前のコンピュータでコンパイルされたことも分かった。
    GUIも対応しているようだ。GUIで脅迫文などを表示するのでは無いかと考えられる。
    また、関連があるとみられる「mssecsvc.exe」「tasksche.exe」「WanaCrypt0r」はランサムウェアのwannacry、wannacryの亜種のようだ。
    こちらも後に解析していきたい。また、通信していると考えられるIPと何を行っているかについては動的解析によって調査する。

    ちなみに、wannacryは Windowsを標的としたワーム型ランサムウェアである。
    2017年5月12日から大規模なサイバー攻撃が開始され150か国、23万台以上のコンピュータに感染し、
    コンピュータの身代金として暗号通貨ビットコインを要求する手法で世界中に大きな被害を与えた。
    (引用:NEC Solution Innovators, n.d.)
    Cryptoapiは、アプリケーション開発者が認証、エンコード、暗号化を Windows ベースのアプリケーションに 追加できるようにする機能を持つ (間接引用:Microsoft, n.d.)

動的解析

Any.Runで動かしてみると、PlayGameという関数が実行されたのみでHTTP/DNS共に一切の通信をしなかった。
また、PlayGameというプログラムが動作したのみで、他にはコンピュータに何も影響を及ぼさなかった。

any.run まや、仮想環境化で本ファイルを実行しようとすると、windows defenderのリアルタイム保護が働き
ランサムウェアが見つかりました。」という通知が表示され、本ソフトウェアが自動的に削除された。

静的解析

Imports

・KERNEL32
 CloseHandle
 WriteFile
 CreateFileA
 SizeofResourse
 LockResourse
 LoadResourse
 FindResourseA
 CreateProcessA
・MSVCRT
 free
 initterm
 malloc
 
adjust_fdiv
 sprintf


PlayGame()


動的解析でエキスポートされていたPlayGame関数をGhidraを用いてリバースエンジニアしてみると、
以下のようであった。

PlayGame(void){
sprintf(&DAT_10003038,”C:\\WINDOWS\\mssecsvc.exe”)
  FUN_10001016();
  FUN_100010ab();
  return 0;
 
 
}

sprintfで&DAT_10003038に”C:\WINDOWS\mssecsvc.exe”を渡すと同時に、
FUN_10001016()
FUN_100010ab()
の2つの関数が実行されていた。
それぞれの関数についてざっくり見ていく。

FUN_10001016()

FUN_10001016(void)
 
{
  HRSRC hResInfo;
  HGLOBAL hResData;
  DWORD *pDVar1;
  DWORD DVar2;
  HANDLE hFile;
  DWORD local_4;
 
  hResInfo = FindResourceA(DAT_1000313c,(LPCSTR)0x65,&DAT_10003010);
  if ((((hResInfo != (HRSRC)0x0) &&
       (hResData = LoadResource(DAT_1000313c,hResInfo), hResData != (HGLOBAL)0x0)) &&
      (pDVar1 = (DWORD *)LockResource(hResData), pDVar1 != (DWORD *)0x0)) &&
     (DVar2 = SizeofResource(DAT_1000313c,hResInfo), DVar2 != 0)) {
    DVar2 = *pDVar1;
    hFile = CreateFileA(&DAT_10003038,0x40000000,2,(LPSECURITY_ATTRIBUTES)0x0,2,4,(HANDLE)0x0);
    if (hFile != (HANDLE)0xffffffff) {
      WriteFile(hFile,pDVar1 + 1,DVar2,&local_4,(LPOVERLAPPED)0x0);
      CloseHandle(hFile);
    }
    return 1;
  }
  return 0;
}

hResInfoは、FindResourseAはDAT_1000313cが指すポインタに&DAT_10003010型の0x65を検索している。
関数が成功した場合、戻り値は指定されたリソースの情報ブロックへのハンドルで、リソースへのハンドルを取得するには、このハンドルを LoadResource 関数に渡す必要がある。
関数が失敗した場合、戻り値は NULLを返す。 (FindResourceA 関数 (Winbase.h) - Win32 Apps, 2022)

if文が少し分かりづらいので、箇条書きに直し、解釈を入れる。

・hResInfo != (HRSRC)0x0 && hResData = LoadResource(DAT_1000313c,hResInfo)

hResInfoがNULL(アドレスが0x0)では無いかを確認する。また、DAT_1000313cの最初のバイトへのポインターを取得するために使用できるhResInfoを取得する。
関数が成功した場合、戻り値はリソースに関連付けられているデータへのハンドル。
関数が失敗した場合、戻り値は NULL (LoadResource 関数 (Libloaderapi.h) - Win32 Apps, 2022)


・hResData != (HGLOBAL)0x0 && pDVar1 = (DWORD )LockResource(hResData)

hResInfoがNULL(アドレスが0x0)では無いかを確認する。また、 hResDataへのポインターを取得する。
関数が成功した場合、戻り値はリソースの最初のバイトへのポインター。関数が失敗した場合は NULL 。(LockResource 関数 (Libloaderapi.h) - Win32 Apps, 2022)


・pDVar1 != (DWORD
)0x0)) && DVar2 = SizeofResource(DAT_1000313c,hResInfo)

hResInfoがNULL(アドレスが0x0)では無いかを確認する。また、hResInfoが指すリソースのサイズ (バイト単位) を取得。関数が成功した場合、戻り値はリソース内のバイト数。
関数が失敗した場合は、0 を返す。
(SizeofResource 関数 (Libloaderapi.h) - Win32 Apps, 2022)


・DVar2 != 0

DVar2が0(アドレスが0x0)では無いかを確認する。




各処理が終わるごとに、前の関数が成功しているかを確かめ、次の処理を行っている様子が分かった。
黄色でハイライトされている部分の下では、上で得た情報を元にCreateFileA関数でファイルを作ろうとし、成功した場合は書き込みを行うようだ。

FUN_100010ab()

FUN_100010ab(void)
 
{
  BOOL var1;
  int var2;
  LPSTR *ppCVar1;
  _STARTUPINFOA local_58;
  _PROCESS_INFORMATION local_14;
 
  local_14.hProcess = (HANDLE)0x0;
  local_14.hThread = (HANDLE)0x0;
  local_14.dwProcessId = 0;
  local_14.dwThreadId = 0;
  ppCVar1 = &local_58.lpReserved;
  for (var2 = 0x10; var2 != 0; var2 = var2 + -1) {
    *ppCVar1 = (LPSTR)0x0;
    ppCVar1 = ppCVar1 + 1;
  }
  local_58.cb = 0x44;
  local_58.wShowWindow = 0;
  local_58.dwFlags = 0x81;
  var1 = CreateProcessA((LPCSTR)0x0,&DAT_10003038,(LPSECURITY_ATTRIBUTES)0x0,
                        (LPSECURITY_ATTRIBUTES)0x0,0,0x8000000,(LPVOID)0x0,(LPCSTR)0x0,&local_58,
                        &local_14);
  if (var1 != 0) {
    CloseHandle(local_14.hThread);
    CloseHandle(local_14.hProcess);
  }
  return 0;
}
 


となっており、黄色でハイライトされている部分でなにやら分岐の処理を行っている事がわかる。
黄色でハイライトされている部分の逆コンパイル前のアセンブリは以下のようになっている。

TEST EAX,EAXに注目してほしい。

TESTは、論理積(AND)命令であるが、ANDの結果を保存せず、フラグだけ変化するため、条件分岐によく使われる。
ANDの結果が0だったらZF=1になり、ZFが立つ(JZ=1)ので、その下のJZ命令で、LAB_10001110にジャンプするようだ。
(アセンブラに手を出してみる【ジャンプ命令編】, 2020)
(//, n.d.)


また、var1はBool型のCreateProcessA関数の結果であり、この関数に失敗すると0が返されるようだ。
そのため、上の分岐は、CreateProcessA関数が成功したかどうかを見ているようだ。



以上で本ソフトウェアの解析を終える。
表層解析では、ランサムウェアかと思われたが、動的解析・静的解析では特にその特徴を見つけることが出来ず、
本ソフトウェアが何であるのかを断定することが出来なかった。引き続き、学習を続け、改めて本ソフトウェアがどんな挙動をするのかを調べていきたい。





参考文献


References //. (n.d.). // - Wikipedia. Retrieved December 10, 2022, from https://wiki.onakasuita.org/pukiwiki/?TEST
アセンブラに手を出してみる【ジャンプ命令編】. (2020, April 3). いろはの物置き場. Retrieved December 10, 2022, from https://168iroha.net/blog/topic/?id=202004031013&sorting=post_date
FindResourceA 関数 (winbase.h) - Win32 apps. (2022, October 5). Microsoft Learn. Retrieved December 11, 2022, from https://learn.microsoft.com/ja-jp/windows/win32/api/winbase/nf-winbase-findresourcea
LoadResource 関数 (libloaderapi.h) - Win32 apps. (2022, October 4). Microsoft Learn. Retrieved December 11, 2022, from https://learn.microsoft.com/ja-jp/windows/win32/api/libloaderapi/nf-libloaderapi-loadresource
LockResource 関数 (libloaderapi.h) - Win32 apps. (2022, October 5). Microsoft Learn. Retrieved December 11, 2022, from https://learn.microsoft.com/ja-jp/windows/win32/api/libloaderapi/nf-libloaderapi-lockresource
Microsoft. (n.d.). C (セキュリティ用語集). C (セキュリティ用語集). Retrieved December 1, 2022, from https://learn.microsoft.com/ja-jp/windows/win32/secgloss/c-gly NEC Solution Innovators. (n.d.). WannaCry(マルウェアランサムウェア) | セキュリティ用語集 | サイバーセキュリティ. NECソリューションイノベータ. Retrieved December 1, 2022, from https://www.nec-solutioninnovators.co.jp/ss/insider/security-words/39.html
SizeofResource 関数 (libloaderapi.h) - Win32 apps. (2022, September 27). Microsoft Learn. Retrieved December 11, 2022, from https://learn.microsoft.com/ja-jp/windows/win32/api/libloaderapi/nf-libloaderapi-sizeofresource

pythonでtwitterに定期ツイート・リプライさせる [python][twitter]

https://cdn-ak.f.st-hatena.com/images/fotolife/Q/QWERTYtan/20221210/20221210161846.png

今回は、自然言語処理AIとtwitterAPIを使って定期的にツイート・リプライに返信していきましょう。

この記事にぴったりな人

  • 自然言語処理AIを作ったけど、自己満になってしまってやるせない。
  • 自然言語処理に興味がある。
  • ありきたりなtwitterbotなんか面白くない。

ちなみに、私は「凪ノなぎ」というAIbotの開発・運用をしており、その実際のコードの公開・簡単な説明をしていきたいと思います。
twitterアカウントはこちら。
twitter.com
みなさんもぜひフォローとリプライをお願いします。
ちょっとやってみたいけど、完成形がどのようになるのか分からなくて心配という方もぜひ一度「凪ノなぎ」のツイートやリプを見て、その後にやってみるかどうかを決めるのもありだと思います。

「凪ノなぎ」の要点は、主に3つ

「凪ノなぎ」の自然言語処理部分は、無料公開されているrinna/japanese-gpt2-mediumをファインチューニングし、それを「凪ノなぎ」として運用しています。
以下のブログ内のコードは、全てgithubで公開しているので気になった方は是非試してみてください。

github.com

開発の準備

自然言語処理AIについて

huggingfaceでは、学習済みの機械学習モデルやデータセットなどを公開されており、それをライセンスに応じて使うことが出来ます。
また、本来自然言語処理では、形態素解析構文解析→意味解析→文脈解析という順序で行い、それぞれの処理を行うために様々なライブラリを使わなければならないのですがhuggingfaceで公開されているモデルは、これらの処理をはるかに短くわかりやすいコードで使うことができるのでとっても便利です。感謝してます。
今回使わせていただいているrinnaモデルはrinna株式会社さんが開発されたもので、主にwikipedia/cc100をトレーニングに使用したようです。
しかし、公開されているモデルはtwitter向きではないので、ファインチューニングを行い、女の子らしさとtwitterらしさを出すことにしました。
ファインチューニングとは、学習済みデータを自分の使いたいように調整することです。
女の子らしさが欲しかったのでネットの海をさまよい、女の子のセリフを軽くまとめました。
実際にファインチューニングする言葉は、train.txtにまとめてあります。
それらを実際にtrain_rinnna.pyでファインチューニングしました。
簡単にファインチューニングのコードを見ていきましょう。

自然言語処理についてはこちらの方のYoutubeがとってもわかりやすいのでおすすめです。
youtu.be



ファインチューニング

githubのコードはこちら
では、コードの簡単な説明をしていきます。

これらは、huggingfaceで公開されているモデルを使うときのおまじないです。
とりあえず、書いておきましょう。train_rinnna.py#L9-L12

tokenizer = T5Tokenizer.from_pretrained("rinna/japanese-gpt2-medium")
tokenizer.do_lower_case = True  # due to some bug of tokenizer config loading


model = AutoModelForCausalLM.from_pretrained("rinna/japanese-gpt2-medium")



ファインチューニングするコードは、大体定型文で決まっていますが、場合に応じて変えないといけないのは下のtrain.txtの部分です。
train.txtには、自分がファインチューニングした言葉を つめたテキストファイルを入れます。
ファインチューニングは、いわゆる教師あり学習です。なので、trainでトレーニングし、
その結果があっているかどうかをtestで指定したテキストファイルで検証し、正解であるtrain.txt内の言葉に近づけていくようにしていきます。train_rinnna.py#L17-L19

    data_files={
        "train":"train.txt",
        "test":"train.txt"


ここではどれくらいトレーニングの設定をします。
・output_dir:レーニング結果の保存場所
・num_train_epochs : 訓練のエポック数
・per_device_train_batch_size : バッチサイズ。(指定したテキストファイルをいくつに分けてトレーニングを行うか)
・load_best_model_at_end=True:学習後に最良のモデルを自動でロード
・evaluation_strategy:指定した値のステップ数ごとにバリデーション(検証) train_rinnna.py#L30-L37

training_args = TrainingArguments(
    output_dir="output",
    num_train_epochs=3,
    per_device_train_batch_size=2,
    per_device_eval_batch_size=2,
    load_best_model_at_end=True,
    evaluation_strategy="steps"
)



上のtrainerで、設定したものをまとめており、それを実行する。train_rinnna.py#L54

trainer.train()

定期ツイート

上のファインチューニングでトレーニングしたものを使用して、定期的にツイートするようにしていきます。
定期ツイートは、2段階に分けることが出来ます。
pythonでツイート
windowsのタスクスケジューラーで定期的に実行
要はpython単体でツイートするコードを書くことができれば、あとは他のプログラムやサービスに任せれば定期的に実行することができるということです。
*pythonのsleep関数で定期的に実行しようとするのはあまりおすすめしません。
なので、今回はpythonでツイートするコードを書いて行きましょう。
githubのコードはこちら
では、コードの簡単な説明をしていきます。

pythonでツイート

twitterAPIの設定

twitterbotではtwitterAPIが必要になり、それをここに貼り付けて設定します。
変えなければならないのは、CONSUMER_KEY・CONSUMER_SECRET・ACCESS_TOKEN・ACCESS_SECRETのみで、後はコピペで良いと思います。
Autotweet.py#L11-L33

#Twitter各種設定
#取得したtwitterAPIを貼り付ける
CONSUMER_KEY = ''
CONSUMER_SECRET = ''
ACCESS_TOKEN = ''
ACCESS_SECRET = ''




#twitter各種設定
auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET)
auth.set_access_token(ACCESS_TOKEN, ACCESS_SECRET)
api = tweepy.API(auth,wait_on_rate_limit=True)




# OAuthの認証オブジェクトの作成
oauth = twitter.OAuth(ACCESS_TOKEN,
                      ACCESS_SECRET,
                      CONSUMER_KEY,
                      CONSUMER_SECRET)
# Twitter REST APIを利用するためのオブジェクト
twitter_api = twitter.Twitter(auth=oauth)
# Twitter Streaming APIを利用するためのオブジェクト
twitter_stream = twitter.TwitterStream(auth=oauth)

ツイート処理

お願い:voc_list_kiso_kansei.csvをjapanese_words.csvとしてnagino_nagi_tweetBot_publicのディレクトリ内に入れてください。
では、次に実際にtweetを行う処理について見ていきます。
まず、何についてAIが文を作るのかの単語を指定しなければならないため、日本語の単語を収録したjapanese.csvの中から単語をランダムに1つ選ぶ処理をします。

    #csvから単語のリストを読み込む
    csv_file = open("japanese_words.csv", "r", encoding="shift_jis")
    f = csv.reader(csv_file, delimiter=",", doublequote=True, lineterminator="\r\n", quotechar='"', skipinitialspace=True)
    header = next(f)


    #単語を1文字取る
    japanese_word=[]
    for row in f:
        #rowはList
        japanese_word.append(row[2])




    tweet_seed = random.choice(japanese_word)



次に、ファインチューニングしたモデルを設定します。
ここでは、modelをoutput\checkpoint-5500としていますが、
modelには、上のファインチューニングしたモデル内でcheckpointの数字が一番大きいディレクトリを指定してください。
ファインチューニングを行っていない場合は、modelに「rinna/japanese-gpt2-medium」を指定していただければと思います。
Autotweet.py#L54-L57

        # トークナイザーとモデルの準備
    tokenizer = T5Tokenizer.from_pretrained("rinna/japanese-gpt2-medium")
    tokenizer.do_lower_case = True  # due to some bug of tokenizer config loading
    model = AutoModelForCausalLM.from_pretrained("output\checkpoint-5500")



上でランダムに選んだ単語の中に全角が紛れていることがあるかもしれないので、全角を半角に直す。
また、大文字のアルファベットは小文字に直しています。
Autotweet.py#L63

        #.transrate()で全角を半角に直す
        #.lower()でアルファベットを小文字に直す
    word = tweet_seed.translate(str.maketrans({chr(0xFF01 + i): chr(0x21 + i) for i in range(94)})).lower()



実際に推論を行っています。
また、時折、存在しない写真のurl(pic.twitter)が生成される事があるため3文生成し、リストに入れています。
生成後、それらを除くような処理をしています。
何も生成されなかった場合、「...」とするようにしています。また、特殊文字・記号は取り除いています。
Autotweet.py#L65-L89

    # 推論の実行
    input = tokenizer.encode(word,return_tensors="pt",)
    #do_sample=True、ランダムな自然な文を生成するため。repetition_penalty = 1.1、同じ言葉が反復して出てこないようにするため。num_return_sequences、文の数
    output = model.generate(input, do_sample=True, max_length=100, num_return_sequences=3, repetition_penalty =1.0)
    #skip_special_tokens、いらない文字を無くすため
    become_voice_list=[]
    become_voice_list = tokenizer.batch_decode(output,skip_special_tokens=True)


    #推論された文字を調整
    #pic.twitterが入ってる場合は、次の配列に移る
    for i in become_voice_list:
        
        if 'pic' in i:
            print('スキップ:'+i)
            continue
        else:
            become_voice_str = "".join(i)
            #become_voice_str=become_voice_str.replace(word,'')


            if become_voice_str == '':
                become_voice_str = '...'




    #文章的に直すところ
    voice = become_voice_str.replace("[" , "").replace("@" , "").replace("ω" , "").replace("_","").replace('&','')



設定したtwitterAPIを使用してツイートします。

    #リストに含まれるツイート内容をランダムでツイート
    print(voice)
    api.update_status(voice)




定期実行

windowsタスクスケジューラーを使っていくのですが、直接.pyをpythonで実行しようとしてもうまく動きませんでした。
なので、以下のバッチファイルを書き、バッチファイルをタスクスケジューラーで設定し30分ごとに実行させています。

@if not "%~0"=="%~dp0.\%~nx0" start /min cmd /c,"%~dp0.\%~nx0" %* & goto :eof
python 場所/Autotweet.py




定期リプライ

ファインチューニングでトレーニングしたものを使用して、定期的にツイートするようにしていきます。
定期ツイートは、3段階に分けることが出来ます。
・タイムラインからリプライを取得 ・リプライ ・定期実行 が、定期ツイートと重なる部分も多くあるので、重なる部分の説明は省きます。
githubのコードはこちら

タイムライン取得

目的は、「自分のツイートに対するリプライを取得したい。」
そもそも、twitterAPIにおけるタイムラインは、2つに分けられます。
・user_timeline
特定したユーザーのタイムラインを取得できる。
・home_timeline
自分のタイムラインを取得できる。
自分のツイートに対するリプライは、home_timelineに表示されるのでhome_timelineかを取得し、 リプライを探していきます。

home_timelineから3200のツイートを取得します。
その中で自分のアカウント名がある場合は、そのツイートを取得しデータを整形します。
下のコードで処理は出来ますが、より深くタイムラインの取得について詳しく知りたい方は、
タイムラインの取得と整形は奥が深いのでこちらの記事におまかせします。
twitter_Auto_reply.py#L86-L107

    for i, tweet in enumerate(tweepy.Cursor(api.home_timeline).items(3200)):


        #.find()が-1のときはその中に無い
        if tweet.text.find('@アカウント名') != -1:
            #print("ツイート本文:" +tweet.text+'投稿者:'+str(tweet.user.name)+str(tweet.user.screen_name)+"ツイートid:"+str(tweet.id))


            before_seed = tweet.text.split(" ")
            tweet_seed = before_seed[-1].replace("\n","")


            #.transrate()で全角を半角に直す
            #.lower()でアルファベットを小文字に直す
            word = tweet_seed.translate(str.maketrans({chr(0xFF01 + i): chr(0x21 + i) for i in range(94)}))
            print(word)




次に取得したツイートに対してのリプライがすでに行われているかどうかを調べる事が必要になります。
仮に、この確かめを行わなかった場合、リプライしていただいたツイートに何回もリプライを返してしまうことになります。
すでにリプライが行われた他者の自分に対するリプライは、すべてauto_rep.txtに保存します。
そのため、このauto_rep.txtにツイートがあるかを確かめ、なかった場合は、リプライ処理を行うようになっています。
twitter_Auto_reply.py#L109-L129

            #テキストファイルにあるかどうか
            if word+'\n' in datafile:
                print('済み')
                
            else:
                print('リプライ処理')


                #.txtに書き込み
                
                f = open('auto_rep.txt', 'a',encoding='utf-8')
                f.write(word+'\n')
                f.close()


                voice = NaginoNagi_GPT(word)
                # 特定のツイートへのリプライの場合
                reply_text = '@'+tweet.user.screen_name +str(before_seed[0:-2]).replace("[",' ').replace("]",'').replace("'",'')+ '\n'
                reply_text += voice
                print("reply->>>>"+reply_text)
                
                #リプライ
                twitter_api.statuses.update(status=reply_text, in_reply_to_status_id=tweet.id)

後は、上のツイート処理と特に変わりがないため割愛させていただきます。


質問など訂正があった場合は、コメント・twitterにお願い致します。



参考

自然言語処理(AI)

Androidアプリのリリースで詰まった話

かんたんなAndroidのアプリを開発していて、

debug版のアプリの"google signin"は出来るのに、release版では"google signin"が

com.google.android.gms.common.api.ApiException:10

のエラーによって出来ない。

結果からいうと、このエラーは releaseのsha-1が設定されていないことが原因となります。

断定方法

この画面の右端にあるgradleタブの ゾウをクリック "gradle signingReport"と入力 そして、下の写真のように Variant: releaseの部分が、nullになっていたら、この問題はここが起こしているといって間違いないと思います。

qiita.com

Androidのnavigationでの矢印の色変更

Androidのnavigationコンポーネントを利用してActionBarを自動で作ったときに矢印の色を変更するのに、 少し手間取ったので備忘録として書いておく。

今回は、デフォルトの白の矢印を下のようなこの黒い矢印にしたい。↓

themes.xmlにて

<!-- デフォルトのTheme -->
<style name="MyTheme" parent="Theme.AppCompat">
   <item name="drawerArrowStyle">@style/MyDrawerArrowToggle</item>
</style>

<!-- デフォルトの下に貼る -->
<style name="MyDrawerArrowToggle" parent="Widget.AppCompat.DrawerArrowToggle">
  <item name="color">@color/white</item>
</style>

opencvとPytorchを組み合わせたときのバグ

なぜか、25個以上のバウンディングボックスを表示できない

import torch
import cv2
import numpy as np

#定数
IMAGE_PATH = '/home/snowyowl/Downloads/yolov5-master/data/images/252532.jpg'

#yolov5を動かす
model = torch.hub.load('/home/snowyowl/Downloads/yolov5-master', 'custom', path='/home/snowyowl/Downloads/yolov5-master/yolov5s.pt', source='local')

img = cv2.imread(IMAGE_PATH) 
results = model(img)
results.display(pprint=True)


image 1/1 /home/snowyowl/Downloads/yolov5-master/data/images/classroom.jpg: 480x640 33 desks, Done. (0.070s)
↑yolov5で直接実行

image 1/1: 3024x4032 25 desks


25で止まってる。Qなんで?
A

import torch
import cv2
import numpy as np
 
#定数
IMAGE_PATH = '/home/snowyowl/Downloads/yolov5-master/data/images/classroom.jpg'
 
#yolov5を動かす runs/train/exp80/weights/best.pt
model = torch.hub.load('/home/snowyowl/Downloads/yolov5-master', 'custom', path='/home/snowyowl/Downloads/yolov5-master/yolov5s.pt', source='local')
results = model(IMAGE_PATH)
results.display(pprint=True)
results.show()

多分opencvの方の問題
results = model(IMAGE_PATH)
modelの引数を直接IMAGE_PATHにしたら、直った

parrot osの/etc/apt/sources.listを編集する

他のubuntuやkali linuxでは/etc/apt/sources.listを直接編集すると、コマンドのsourceをダウンロードすることができるのだが、 parrot osでは/etc/apt/sources.list.d/parrot.listにまとめられており、/etc/apt/sources.listは空ファイルとなっている。

↓/etc/apt/sources.list

# This file is empty, feel free to
# add here your custom APT repositories

# The standard Parrot repositories
# are NOT here. If you want to
# edit them, take a look into
#                /etc/apt/sources.list.d/parrot.list



# If you want to change the
# default parrot repositories by selectng
# another localized mirror,
# then use the command
#                     parrot-mirror-selector
#
# and see its usage message to
# know what mirrors are available

そのため、 /etc/apt/sources.list.d/parrot.list

のコメントの#をすべて外す。

## Parrot 4.x Repositories
deb https://deb.parrot.sh/parrot rolling main contrib non-free
deb https://deb.parrot.sh/parrot rolling-security main contrib non-free
deb-src https://deb.parrot.sh/parrot rolling main contrib non-free
deb-src https://deb.parrot.sh/parrot rolling-security main contrib non-free

すると、apt source "好きなコマンド"で好きなコマンドのsourceをダウンロードすることができる。