Skip to content

Commit

Permalink
Merge pull request #37 from claustra01/feat/txt2txt
Browse files Browse the repository at this point in the history
テキスト入力でもイベントの登録をできるようにする
  • Loading branch information
claustra01 authored Apr 29, 2024
2 parents 6600400 + 2e83c54 commit f30be0e
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 3 deletions.
104 changes: 103 additions & 1 deletion bot/handler/callback.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,113 @@ func Callback(w http.ResponseWriter, req *http.Request, bot *linebot.LineBot) {
case webhook.MessageEvent:
switch message := e.Message.(type) {
case webhook.TextMessageContent:

refreshToken, err := db.GetRefreshToken(e.Source.(webhook.UserSource).UserId)
if err != nil {
log.Printf("Failed to get refresh token: %+v\n", err)
replyText := fmt.Sprintf("まずはこのリンクからGoogleでログインしてね!!\n%s", liffUrl)
_, err = bot.ReplyMessage(
&linebot.ReplyMessageRequest{
ReplyToken: e.ReplyToken,
Messages: []linebot.MessageInterface{
linebot.NewTextMessage(replyText),
},
},
)
if err != nil {
log.Print(err)
}
}

googleClient := google.NewOAuthClient(context.Background())
accessToken, err := googleClient.GetAccessToken(refreshToken)
if err != nil {
log.Printf("Failed to get access token: %+v\n", err)
replyText := fmt.Sprintf("まずはこのリンクからGoogleでログインしてね!!\n%s", liffUrl)
_, err = bot.ReplyMessage(
&linebot.ReplyMessageRequest{
ReplyToken: e.ReplyToken,
Messages: []linebot.MessageInterface{
linebot.NewTextMessage(replyText),
},
},
)
if err != nil {
log.Print(err)
}
}

gpt, err := openai.NewGpt4Vision(context.Background())
if err != nil {
log.Printf("Failed to create GPT-4 client: %+v\n", err)
_, err = bot.ReplyMessage(
&linebot.ReplyMessageRequest{
ReplyToken: e.ReplyToken,
Messages: []linebot.MessageInterface{
linebot.NewTextMessage("OpenAIのエラーです。"),
},
},
)
if err != nil {
log.Print(err)
}
}

eventJson, err := gpt.Txt2Txt(message.Text)
if err != nil {
log.Printf("Failed to convert text to text: %+v\n", err)
_, err = bot.ReplyMessage(
&linebot.ReplyMessageRequest{
ReplyToken: e.ReplyToken,
Messages: []linebot.MessageInterface{
linebot.NewTextMessage("イベントが見つかりませんでした。"),
},
},
)
if err != nil {
log.Print(err)
}
}

content, err := google.ParseCalendarContent(eventJson)
if err != nil {
log.Printf("Failed to parse calendar content: %+v\n", err)
_, err = bot.ReplyMessage(
&linebot.ReplyMessageRequest{
ReplyToken: e.ReplyToken,
Messages: []linebot.MessageInterface{
linebot.NewTextMessage("イベントが見つかりませんでした。"),
},
},
)
if err != nil {
log.Print(err)
}
}

err = googleClient.RegisterCalenderEvent(content, accessToken)
if err != nil {
log.Printf("Failed to register event: %+v\n", err)
_, err = bot.ReplyMessage(
&linebot.ReplyMessageRequest{
ReplyToken: e.ReplyToken,
Messages: []linebot.MessageInterface{
linebot.NewTextMessage("イベントの登録に失敗しました。"),
},
},
)
if err != nil {
log.Print(err)
}
}

if _, err = bot.ReplyMessage(
&linebot.ReplyMessageRequest{
ReplyToken: e.ReplyToken,
Messages: []linebot.MessageInterface{
linebot.NewTextMessage(message.Text),
linebot.NewTextMessage(
fmt.Sprintf("カレンダーに「%s」の予定を登録したよ!!\n場所: %s\n開始: %s", content.Summary, content.Location, content.Start.Format("2006-01-02 15:04")),
),
},
},
); err != nil {
Expand Down
5 changes: 3 additions & 2 deletions bot/openai/img2txt.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ func (c *Gpt4Vision) Img2Txt(img image.Image, format string) (string, error) {
return "", err
}

now := time.Now()
prompt := fmt.Sprintf(`
この後に送る画像は、カレンダーに登録するようなイベントや予定の内容が含まれるような、写真もしくはスクリーンショットです。
この後に送る画像は、カレンダーに登録するようなイベントや予定の内容が含まれる、写真もしくはスクリーンショットです。
その画像の内容をGoogleカレンダーへ登録するため、以下のような構造体を用意しました。この構造体に展開できるようなJSON文字列を返してください。
ただし、時間については特に明示されない限り日本時間(UTC+9)とします。
また、Typeについては、「event」「work」「reminder」「unknown」のいずれかとし、eventは遊びなどを示すもの、workは仕事や学業に関するもの、reminderは何らかの期限を表すものとします。
Expand All @@ -62,7 +63,7 @@ func (c *Gpt4Vision) Img2Txt(img image.Image, format string) (string, error) {
End time.Time 'json:"end"'
}
'''
`, time.Now().Format("2006"), time.Now().Format("01"), time.Now().Format("02"))
`, now.Format("2006"), now.Format("01"), now.Format("02"))

reqBody := OpenAIRequest{
Model: c.model,
Expand Down
87 changes: 87 additions & 0 deletions bot/openai/txt2txt.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package openai

import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)

func (c *Gpt4Vision) Txt2Txt(eventTxt string) (string, error) {
now := time.Now()
prompt := fmt.Sprintf(`
この後に送るテキストは、カレンダーに登録するようなイベントや予定の内容が含まれる、ユーザーが入力した文字列です。
その画像の内容をGoogleカレンダーへ登録するため、以下のような構造体を用意しました。この構造体に展開できるようなJSON文字列を返してください。
ただし、時間については特に明示されない限り日本時間(UTC+9)とします。
また、Typeについては、「event」「work」「reminder」「unknown」のいずれかとし、eventは遊びなどを示すもの、workは仕事や学業に関するもの、reminderは何らかの期限を表すものとします。
画像がイベントや予定の内容ではない無関係な画像だと判断した場合のみ、unknownを使用してください。
なお、JSON以外の文字列、すなわち画像自体の説明テキストなどの情報は不要です。必ずJSON文字列のみを返してください。
改行やコードブロック等に関連する各種記号も不要です。**絶対に**一行のJSON文字列のみを返してください。
ちなみに、今日は%s年%s月%s日です。
'''go
type CalendarContent struct {
Type string 'json:"type"'
Summary string 'json:"summary"'
Location string 'json:"location"'
Start time.Time 'json:"start"'
End time.Time 'json:"end"'
}
'''
`, now.Format("2006"), now.Format("01"), now.Format("02"))

reqBody := OpenAIRequest{
Model: c.model,
Messages: []RequestMessage{
{
Role: "user",
Content: []RequestMessageContent{
{
Type: "text",
Text: prompt,
},
{
Type: "text",
Text: eventTxt,
},
},
},
},
MaxTokens: 300,
}

reqJson, err := json.Marshal(reqBody)
if err != nil {
return "", err
}

req, err := http.NewRequest(http.MethodPost, c.endpoint.String(), bytes.NewBuffer(reqJson))
if err != nil {
return "", err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+c.apiKey)

resp, err := c.httpClient.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()

respBody, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}

var respData OpenAIResponse
err = json.Unmarshal(respBody, &respData)
if err != nil {
return "", err
}
if len(respData.Choices) != 1 {
return "", fmt.Errorf("Invalid choices in response")
}

return respData.Choices[0].Message.Content, nil
}

0 comments on commit f30be0e

Please sign in to comment.