OmniAICreator/Qiita-1.07M huggingface dataset:
Python_Tool_フォルダ内Text文字列の一括抽出

# textファイルの(A)〜(B)までの文字列を抜き出す

# はじめに
この記事は
あるフォルダ(Fフォルダ)の中に入っているtextファイルの文字列(A)〜(B)までを書き出すTooLを作成するものです。


### 使用例
・NW機器のコマンド出力一覧からあるコマンド結果のみを書き出す
・テキストの一覧から必要部分だけを書き出す。

# 挙動
~~~~ 
例）
Fフォルダ
	└TEST1.log
	└TEST2.log
	└TEST3.log
	└TEST4.log

このToolで全ての.logファイルの
文字列(A)〜(B)までを抜き出して、afterフォルダ内にコピーを作る


Fフォルダ
	└TEST1.log
	└TEST2.log
	└TEST3.log
	└TEST4.log
    	└after
        	└TEST1.log
        	└TEST2.log
        	└TEST3.log
            └TEST4.log
            ※文字列(A)〜(B)までを抽出したファイルが出来る。

~~~~ 



# 準備物
・Python実行環境
 
・エディタ


 # 1.必要データを確認する
 ■必要データ
　FフォルダPath	　　=	例）[ForderPath]
　ファイル拡張子	　　=	".log"
　開始位置　文字列(A)		=　[#show run]	
　終了位置　文字列(B)	=	[end]


 # 2.以下コードにデータを入力する
 
 ```python 
import os

# フォルダの指定
input_folder = r"(FフォルダPath)"
after_folder = os.path.join(input_folder, "after")

# "after"フォルダを作成
os.makedirs(after_folder, exist_ok=True)

# .txtファイルを処理
for file_name in os.listdir(input_folder):
    if file_name.endswith(".log"):
        input_file_path = os.path.join(input_folder, file_name)
        output_file_path = os.path.join(after_folder, file_name)
        print(input_file_path)
        
        with open(input_file_path, "r", encoding="utf-8") as f:
            lines = f.readlines()
            
        
        # "#show run" から "end" までを抽出
        extracting = False
        show_run_cp = []
        for line in lines:
            if "#show run" in line:
                extracting = True
            if extracting:
                show_run_cp.append(line)
            if line.strip() == "end":
                break
        
        # 抽出した内容を新しい.txtに書き込み
        with open(output_file_path, "w", encoding="utf-8") as f:
            f.writelines(show_run_cp)

print("処理が完了しました。")

``` 

データを入力したら、Pythonファイルとして保存する、今回は「00_remake.py」とする。

### ※文字列(A)〜(B)について
詳しくは、lines というリスト内の行を順に処理し、文字列(A)を**含む**行が見つかったら、その行以降を show_run_cp に追加し、文字列(B) **のみ**の行が出てきたら処理を終了する

　
 
 # 3.処理の実行
 ![スクリーンショット 2025-02-15 19.40.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3946669/7e823567-3d93-4561-bdd0-ca72b6ccaa9e.png)

00_remake.pyをエディタで開き実行する。

 
![スクリーンショット 2025-02-15 19.42.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3946669/14d22f51-0f37-4873-9657-227cb164f7e5.png)

afterフォルダが自動作成され、その中に文字列(A)〜(B)のコピーを抽出したTextファイルが作成される。
 
![スクリーンショット 2025-02-15 19.43.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3946669/744f3f75-3333-4506-8fe1-521318f579ef.png)

これで完了です！お疲れ様でした。
Javaの基本のき

こんにちは！**みゅみゅ**と申します！
専門学校１年生（そろそろ２年生）です。
授業だけではなかなか定着しないので、復習も兼ねてアウトプットしていけたらなあと思います。

## このページで扱うこと
1. Javaとは・Javaの特徴
1. 簡単なコードの作成

## Javaって？
Javaは以下のような特徴を持つ言語です。
1. **実行するOSを選ばない**：ソースコードは中間言語というものに変換され、各端末のJVM(Java Virtual Machine)上で実行されます。動作の安定性も支持される要因の一つだそうです。
　
1. **オブジェクト指向言語**：クラスを基に生成できるオブジェクトというものの組み合わせでプログラムを作っていきます。継承やポリモーフィズムという仕組みによって、効率的に開発ができます。
ただ、簡単なコードを書くだけなら、むしろコードが長くなる場面もあるようです。
　
1. **メモリ管理が自動**：一部の言語ではメモリ領域の管理も自分でやる必要がありますが、Javaでは**ガベージコレクション**という仕組みによって、自動でメモリをやりくりしてくれます。考えることを減らせるのは、開発ではありがたい要素の一つですね。

Javaはとても多くの開発に利用されている言語で、最近就活のための企業調べをしていても、研修ではJavaを利用している企業さんを多く見ます。

## 簡単なコードを書いてみる
まずは定番のHelloWorld!から見てみましょう！
```java:Hello.java
public class Hello{
    public static void main(String[] args){
        System.out.println("Hello World!");
    }
}
```
実行結果
```
Hello World!
```

System.out.println()のカッコの中に出力したい文字列を入れます。
基本的に、mainと書いてある行から始まるカッコ｛｝の中に処理を書いていきます。

:::note
このmain(){～～～}の部分を「main関数」と呼びます。
この中にやりたいことを書く！
:::

### 変数を使ってみる
よくある例えですが、変数は値を入れる箱のようなものです。この例では整数を入れられるnt_valという名前の箱を作り、そこに１を入れたり、３を入れたりしています。

```Variable.java
public class Variable{
    public static void main(String[] args){
    
        int int_val;
        int_val = 1;

        double double_val = 3.1415926535;
        char char_val = 'a';
        boolean boolean_val = false;
        String string_val = "hello";

        final int const_int_val = 5; //定数

        int_val = 3;
        //const_int_val = 0; //これはエラーが出ます。
    }
}
```
変数は　**[データ型] [変数名]**　の形で作ることができます。double_valのように、作成と同時に値を設定することもできます。最初に**final**を付けると、その後値を変えることができない**定数**という変数を作成できます。

整数、小数のデータ型は上記以外にも表せる数値の範囲の違いでいくつかありますが、よく使われるのはintとdoubleです。
他にも、１文字を扱うchar型、Trueとfalseという２種類の値のみを扱うboolean型などがあります。
文字列を扱うためのString型のみ、先頭が大文字です。(実はintなどと異なり、Stirngはクラスという少し違う存在として扱われています。)

:::note
変数は　**[データ型] [変数名]**　の形で作る！
:::

### 標準入出力
```stdin_stdout.java
import java.util.Scanner;

public class Stdin_stdout{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int input_value = sc.nextInt();
        sc.close();

        System.out.println(input_value);
    }
}
```
　実行するとコンソールがユーザの入力を待ちます。このコードでは整数を入力してエンターを押すと、input_valueにその整数が格納され、出力されます。
 
:::note alert
整数以外を入れるとInputMismatchExceptionというエラーが出ます。
:::
 
　先頭のimportによって、main内のScanner sc = new Scanner(System.in)にも出てくるScannerクラスを利用できるようにしています。（クラスの概念は理解するまで時間がかかるかもしれません…~~私もあまり理解できていません~~慣れるまでは深く考えなくてもいいかもしれません。）
出力はおなじみSystem.out.println()です。（出力後に改行をしないprint()というものもあります。）

:::note
Scannerクラスを使うと、ユーザの入力をプログラム内で利用できる！
:::


## まとめ
* やりたいことはmainの中に書く！
* 変数は　**[データ型] [変数名]**　の形で作る！
* Scannerクラスを使うと、ユーザの入力をプログラム内で利用できる！


## おわりに
初めての投稿になりましたが、ここまで見ていただきありがとうございました。初心者なりに見やすいデザインと丁寧な解説を試みたつもりではありますが、見づらい部分や誤りがありましたら、指摘して頂けると幸いです。
ぜひたくさんコメント下さるとうれしいです。これからよろしくお願いします。
初心者によるメモ（アルゴ式「パスワードの強度判定（5）」）

## 問題
ロジック実装中級

https://algo-method.com/tasks/8a52ff9275e57dc0

## 考察
与えられた三つの条件に合致するか判定する関数をつくる。このとき、わけてつくったほうがうまくいく。

## ACコード
```py
def check(s):
    for i in range(len(s)-1):
        if int(s[i]) != int(s[i+1]):
            return False
    return True

def check2(s):
    for i in range(len(s)-1):
        if int(s[i+1]) - int(s[i]) != 1:
            return False
    return True

def check3(s):
    for i in range(len(s)-1):
        if int(s[i]) - int(s[i+1]) != 1:
            return False
    return True

def is_check(s):
    if check(s) or check2(s) or check3(s):
        return True
    else:
        return False
        
s=input()

if is_check(s):
    print("dangerous")
else:
    print("safe")
```
【物語で学ぶ Swift Concurrency】CoreLocation の安全な位置情報取得

## 登場人物

- **先生**：プログラミング部顧問の先生  
- **はるか**：高校2年生。最近 Swift の勉強を始めた  
- **あきと**：高校3年生。プログラミング部の先輩  

---

## 1. はじまり

**はるか**「先生、iPhone で位置情報を取得する方法を教えてもらったんですけど、CoreLocation ってメインスレッドとは限らないところで呼ばれることがあるんですか？」

**先生**「いい質問だね。CoreLocation のデリゲートメソッドは、必ずしもメインスレッドで呼ばれないことがあるんだ。並行処理の観点で注意が必要なんだよ。」

**あきと**「あ、Swift Concurrency で actor を使えばスレッドの混乱を防げる…っていう話ですね！」

**先生**「そうそう。特に @MainActor を使う場合、CoreLocation からのコールバックがメインスレッドじゃないときに直接 UI 関連のプロパティを触ると問題が起きるんだ。」

---

## 2. CoffeeLocationDelegate のクラスを見てみよう

**先生**「じゃあ実際のコード例を見よう。CoffeeLocationDelegate というクラスを作って、CoreLocation からの位置情報を受け取るときにどうするかを紹介するよ。」

以下のようなコードを書くイメージだ。

```swift
    @MainActor
    class CoffeeLocationDelegate: NSObject, CLLocationManagerDelegate {
        var location: CLLocation?
        var manager: CLLocationManager?

        override init() {
            super.init()
            manager = CLLocationManager()
            manager?.delegate = self
            manager?.startUpdatingLocation()
        }

        nonisolated func locationManager(
            _ manager: CLLocationManager,
            didUpdateLocations locations: [CLLocation]
        ) {
            Task {
                await MainActor.run {
                    self.location = locations.last
                }
            }
        }
    }
```
---

## 3. 先生と一緒にコードを解読

### @MainActor

**はるか**「このクラス全体に @MainActor ってついてますね。これはなんですか？」

**先生**「@MainActor は、『このクラスはメインアクター上で動きます』という宣言だよ。UI の更新を行う場合はメインアクターに乗せておくと安全なんだ。」

### nonisolated

**あきと**「でも、その中の locationManager(_:didUpdateLocations:) というデリゲートメソッドには nonisolated って書いてあります。これは？」

**先生**「nonisolated は、『このメソッドはアクターに属さない』と宣言しているんだ。CoreLocation は位置情報を別のスレッドで処理して、いつどのスレッドからコールバックを呼ぶか分からないからね。もし @MainActor を付けたままだと、『必ずメインアクター上で呼ばれる』とコンパイラが思い込んでしまい、実際に別スレッドから呼ばれたときに並行性のエラーや警告が出ちゃうんだ。そこで、nonisolated を付けて『ここはアクター分離されていません』と伝えて、別スレッドから呼ばれても大丈夫にしてるんだよ。」
### MainActor.run

**はるか**「でも、そのメソッドの中で Task { await MainActor.run { ... } } ってやってますよね？」

**先生**「そこがポイント！ nonisolated でアクター外から呼ばれるのはいいんだけど、このクラスのプロパティ location を更新するときにはメインアクターに戻らないといけない。だから Task と await MainActor.run を使って、実際にメインアクターへ切り替えているんだよ。」

---

## 4. どうしてこんな面倒なことをするの？

**あきと**「正直、MainActor.assumeIsolated っていうのを使って“今は絶対にメインアクター上だ！”って宣言しちゃう手もあるんですよね？」

**先生**「うん。MainActor.assumeIsolated は確かにコンパイラを黙らせる手段にはなる。でも、もし本当にメインスレッド以外で呼ばれたら、並行性バグを起こす危険があるんだ。MainActor.run はスレッドをちゃんとメインアクターに移してくれるから安全なんだよ。」

**はるか**「なるほど…。無理やり『大丈夫！』っていうより、ちゃんと安全なやり方でメインアクターに戻すほうが安心ですね。」

---

## 5. まとめ

**先生**「最後にポイントをおさらいしよう。全部で5つあるから整理してね！」

1. CoreLocation のデリゲートはメインスレッドで呼ばれる保証がない。  
2. MainActor クラスでデリゲートを扱う場合、nonisolated を使ってアクター外から呼ばれても大丈夫にする。  
3. メインアクター上のプロパティを更新するときは Task { await MainActor.run { ... } } で安全に切り替える。  
4. MainActor.assumeIsolated は自己責任での宣言。CoreLocation のように実際にスレッドが不定な場合は危険。  


---

**先生**「以上が、CoffeeLocationDelegate を例にした CoreLocation × Swift Concurrency の解説だよ。ぜひ参考にして、安全に位置情報を扱ってみてね。」

**はるか**「ありがとうございます！実際にコードを書いて動かしてみます！」

**あきと**「自分も改めて確認できました。ありがとうございます！」

**先生**「じゃあみんな、Happy Coding!」
1480. Running Sum of 1d Array - Day 1


## 問題
![Screenshot 2025-02-15 at 14.52.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3672923/334f7b48-989c-4b5c-978a-4e8808884dbe.png)

## 解答コード

```rust:main.rs
impl Solution {
    pub fn running_sum(nums: Vec<i32>) -> Vec<i32> {
        let mut vec: Vec<i32> = vec![nums[0]];

        for i in 1..nums.len() {
            vec.push(vec[i-1] + nums[i])
        }

        vec
    }
}
```

## 解説
Rustでベクタを使用して、解答を導きました。
1. `mut`演算子をつけて変数`vet`可変にし、且つ`nums`の最初の要素で初期化しています
1. forループは`nums`の要素の１つ目から`nums.len()`までのインデックスまでを繰り返し、現在の`nums`の累積和を計算し、`vec`に追加します

初めは初期化をした後、存在し得ない`vec`の0個目の要素にアクセスしていたので怒られていましたね〜。
```rust:main.rs
// Bad! Because complipe Error!
// Line 4: Char 12: index out of bounds:
// the len is 0 but the index is 0 
impl Solution {
    pub fn running_sum(nums: Vec<i32>) -> Vec<i32> {
        let mut vec: Vec<i32> = Vec::new();
        vec[0] = nums[1];

        for i in 1..nums.len() {
            vec[i] = vec[i] + nums[i - 1];
        }
        vec
    }
}
```
【Flutter】StatefulWidgetのライフサイクルを完全理解する

# 全体の流れ
StatefulWidgetは4つの状態を遷移させながら画面描画・リソースの解放を行なっています。

StatefulWidgetのソースを見てみると以下のように定義されています。
enum型の`_StateLifecycle`という名前で管理されていますね。
```flamework.dart
/// Tracks the lifecycle of [State] objects when asserts are enabled.
enum _StateLifecycle {
  /// The [State] object has been created. [State.initState] is called at this
  /// time.
  created,

  /// The [State.initState] method has been called but the [State] object is
  /// not yet ready to build. [State.didChangeDependencies] is called at this time.
  initialized,

  /// The [State] object is ready to build and [State.dispose] has not yet been
  /// called.
  ready,

  /// The [State.dispose] method has been called and the [State] object is
  /// no longer able to build.
  defunct,
}
```

各状態ごとに実行されている処理はおおまかに以下の通り。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3889500/4f1017d7-5149-4bf4-a2e3-2c8adf1f877b.png)


# created
statefulWidgetの`createState()`が呼び出されると状態がcreatedに遷移します。

cteate状態では状態の初期化を行う`initState()`が実行されます。
注意したいのは、このときはまだBuildContextが生成されていないということ。

BuildContextを使った初期化処理は`initState()`内では実行できません！
（筆者はこのルールを知らずにエラーを直すのにめちゃくちゃ時間がかかりました…😩）

# initialized
`initState()`が完了すると、状態がinitializedに遷移します。

initialized状態ではStateオブジェクトの依存関係に変化があった場合に呼び出される`didChangeDependencies()`が実行されます。

`didChangeDependencies()`の実行前にBuildContextの生成が行われるため、BuildContextを使った初期化処理はここで記述することになります。

`initState()`がwidget初期化時に一度だけ呼び出されるのに対して、`didChangeDependencies()`は依存関係が変わる（親widgetの変化とか）ごとに呼び出されます。

# ready
`didChangeDependencies()`の完了後、readyに遷移します。

初回構築時はwidgetを生成する`build()`がそのまま実行されますが、親widgetの再構築後は`didUpdateWidget()` 、Stateの変更時は`setState()`を経由して`build()`が実行されます。

Stateオブジェクトがウィジェットツリーから削除されるたびに`deactivate()`が実行されます。この時点ではまだ再ビルドされる可能性があります。

# defunct
widgetが完全に破棄された状態。

widgetがツリーから完全に削除され、二度とビルドされなくなったら`dispose()`が実行され、リソースが解放されます。

`dispose()`が実行された後、再ビルドする必要がなくなったWidgetはdefunct遷移します。


### これであなたも今日からライフサイクルマスター💪

# 参考
https://qiita.com/Kurunp/items/116288b8ab2c409d2ee5

https://zenn.dev/mukkun69n/articles/552173cb084e18

# 最後に…
最後に少しだけ宣伝させてください。

株式会社Visionでは広報活動の一環として有志を募ってアプリを開発し、ついに先日リリースしました!（もちろんFlutterを使ってます！）

アプリ名は「過去イチ」
カテゴリごとに自分だけのランキングを作成して記録できます

第一弾ですので使える機能はかなり限られていますが、ご興味のある方はぜひ🙏

👇Android版

https://play.google.com/store/apps/details?id=jp.co.vision_sys.kakoichi

👇iOS版

https://apps.apple.com/jp/app/%E9%81%8E%E5%8E%BB%E3%82%A4%E3%83%81/id6740838107
【Linux】grepのちょっとした応用(?)

# ▼使用場面
≪文字列1≫と≪文字列2≫の両方を含んだ行を取り出したいときに有効

# ▼構文
grep ≪文字列1≫ ≪ファイル名≫ | grep ≪文字列2≫

# ▼例
```
[root@localhost work]# cat test
大阪梅田
大阪淀屋橋
大阪心斎橋
大阪堂島
大阪難波
大阪高槻
[root@localhost work]# grep "大阪" test | grep "梅田"
大阪梅田
[root@localhost work]# grep "大阪" test | grep "堂島"
大阪堂島
[root@localhost work]#
```
まぁ応用でもなんでもないか。。。。
Homebrewのパッケージリストをgit管理する

# はじめに

MacではHomebrewを使ったパッケージ管理が主流ですが、

「Homebrewのパッケージリストがカオスになってきた…」
「こんなパッケージいつインストールしたっけ…」
「整理したいけどどれを消していいかわからない…」

といった問題を抱えている方も多いはず。


そんな課題を解決するために、HomebrewとGitを組み合わせたパッケージ管理方法を紹介します！！



# 解決策

brewfileをgit管理することで、パッケージのインストール日時や実行コマンドをcommitとして残すことができます。
具体的には以下のように `brew install` や `brew update` 等を叩いたときに自動で差分がcommitされるようにすることが可能です。

```bash
> brew install postgresql@17
Running brew install postgresql@17 with brewfile commit...

...

[main d84d872] brew install postgresql@17
 1 file changed, 1 insertion(+)
Changes committed with message: brew install postgresql@17
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/275851/187bd9c4-b7ba-456a-b4ce-85ccac16be50.png)

# 設定手順

## 1. ディレクトリ作成とGitリポジトリの初期化
まず、Brewfileを管理するためのディレクトリを作成し、Gitリポジトリを初期化します。

```bash
mkdir brewfile
cd brewfile
git init
```

## 2. 初期Brewfileの作成
現在のHomebrew環境をBrewfileに記録します。

```bash
brew bundle dump --file=./Brewfile --force
```

これで、Brewfileにインストールされているパッケージ情報が記録されます。

## 3. 自動コミットスクリプトの作成
以下の内容でスクリプト`brew_with_commit.sh`を作成します。

```bash
#!/bin/bash

GIT_DIR=~/dev/brewfile
BREWFILE=$GIT_DIR/Brewfile

# 差分が発生するbrewコマンドのリスト
DIFF_COMMANDS=("install" "uninstall" "upgrade" "update" "tap" "untap")

# コマンドが差分を生じる場合のみBrewfile更新
if [[ " ${DIFF_COMMANDS[@]} " =~ " $1 " ]]; then
  cd "$GIT_DIR"
  brew bundle dump --file="$BREWFILE" --force

  # 差分がある場合のみgitコミット
  if ! git diff --quiet "$BREWFILE"; then
    git add "$BREWFILE"
    git commit -m "brew $*"
    echo "Changes committed with message: brew $*"
  else
    echo "No changes to commit."
  fi

  cd - > /dev/null
else
  echo "No Brewfile update required for command: brew $*"
fi
```

## 4. スクリプトに実行権限を付与
```bash
chmod +x ~/dev/brewfile/brew_with_commit.sh
```

## 5. zshrcまたはbashrcにエイリアスを設定
`~/.zshrc` または `~/.bashrc` に以下を追記します。

※`brewfile`ディレクトリ配置先によって適宜書き換えてください

```bash
alias brew='~/brewfile/brew_with_commit.sh'
```

その後、設定を反映します。

```bash
source ~/.zshrc
```

# 使い方
通常のbrewコマンドを使うだけで、自動的にBrewfileが更新され、Gitにコミットされます。


```bash
> brew install wget
# => brew install wget 実行後 Brewfile更新 & コミット

> brew update
# => パッケージ更新後、自動でBrewfileをコミット

> brew search git
# => Brewfile更新なし、コミットもなし
```

# おわりに
brewパッケージ一覧に変更差分が残るため、後から経緯を追いやすくなるはず。

拡張として

- リモートリポジトリと紐づけて`push`まで自動実行する
- brewコマンド実行時に `-m` オプションでコメントを残せる
- パッケージのバージョン履歴を残す

あたりを追加してみても面白いかも。
Eelを使ってチャットアプリを作った話

# はじめに
こんにちは！    
Saku0512です。    

今回は[Eel](https://github.com/python-eel/Eel)を使ってチャットアプリを作った話をします。    

# そもそもEelってなんだ？
PythonのEelは、Pythonでデスクトップアプリを簡単に作成できるライブラリです。    
バックエンドをPythonで処理し、フロントエンドをHTML/CSS/JavaScriptで構築できます。

### 特徴
- バックエンドをPythonで処理し、フロントエンドをHTML/CSS/JavaScriptで構築できる
- Pythonの関数をJavaScriptから呼び出すことや、JavaScriptの関数をPythonから呼び出すことができる
- Webサーバーを立てて、ローカルで動作する

### インストール
```bash
pip install eel
```

### サンプルコード
```python
import eel

# フロントエンドのHTMLフォルダを指定
eel.init('web')

@eel.expose  # Python関数をJavaScriptから呼び出せるようにする
def say_hello(name):
    return f"Hello, {name}!"

# アプリを起動
eel.start('index.html', size=(400, 300))
```

```html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Eelアプリ</title>
</head>
<body>
    <h1>EelでPythonとJSを連携</h1>
    <button onclick="callPython()">Pythonを呼ぶ</button>
    <p id="output"></p>

    <script type="text/javascript">
        function callPython() {
            eel.say_hello("Eelユーザー")(function(response) {
                document.getElementById("output").innerText = response;
            });
        }
    </script>
</body>
</html>
```
### ディレクトリ構造
```
.
├ main.py
└ web/
 　└ index.html
```


### 実行方法
```bash
python main.py
```

### 仕組み
1. `eel.init('web')`で`/web`フォルダ内のファイルを読み込む
2. `eel.start('index.html', size=(400, 300))`でアプリを起動
3. `@eel.expose`でPython関数をJavaScriptから呼び出せるようにする
4. `eel.say_hello("Eelユーザー")`でPython関数を呼び出し、結果をJavaScriptに返す

詳細は[公式ドキュメント](https://github.com/python-eel/Eel)を参照してください。

# 作ったアプリの解説
![Sample_MAIKE.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3936581/b6e49715-666b-424b-a289-31cfcf0045c8.png)
### 概要
  
[`Open AI API`](https://openai.com/ja-JP/api/)を用いてチャット機能を実装し、[`botui`](https://botui.org/)を用いてチャット画面を作成しました。    
ソースコードは[GitHub](https://github.com/Saku0512/school_MAIKEChat)に公開しています。    

### 実装した機能
- ユーザー登録・ログイン
  1. `MySQL`を用いてユーザー登録・ログインを実装。  
  2. `redis`を用いてセッション管理を実装。  
- チャット
  1. `Eel`を用いてjsからpythonに処理を移す。  
  2. `Open AI API`を用いてチャット機能を実装。 
  3. APIから返ってきた文字列を整形してhtmlコードにする。 
  4. `botui`を用いてチャット画面を作成。  
- 音声入力
  - `Web Speech API`を用いて音声入力を実装。  
- ソースコード実行
  - `paiza.io`を用いてソースコード実行。  
  - `C`, `C#`, `C++`, `Python`, `JavaScript`, `Java`, `Ruby`, `PHP`に対応。
Python入門

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3300497/311b7dc4-6961-452e-b9b8-0d31002a2efd.png" width="300">


# Python入門書で学んだ内容の備忘録です。

# 目次

### 1. 変数とデータ型
- 式と演算
- 変数
- データ型

### 2. コレクション
- リスト
- ディクショナリ
- タプル
- セット
- 相互変換
- ネスト

### 3. 条件分岐
- プログラムの流れ
- if文
- 条件式
- 分岐構文のバリデーション

### 4. 繰り返し
- while文
- for文
- 繰り返しの制御

### 5. 関数
- オリジナル関数
- 引数と戻り値
- 応用テクニック
- 独立性

### 6. オブジェクト
- 値の正体
- オブジェクトの設計図
- 落とし穴


### 7. モジュール
- 組み込み関数
- モジュールの利用
- パッケージの利用
- 外部ライブラリの利用
rust ジェネリクス関数について

https://zenn.dev/toga/books/rust-atcoder-old/viewer/31-generic-function

このサイトより、
```rs
fn second_f64_i32(tuple: (f64, i32)) -> i32 {
    tuple.1
}
fn second_f32_i32(tuple: (f32, i32)) -> i32 {
    tuple.1
}
fn second_bool_i32(tuple: (bool, i32)) -> i32 {
    tuple.1
}
```
これをジェネリクスにより
```rs
fn second_any_i32<T>(tuple: (T, i32)) -> i32 {
    tuple.1
}
```
こう表すことができた。

## 戻り値に関するジェネリクスを考える

引数がT型で受け取れることは分かったが、戻り値はどうなのか

```rs
fn getStringInput(message: &str) -> String {
    let mut input = String::new();
    print!("{}", message);
    io::stdout().flush().unwrap();
    input.clear();
    io::stdin().read_line(&mut input).expect("failed to read line");
    return input.trim().to_string();
}

fn getIntInput(message: &str) -> i32 {
    let mut input = String::new();
    print!("{}", message);
    io::stdout().flush().unwrap();
    input.clear();
    io::stdin().read_line(&mut input).expect("failed to read line");
    return input.trim().parse().expect("invalid number");
}
```

これ、戻り値がの型が違うだけだから、まとめたいね
```rs
use std::str::FromStr;

fn get_input<T: FromStr>(message: &str) -> T 
where 
    T::Err: std::fmt::Debug, // `parse()` のエラーメッセージを扱うための制約
{
    let mut input = String::new();
    print!("{}", message);
    io::stdout().flush().unwrap();
    
    io::stdin().read_line(&mut input).expect("Failed to read line");
    
    input.trim().parse().expect("Invalid input")
}
```

こうしたらできました

ここでwhereで記載されている` T::Err: std::fmt::Debug`をトレイト境界といいます。
これは、
```rs
fn print<T>(x: T) {
    println!("{}", x);
}
```
このようなプログラムで、i32とか&strは受け取れるけど、タプル型を受け取れないですね
コンパイルエラーになります。
要するに、i32とか&strとタプル型の間に存在するT型として扱える形式の限界をトレイト境界といいます
したがってこのようなプログラムでトレイト境界を指定する必要があり、以下のように記述されます

```rs
fn print<T: std::fmt::Display>(x: T) {
    println!("{}", x);
}
```

「 T が std::fmt::Display の条件を満たす」という意味で、この記法以外にもimplや上で使ったようなwhereでの記法があります　それは記事の初めのリンクで詳しく書かれています
【実験】Windows OpenSSHのパーミッション設定を色々試す

Windows上にOpenSSHサーバを建て，使っています．セキュリティのため，認証方式として公開鍵認証を使用しているのですが，様々な原因で認証エラー"Permission Denied (publickey)"が出て面倒くさかったです．

原因は主にWindowsのパーミッションです．パーミッションの設定が少しでも間違っていると認証エラーが発生します．ここでは適切なパーミッション設定方法についてまとめます．

## アカウント構成
はじめに，アカウントの構成を示します．サーバを建てているWindows PCは他の人と共用なので，以下のようなアカウントが入っています．
アカウント名 | 説明 | Administrator**s**グループ
---|---|---
Administrator|休止している(`ACTIVE=NO`)|◯
Public|皆が使う用．このアカウントでOpenSSHサーバを起動(`Start-Service sshd`)する．|◯
Private|各個人が使う用．アカウント名は各々の名前になっている．これらのアカウントへSSHでアクセスしたい．|×

:::note warn
適切なパーミッション設定はアカウント構成によって変わってきます．
:::

## 結論：適切なパーミッション設定
各個人が使う用のアカウントのホームディレクトリにて，以下のディレクトリとファイルを作ることになります．
```plaintext
.ssh
.ssh/authorized_keys
```
これら2件に対し，適切にパーミッション設定を行うことが必要です．

1. [プロパティ]→[セキュリティ]→[詳細設定]より **[継承の無効化]** を選択します．
1. アクセス許可を与えるプリンシパルを以下のいずれかに限定します．いずれもアクセスはフルコントロールです：

> ✅
> * [ユーザ] 自分のアカウント
> * [ユーザ] SYSTEM

自分のアカウントに加えSYSTEMを追加したらうまくいきました．

> ✅
> * [ユーザ] 自分のアカウント
> * **[グループ]** Administrator**s**

グループであるAdministrator**s**（←複数形だよ！）を与えてもうまくいきました．

### 動かなかった例
> ❌
> * [ユーザ] 自分のアカウント

OpenSSHサーバを起動している主体が読み込んでこれないので，動かないのだと思います．
例えば，次の記事などでは現行のアカウントを追加するだけで良いとされていますが，それはあくまでも**OpenSSHサーバを起動するアカウントとSSHでアクセスするアカウントが同じ時に限ります**．適切なパーミッション設定はユーザ構成によって変わってくることに注意が必要です．

https://qiita.com/eltociear/items/02e8b1f5590b49eb9d87

> ❌
> * [ユーザ] 自分のアカウント
> * **[ユーザ]** Administrator

私の場合，Administratorは休止中であり，これにアクセスを与えても動きませんでした．

> ❌
> * [ユーザ] 自分のアカウント
> * [ユーザ] Public

PublicでOpenSSHを起動するのだから，Publicを追加すればいいのでは？と思ったのですが，動きませんでした．SYSTEMと自分自身以外のユーザを追加してはいけないのかも（？）．

## 他にパーミッション設定を注意せねばならない場所
各個人の`.ssh/`だけではなく，OpenSSHに必要な各種フォルダのパーミッションも適切に設定する必要があります．

例えば，`C:¥ProgramData¥ssh¥logs`のパーミッションに個人アカウントを追加してしまうと，OpenSSHが起動しませんでした（例外を吐いて終了した）．

## 参考：`sshd_config`
```plaintext:C:¥ProgramData¥ssh¥sshd_config
Protocol 2
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
AllowUsers Private

Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
```
【物語で学ぶ Swift Concurrency】舞台の俳優と封筒に入った手紙で学ぶ Sendable、actor、await、そして public struct

この記事では、Swift の並行処理の仕組みを、舞台の俳優とその演技に使う小道具のイメージを用いて解説します。ここでは、以下のようなアナロジーを使います：

- **actor:** 舞台上で独立した役割を果たす俳優  
- **await:** 俳優が自分のセリフ（処理）を終えるのを待ってから、次のシーンに進むタイミング  
- **Sendable:** 俳優同士が台本に沿って安全に情報を交換できる仕組み  
- **public struct:** 舞台上で俳優が使用する小道具、たとえば「封筒に入った手紙」。この手紙は一度作られると内容が変わらず、どのシーンでも同じ安全な情報を伝えます。

---

## Swift の並行処理と舞台のイメージ

Swift は複数のタスクやスレッドが同時に動く並行処理をサポートしています。しかし、複数の作業が同時に同じデータにアクセスすると、予期しないエラー（データ競合やレースコンディション）が発生するリスクがあります。これを防ぐため、Swift ではいくつかの仕組みが用意されています。

### actor: 舞台の俳優

- **独立した役割:**  
  actor は、舞台上で各俳優が自分の役割（内部状態や処理）をしっかり果たすように、他と干渉せずに独立して動きます。  
- **台本（メッセージパッシング）:**  
  俳優同士は台本に沿ってセリフをやり取りしながら演技します。同じように、actor は必要な情報をメッセージパッシングを通じて交換し、並行環境で安全に処理を行います。

### await: セリフ終了を待つタイミング

- **待機の役割:**  
  await は、俳優が自分のセリフ（非同期処理）を終えるのを待ってから次のシーンに進むように、処理の完了を待つためのキーワードです。  
- **正しい進行:**  
  これにより、actor の処理結果が確実に返ってくるまで次の命令に進まないので、全体の動作がスムーズかつ安全になります。

### Sendable: 安全な情報交換の台本

- **安全性の保証:**  
  Sendable プロトコルは、ある型の値が並行環境間で安全に共有・転送できることを保証します。  
- **俳優の台本:**  
  俳優同士が台本に従って必要な情報を正しくやり取りするように、Sendable に準拠している型は、どのシーンでも安全に情報が渡されることが保証されます。

---

## public struct を封筒に入った手紙に例える

public な構造体（struct）は、モジュール外でも利用されるため、特に安全性が求められます。  
ここで、public struct を **「封筒に入った手紙」** に例えてみましょう。

- **封筒に入った手紙:**  
  一度印刷された手紙は内容が変わりません。同じ封筒に入った手紙は、どのシーン（タスクやスレッド）に持って行っても、同じ情報を伝えます。  
- **不変性:**  
  public struct が持つ値がイミュータブル（変更不可能）であれば、まさにこの封筒に入った手紙のように、安全に他の環境へ転送することができます。  
- **Sendable の保証:**  
  public な型は外部に公開されるため、Swift コンパイラは自動で Sendable と判断しません。開発者が明示的に `Sendable` に準拠させることで、まるでどのシーンに出ても安心して使える「信頼できる封筒に入った手紙」であることを保証するのです。

#### 例: public struct の宣言

```swift
public struct MyPoint: Sendable {
    public let x: Int
    public let y: Int

    public init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
}
```

このように、public struct を Sendable に準拠させることで、どのシーン（並行環境）においても安全にその情報（手紙）が渡されることを保証します。

## 内部型と public 型の違い

- **内部型の場合:**  
  internal や private な型は、モジュール内だけで使用されるため、すべてのプロパティがイミュータブルであれば、Swift は自動的に Sendable と推論することがあります。これは、舞台裏で俳優同士が安全に連携している状況に似ています。


- **public 型の場合:**  
  public 型は、外部のモジュールや環境でも使われるため、より厳密な安全性が求められます。コンパイラは自動で Sendable と判断せず、明示的な準拠宣言が必要です。これは、スポットライトを浴びる舞台俳優が、どのシーンでも安全に演技できるように、事前に安全性を保証する必要があるのと同じです。



## まとめ

- **actor と await:**  
  - **actor:** 舞台の俳優のように、各 actor は独立した役割を持ち、自分の内部状態を安全に管理し、台本（メッセージパッシング）を通じて必要な情報をやり取りします。
  - **await:** 俳優が自分のセリフを終えるのを待ってから次のシーンに進むように、await は非同期処理の完了を待つためのキーワードです。

- **Sendable と型の安全性:**  
  - **内部型:** 
  モジュール内であれば、自動的に Sendable と推論される場合があります。
  
  - **public 型（actor や struct）:** 
  外部に公開されるため、明示的に Sendable に準拠させる必要があり、これは信頼できる「封筒に入った手紙」や、どのシーンでも安全に演技できる俳優として保証されることを意味します。



これらの仕組みを理解することで、Swift の並行処理における安全な情報交換がどのように実現されているかを、舞台の俳優や封筒に入った手紙のイメージで直感的に把握できます。これを活用して、堅牢で効率的な Swift コードを書いていきましょう！
ifconfigの出力結果を理解したい

## はじめに

:::note info
ここでは、Linuxコマンドの一つ「ifconfig」 について詳しく解説していきます。
:::
わからないことを何とかわかる言葉に変換しているので、厳密に正確ではないかもしれません。
違っていたら優しく教えてください。

## 書こうと思ったきっかけ
ネットワークを理解したくて、手始めにifconfigの出力結果を理解しようと思い書きました。


## ifconfigとは？
Mac OSでネットワークインターフェースの設定を表示するコマンドです。
ちなみにwindows OS の場合は 「ipconfig」です。

「ネットワークインターフェース」て何やねん。
パソコンがネットワークとやり取りするための「口(👄)」だと思ってください。
この「口」、いっぱいあります。

 さてifconfigコマンド。
ifconfig [オプション] [インターフェース名] [パラメータ]
と後ろに色々付けてもいいみたいですが、今回はシンプルにifconfigだけを実行します。


## 実際にやってみた
### ▪️１つ目の👄
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3999989/d00190e5-3f39-404d-88b4-ad59702b6661.png)
自分自身と通信するための👄みたいです。
細かく見ていきます。
まず、``` lo0 ``` は口の名前です。```lo``` は LOOPBACKの略らしいです。てっきりLocalの略だと思うてました。
次、``` flags=8049 <UP,LOOPBACK,RUNNING,MULTICAST>  ```
これは、lo0が起動しているかなどを教えてくれてます。
flags=8049 は 16進数 (0x8049) らしいので、2進数 に変換すると、

0x8049 = 1000 0000 0100 1001 (2進数)
このビットから、次のフラグが設定されているらしい。

| フラグ名      | 値 (16進数) | 値 (2進数)              | 説明 |
|--------------|------------|---------------------|------|
| UP          | `0x1`      | `0000 0000 0000 0001` | インターフェースが **有効**（動作中） |
| LOOPBACK    | `0x8`      | `0000 0000 0000 1000` | 自分自身と通信 |
| RUNNING     | `0x40`     | `0000 0000 0100 0000` | インターフェースが現在 **動作中** |
| MULTICAST   | `0x8000`   | `1000 0000 0000 0000` | マルチキャスト対応（マルチキャスト通信が可能） |

「マルチキャスト」とは「1対多の通信」って思ってください。

次、``` mtu 16384 ``` 
1回の送信で扱える最大データサイズが 16,384 バイトです。

疲れてきたのでoptions以降は割愛します。

### ▪️2つ目の👄
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3999989/82f69e2f-6206-4515-a981-b360118faae0.png)


ネットワーク通信を行うための👄みたいです。
細かく見ていきます。
``` flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST>```
このen0は、
- UP＝有効
- BROADCAST＝ブロードキャスト対応（ネットワーク上の全デバイスへ送信可能）
- SMART=スマート機能（何らかの便利機能だと思ってください）
- RUNNING＝動作中
- SIMPLEX=単方向通信対応（送信のみまたは受信のみの可能性）
- MULTICAST=マルチキャスト対応

次、``` mtu 1500 ```
MTU (Maximum Transmission Unit) = 1500 バイト
1回の送信で扱える最大データサイズです。

optionsは割愛。

``` ether xx:xx:xx:xx:xx:xx ```
Macアドレスです。

```inet6 xx:xx:xx:xx:xx:xx ```
IPv6アドレスです。

``` inet xxxxxxxxxxxxxx ```
IPv4アドレスです。

``` status: active ```
現在アクティブであり、ネットワーク接続が確立されていることを示しています。



## まとめ
ifconfigの出力結果について、主なネットワークインターフェースに絞って紐解いてみました。次からは暗号の羅列に見えることはないよね？


## 参考文献


https://it-biz.online/it-skills/netwrok-interface/#toc1


https://learningift.com/blogs/HftlYees1j7/
メンター制度導入を提案した話

# はじめに
米田です。
この度、会社にメンター制度の導入を提案し、**無事導入**することになりました!
この記事では、**提案に至った経緯から導入決定まで**を振り返っていこうと思います。


# 提案に至った経緯
私がメンター制度を提案した理由は、実際にOJT研修を受ける中で、次のような不満を感じていたからです。

##### ・頼り先がわからない問題
配属当初、私は自分の教育担当がわからない状態で業務を学びました。
わからないことがある度、有識者っぽい方を探して聞いていました笑
**誰に頼ればいいかわからない中での業務遂行**となり、正直心細かったです。

##### ・テレワーク、余計に心細い問題
そんな状態のまま、配属翌週からテレワークが始まりました。
今までは近くにいる方に頼って解決してきましたが、テレワークでは困ったら都度チャットを送ることになります。**対面時に比べ聞くことへのハードルが高く**、最初はかなり戸惑いました。
また、テレワークでは必要な時しかミーティングをしないため、基本的に雑談はありません。まだ現場に馴染んでいない段階でのテレワークは、**お互いを知るにはなかなか難しい環境**だなと感じました。
一日中誰とも話さない日も多かったので、コミュニケーションが好きな私にとっては少し寂しいな～と思いながら働いていました。。

### 相談して助けてもらった
上司に相談したところ、すぐに動いていただけました。
私の業務進捗を毎日確認していただけるようになり、**安心して働ける**ようになりました。
テレワークについても、出社頻度を増やすよう動いてくださり、**より楽しく働ける**ようになりました


### 相談の場さえあれば、フォローにつなげられる
このように、**相談**さえできれば、フォローのために全力で動いてくださる方がたくさんいます。ですが、入社したばかりの新人にとって、**誰かに相談することは難しい**です。テレワークのため、上司も新人の異変に気付くことが難しく、**フォローに繋げづらい**という状況でした。

そこで、新人の声を拾い上げる「**メンター制度**」を導入し、現場とは違う相談窓口を作ることで**新人の精神的負担を減らそう**と考えました。

## 導入に際しての課題
##### **・現場の受け入れ態勢**
この制度にはメンターが必要不可欠ですが、担当は現場社員にお願いすることになります。
現場からしてみるといきなり負担が増えることになるため、**現実的に導入可能なのか?必要性を感じているのか?** といった懸念がありました。

##### **・制度として継続運用できるか**
メンター制度の基本は、

**1.会社がメンターを選定
2.メンター担当者への趣旨説明・教育
3.会社がフォローしつつ、基本的にメンターが自立して稼働**
といった流れです。

初年度は私がメンター担当をするため趣旨を理解していますが、今後は選定されたメンターが趣旨を理解して動いていくことになります。継続運用のため、**「メンターのフレームワークをどの程度作れるか」** が課題でした。

これらの課題を解決するため、
**「初年度を試験導入とし、試験運用の中で制度改善やフレームワーク作成を行ったのち、改めて導入可否を判断する」** ことを計画しました。


# 提案に向けて行ったこと
##### **・周囲へのヒアリング**
同期や先輩社員に1年目がどんな状況だったかを聞き、**この制度が本当に必要か**を確認しました。
結果、相談先がわからない不安を抱えていた社員が多いとわかり、本格的に制度提案に向けて動くことを決めました。

##### **・会社側への頭出し**
会社側と現場リーダーに「こんな制度があったらどう思いますか?」と軽く聞いてみて、**反応を確認**しました。
双方から好意的な反応をいただけたため、「現場への負担を最小限にする」ことさえクリアできれば十分実現可能と判断し、制度設計に踏み切りました。

##### **・制度設計、導入計画**
確実な導入には現実味を持たせることが一番と考え、**制度案・導入計画案も作成したうえで提案しよう**と考えました。
制度設計や導入計画策定で意識したことについては、後日別記事で加工と思います!

##### **・提案書の作成**
来年度社員の入社まで時間がなかったため、ここは**chatGPTをフル活用**しました笑
部品を渡すだけで簡単なたたき台を作成してくれたので、2,3日で提案書を仕上げることができ、スムーズな導入につながりました。

# 試験導入決定まで
##### **・提案書をもとに会社側と打ち合わせ**
仕上がった提案書をもとに、会社側と打ち合わせを行いました。
周知の範囲・タイミングなど**とにかく課題が多く**、打ち合わせは3時間に及びました笑
協力的に動いてくださったこともあり、一度の打ち合わせで大枠がまとまり、あとは上層部に上げるのみとなりました。

##### **・上層部への提案**
こちらもかなり前向きに捉えてくださり、**その場で試験導入が決まり**ました。
あまりにもトントン拍子で進み、「本当に決まったのか..?導入していいのか..?」と、疑いましたが、**とにかく達成感でいっぱい**でした!

# さいごに
今回の制度導入にあたり、**会社の皆さんには大変ご尽力**いただきました。
新人の意見を真剣に受け止めて動いてくださったこと、大変感謝しています。

導入させていただくからには、本当に効果のあるフォローをし、それを制度として残していくことが重要です。
今年度の試験実施後、関係者からフィードバックをもらったうえで制度を評価し、**より現実的で効果のある制度**にしていこうと考えています。

また、OJT制度についても、負担なく変えられる部分があるのではないかと考えています。
すぐにできることとして、**「OJT担当者を明確にすること」「OJT担当者が毎日新人の状況を確認すること」**　の二点を提案しました。
こういった制度を少しずつ取り入れていくことで、**会社全体で新人を受け入れていく風土**を作っていけたらいいなと考えています。
PHP勉強メモ20250215（関数・メソッド・変数名・文字列変換）

## 前回
https://qiita.com/sioiriomame/items/802329de4d3488d456ab

## 関数とメソッドは違う
勉強不足で本当に恐縮なのですが、PHPではメソッドのことを関数と呼ぶのだと思っていた。違うらしい。

https://qiita.com/tadsan/items/4dd4d5fad4048eafa99b

以下が大雑把な理解

- 単体で定義している → 関数　汎用的処理 グローバルに呼び出せる（名前空間に所属することもある）
- クラスに所属している → メソッド Javaと同じ感じでインスタンスオブジェクトから呼び出すものとstaticで呼び出せるものがある。基本的にはインスタンスからは `->` でstaticメソッドは `::` で呼び出せる。（例外あり）
<br/>

- 関数とメソッドは同名のこともありえる。
- インスタンスオブジェクトから呼び出すメソッドは、同じクラス内であっても `$this->` を省略することはできない
- staticメソッドは同じクラスから呼び出す時は `self::methodName();` または `static::methodName();`
<br/>

- フレームワークによって異なるが、関数名はスネークケース、メソッド名はキャメルケースが一般的（ちなみに変数名はcakePHPの場合、キャメルケースが一般的。ただしデータベースのカラム名や配列のキーはスネークケースが多いらしい。）


## 数値 ↔︎　文字列変換
PHPは動的型付け言語であり、変数の型は「代入された値」によって決まる。
また、コンテキストによって自動的に型変換（暗黙的型変換）が行われることがある。

https://qiita.com/yukachin0414/items/be56b43a78fd3832333d


### 文字列→数値
- intval, floatval
整数： `intval($str);`
浮動小数点数： `floatval($str);`
- キャスト
整数： `(int)$str;`
浮動小数点数： `(float)$str;`

https://thousand-tech.blog/php/%E3%80%90php%E3%80%91%E6%96%87%E5%AD%97%E5%88%97%E3%81%8B%E3%82%89%E6%95%B0%E5%80%A4%E3%81%AB%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/

### 数値→文字列
- strval
`strval($num)`
- キャスト
`(string)$num`

http://php.net/manual/ja/function.strval.php
【AIエージェント】簡単な情報収集エージェントを構築・監視してみた

# はじめに
前回記事でOllamaを使ってローカルLLMを呼び出すことまで実施しました。

https://qiita.com/ryu-ki/items/8df42e80c48a734c2738

今回はローカルLLMを用いて、エージェントを構築し、構築したエージェントを監視するところまで実施したので、自身のやったことを整理するために本記事を書きました。

# LangGraphとは
LangChainをベースにしたライブラリで、LLMのワークフローを構築するために使われます。
特に、グラフ構造を活用して、複雑な対話フローやデータフローを柔軟に設計できることが特徴です。

以下の画像のようなイメージです。
（https://blog.langchain.dev/langgraph-multi-agent-workflows/ より引用）

![langgraph_multi_agent_diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3921802/9e760ce7-eb41-4fea-95ed-0c1642c9ed69.png)

https://blog.langchain.dev/langgraph/

# 構築したエージェント
下図が今回構築したものをグラフ化したものになります。
（Langfuseにより出力・Langfuseについては後述）

![rearch_agent_graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3921802/5600269e-8765-4da7-90be-34c1d13884fd.png)

簡単に流れを説明すると、以下の3ステップからなります。
1. __collect_basic__：基本情報の収集・要約
1. __collect_trends__：最新のトレンドの収集・分析・要約
1. __summarize__：上記2つの情報の要約

:::note
長くなってしまうので、ここではエージェントの詳細な実装については省略します。
:::

# Langfuseとは
一言でいうと、LLMアプリのためのOSS監視ツールです。

https://langfuse.com/

公式ドキュメント（Why Langfuse?）では以下のように紹介されていました。

https://langfuse.com/docs

- 最も利用されているオープンソースのLLMOpsプラットフォーム
- モデルやフレームワークにとらわれない
- 本番環境向けの構築
- 徐々に導入可能、1つの機能から始めて、時間をかけてプラットフォーム全体に拡張
- APIファースト、カスタム統合のためにAPI経由ですべての機能が利用可能
- オプションで、Langfuseは簡単にセルフホスト可能

# 監視してみる
## Langfuseの準備
いくつかの方法があるそうですが、一番簡単そうなローカルで準備したいと思います。
以下ページを参考に準備します。

https://langfuse.com/self-hosting/local

```bash:リポジトリのクローンと移動
git clone https://github.com/langfuse/langfuse.git
cd langfuse
```

```bash:Langfuseの立ち上げ
docker compose up
```

これで、`http://localhost:3000`へアクセスすると利用することができます。
また、`settings/api-keys`からAPIキーを取得することができます。

## コードの修正
以下ページを参考に、作成したコードを修正しました。

https://qiita.com/moritalous/items/76ba9f2ad200df335d07

https://langfuse.com/docs/integrations/langchain/example-python-langgraph#use-langfuse-with-langgraph-server

- コンストラクタへの追加内容（APIキーは `.env` にて管理）
```py
from langfuse.callback import CallbackHandler

self.langfuse_handler = CallbackHandler(
    secret_key=os.environ.get("LANGFUSE_SECRET_KEY"),
    public_key=os.environ.get("LANGFUSE_PUBLIC_KEY"),
    host=os.environ.get("LANGFUSE_HOST"),
)
```

- ワークフロー構築の際に変更する内容
```py
# 変更前
workflow.compile()

# 変更後
workflow.compile().with_config({"callbacks": [self.langfuse_handler]})
```


## 監視できているか確認
コードの修正後、再度エージェントを使ってみると、以下のようにtracesが生成されており、構造的にそれぞれの要素の入出力や、所要時間などを確認することができました。
（また、ベータ機能として前述のようにエージェントのグラフを表示することもできていました）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3921802/61da0e50-3ec9-4d84-a5ac-ba4d997f581e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3921802/2e067e03-fe53-410e-9717-d37211fe0ade.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3921802/e4d07511-07e4-41da-b507-045bb9618625.png)


# おわりに
思った以上に簡単にLangfuseを構築できたので驚きました。（実質`CallbackHandler`の設定と、`.with_config({"callbacks": [self.langfuse_handler]})`を追加しただけ）
これでデータの流れなどが分かりやすくなったので、プロンプトの調整や受け渡すデータの形式の見直しなどの作業がはかどるように思います。
また、評価がまだあまりできていないのでそちら方面（RAGASなど）の深堀りもしていきたいと思います。
ありがとうございました。

# 参考サイト

https://qiita.com/minorun365/items/70ad2f5a0afaac6e5cb9
Linuxの圧縮、解凍コマンドを毎回検索するのはやめよう

いつもファイルを解凍する時は都度調べてはコピペをしていたので、
最低限必要そうな解凍・圧縮コマンドを覚えることにしました。
(ちょっとzipは無視します。)

# 結論
以下2つを覚えればどうにかなる。
(-a オプションを使うとファイル名に合わせ自動で圧縮・解凍してくれるとコメントをいただきましたので修正しました。)

圧縮:
```
tar -acvf xxxx.tar.gz xxxx
```

解凍(展開):
```
tar -axvf xxxx.tar.gz
```


ちなみに-fはファイル名の直前に置かないといけない制約があるので
オプションの順序は-fを一番最後にしたら後は好きにして大丈夫でした。


# 結論に至ったワケ

## よく見る〇〇.gzと〇〇.tar.gzの違いってなに？
〇〇.tar.gz:圧縮された複数のファイルとかディレクトリがまとまってるもの
〇〇.gz:圧縮されてる単一ファイル

単一のファイルをtar.gzファイルとして圧縮できるので〇〇.tar.gzの方だけ解凍・圧縮方法覚えればいいんじゃない？

## じゃあ、〇〇.tar.gz、〇〇.tar.bz2、〇〇.tar.xzの違いは？
圧縮方法、圧縮率が違うとのこと。(結局圧縮ファイルには変わりないね。)

## ということで
コマンドを調べてみたら全てtarコマンド一つで解決できそう。
しかも解凍と圧縮で**c**と**x**でオプションが1個変えるだけでよいという親切設計！

## やってみよう

## 圧縮方法
```
# tar -zcf test.tar.gz test 
日本語訳:tarコマンドでtestディレクトリのgz(-z)をcreate(-c)します。file(-f)名はtest.tar.gz
```
- 使用オプション
-z(gz):gzファイル
-c(create):圧縮する
-f(file):ファイル名

## 解凍方法
```
# tar -zxf test.tar.gz
日本語訳:tarコマンドでfile(-f)名がtest.tar.gz(-z)をextract(-x)します。
```
-z(gz):gzファイル
-x(extract):解凍(展開)する
-f(file):ファイル名

## -vを追加してみる
-v(verbose)は処理したファイルを出力するオプション
```
# tar -zcvf test.tar.gz test
test/
test/NO1
test/NO2
test/NO3
test/NO4
test/NO5
```
ちゃんと処理できてるか確認できるのいいね、採用。

## -aを使用してみる
-aオプションでコマンド実行をすると自動的にファイル形式を合わせてくれると情報をいただきましたのでやってみます。

```
# tar -acvf test.tar.gz test
# tar -acvf test.tar.bz2 test
# tar -acvf test.tar.xz test

# ls -ll
total 12
drwxr-xr-x. 2 root root  61 Feb 17 21:02 test
-rw-r--r--. 1 root root 180 Feb 17 21:02 test.tar.bz2
-rw-r--r--. 1 root root 189 Feb 17 21:02 test.tar.gz
-rw-r--r--. 1 root root 220 Feb 17 21:02 test.tar.xz

# file test.tar.gz
test.tar.gz: gzip compressed data, from Unix, original size modulo 2^32 10240
# file test.tar.bz2
test.tar.bz2: bzip2 compressed data, block size = 900k
# file test.tar.xz
test.tar.xz: XZ compressed data
```
少し見にくいですが、-aを使って拡張子を任意の形式にするとしっかりと-a(auto)で圧縮してくれることが分かりました。

## ちなみに
```
# tar -zcvf test.tar.xz test
test/
test/no1
test/no2
test/no3
test/no4
test/no5

# file test.tar.xz
test.tar.xz: gzip compressed data, from Unix, original size modulo 2^32 10240
```
本来gzipファイルを指定する-zを使って、xzファイルを作成しようとすると
名前は〇〇.tar.xzなのに中身はgzipで圧縮されるということが起きます。

## gz2、xzファイルにしたい場合のオプション
|  オプション  | 意味|
| ---- | ---- |
|  -z  | gzip形式 |
|  -j  |  bzip2形式 |
|  -J  | xz形式 |

-zはgzだからなんとなく分かるけど、-jと-Jはなんでjなんだ。
(開発者の方がこの記事見てたら理由をコメントに書いてください。)
## まとめ
・オプションって英語の頭文字になることが多いからそれを含めて理解したら覚えやすくなった。
・なんで-jと-Jはjなんだ。
Docker起動時に発生する`Failed to allocate manager object, freezing.`エラーを解決した方法

## はじめに
既存プロジェクトの環境構築を行なった際に、コンテナのビルド実行時にコンテナ内のログにエラーが出力されました。解決に時間がかかったため、自分が試した方法をまとめます。

![スクリーンショット 2025-02-15 1.03.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3959267/572965ed-1f4f-485b-9eb6-397b5826402d.png)


## 原因
csgroupにはv1とv2が存在しており、Dockerのv20.10以降では`csgroup v2`がデフォルトで設定されているようです。プロジェクトのDockerイメージは、CentOS 7をベースとした「Amazon Linux2」を使用していましたが、`csgroup v2`を使用するコンテナではCentOS 7を動かせないという情報を見つけました。

私の環境では、Docker v27.4.0を使用しており、`csgroup v2`であったことから今回のエラーが発生したと考えられます。

:::note info
Dockerのシステム情報は `docker info` コマンドで確認できます。
※下記は自分のPC上で実行した結果であり、今回関連しているシステム情報のみを載せています
```
Server Version: 27.4.0
Cgroup Version: 2
```
:::

:::note info 
csgroupは「Controlle Group」の略で、グループ化されたプロセスのリソース(CPUやメモリ等)に対して使用量の監視や制限等を行います。
:::

## 解決方法① cgroupの設定を変更する
PCの `settings-store.json` ファイルを開き、cgroupの設定を書き換えます。
```
vi ~/Library/Group\ Containers/group.com.docker/settings-store.json
```

setting-store.jsonファイルの設定に以下を追記し、保存します。
```setting-store.json
"DeprecatedCgroupv1": true
```

catコマンドで設定が追記されていることを確認できたらPCを再起動します。
```
cat ~/Library/Group\ Containers/group.com.docker/settings-store.json
```

csgroupをv2からv1に変更できたので、期待を込めてビルドしましたがエラーの内容は変わりませんでした。。。

## 解決方法② コンテナにcgroupをマウントする
上記の方法でエラーが解消しない場合、コンテナにcgroupがマウントされるように設定します。

```docker-compose.yml
api:
    build: ./api
    volumes:
      ~略~
      - /sys/fs/cgroup:/sys/fs/cgroup #追記
    ports:
      - "8080:80"
    cap_add: 
      - SYS_ADMIN #追記
    environment:
      - container=docker #追記
```

:::note warn
cgroupの設定で「:ro (read only)」オプションを付けて実行すると 'read-only file system' エラーが発生するためオプションの設定はしません。

```diff_ruby
+ /sys/fs/cgroup:/sys/fs/cgroup
- /sys/fs/cgroup:/sys/fs/cgroup:ro 
```
:::

再度ビルドを実行するとログのエラーが解消しました！

## まとめ
今回の環境構築では、プロジェクトが想定しているDockerのシステム情報に、自分のDockerの設定を合わせることで解決できました。
プロジェクトで使用しているDockerイメージが古い場合は、エラーが出た際にDockerのバージョンが関係していないかという点にも考慮する必要があるなと思いました。
20250215

Declare PtrSafe Sub SetCursorPos Lib "user32" (ByVal x As Long, ByVal y As Long)

Sub MoveMouseRelativeToWindow()
    Dim windowLeft As Long
    Dim windowTop As Long
    Dim windowWidth As Long
    Dim windowHeight As Long
    Dim centerX As Long
    Dim centerY As Long
    Dim targetX As Long
    Dim targetY As Long
    
    ' 仮のウィンドウ位置とサイズ（実際はAPIなどで取得）
    windowLeft = 100 ' ウィンドウの左端
    windowTop = 100  ' ウィンドウの上端
    windowWidth = 800 ' ウィンドウの幅
    windowHeight = 600 ' ウィンドウの高さ

    ' ウィンドウの中央座標を計算
    centerX = windowLeft + windowWidth / 2
    centerY = windowTop + windowHeight / 2

    ' 中央にカーソルを移動
    SetCursorPos centerX, centerY

    ' ウィンドウ中央から30% X, 50% Yの位置にマウスを移動
    targetX = centerX + (windowWidth * 0.3) ' ウィンドウの30%の位置
    targetY = centerY + (windowHeight * 0.5) ' ウィンドウの50%の位置

    ' 新しい位置にカーソルを移動
    SetCursorPos targetX, targetY
End Sub
plotlyで収入と手取り、年金、保険料を可視化してみる

# やってみたこと
年収が1000万円の場合の手取りと年金・保険料のフローを可視化してみたかった
※そんなにもらってない。

## 使用した技術
- Python
- Jupyter
- plotly

## データ
ChatGPTに雑に聞いてみた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69163/23d4cdd9-0ee7-44e3-9ec5-ffd26cb7d0e0.png)

# コード
```
import plotly.graph_objects as go
import plotly.io as pio
pio.renderers.default = 'notebook'

fig = go.Figure(data=[go.Sankey(
    node = dict(
      pad = 15,
      thickness = 20,
      line = dict(color = "black", width = 0.5),
      label = ["0給与", "1賞与", "2児童手当", "3投資収入", "4総収入", "5所得税", "6住民税", "7年金", "8健康保険", "9雇用保険", "10手取り", "11税・保険", "12大阪万博"],
      color = "blue"
    ),
    link = dict(
      source = [0, 1, 2, 3,11,11,11,11,11, 4, 4,5], 
      target = [4, 4, 4, 4, 5, 6, 7, 8, 9, 10,11,12],
      value =  [800, 200, 20, 10, 85,65,49,72,7, 752,278,0.3]
  ))])

fig.update_layout(title_text="年収が1000万円の場合の手取りと年貢のフロー", font_size=10)
fig.show()
```

# 結果
だいたい3割弱持っていかれる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69163/0dde2531-eabb-4620-ad6f-005a703f5262.png)
ガチ初心者のAzure利用開始日記「アカウント作成」2025年2月版

# Azureの勉強開始
こんにちは。初心者(Azure未経験)にもかかわらず、無謀にも3月7日にAzureのユーザーコミュニティで登壇予定のため備忘として書いています。そもそもアカウントすら持っておりません。。。

https://jazug.connpass.com/event/339549/

# Azure portalにログインしてみた
Azureのアカウントを持っていない状態で、個人のMicrosoftアカウントでAzure portalにログインしてみました。Teamsでテナントにゲストとして入れてもらっていたいくつかのテナントが表示されております。いや、ログインできるんかい…。

https://portal.azure.com/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/12e94a3b-55ef-4844-a019-2d63f75a7ac0.png)

# Azure無料アカウントの作成
もちろん他の方のテナントに迷惑をかけるといけないので、以下から無料アカウントを作成しました。

https://azure.microsoft.com/ja-jp/pricing/purchase-options/azure-account?icid=pricing

左側の無料アカウントをクリックして作成。30日間は200ドル分のクレジットがつくようです。
30日以内または200ドルのクレジット使用後は従量課金制価格に移行して12か月間無料で使えるサービスのロックが解除されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/7f92bc92-c79f-41db-b6a1-b16fa85f6546.png)


必要事項を埋めていきます。請求はされないけれど、クレジットカードも登録が必須のようです。
ちゃんと自動請求なしなのは…一応親切…。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/a0bce4ed-3032-49b8-bbc4-cbcb7db1de4d.png)

作成が完了すると急に英語の画面が出ます。
Go to Azure portalを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/417f0703-d471-44d0-b0e1-227aed09408f.png)

# Azure portalへのアクセス
クイックスタートセンターが表示されますが、ほかの人のテナント（ディレクトリ）になっているままなので、テナントを切り替えておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/bd6670e0-bc82-4028-90c3-8380557a1c39.png)

右上の歯車ボタンを押すと自分のいるディレクトリが表示されます。無料アカウントを作成したことで、「規定のディレクトリ」が出てきますので切り替えます。これで安心。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/537d24d6-3ed4-4369-9da9-554edfa83ccf.png)

クイックスタートガイドに戻り、チュートリアルにのっとって説明をききます。。
YouTubeの動画が出てきますが、日本語字幕ないので注意…。
AzureのMVPの方が丁寧に説明してくれるので、英語わからなくても何とかなります。

ポータルの見方、無料アカウントのしくみ、ソリューションの始め方から教えてくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3629241/50895b78-7583-4368-a6a3-65201a199d80.png)

動画を進めるとAzure アーキテクチャ センターの説明やリソースの管理、リージョンの指定、コスト管理などなど丁寧に教えてくれます。

https://learn.microsoft.com/ja-jp/azure/architecture/

アカウントの作成までできました。次の記事（あるのか・・・？）では何かしら構築していきたいと思います。。。！
Chakra UI v3 でWrapのインポートがエラーになる

## 事象
下記のようなエラー分がなぜか表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3381618/94400c75-d20d-4adb-90fc-aa1dde810761.png)
なんで…？
package.jsonのdependenciesもちゃんとインストールされている。
```package.json
  "dependencies": {
    "@chakra-ui/icons": "^2.2.4",
    "@chakra-ui/react": "^3.5.1",
    "@emotion/react": "^11.14.0"
  }
```
画面を立ち上げてみると、以下エラーが表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3381618/6a122f7f-b389-7bd2-513d-34f230b31d36.png)

## 解決方法
@chakra-ui/reactをアンインストールして、再インストールでバージョンを「3.8.0」に上げることでWrapも正常に機能するようになった。
（なんで3.5.1でダウンロードされてたかは謎…）

Chakra uiの公式ページを参考にコマンド押下
```
npm uninstall @chakra-ui/react @emotion/react
```
からの
```
npm i @chakra-ui/react @emotion/react
```
これでchakra-ui/reactのバージョンをpackage.jsonで確認
```package.json
  "dependencies": {
    "@chakra-ui/icons": "^2.2.4",
    "@chakra-ui/react": "^3.8.0",
    "@emotion/react": "^11.14.0",
    "axios": "^1.7.9",
    "next-themes": "^0.4.4",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "react-icons": "^5.4.0",
    "react-router-dom": "^7.1.5"
  }
```

バージョンが最新になっているか（または意図したバージョンになっているか）は
しっかり確認しましょう！
（これで何時間費やしたことか・）
AIに気付かされた、OSSやブログ記事のハードルを自分で上げていた話

初Qiitaドキドキ
使い方がまだ良くわかってませんが、とりあえず文字を書いてみようと
.
.
ところで、昨日、風呂に入っていたら突然、自分の市場価値が気になりまして（突然
みなさん、一度は考えたことあると思います、転職時に
「じゃあ、年収いくらご希望ですか？」のあの答えのことです。

Xに上げて業界のえｒ…いひとに聞いてみるか、あるいは
と考えていたら、まず最近若干ドラ〇もん化しているAIに聞いてみることにしました。
.
.
どら…ごほん、Copilot!私の市場価値がわからないよーぴえん。

![00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011870/3f27adf6-01f3-427e-934b-c01f6c649384.png)


あれ、このドラ〇もん…便利グッズ出してくれないぞ←
とまあ相談開始です。

資格はお金がかかるし、フィードバックもらうひともいない…
うーーーん。一番現実的な案はやはりＯＳＳを作って投稿することらしい。

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011870/2d68a5a0-aacb-4cba-915e-bfefafc95620.png)


うーーーーん。ＯＳＳかー…勇気必要過ぎだよねえ（チキン

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011870/16ec6f78-733b-46a5-9aa2-170ef966657c.png)

.
突然の強気（深夜テンション）で急に少しだけやる気を出す私。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011870/14ff730b-827a-46ab-bc10-895096ec4d14.png)

.
深夜テンションとCopilitのポジティブな対応でどんどんやる気になるちょｒ…私。
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011870/3516725f-0b9d-416b-b968-06edf6b319a6.png)
![06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011870/1e95bee8-3007-4109-bf33-b36cbf803834.png)
.
ネガティブな私とポジティブなCopilotの戦いが繰り広がる。
![08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011870/969f5bda-eaa1-460a-a35f-9c17e8280765.png)
![09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011870/6c1ab170-a83c-4758-bf65-98225ed98827.png)
.
.
なるほど…非公開…！それなら…！
とそのとき、突然のひらめきと気づきが…！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011870/db6385c4-72cb-4bd6-85f4-fe02c400646d.png)
![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011870/7d021dd9-c727-4f61-8446-13b90caef299.png)
![14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011870/95a39297-0c69-4bad-9997-50088230ade3.png)
.
.
私が作ったツールなんて…
座り過ぎと睡眠不足を改善するための「決まった時間になると強制シャットダウンするバッチ」と「90分経つとフルスクリーンで10分ストレッチしろ！」と知らせてくれるバッチと、
業務10分前に「そろそろ切り上げろ」バッチと残業申請になる時間10分前に
「やばい。これ以上はダメだ！」と知らせてくれるバッチと
業務に使う自動化ツールと、あとＨＴＴＰメソッドチェックする自作ツールと、
診断用ツールと、あの環境チェックツールと…
あれ？？？私ツール結構作ってない？？？
.
.
.
そうです。私実はツールたくさん作っていたのです。
とここから大困惑。

![15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011870/60c3cb5a-9d1e-4f3a-8b9e-f92d09182caf.png)
![16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011870/567eb179-1c5c-4873-b01d-76038b909731.png)
.
.
そして、もう一つの気付きが…！
私みたいに自分で作ったツールにあまり価値を与えず、
そのまま終わってしまっているひとはたくさんいるのでは…？
というかここに一人いたよ。絶対いるよ…！

それをブログに書いてこの気付きを共有すれば、見てくれたひとも同じ気づきをしてくれるのでは？（深夜テンション）
と一人で盛り上がる深夜の私。

![18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4011870/dd6f577d-c45f-40a8-910d-2666f4b5abc4.png)
.
しかし、これはまた別のことも意味をしていて、
いつの間にか私は自分の作ったツール以外にもブログなどにも
身構えすぎて公開記事を書くのを恐れすぎていたかもしれません。
（ツール同様一人で考えて書いて満足してしまう）

見てくれたらありがたいし、見てくれなくてもアウトプットの練習になるのだからそれで良い。
あまり意味を与えず、アウトプットできる環境にしていく第一歩になれば良いのでは…と！

ということで勇気を絞り出して書いてみました！
（しかも意外とすぐ書けた。寝起きの私が、あれ？？？）
え？ＯＳＳ？うーん。とりあえずGithubのアカウントは作ります！←（え
.
.
みんなもとりあえずAIとお話してブログ書いてGithub垢作れば良いと思うの←
.

それでは、良い一日を！👋
Best regards,
おひとり様LLMをしよう！（スマートフォン偏）

次の記事

https://qiita.com/azsoft-jp/items/7f9544ebd5dc6f82e7c1
## TL;DR

- 日本語に特化したテキスト生成AIのモデルがリリースされたよ
- かなり軽量なので、スマートフォンでも動くよ
- オフラインでも回答を生成できるよ
- みんなもお手持ちのスマートフォンで動かしてみよう！

## TinySwallow-1.5Bとは
先日、SakanaAIより、TinySwallow-1.5BというテキストAIモデルがリリースされました。

TinySwallow-1.5Bは、Sakana AIが新手法「TAID（Temporally Adaptive Interpolated Distillation）」を用いて開発した日本語小規模言語モデルです。約15億パラメータで構成され、同規模のモデル中で最高水準の日本語ベンチマークスコアを達成しています。このモデルは、スマートフォンなどのエッジデバイス上でオフライン動作が可能で、効率的な知識蒸留により高性能を実現しています。

**特徴：**
- **高性能**：同規模帯で最高水準の日本語ベンチマークスコアを達成
- **小規模**：約15億パラメータで、エッジデバイス上での動作が可能
- **オフライン動作**：スマートフォンやPC上で、外部APIを介さずに利用可能
- **新手法TAIDの採用**：効率的な知識蒸留により、高性能と小規模の両立を実現
- **オープンアクセス**：モデルはHugging Face Hubで公開され、誰でも利用可能

 今回はこの「TinySwallow-1.5B」をオフラインで動かしていきましょう。

## 手順
### Andrid
#### 1.アプリのダウンロード
まず、「PocketPal AI」というアプリをGoogle Play Storeからダウンロードしてください。
[PocketPal AIをダウンロード](https://play.google.com/store/apps/details?id=com.pocketpalai&hl=jp_JP)

#### 2.アプリの起動・モデルファイルのダウンロード
アプリを起動したら「Go to Models」を押します。

右下の＋マークから、「Add from Hugging Face」を押します。

「Tinyswallow」を検索してダウンロードします。
- Q8バージョン：より正確な応答が可能ですが、やや遅めです
- Q5バージョン：Q8より精度は落ちますが、より速く動作します

Modelsを開いてダウンロードしたモデルの下にある「Load」を押します。

#### 3.使ってみる

### iPhone,iPad
#### 1. アプリのダウンロード

まずは「LLMFarm」というアプリをApp Storeからダウンロードしてください。
[LLMFarmをダウンロード](https://apps.apple.com/ru/app/llm-farm/id6461209867?l=en-GB&platform=iphone)

#### 2. モデルファイルのダウンロード

TinySwallowには2つのバージョンがあります：

- Q8バージョン：より正確な応答が可能ですが、やや遅めです（14.75トークン/秒）
  - [Q8をダウンロード](https://huggingface.co/SakanaAI/TinySwallow-1.5B-Instruct-GGUF/resolve/main/tinyswallow-1.5b-instruct-q8_0.gguf?download=true)

- Q5バージョン：Q8より精度は落ちますが、より速く動作します（19.89トークン/秒）
  - [Q5をダウンロード](https://huggingface.co/SakanaAI/TinySwallow-1.5B-Instruct-GGUF/resolve/main/tinyswallow-1.5b-instruct-q5_k_m.gguf?download=true)



#### 3. LLMFarmでの設定

1. ダウンロードしたLLMFarmアプリを開きます
2. 画面右上の＋ボタンをタップします
3. 「Basic」タブの「Model」セクションで「Select model」をタップします
4. 「import from file」から、先ほどダウンロードしたファイルを選択します
5. タイトルに「TinySwallow」と入力します
6. 「Settings template」をタップし、「ChatML」を選択します

#### 4. 追加設定（任意）

以下の設定を変更することで、より良い結果が得られる場合があります：

「Sampling」タブで：
- Temperature: 0.7
- Top_k: 20

「Prompt」タブでは、システムプロンプト（回答のベースとなる命令）を追加できます：

```
[system](あなたは、優秀なアシスタントです。)

user
{{prompt}}


assistant

```

### 5. 使ってみる

「Save」をタップして保存すれば、チャットを開始できます！


##