RSSフィードアグリゲーター実装やレコメンドシステムへの拡張を狙ったものの開発記録
以下は採用技術候補
言語やフレームワークなどを羅列する。
当初はデスクトップアプリを想定していたが、Webアプリのほうが良いかも?
-
フロントエンド
- TypeScript
- React
- emotion
Next.js?
-
SvelteSveltekit
- Chakra UI
-
バックエンド
- Go
- Echo
- Rust
actix-web- axum
- serde
- tokio
- anyhow
- sqlx
- Kotlin?
- Ktor
- Micronaut
- F#
- .net Core
- Go
-
ML系
- Julia
-
DB
SQLite3- MySQL
-
ネイティブApp (超余裕があれば)
- Kotlin Multi Platform?
- Flatter / Dart?
- Swift / Kotlin (超余裕があれば)
-
デザイン
- Figma
- FugJam
該当リポジトリは以下
Webアプリなら、MySQLを使ったほうが良いのでは。
Docker Composeで動くように構成して、最初は自分を含めた開発者が使えれば良くて、その後クラウドに持っていくとか、ネイティブ側の実装をすれば良い気がしてきた。
Docker composeの構成が完了した。荒いけど。
docker build' error: "failed to solve with frontend dockerfile.v0
このエラーで詰まった。
原因は単純で、対象のディレクトリに「Dockerfile」という名前のファイルがないことだった。
GoにおけるMySQL接続のベストプラクティス
今更ながら、ReactのSuspenseについて学んだ
RSSフィードの取得を並列化、画像の読み込みの廃止と絵文字での代替、APIサーバーからの転送データ容量の削減を行い、2秒ほどかかっていたトップページへの遷移と描画を、600ms代まで短縮した。
Nginxでリバースプロキシー
ロードバランサを前段に立てたら、かなり遅くなった。
なので、CSSファイルとJSファイルをキャッシュするようにする。
600ms -> 1.5 ~ 2.2sec
くらい遅くなった
LightHouseのスコアが悪化したので、パフォーマンスチューニングをする。
前:
ビルドしたらパフォーマンスが当然良くなった。
Chakura UI, React DOMなどが大きすぎて、Nginxのgzipエンコーディングを有効にしているのに遅いと思ったら、普通に計測する際にはビルドしてポート4173で実行すれば良いだけの話だった。
上記の記事を参考にして、コマンドを修正。
go test -v -coverprofile=cover_file.out ./...
go tool cover -html=./cover_file.out -o cover_file.html
並列処理が正しく実装できておらず、意味のないものだったため修正した。
仕事の関係で一旦休憩
実世界のプロダクトレベルの品質を意識して、それらの実装を習得することが目的なのが本プロジェクトである。
そのためには、テストファーストでの実装を意識する必要がある。
GItHub Actionsは悪用などをされるとめんどくさいので、とりあえずGoのローカルコミットを行った際にGitのhooksである、pre-commitが機能するようにした。
これを行うことで、Commitする度にGoのユニットテストが実行される。
以下のファイルを「PROJECT_ROOT/.git/hooks/」に設置すると、コミット時に実行されて検証できる。
#!/bin/sh
cd "$(git rev-parse --show-toplevel)"
pwd
cd ./InsightStream/InsightStream/
pwd
export PATH=$PATH:/usr/local/go/bin
go test ./...
ちょっと時間が空いてしまったが再開。
現在はchatGPTが猛威を振るっていて、その「要約」という能力に非常に惹かれている。
そこで、あらかじめRSSフィードを登録しておき、それらを定期的に更新し、要約、関連記事や関連事項ごとにネットワークを生成するようなアプリを作れないか検討中。
どうやっても深層学習は避けられなさそうなので、その辺りも少しずつ勉強する。
DDDを用いた設計について勉強する必要あり。
なぜならプロダクションレベルの品質のコードを目指すことが、本プロジェクトの主目標であり、それには複雑なコードを各責務に応じて分割し整理することが必要だから。
肝となる推薦システムに最近流行りの、というか革新的だと理解しているTransformerをベースとした推薦モデルを作れば、理想に近づくかも?
深層学習とか全くわからない。この記事は参考になりそう。
というよりこの方の書かれている記事の第2弾の方がやりたいことへ近づいている気がする。
しばらく休止。他を優先。
やる気出てきたので、再開。
なんかパフォーマンス落ちていたので、改修入れる
npm run dev
で動かしていたからだった...
前もやった気がする。抜けてる。
記事を要約しておいて、RDBに格納する機能がほしいので、OSSのLLMを使用したAPIサーバーを立てて、そこへ問い合わせる構成にしてみたい。
かつ、なるべく多くのマシンで動くように、メモリ使用量も少ないモデルを選びたい。
Python環境構築にはRyeを試してみる
Rustでごりごりに重い処理をしたいと思ったが、目的と手段が逆転している気がする。
とりあえず、3つずつ各RSSリストで保持している記事リンクを展開して、個別のRSSフィードとして保存するバッチ的なプログラムを実装することにした。
MySQLに限って言えば、strに変換後にむりやりuuidに変換することで解決。
もっとスマートな方法があるはず...
PostgresSQLではuuidのフィーチャーがサポートされているっぽい
時間のバインドはこれ
Memo
Rust
MySQL: Json to struct
現状GoのAPIサーバーから、RustのサービスへRSSフィードリストをフィード単体への分割変換保存が可能になったが、フィードのテーブルに異なるカテゴリーで同URLのRSSフィードが入ってきた場合には、それらは別個のものとしてみなされる。そのため、内容はほぼ同一のRSSフィードが複数存在することになる。
今後はRust側のサービスで、同一のURLをUpsertなどで弾く処理をする処理を実装する。
フィードへ分割した際に増殖するバグがあった。MySQLでUpsertに近いことをするには以下の、「 ON DUPLICATE KEY UPDATE」を用いることで可能らしい。
let _row = sqlx::query(
"INSERT INTO feeds (id, site_url, title, description, feed_url, language, favorites, dt_created, dt_updated)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE feed_url = ?;",
)
Juliaによる共起ネットワークの生成を試みる
この記事を参考にNewsAPIを使用する際のクエリとなる単語を共起ネットワークで生成する
既存のサイトURLでGROUP_BYして、JSONのタイトルリストにマージするクエリ。
SELECT site_url, JSON_ARRAYAGG(title) as titles
FROM feeds
GROUP BY site_url;
重い腰を上げてユーザー認証の方法を検討中
計画。雰囲気で英語を書いている
無限スクロールはコストが大きかったり、考慮事項が多かったりする。
ページネーションも案外難しい。
dekita
make the sh file to automate system activation
取得したフィードをタイムライン表示して、無限スクロールできるようにしたが、同じフィードが表示されることがある。
たとえば、以下の条件の場合
・Zennで「iOS」を購読している
・Zennで「Swift」を購読している
上記の場合には、非常に分野が近しい、というより単一の記事に両方のタグがつくことがある。そのため、前述の同じフィードが複数回表示される現象が発生する。
そこで、ただの雑なアイデアだが、将来的にはフィードの属性をタグ付けして、重複を弾いて表示できるようにしたい。
とりあえず、同一URLのものを弾くような単純な実装で対処した。
MySQLのoffset句について誤解していたので、直した。
LIMITはそのままでOFFSETの数を増やすことで、例えば下記クエリなら、「41〜80」番目の取得ができる。
SELECT * FROM feeds
ORDER BY dt_updated DESC, feed_url DESC
LIMIT 40
OFFSET 80;
このクエリのコストについても検討する。
タイムラインの取得はフィードが常に新しいものから取得するから、以下のインデックスを貼ることで、コストを低減させた。
3300レコードへの実行に対して、365.0であったクエリのTotal Costが、2.37まで下がった。
インデックスを貼ることは慎重に行わなければならないが、最新のフィードを取得することはタイムライン表示では必須であり、また今後も必要とされる可能性があるので、この決定にした。
CREATE INDEX idx_feeds_dt_updated_feed_url ON feeds (dt_updated DESC, feed_url DESC);
過去90日更新のなかったRSSフィードの更新を停止する機能を実装した。
アカウント機能とRSSフィードのフォロワー管理機能実装のために、早急に認証機能を実装する必要があるが、重い腰が上がらない。
Goのtestとそのカバレッジ出力を1行で行うコマンド
go test ./... -coverprofile=coverage.out && go tool cover -html=coverage.out
既存の蓄積されたフィードに対しての検索機能の追加を思いついた。
- .envでの環境変数の取り扱いをやめたい
- ESなどの検索機能の強化をしたい
- LLMを利用した、記事の要約と、加工されたデータを保持し、活用する機能を実装したい
- ユーザー認証機能を実装したい
- それによって、フィードの各機能を実装したい
- お気に入り機能
- ブックマーク機能
- 人気フィードの管理
go install がおかしいときの覚書
- .envでの環境変数の取り扱いをやめたい
OAuthなんもわからん
この記事が参考になりそう。
これも
Goで書いたAPIサーバーを、Rustで書き直してみる。
Go言語 100Tipsを基に、既存のAPIサーバーを書き直す
再掲。作業が滞っていたので。
- .envでの環境変数の取り扱いをやめたい
- ESなどの検索機能の強化をしたい
- LLMを利用した、記事の要約と、加工されたデータを保持し、活用する機能を実装したい
- ユーザー認証機能を実装したい
- それによって、フィードの各機能を実装したい
- お気に入り機能
- ブックマーク機能
- 人気フィードの管理
gRPC FederationによるBFFの責務を削減する試みが気になっている
ローカルLLMと自作のRSSフィード取集ツールを活用して、毎朝や日次での要約やトピックまとめをしてくれるアプリ作れると思った。
Kotlinが初めてレベルの状態で、書いていて楽しかったのでAPIサーバーはKotlinとKtorで作りたい。
自分で使っていて欲しいと思った機能。
全て、/mobileパス配下の機能になる。
- フィルター機能
- フォローリスト管理機能