[C++] 349 FLTK : ChatGPTアプリの製作 その36 jsonファイルをフォルダに振り分ける

[Mac M2 Pro 12CPU, MacOS Ventura 13.5, clang 14.0.3]

自製ChatGPTアプリに関する記事は3月以来5ヶ月ぶりです。記事にはしていませんが、これまで何度も更新を重ねグレードアップしています。

ChatGPTアプリでのやりとりはjsonファイルとして保存しています。大分ファイルがたまってきたため、年月フォルダ(今月の場合は”2308″)を自動作成して振り分けるMovJSボタンを実装しました。

ChatGPTにコードを書いてもらいました。一応コードはチェックして問題なさそうなのでビルド&実行したところ一発で成功しました。

実装完了までものの10分です。AIアシストでプログラミングすると生産性爆上がりです。

#include <iostream>
#include <filesystem>
#include <fstream>

namespace fs = std::filesystem;

void movJSONCB(Fl_Widget*, void*){
    fs::path srcDir = "/ChatGPT";

    // srcDirにあるjsonファイルのpathをリスト化する
    std::vector<fs::path> jsonFiles;
    for (const auto& entry : fs::directory_iterator(srcDir)) {
        if (entry.path().extension() == ".json") {
            jsonFiles.push_back(entry.path());
        }
    }
    
    // ファイル名の先頭4文字のフォルダを作成する
    for (const auto& jsonFile : jsonFiles) {
        std::string folderName = jsonFile.filename().stem().string().substr(0, 4);
        fs::path folderPath = srcDir / folderName;
        
        // フォルダがすでに存在する場合は上書き作成しない
        if (!fs::exists(folderPath)) {
            fs::create_directory(folderPath);
        }
        
        // ファイルをそれぞれのフォルダに振り分ける
        fs::path destinationPath = folderPath / jsonFile.filename();
        fs::rename(jsonFile, destinationPath);
    }
}

[AI] GPT-4 APIの利用資格 2023/08

先月7月からOpenAIへ1ドル以上の支払実績のあるユーザーにGPT-4 API利用資格が付与されるようになりました。

低課金ユーザーの私は7月0.52ドル、8月1.5ドルの支払いでようやく資格を得ることができましたが、今のところGPT-4を使える状態になっていません。

モデルの利用可否はOpenAIサイトのPlaygroundで確認できます。

Bingで使った感触ではGPT-4は能書きが多いだけでコーディングのアシストには余り向いていない印象ですが、早く突っ込んだ検証をしたいです。

自製アプリはGPT-4に対応済み

23/08/09追記
23時の時点でGPT-4 APIを使えるようになっていました。これから検証に取り掛かります。

GPT-4 APIが使用可能になった

[C++] 348 size_tの大きさ

[Mac M2 Pro 12CPU, MacOS Ventura 13.3.1, clang 14.0.3]

size_tはサイズを表す符号なし整数型データです。

符号なしの整数型であればunsigned intでいいのではないかと考えることもできますが、size_tはポインタを格納する場合もあるため4バイトのunsigned intでは足りないです。8バイト必要になります(64ビットプラットフォームの場合)。

コードで出力しようとするとintと同じように扱えるので何のために存在しているのか疑問に思っていましたが、ようやく理解できました。

[C++] 347 BBS閲覧アプリの製作 その31 無効なシーケンス混入による文字コード変換失敗 iconv / CP932

[Mac M2 Pro 12CPU, MacOS Ventura 13.3.1, clang 14.0.3]
(今回からM2 Pro 12コアCPUを使用)

とあるdatファイルをCP932からUTF-8へ変換しようとしたところエラーになりました。

どうやら無効なシーケンスが混ざっているようです。

以下のようにConvertShiftJISToUTF8関数を修正しました。

string ConvertShiftJISToUTF8(const string& input) {
    string output;

    // iconv_t cd = iconv_open("UTF-8", "SHIFT_JISX0213");
    iconv_t cd = iconv_open("UTF-8", "CP932");
    if (cd == (iconv_t)-1) {
        std::cerr << "Error: Failed to open iconv" << std::endl;
        return output;
    }

    size_t inBytes = input.size();
    size_t outBytes = inBytes * 4;
    char* inBuf = const_cast<char*>(input.c_str());
    char* outBuf = new char[outBytes];
    char* outPtr = outBuf;

    while (iconv(cd, &inBuf, &inBytes, &outPtr, &outBytes) == (size_t)-1) {
        if (errno == EILSEQ) {
            std::cerr << "EILSEQ:入力バッファに無効なシーケンスが含まれている" << std::endl;
            inBuf += 1; // 無効なシーケンスの分だけ入力バッファを進める
            inBytes -= 1; // 無効なシーケンスの分だけ入力バッファのサイズを減らす

        } else if (errno == EINVAL) {
            std::cerr << "EINVAL:入力バッファの終端が不完全" << std::endl;
            delete[] outBuf;
            iconv_close(cd);

            return "";
        } else if (errno == E2BIG) {
            std::cerr << "E2BIG:出力バッファが不足している" << std::endl;
            delete[] outBuf;
            iconv_close(cd);

            return "";
        } else {
            std::cerr << "その他のエラー" << std::endl;
            delete[] outBuf;
            iconv_close(cd);

            return "";
        }
    }
    output.assign(outBuf, outPtr - outBuf);

    delete[] outBuf;
    iconv_close(cd);

    return output;
}

ChatGPTに有益なヒントをもらいましたが、例示するコードが実にいい加減で少し振り回されました。追及しても虚偽説明が積み上がっていくばかりで無意味なやりとりになります。ChatGPTはネット情報から引用するだけで、検証する能力は皆無ですね。まあそんなもんです。

datファイルがCP932ではなく他のシフトJISを採用している可能性も考えましたが、今回は当てはまりませんでした。

ちなみにCP932(Windows-31J)と他のシフトJISとの文字集合の関係は以下のオイラー図のようになります。CP932は黄色です。

User:Hissakun~commonswiki, CC 表示-継承 3.0, https://commons.wikimedia.org/w/index.php?curid=82138426による

[C++] 346 BBS閲覧アプリの製作 その30 レス番号へスクロール JavaScript

[M1 Mac, MacOS Ventura 13.3.1, clang 14.0.3]

レスアンカー先へクリックでスクロールできるようにしました。

意外と手間取りました。HTML埋め込みのJavaScriptではtopプロパティで絶対Y座標が取得できるのですが、JavaScriptファイルでは相対Y座標でした。

なのでwindow.scrollYで現在位置を把握し、これにアンカー先の相対Y座標を加算する形になります。

// クリックしたレス番号までスクロール
function moveToRes(element){
    var resNum = element.innerText.replace(/>>/g, '');
    console.log("resNum: " + resNum);

    var targetElement = document.getElementById(resNum);
    var rect = targetElement.getBoundingClientRect();
    var yTo = rect.top;
    console.log("yTo = " + yTo);

    var currentY = window.scrollY;
    var scrollToY = currentY + yTo;
    console.log("scrollToY = " + scrollToY);

    scrollTo(0, scrollToY);
}

[JavaScript] 16 変数をファイルにして自動ダウンロード Blobオブジェクト

[M1 Mac, MacOS Ventura 13.3.1]

JavaScript内で生成した変数を他のプログラムで使えるようにするのは、C++ユーザーにとって最初はなかなか難易度が高いです。セキュリティ対策のため、JavaScript(非Node.js)はローカルファイルを作成して保存することができません。

今回はBlobオブジェクトを使ってファイル化しダウンロードするようにしました。

ChromeやEdgeでは自動的にダウンロードされ、Safariでは許可ボタンのクリックを経てダウンロードされます。つまりSafariでは自動化不可です。

ただ、モーダルダイアログにある許可ボタンの座標が分かれば、最近紹介したmacOSのApplication Servicesを使って自動クリックできそうな感じではあります。ややこしそうなので今回はやめておきます。

製作中のBBSブラウザで使用しているFl_WebViewはダウンロード機能を実装していないため、変数をファイル化してもダウンロードはできません。

// クリックしたaタグを含むpタグのIDを取得、ファイル化してダウンロード
function getID(element) {
    let id = element.closest('p').id;
    console.log("id = " + id);
  
    let data = new Blob([id], { type: 'text/plain' });
    let link = document.createElement('a');
    link.href = URL.createObjectURL(data);
    link.download = 'test.txt';
    link.click();
}