チャットワークのAPIを使ってみました.プロンプトでほぼ書いています.

2025.07.13

Logging

おはようございます.チャットワークのAPIを使ってみました.プロンプトでほぼ書いたコードになります、チャットGPTの無料版にリファレンスのURLリンクとPHPのクラス化、リターンに$thisで返却出来る所は$thisを使用してスマートにコードを書いてと指示を出しました.

出来上がったコードが下記になります.ソースコードは自分の方でモンキーテスト的に動かしてみましたが、ちゃんと動作するようです.

<?php
class ChatworkClient
{
    private string $apiToken;
    private string $baseUrl = 'https://api.chatwork.com/v2';
    private int $retryCount = 3;
    private int $retryDelay = 1000000; // microseconds

    public function __construct(string $apiToken)
    {
        $this->apiToken = $apiToken;
    }

    public function setRetry(int $count, int $delayMicroseconds): self
    {
        $this->retryCount = $count;
        $this->retryDelay = $delayMicroseconds;
        return $this;
    }

    private function request(string $method, string $path, array $params = []): array
    {
        $attempts = 0;

        while ($attempts < $this->retryCount) {
            $attempts++;

            $ch = curl_init();
            $url = $this->baseUrl . $path;

            if ($method === 'GET' && $params) {
                $url .= '?' . http_build_query($params);
            }

            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

            $headers = ['X-ChatWorkToken: ' . $this->apiToken];

            if (in_array($method, ['POST', 'PUT', 'DELETE'])) {
                curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
                curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
                $headers[] = 'Content-Type: application/x-www-form-urlencoded';
            }

            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

            $body = curl_exec($ch);
            $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $error = curl_error($ch);
            curl_close($ch);

            if ($error) {
                if ($attempts < $this->retryCount) {
                    usleep($this->retryDelay);
                    continue;
                }
                throw new RuntimeException("cURL error after {$attempts} attempts: {$error}");
            }

            if ($status >= 200 && $status < 300) {
                return [
                    'status' => $status,
                    'body' => $body ? json_decode($body, true) : null,
                ];
            }

            if ($attempts < $this->retryCount && $status >= 500) {
                usleep($this->retryDelay);
                continue;
            }

            return [
                'status' => $status,
                'body' => $body ? json_decode($body, true) : null,
            ];
        }

        throw new RuntimeException("Request failed after {$this->retryCount} attempts");
    }

    public function setToken(string $token): self
    {
        $this->apiToken = $token;
        return $this;
    }

    public function me(): array
    {
        return $this->request('GET', '/me');
    }
    public function getMyStatus(): array
    {
        return $this->request('GET', '/my/status');
    }
    public function getMyTasks(array $filters = []): array
    {
        return $this->request('GET', '/my/tasks', $filters);
    }
    public function getContacts(): array
    {
        return $this->request('GET', '/contacts');
    }
    public function getRooms(): array
    {
        return $this->request('GET', '/rooms');
    }
    public function createRoom(array $params): array
    {
        return $this->request('POST', '/rooms', $params);
    }
    public function getRoom(int $roomId): array
    {
        return $this->request('GET', "/rooms/{$roomId}");
    }
    public function updateRoom(int $roomId, array $params): array
    {
        return $this->request('PUT', "/rooms/{$roomId}", $params);
    }
    public function deleteRoom(int $roomId, string $action = 'leave'): array
    {
        return $this->request('DELETE', "/rooms/{$roomId}", ['action_type' => $action]);
    }

    public function getMembers(int $roomId): array
    {
        return $this->request('GET', "/rooms/{$roomId}/members");
    }
    public function updateMembers(int $roomId, array $params): array
    {
        return $this->request('PUT', "/rooms/{$roomId}/members", $params);
    }

    public function getMessages(int $roomId, bool $force = false): array
    {
        return $this->request('GET', "/rooms/{$roomId}/messages", ['force' => $force ? 1 : 0]);
    }

    public function postMessage(int $roomId, string $body, bool $selfUnread = false): self
    {
        $this->request('POST', "/rooms/{$roomId}/messages", ['body' => $body, 'self_unread' => $selfUnread ? 1 : 0]);
        return $this;
    }

    public function markRead(int $roomId): self
    {
        $this->request('PUT', "/rooms/{$roomId}/messages/read");
        return $this;
    }

    public function markUnread(int $roomId): self
    {
        $this->request('PUT', "/rooms/{$roomId}/messages/unread");
        return $this;
    }

    public function getMessage(int $roomId, int $messageId): array
    {
        return $this->request('GET', "/rooms/{$roomId}/messages/{$messageId}");
    }

    public function getRoomTasks(int $roomId, array $filters = []): array
    {
        return $this->request('GET', "/rooms/{$roomId}/tasks", $filters);
    }

    public function createTask(int $roomId, array $params): array
    {
        return $this->request('POST', "/rooms/{$roomId}/tasks", $params);
    }

    public function uploadFile(int $roomId, string $filePath, string $message = ''): array
    {
        if (!file_exists($filePath)) {
            throw new InvalidArgumentException("File not found: {$filePath}");
        }

        $ch = curl_init();
        $url = $this->baseUrl . "/rooms/{$roomId}/files";
        $cfile = curl_file_create($filePath);

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-ChatWorkToken: ' . $this->apiToken]);
        curl_setopt($ch, CURLOPT_POSTFIELDS, ['file' => $cfile, 'message' => $message]);

        $body = curl_exec($ch);
        $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

        if (curl_errno($ch)) {
            throw new RuntimeException(curl_error($ch));
        }

        curl_close($ch);
        return ['status' => $status, 'body' => json_decode($body, true)];
    }
}

人が今回のコードを書いた場合、早い人でも10分ぐらいはコードを書かないといけないと思います、どんなに早くてもそれぐらいの時間は必要だと思いますが、生成AIはこれを数十秒で書ける訳ですから、確実に時間短縮になります.

なので人工知能が使える現場は間違いなく最初のコード出力は人工知能に任せた方が良いです.特に新規案件の土台は生成AIに任せると開発コストは削減出来ます.

明日へ続く

著者名  @taoka_toshiaki

※この記事は著者が40代前半に書いたものです.

Profile
高知県在住の@taoka_toshiakiです、記事を読んで頂きありがとうございます.
数十年前から息を吸うように日々記事を書いてます.たまに休んだりする日もありますがほぼ毎日投稿を心掛けています😅.
SNSも使っています、フォロー、いいね、シェア宜しくお願い致します🙇.
SNS::@taoka_toshiaki

OFUSEで応援を送る

タグ

```, クラス, コード, コスト, これ, スマート, ソース, それ, チャット, テスト, プロンプト, モンキー, よう, リターン, リファレンス, リンク, ワーク, 下記, 人工, 今回, 使用, 出力, 削減, 動作, 土台, 場合, 必要, 指示, 新規, 明日, 時間, 最初, 案件, 無料, 現場, 生成, 知能, 短縮, 確実, 自分, 返却, 開発, 間違い,

まだ間に合うスタディサプリ、価格変更まじか?

2020.01.20

Logging

センター試験どうでしたか?良かった人、ダメだった人、いろいろだと思いますが、やり直しは生きてたら何度も出来るので諦めず冷静に自分を見つめ、何をどうしたら成功するのかを考える時間も大切です。

さて、来年受験する方に悲報です、こんな内容のメールが 先日スタディサプリから届きました。内容はこんなの。

このたび、2020年2月18日正午以降に新規でお申し込みをいただいたお客様、再申し込みいただいたお客様に対して、スタディサプリベーシックコースの提供価格を月額980円(税抜)から1,980円(税抜)に変更することとなりました。

引用元:スタディサプリ

『何でやねん!』と一瞬思いました。

ちょっと痛い価格の高騰です。その分、質の良い解説動画や教材になるでしょうと思いたい、今まで契約している人は980円でOKですよ(今のところは)という事なので良かったのですが、1000円UPって自分で支払っている学生さんなどには大きな痛手のような気がします。

スタディサプリってリクルートがやっているサービスなので(自分の記憶ではアプリサービスを買収した)、経営的な事で値上げしたというよりはサービスを向上させようという考えの下で値上げしたと思います。自分が思うに変な先生に習うよりスタディサプリを使って勉強することをオススメしますし、いじめで不登校になってしまった方にもスタディサプリはオススメします。

もっとハイスペックな勉強をしたいという方はググるといろいろなサービスが世界にあります。例えば『ゆにたす』、まだサービス始まったばかりなのでこれからどうなるかは未知数だけど大学理系専門予備校(高校の数学などの解説動画あり)は結構良いじゃないかなと思います。気になった方は下記にURL貼っときます。

https://uni-tasu.jp/

追記:スタディプラスとポルトというサービスがあります。
こちら980円(ポルト)ということなので2月18日以降に記事を閲覧した方は
こちらも検討してみてはどうでしょうか?
(動画解説なし今のところは)
https://info.studyplus.co.jp/
https://porto-book.jp/

著者名  @taoka_toshiaki

※この記事は著者が40代前半に書いたものです.

Profile
高知県在住の@taoka_toshiakiです、記事を読んで頂きありがとうございます.
数十年前から息を吸うように日々記事を書いてます.たまに休んだりする日もありますがほぼ毎日投稿を心掛けています😅.
SNSも使っています、フォロー、いいね、シェア宜しくお願い致します🙇.
SNS::@taoka_toshiaki

OFUSEで応援を送る

タグ

, 1000, 18, 2, 2020, 980, OK, UP, いろいろ, お客様, お申し込み, コース, こと, サプリ, スタディ, センター, たび, ため, ところ, ベーシック, メール, 一瞬, , , , , 何度, 価格, 先日, 内容, 冷静, , 動画, 受験, 変更, 大切, 契約, 学生, 引用, 悲報, 成功, 提供, 教材, 新規, , 時間, 月額, 来年, 正午, 痛手, 税抜, 自分, 解説, 試験, , 高騰,

WordPressのメディアライブラリについて愚痴る。

2020.01.08

Logging

過去のデータベースを引き継いでいればメディアライブラリのデータは
壊れないが、途中でXMLなどデータをインポートすると
メディアライブラリでは管理出来なくなってしまう。

これを呼び戻すには Add From Server やmedia from ftpなどのプラグインを
使用して呼び戻すしか無いようだと思っていたが、唯これをしてしまうと
いささか問題があるので使えない。
このプラグインは基本的に新規で構築する際に
画像をFTPで一先ず一括アップロードして使用する場合などに対しての
プラグインである物なのでいささか違う。

なので今回、自分で自作しようと思っていたが、、、
特に過去の画像を編集するつもりもないので辞めた。
ちなみにメディアライブラリの画像はwp_postsとwp_postmetaに
保存されている。

下記のURLを見て昔、これでトラブルになった事を思い出した。
WordPressで画像はどのようにデータベースに記録されているか

上記のようなことから、データベースの画像の欠損を復元するのは
正直なところ面倒。投稿データには大体、データは残っているのだが
メタデータが欠損していてメディアライブラリに表示されないということが
殆どだと思うが、このメタデータを復元するのは至難、なぜなら
投稿データって使っているIDとメタデータのIDのリンクを上手く結びつける
事ができないからとてもエンジニア泣かせである。

要するにメタデータIDの方が以前使っていたIDを別の要素のIDが
使っていたりして…。
これを整理しながら元に戻すのは非常に至難だと言うこと。

なので、結論を言えばちゃんとデータベースのバックアップ取りましょう?

著者名  @taoka_toshiaki

※この記事は著者が40代前半に書いたものです.

Profile
高知県在住の@taoka_toshiakiです、記事を読んで頂きありがとうございます.
数十年前から息を吸うように日々記事を書いてます.たまに休んだりする日もありますがほぼ毎日投稿を心掛けています😅.
SNSも使っています、フォロー、いいね、シェア宜しくお願い致します🙇.
SNS::@taoka_toshiaki

OFUSEで応援を送る

タグ

Add, from, FTP, media', postmeta, posts, SERVER, url, WordPress, wp, xml, アップロード, インポート, これ, つもり, データ, データベース, トラブル, プラグイン, メディア, ライブラリ, 一括, 下記, , 今回, 使用, 保存, 問題, 場合, 新規, , 構築, , 画像, 管理, 編集, 自作, 自分, 記録, 途中, 過去, ,

クローラーするサービスの基礎。

2016.11.19

Logging

クローラーするサービスの基礎のソースを載せときます。殆どサイボウズ・ラボの人が書いたコードです。
このサンプルソースをそのまま貼り付けても一階層のリンクしか取得できません。
再帰処理の部分をコメントアウトしているからです。ちなみにコメントアウトを外してもメモリオーバーでおそらく
大体のサーバでエラーが出力されます。どうしたら良いのかといえば、DBに1階層目のリンクデータ、2階層目のリンクデータという様に保存する機能を施す。次にajaxで階層を受け渡しながら、再帰処理を行う。
再帰処理が終わる要素はそれ以上、下階層がないことを判断する。そのためには保存したデータを検索することが重要になる。=(イコール)
新規にデータを登録しているうちは、再帰処理を終わらせないようにすることが大事になる。
これの機能を加えることで巡回する事が可能になる。ここで注意しないといけないのが、外部リンクを保存しないことです。外部リンクまで保存していると巡回は永遠に終わらないでしょう・・・。
トイウコトデ
ほぼ??コピペソースを貼っときます。

<?php
echo json_encode($obj);
exit;
function get_linkarray($link)
{
	$context = stream_context_create(array("http" => array("method" => "GET", "header" => "User-Agent: simplecrawler.library.php 0.0.1")));
	$resultR = array();
	$resultS = simplecrawler($context, $link, $link, parse_url($link));
	foreach ($resultS as $k => $v) {
		$resultR[] = $v;
	}
	return $resultR;
}
function simplecrawler($context, $link, $burl, $base, $linkArrayDat = array())
{
	$linkArrayPre = crawler_link(crawler_page($link, $burl, $base, $context), $link, parse_url($link));
	foreach ($linkArrayPre as $k => $v) {
		if (!isset($linkArrayDat[$v])) {
			$linkArrayDat[$v] = $v;
			//$linkArrayDat = array_merge($linkArrayDat, simplecrawler($context, $v, $burl, $base, $linkArrayDat));
		}
	}
	return $linkArrayDat;
}
function crawler_page($link, $burl, $base, $context)
{
	if (strpos($link, $burl) === 0) {
		$page = @file_get_contents($link, false, $context);
		return $page === FALSE ? null : $page;
	} else {
		return null;
	}
}
function crawler_link($page, $burl, $base)
{
	$linkArray = array();
	if ($page === null) {
		return $linkArray;
	}
	preg_match_all("/[\s\n\t]+href\s?=\s?”(.*?)”/i", $page, $href);
	for ($i = 0; $i < count($href[1]); $i++) {
		$link = $href[1][$i];
		if (preg_match("/^http(s)*\:\/\//", $link)) {
			$result = $link;
		} elseif (preg_match("/^\/.+$/", $link)) {
			$result = $base["scheme"] . "://" . $base["host"] . $link;
		} else {
			// echo $base["path"] . “\n”;
			$b = preg_split("/\//", dirname($base["path"]));
			$t = preg_split("/\//", $link);
			foreach ($t as $v) {
				$l = $v === "." ? true : ($v === ".." ? array_pop($b) : array_push($b, $v));
			}
			$result = $base["scheme"] . "://" . $base["host"] . join("/", $b);
		}
		$linkArray[$result] = $result;
	}
	return $linkArray;
}

著者名  @taoka_toshiaki

※この記事は著者が30代前半に書いたものです.

Profile
高知県在住の@taoka_toshiakiです、記事を読んで頂きありがとうございます.
数十年前から息を吸うように日々記事を書いてます.たまに休んだりする日もありますがほぼ毎日投稿を心掛けています😅.
SNSも使っています、フォロー、いいね、シェア宜しくお願い致します🙇.
SNS::@taoka_toshiaki

OFUSEで応援を送る

タグ

, 2, ajax, db, アウト, イコール, うち, エラー, オーバー, クローラー, コード, ここ, こと, コメント, これ, サーバ, サービス, サイボウズ, サンプル, ソース, それ, ため, データ, トイウ, メモリ, ラボ, リンク, , , , , 保存, 再帰, 処理, 出力, 判断, 取得, 可能, 基礎, 外部, 大事, 大体, 巡回, 新規, 検索, 機能, 殆ど, 永遠, 注意, 登録, 要素, 部分, 重要, 階層,