ChatGPTを使ってみる

ちょっと試してみたくなった。

ユーザー登録

ユーザー登録だけで、今は無料で使用できる。最初に以下のページにアクセスし、「TRY CHATGPT」をクリックしてユーザー登録を行う。
https://openai.com/blog/chatgpt/

使ってみる

試しに「ChatGPTを上手に使うには?」と質問してみた。

ChatGPT:ChatGPTを上手に使うには以下のようなポイントがあります。

  1. 明確な質問をすること: ChatGPTには具体的な質問をすることが重要です。
  2. 十分な情報を提供すること: 質問に対する回答を最適化するために、できるだけ多くの情報を提供することが大切です。
  3. 自然な言語を使うこと: ChatGPTは人工知能モデルですが、自然な言語を使うことで、より正確な回答を得ることができます。
  4. 信頼性の高い情報ソースからの情報を求めること: ChatGPTはトレーニングデータに基づいていますが、常に正確な情報を保証することはできません。正確な情報を求める場合は信頼性の高い情報ソースからの情報を求めることをお勧めします。

対話式に質問を続けられるはすなので、さらに意地悪に質問を掘り下げてみた。

「ChatGPTからの回答が間違えている可能性はどのくらいあるのか?」

ChatGPT:ChatGPTはOpenAIによってトレーニングされた大規模な言語モデルですが、常に正確な回答を保証することはできません。トレーニングデータに基づいて回答を生成しますが、トレーニングデータに誤りが含まれていたり、最新の情報が含まれていなかったりする場合があります。また、ChatGPTは意図や文脈を正確に理解することもできない場合があります。そのため、ChatGPTからの回答を単独で信頼することは避け、常に他の情報源と照らし合わせて判断することが重要です。

「そうではなくて、間違いが含まれている可能性の具体的な数値を知りたい。」

ChatGPT:具体的な数値は提供されていませんが、ChatGPTは高精度の言語モデルであり、多くの場合、正確な回答を生成します。ただし、トレーニングデータに基づいているため、トレーニングデータに含まれていない情報や最新の情報に対する回答など、間違いが含まれる可能性があります。また、文脈や意図の誤りなどもありますので、常に他の情報源と照らし合わせて判断することが重要です。

「最新の情報ほど間違いが含まれている可能性が高いということか?」

ChatGPT:はい、そのような傾向があります。トレーニングデータは一定期間前の情報であり、最新の情報は含まれていない可能性があります。また、最新の情報はまだ完全には明らかでない場合もありますので、正確性が低い可能性があります。そのため、最新の情報に関する質問に対しては特に他の情報源と照らし合わせて確認することが重要です。

まとめ

同じような回答になってしまっているところもあるが、自然に会話しているように文章が繋がっている。本当にすごいツールが出てきたと思う。

Java 8のOptionalクラスの考察

動機

Optionalについて、うまく使えていない気がするため、改めて整理してみる。

実装例

Nullチェック

nullの一番の問題点は、nullチェックを行わなくともコンパイルエラーにならないこと。そして実行時にNullPointerExceptionが発生する可能性があること。

例として、nullチェックを行う場合について考えてみる。

public String getFruit() {
    return 果物の名前または、nullを返却する処理とする;
}

public void fruitCheck() {
    var fruit = getFruit();

    if (fruit != null) {
        System.out.println(fruit + " are delicious.");            
    }
}

これを単純にOptionalに置き換えると下記のようになる。

public Optional<String> getFruit() {
    String name = 果物の名前または、nullを返却する処理とする;
    return Optional.ofNullable(name);
}

public void fruitCheck() {
    var fruit = getFruit();

    if (fruit.isPresent()) {
        System.out.println(fruit.get() + " are delicious.");
    }
}

これだと、nullチェックを行っているときと変わらない。この処理を典型的な関数型プログラミングのスタイルに書き換えてみる。

public void fruitCheck() {
    var fruit = getFruit();

    fruit.ifPresent(name -> System.out.println(name + " are delicious."));
}

elseの処理が必要な場合は、下記のように書ける。

fruit.ifPresentOrElse(name -> System.out.println(name + " are delicious."),
        () -> System.out.println("I'm hungry."));

Nullの場合にデフォルト値を設定する処理

getFruit()のメソッドでnullを返すのではなく、nullの場合デフォルトの値を返す場合を考えてみる。

public String getFruit() {
    String name = 果物の名前または、nullを返却する処理とする;

    if (name != null) {
        return name;
    } else {
        return "Apple";
    }
}

public void fruitCheck() {
    var fruit = getFruit();

    System.out.println(fruit + " are delicious.");            
}

Optionalに置き換えると下記のようになる。

public String getFruit() {
    String name = 果物の名前または、nullを返却する処理とする;

    return Optional.ofNullable(name).orElse("Apple");
}

関数型プログラミングのスタイルになって、Nullチェックのミスも減るだろうか。

Nullチェックするとともに値のチェックも行う場合

public void fruitCheck() {
    var fruit = getFruit();

    if (fruit != null && fruit.equals("Banana")) {
        System.out.println(fruit + " are very delicious.");            
    }
}
public void fruitCheck() {
    var fruit = getFruit();

    fruit.filter(name -> name.equals("Banana"))
            .ifPresent(name -> System.out.println(name + " are delicious."));
}

Nuxt 3が出たので使ってみる

動機

Vue 3に対応したNuxt 3がリリースされたので、早速使ってみる。

ゴール

以前作成した下記のアプリと同等の機能を実装する。すでに、Vue3対応は完了しているため、大きな変更は必要ないはず。
https://github.com/hide6644/crawler-client

今回はインストールまで行う。インストール途中に「

ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time

」のワーニングが表示されるが、今は気にしても仕方がないので、無視する。

インストール

実行環境
Windows 11
node 18

npx nuxi init プロジェクト名
cd プロジェクト名
npm install

実行

npm run dev

実行後、http://localhost:3000/にアクセスすると、welcomeページが表示される。

開発環境

開発環境には、Visual Studio Codeを使用する。インストール済みであれば、先ほどのインストールフォルダで、「code ./」を実行すると即座に起動できる。
(プラグインVolar ExtensionTypeScript Vue Plugin (Volar)のインストール推奨)

Javaでファイル内容を比較し、結果を別ファイルに出力する

目的

キーが1対1の関係になっている2つのファイルを1行ずつ読みだし内容を比較する。その比較結果を別のファイルに出力するプログラムをJavaで作成する。

要件

〇入力ファイル
 ・在庫ファイル
   商品コード
   在庫数
 ・注文ファイル
   商品コード
   注文数
 ※それぞれ、商品コードで一意、昇順になっている。

〇出力ファイル
 ・新在庫ファイル
   商品コード
   在庫数
 ・エラーファイル
   商品コード
   注文数
 新在庫ファイル・・・入力ファイルの在庫と注文を突合して、在庫数から注文数を引いた数量を記録する
 エラーファイル・・・注文に対して、在庫がない、在庫が足りない場合はエラーとし、当ファイルに出力する

〇その他
 入力ファイルのサイズが大きいため、1行ずつ読み込んで処理していく必要がある。

実装例

public void matching() {
    try (var stockFile = Files.newBufferedReader(Paths.get("src/stock.txt"));
            var orderFile = Files.newBufferedReader(Paths.get("src/order.txt"));
            var newStockFile = Files.newBufferedWriter(Paths.get("src/newStock.txt"));
            var errorOrderFile = Files.newBufferedWriter(Paths.get("src/errorOrder.txt"));) {
        // 入力ファイルの1行目を読み込む
        // 文字列からオブジェクトに変換する
        Stock stock = Stock.createFromLine(stockFile.readLine());
        Order order = Order.createFromLine(orderFile.readLine());

        // どちらかのファイルの行があるうちは処理を続ける
        while (stock.getKey() < Integer.MAX_VALUE || order.getKey() < Integer.MAX_VALUE) {
            // 比較するコードを取得。(この例ではコードを数値としている)
            // コードで昇順になっているのでコードの大小を比較すれば、
            // 一方のファイルにしかない商品もわかる
            int stockKey = stock.getKey();
            int orderKey = order.getKey();

            if (stockKey - orderKey == 0) {
                // コードが一致
                int qty = stock.getQuantity() - order.getQuantity();

                if (qty < 0) {
                    // 在庫不足
                    // エラーファイル出力
                    errorOrderFile.write(order.toErrorOrder("01").toLine());
                    errorOrderFile.newLine();
                } else {
                    stock.setQuantity(qty);
                }

                // オブジェクトから1行分の文字列を生成し、書き出す
                newStockFile.write(stock.toNewStock().toLine());
                newStockFile.newLine();
                // 次の行を読み込む
                stock = Stock.createFromLine(stockFile.readLine());
                order = Order.createFromLine(orderFile.readLine());
            } else if (stockKey - orderKey > 0) {
                // 商品なし
                // エラーファイル出力
                errorOrderFile.write(order.toErrorOrder("02").toLine());
                errorOrderFile.newLine();
                // 次の行を読み込む
                order = Order.createFromLine(orderFile.readLine());
            } else {
                // 注文なし
                newStockFile.write(stock.toNewStock().toLine());
                newStockFile.newLine();
                // 次の行を読み込む
                stock = Stock.createFromLine(stockFile.readLine());
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

※他にも「var」宣言を使える箇所があるが、わかりやすくするため、あえて通常の宣言にしている。

@Builder
@Data
public class Order {

    private String category;
    private String code;
    private Integer quantity;

    public Integer getKey() {
        if (category == null && code == null) {
            return Integer.MAX_VALUE;
        } else {
            return Integer.valueOf(category + code);
        }
    }

    public ErrorOrder toErrorOrder(String errorCode) {
        return ErrorOrder.builder()
                .category(category)
                .code(code)
                .quantity(quantity)
                .errorCode(errorCode)
                .build();
    }

    public static Order createFromLine(String line) {
        if (line == null) {
            return Order.builder().build();
        } else if (line.length() < 35) {
            throw new IllegalArgumentException();
        }

        return Order.builder()
                .category(line.substring(4, 5))
                .code(line.substring(6, 7))
                .quantity(Integer.valueOf(line.substring(8, 9)))
                .build();
    }
}

NextCloudをUbuntu 22.04で動かす

前提条件

下記が導入済みであること
Apache 2
PHP 8.1
MariaDB

NextCloudのインストール

NextCloudのダウンロード

NextCloudのページからzipファイルをダウンロードする。

cd /var/www/html
wget https://download.nextcloud.com/server/releases/nextcloud-25.0.1.zip

NextCloudの配置

unzip nextcloud-25.0.1.zip
chown -R www-data:www-data /var/www/html/nextcloud

Apacheの設定

vi /etc/apache2/sites-available/nextcloud.conf
<Directory /var/www/html/nextcloud/>
  Require all granted
  Options FollowSymlinks MultiViews
  AllowOverride All
  <IfModule mod_dav.c>
    Dav off
  </IfModule>
</Directory>
sudo a2ensite nextcloud.conf
sudo a2enmod rewrite
sudo systemctl restart apache2
メモリエラーの解消
/etc/php/8.1/apache2/php.ini
memory_limit = 512M

Spring Boot 3にアップグレードする

目的

Spring Boot 3がリリースされたので、以前作成したプロジェクトをアップグレードしてみることにした。

主な変更点

主な変更点は「Spring Framework 6にアップグレードする」に記載したことと同じ。

実際に変更した箇所

依存関係

ライブラリの変更、またはバージョンアップを行った。

  • Spring Boot 3
  • hibernate-search-mapper-orm => hibernate-search-mapper-orm-orm6 6.1

コードの変更点

javaxをjakartaに書き換えただけの部分は省略する。

Spring Securityの設定箇所で@Configurationの追記が必要になった。

@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class WebSecurityConfig {
    ↓
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class WebSecurityConfig {

まとめ

gradleを使用していれば、ほとんどの依存関係の更新も自動で行われるので、かなり簡単にアップグレードできた。

Spring Framework 6にアップグレードする

目的

Spring Framework 6がリリースされ、その他のパッケージも合わせて変更できそうだったので、勉強のために以前作ったプロジェクトをSpring Framework 6にアップグレードしてみることにした。

主な変更点

Jakarta EE 9への対応

大まかに言うとjavaxからjakartaに変わる。

import javax.servlet.http.HttpServletRequest;
    ↓
import jakarta.servlet.http.HttpServletRequest;

さらに、Jakarta EEに対応しているTomcat 10などに、デプロイする必要がある。

実際に変更した箇所

依存関係

ライブラリの変更、またはバージョンアップを行った。

  • greenmail 2
  • hibernate… 6.1
  • hibernate-search-mapper-orm => hibernate-search-mapper-orm-orm6 6.1
  • hibernate-validator 7
  • javax.el => jakarta.el 4
  • javax.servlet => jakarta.servlet 6
  • jakarta.mail 2
  • jakarta.xml.bind-api 3
  • jaxb-runtime 3
  • spring-core… 6
  • spring-data-jpa 3
  • spring-security… 6
  • thymeleaf-spring5 => thymeleaf-spring6 3.1
  • thymeleaf-extras-springsecurity5 => thymeleaf-extras-springsecurity6 3.1

コードの変更点

javaxをjakartaに書き換えただけの部分は省略する。

Spring MVC設定の変更

下記のようThymeleafのspring5パッケージをspring6に変更する。Resolver以外も同様に変更する。

    <bean id="templateResolver" class="org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver">

MultipartResolverはStandardServletMultipartResolverを使用する。
web.xmlの<servlet>タグに<multipart-config>の設定を追加すると有効になる。

<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver" />

Thymeleaf Ver. 3.1にアップグレードも同時に行った場合は下記の変更も必要になる。
Thymeleaf 3.1にアップグレード

web.xmlの変更

下記の通り、変更する。

<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
  version="5.0">

まとめ

javaxからjakartaに変更する箇所は多いが、結構簡単にアップグレード出来た。

Thymeleaf 3.1にアップグレード

公式に記載の通り、#request、#response、#session、#servletContextが使用できなくなった。

1.6 Removal of web-API based expression utility objects
The #request, #response, #session, and #servletContext are no longer available to expressions in Thymeleaf 3.1.

Thymeleaf 3.1: What’s new and how to migrate

下記の通り修正して対応した。

${#servletContext.getAttribute('assetsVersion')}
       ↓
${application.assetsVersion}
${#request.remoteUser}
       ↓
remoteUserをSessionに保持するようにして、
${session.remoteUser}

※ 2022/11/30 追記
Spring Securityを使用している場合、remoteUserを取得するなら、Sessionに保持は不要で、下記で可能だった。
${#authentication.name}

AWSのUbuntuを22.04.1にアップグレードする

AWS上のUbuntuをアップグレードしたときの手順を記録しておく。

注意)アップグレード後、phpが動かなくなってしまった。5の設定変更を実施したら再び動くようになった。

1.ファイアウォールの確認と設定

do-release-upgradeをリモートで実行し、アップグレード作業を行う場合は、1022 portの使用が推奨されている。ファイアウォールを実行している場合、事前にportの開放を行う。

sudo ufw allow 1022/tcp comment 'Temp open port ssh tcp port 1022 for upgrade'

2.セキュリティグループの設定

セキュリティグループのインバウンドルールに1022 portの許可を追加する。アップグレード作業にしか使わないportであるため、アクセス範囲は可能な限り狭く設定する。

3.アップグレードコマンドの実行

sudo do-release-upgrade

スクリプトの実行後、サーバーを再起動する。

4.Tera Termでログイン出来るようにする

Ubuntu 22ではssh-rsaが無効になっているため、Tera Termを使ってログインすることが出来ない。そこで下記のコマンドを実行して、ssh-rsaを有効にする。(Tera Termが使えないだけで、他の手段であればログイン出来る。Powershellや他のLinuxサーバーのsshコマンドでログインする。)

sudo su -
cp -p /etc/ssh/sshd_config /etc/ssh/sshd_config_org
sed -i '1s/^/PubkeyAcceptedAlgorithms=+ssh-rsa\n/' /etc/ssh/sshd_config
grep PubkeyAcceptedAlgorithms /etc/ssh/sshd_config
systemctl restart ssh.service

5.php8.1を有効にする

Ubuntu 22ではphp7.4が削除され、php 8.1が標準になっている。以下のコマンドでphp7.4の設定を削除して、php8.1を有効にする。

sudo a2dismod php7.4
sudo a2enmod php8.1
sudo service apache2 restart

6.セキュリティグループの設定

セキュリティグループのインバウンドルールの1022 portの許可を削除する。

NovelAIを使ってみる

最近話題のNovelAIを使ってみる。

ユーザー登録する

https://novelai.net/

上記ページにアクセスして、ユーザー登録を行う。画像の生成には後述のサブスク登録が必要になるため、ユーザー登録が必要になる。

サブスク登録する

サブスク登録していないと、画像の生成機能を使用することが出来ない。10ドルのプランで1000 Anlas分使用できる。Nomalサイズの画像生成で5 Anlas必要になるため、このプランでは毎月200枚ほど生成出来る計算になる。足りないなら後でプランをアップグレードしたり、Anlasだけ買い足したりすることが出来るので、お試しであれば10ドルのプランで良いと思う。

画像を生成する

Image Generationをクリックする。

Enter your prompt here. に文字を入力する。(英語)

自分が試しに入力した文字は下記の通り。
masterpiece, highest quality, high quality, cyberpunk,
上記とは別にUndesired Contentに以下の文字列を入力した。
lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, artist name

生成された画像は下記の通り。

簡単にきれいな画像を生成することは出来るが、一発でほしいものが出るとは限らない。設定を変えながら何度も生成することになるので、トークンの減りが激しい。