zoom appsのWebhook認証をGo言語で通す

zoom appsでWebhookを使う時は72時間ごとに認証をする必要があります。 Go言語でzoomからのリクエストを処理する実装例です。 package main import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "encoding/json" "log" "net/http" "github.com/gin-gonic/gin" "github.com/ieee0824/getenv" ) type request struct { Payload struct { PlainToken string `json:"plainToken"` } `json:"payload"` EventTs int64 `json:"event_ts"` Event string `json:"event"` } type response struct { PlainToken string `json:"plainToken"` EncryptedToken string `json:"encryptedToken"` } func signHmac(secretKey string, message string) string { mac := hmac.New(sha256.New, []byte(secretKey)) mac.Write([]byte(message)) signature := mac.Sum(nil) ret := hex.EncodeToString(signature) return ret } func handler(ctx *gin.Context) { req := &request{} if err := json....

4月 26, 2023

gopenai-apiでAudio APIを使えるようにしました

昨日 作った OpenAI のAPI wrapperで Audio API を利用できるようにしました。 公式のAPIではDefaultのformatがjsonになっていますがverbose_jsonにしてあります。 vtt, srt はまだ対応させていません。 長いデータを投げてないのでわからないですがQueue/WorkerではなくREST APIなので処理長いとタイムアウトしちゃいそうな気がするけどそのあたりどうなんだろう? 使用例 package main import ( "fmt" "log" "os" "github.com/ieee0824/gopenai-api/api" "github.com/ieee0824/gopenai-api/config" "github.com/samber/lo" ) func main() { a := api.New(&config.Configuration{ ApiKey: lo.ToPtr("API_KEY"), Organization: lo.ToPtr("ORG_ID"), }) f, err := os.Open("test.mp3") if err != nil { log.Fatalln(err) } result, err := a.AudioTranscriptionsV1(&api.AudioTranscriptionsV1Input{ File: f, Model: lo.ToPtr("whisper-1"), Language: lo.ToPtr("ja"), }) if err !...

3月 3, 2023

GoからOpenAIのgpt-3.5-turboを使ってみた

インストール go get github.com/ieee0824/gopenai-api 内容 次のAPIに対応しています. /v1/models /v1/chat/completions chat apiをGPT 3.5 Turboで実行する例 package main import ( "fmt" "github.com/ieee0824/gopenai-api/api" "github.com/ieee0824/gopenai-api/config" "github.com/samber/lo" ) func main() { a := api.New(&config.Configuration{ ApiKey: lo.ToPtr("api-key"), Organization: lo.ToPtr("organization-id"), }) fmt.Println(a.ChatCompletionsV1(&api.ChatCompletionsV1Input{ Model: lo.ToPtr("gpt-3.5-turbo"), Messages: []api.Message{ { Role: "user", Content: "ChatGPT 3.5のapiの使い方を教えてください", }, }, })) } 制作物 gopenai-api

3月 2, 2023

GridレイアウトをCSSを利用したものに変更しました

先日の記事 で画像をGrid表示する話をしましたが、CSSでできるという話を聞いたので置き換えました。 {{ $size := "200x" }} {{ $mobileSize := "100x100"}} <div class="img-view"> {{ range $idx, $elem := .Params }} {{ $res := resources.GetMatch $elem }} {{ $image := $res.Resize $size }} {{ $imageWebP := $res.Resize (printf "%s %s webp q70" $size) }} {{ $mobileImage := $res.Fit $mobileSize}} {{ $mobileImageWebP := $res.Fit (printf "%s %s webp q70" $mobileSize) }} {{ $imageURL := $image.RelPermalink }} {{ $imageWebPURL := $imageWebP....

2月 27, 2023

HugoでGridレイアウトで画像を表示する

HugoでGird配置で画像を表示する shortcodes を実装しました。 先日サンプルで画像を並べたものです。 {{ $size := "200x" }} {{ $mobileSize := "100x100"}} <div class="img-view"> <table> <tbody> {{ range $idx, $elem := .Params }} {{ $res := resources.GetMatch $elem }} {{ $image := $res.Resize $size }} {{ $mobileImage := $res.Fit $mobileSize}} {{ $imageURL := $image.RelPermalink }} {{ $mobileImageURL := $mobileImage.RelPermalink}} {{ if modBool $idx 3 }} <tr> <th> <a href="{{ $res.RelPermalink }}" target="_blank"> <div class="thumb-img"> <img class="pc" src="{{ $imageURL }}" alt="{{ $elem }}" width="{{ $image....

2月 16, 2023

Go 1.20でlambdaで動くプログラムを書いてlocalビルドしてデプロイしたら死んだ

タイトルの通りでプロセスが死にました。 ログはこのような感じです。 2023-02-07T19:39:42.063+09:00 INIT_START Runtime Version: go:1.v13 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 2023-02-07T19:39:42.090+09:00 /var/task/main: /lib64/libc.so.6: version `GLIBC_2.32' not found (required by /var/task/main) 2023-02-07T19:39:42.090+09:00 /var/task/main: /lib64/libc.so.6: version `GLIBC_2.34' not found (required by /var/task/main) 2023-02-07T19:39:42.090+09:00 2023/02/07 10:39:42 exit status 1 glibcの依存で周りで死んでるようですね。 わざわざlambda上にインストールするまでもないのでCGO_ENABLED=0をつけてstatic buildしてしまえば解決です。 $ CGO_ENABLED=0 go build -o main main.go

2月 7, 2023

lambda function URLsのeventをプロキシしてhttp apiに流す

小規模なSlack BotはAWS lambda functions URLsに作ると楽だった の話の続きです. 先日lambda function URLsを利用してhttp apiのような実装を記述する方法を紹介しました. 今回は httpadapter と net/http/httputil を利用してlambda function URLsをリバースプロキシとして動かしてbackend apiに流す方法です. 概略図 実装 普通のリバースプロキシを実装するときはhttputil.ReverseProxyを定義してserverを作って待ち受けるわけですが、 今回の場合はhttputil.ReverseProxyを定義した後httpadapter.NewV2に食わせるだけですね. 次の例はlambdaのeventを受け取ったあとlocalで8080ポートで待ち受けるhttp serverにリクエストを流すproxyの例です. func main() { director := func(req *http.Request) { req.URL.Scheme = "http" req.URL.Host = ":8080" } rp := &httputil.ReverseProxy{Director: director} lambda.Start(httpadapter.NewV2(rp).ProxyWithContext) } すべてlambda関数上で完結させたい場合は func init() などでapiを予め立ち上げた後プロキシしてあげると良いと思います. github.com/ieee0824/le2hp ではそのような実装にしました.

2月 2, 2023

小規模なSlack BotはAWS lambda functions URLsに作ると楽だった

はじめに ここで言う小規模なSlack Botというのは個人で使うようなBotやチームレベルで使う書き捨てレベルのようなもののことです. このような想定のBotを実装するときそこまでちゃんとインフラコストをかけたくありません. 自前でサーバーを用意したとして処理内容と維持管理費用が割に合わないのです. 無料でhttp serverを立ち上げることができるけど定期的にリクエストを送っておかなければプロセスがkillされるようなサービスもあります. そのようなサービスを使う場合定期的にリクエストを送るか立ち上がるまで待った後Botのためのリクエストを送らないと機能しない問題があります. それらの問題を解消するのにlambda functions URLsは要件にあってそうだなぁと思いました. lambda function URLsはlambdaなので課金が発生する時間単位が短いのでたまにしか実行されないようなものでもサーバーを立てて実現するよりお金がかからないです. またlambda function URLsにリクエストを投げるとlambdaのeventが発火して即時にlambda関数が実行されるので待ち時間も発生しません. 一つ問題があるとしたらlambdaのeventとして作成したプログラムから見えるので普段Botをhttpのapiとして実装している場合はhttp requestとlambdaのeventとのギャップを埋める必要があるということです. とはいえそこまで大きな問題にはならないと思います. 特にGo言語の場合は github.com/awslabs/aws-lambda-go-api-proxy/httpadapter を利用するとほとんどhttp serverと同じような実装でアプリケーションを作ることができます. Goでlambda function URLsを使ってリクエスト受ける例 github.com/awslabs/aws-lambda-go-api-proxy/httpadapter を利用した実装例を上げておきます. frameworkを利用しない例 frameworkを利用しない例です. 生のGo言語でhttp serverを実装したことがある人なら雰囲気が解ると思います. package main import ( "io" "net/http" "github.com/aws/aws-lambda-go/lambda" "github.com/awslabs/aws-lambda-go-api-proxy/httpadapter" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "It Works!") }) // lambda function URLsはapi gateway v2と同じeventなのでv2にする必要がある lambda.Start(httpadapter.NewV2(http.DefaultServeMux).ProxyWithContext) } Ginを利用した例 frameworkを利用することもできます. 例えばGinを利用する場合は次のように記述ができます. package main import ( "context" "net/http" "github....

1月 31, 2023

gin製のアプリケーションをランダムに止める

私はGo言語でapiを実装するときしばしばgin-gonic/gin を利用します. マイクロサービスとかでapiが死んだときの検証は結構たいへんです. なのでapiが死んだ状態を再現すべく, gin製のアプリケーションがランダムに 404 とか 503 をランダムに返せるようにするMiddlewareを作成した. alcoholics カオスモンキーとかみたいな利用用途を考えている.

5月 6, 2019

goenvでインストールしたgoのgopathが$HOME/go/$GO_VERSIONになる

たとえばこんな感じ. $ go env | grep GOPATH GOPATH="/Users/johndoe/go/1.12.0" この仕様になったのに気がついたのはgoの1.12が出た頃だ. 別にgoのversionごとにGOPATHを分けたいわけではないので $HOME/go にGOPATHを戻そうと思う. goenv/libexec/goenv-execでGOPATHを制御しているようで, GOENV_DISABLE_GOPATH=1 を指定すると以前のようにGOPATHを $HOME/go にすることができる.

3月 26, 2019