クリスマスイブくらい心穏やかにGithub Issueを解決したい

# GitHub Issue メッセージを優しい言葉に変換するShinyアプリケーション

## はじめに
この記事が公開されるのはクリスマスイブの夜ですけども、そんなことにも目もくれず頑張って作業している方はいらっしゃいますか？

いくらクリスマスイブだろうとも、GithubのIssueはお休みしてくれません。。

GitHubのIssueは、時にはメッセージが厳しく感じられたり、内容が長すぎて要点をつかみにくいことがあります

せめて今日くらいは気持ちよくIssue解決をしたいですよね。

そこで今回はこんなアプリケーションを作ってみました。

---

## 概要
今回紹介するのは、GitHubのIssueメッセージを優しい言葉に変換したり、内容を簡潔にまとめたりすることをサポートするShinyアプリケーションです。このアプリケーションを使うことで、ストレスなくIssueに向き合えます。

具体的にはGemini APIを使用してユーザーがコピペしたIssueメッセージを優しい言葉に変換してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2991110/70dd47a0-1095-82db-3cb8-2a086b1145c4.png)

機能としては以下から選べます。

1. 優しい言葉に変換: 元メッセージに怒りが見えていても、強制的に優しくします。

2. 簡潔にまとめる: Issueの要点のみをまとめてくれます。（相手の感情を消します）

3. Issue内容をGeminiが分析してくれます。


## 実際に使ってみた
こんなことはない気がしますが、試しにめちゃくちゃ怒りのメッセージを用意しました。
```
BROKEN AGAIN!!! FIX THIS IMMEDIATELY!!!! 🤬

This is ABSOLUTELY UNACCEPTABLE!! The search function is COMPLETELY BROKEN for the 5TH TIME THIS MONTH!!! How many times do we need to deal with this same issue?!?!

What's broken (AGAIN):
- Search returns NOTHING
- Console is FULL of errors
- The entire app freezes for 10+ seconds!!!

I've wasted 3 HOURS of my time trying to work around this! This is RIDICULOUS and UNPROFESSIONAL! 

Environment (not that anyone cares since nothing gets fixed anyway):
- Chrome latest version
- Windows 11
- Doesn't matter because IT'S BROKEN EVERYWHERE!!!!!

@developers: DO YOUR JOB!! This is a CRITICAL feature and you keep breaking it!! How do you expect anyone to use this garbage?! Fix it NOW or I'm switching to your competitor's product!!

FIX. THIS. IMMEDIATELY.

Priority: URGENT!!!!!!!!!! (like the last 10 times I reported this)
Labels: bug, critical, fix-now, broken-again, absolutely-unusable

P.S.: And don't you dare close this as "working as intended" again!! 🤬😠😡
```
この地獄のようなメッセージを優しい言葉に変換してもらいます。
shinyアプリ上でコピペをしましょう。
（実際はコピペの際に文章を読んじゃうと悲しくなるくらい厳しい文なので、無心で）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2991110/9d4e88b9-47d5-74f6-0f40-db867b02d99c.png)

なんか文章が返ってきましたね。。
以下が結果です。
```
Subject: Search Function Improvement Opportunity

Hi team,

I'd like to collaborate with you on enhancing the search functionality. I've encountered a situation where the search isn't returning the expected results, which presents a valuable opportunity for us to improve its reliability.

Here are some observations that could help in pinpointing the area for refinement:

* The search currently returns no results.
* The console displays error messages.
* The application experiences a temporary freeze of more than 10 seconds.

I've included my environment details below to aid in the investigation:

* Chrome (latest version)
* Windows 11

I'm confident that by working together, we can identify the root cause and implement a solution to make the search function even better.  This is a critical feature, and improving its stability will greatly benefit everyone.  I'm available to assist in any way I can, such as providing additional information or testing any potential fixes.

Thank you for your time and dedication to making this product the best it can be!

Labels: bug, enhancement, search

Best,
```

非常に優しい言葉になっています。別人でしょうか？
I'd like to collaborate with you on enhancing the search functionality.
とか言っちゃってますね。これならこっちも真剣に向き合う気になります。



### 簡潔にまとめる機能だと？
もはや相手の感情を消し去りましたね。悪くないです。
```
**Title:** Search Functionality Broken - Repeated Issue

**Description:**

The search functionality is currently unavailable, rendering the application unusable. This is a recurring issue, reported multiple times this month.

**Observed Behavior:**

* Search queries return no results.
* Browser console displays numerous errors (please see attached screenshots/error logs).
* Application freezes for over 10 seconds when attempting a search.

**Impact:** This issue blocks critical workflows and significantly impacts productivity.

**Environment:**

* Browser: Chrome (Latest Version)
* Operating System: Windows 11
* Reproducible on multiple platforms (details available upon request).

**Priority:** Critical

**Labels:** bug, critical, search

**Previous related issues:** (List any related issue numbers if applicable)

This issue significantly impacts usability and requires immediate attention.  Please investigate and provide a resolution as soon as possible.
```

## 3. まとめ
いかがでしたでしょうか？
今日くらいはこんな機能に頼ってもいいんじゃないでしょうか？
毎日頑張っている皆さんにとって良いクリスマスプレゼントになりますように。



## 使用したスクリプト

```R
# 必要なパッケージのインストール
if (!require("shiny")) install.packages("shiny")
if (!require("gemini.R")) install.packages("gemini.R")
if (!require("shinyjs")) install.packages("shinyjs")
if (!require("shinythemes")) install.packages("shinythemes")

library(shiny)
library(gemini.R)
library(shinyjs)
library(shinythemes)

# UI定義
ui <- fluidPage(
  theme = shinytheme("flatly"),
  useShinyjs(),
  
  # タイトル
  titlePanel("GitHub Issue Message Converter"),
  
  # サイドバーレイアウト
  sidebarLayout(
    sidebarPanel(
      # Gemini APIキーの入力
      passwordInput("api_key", 
                    "Gemini API Key", 
                    placeholder = "Enter your API key here"),
      
      hr(),
      
      # 出力言語の選択
      radioButtons("output_language", "Output Language:",
                   choices = c("English" = "english",
                               "Japanese" = "japanese"),
                   selected = "english"),
      
      # カスタマイズオプション
      sliderInput("temperature",
                  "Temperature",
                  min = 0,
                  max = 1,
                  value = 0.7,
                  step = 0.1),
      
      selectInput("model",
                  "Model",
                  choices = c("1.5-pro", "1.5-flash"),
                  selected = "1.5-pro"),
      
      hr(),
      
      # 変換スタイルの選択
      radioButtons("style", "Conversion Style:",
                   c("Kind and Empathetic" = "kind",
                     "Professional and Concise" = "professional",
                     "Detailed and Explanatory" = "detailed")),
      
      width = 3
    ),
    
    mainPanel(
      tabsetPanel(
        tabPanel("Convert Message",
                 fluidRow(
                   column(12,
                          textAreaInput("original_text",
                                        "Original Issue Message:",
                                        rows = 10,
                                        width = "100%"),
                          
                          actionButton("convert", "Convert", 
                                       class = "btn-primary",
                                       width = "100%"),
                          
                          br(), br(),
                          
                          div(
                            style = "background-color: #f8f9fa; padding: 15px; border-radius: 5px;",
                            h4("Converted Message:"),
                            verbatimTextOutput("converted_text")
                          ),
                          
                          actionButton("copy", "Copy to Clipboard",
                                       class = "btn-success",
                                       width = "100%")
                   )
                 )
        ),
        
        tabPanel("Help",
                 fluidRow(
                   column(12,
                          h3("How to Use"),
                          tags$ul(
                            tags$li("Enter your Gemini API key"),
                            tags$li("Copy and paste the GitHub issue message you want to convert"),
                            tags$li("Select your preferred output language and conversion style"),
                            tags$li("Adjust parameters if needed"),
                            tags$li("Click 'Convert' to transform your message"),
                            tags$li("Use 'Copy to Clipboard' to copy the converted message")
                          ),
                          
                          h3("Parameters"),
                          tags$ul(
                            tags$li(strong("Temperature: "), "Higher values create more creative output, lower values make output more consistent"),
                            tags$li(strong("Model: "), 
                                    tags$ul(
                                      tags$li("1.5-pro: Higher quality responses but slower"),
                                      tags$li("1.5-flash: Faster responses but slightly lower quality")
                                    )),
                            tags$li(strong("Conversion Style: "),
                                    tags$ul(
                                      tags$li("Kind and Empathetic: Transforms messages into supportive and collaborative communication"),
                                      tags$li("Professional and Concise: Creates clear, technical, and efficient messages"),
                                      tags$li("Detailed and Explanatory: Adds comprehensive context and explanations")
                                    ))
                          )
                   )
                 )
        )
      )
    )
  )
)

# サーバーロジック
server <- function(input, output, session) {
  # スタイルと言語に基づくプロンプトの生成
  get_style_prompt <- function(style, text, language) {
    base_prompt <- switch(style,
                          "kind" = if(language == "english") {
                            "Please rewrite the following GitHub issue content in a very kind and empathetic way. Follow these guidelines:
        1. Rephrase all negative expressions as opportunities for improvement
        2. Avoid mentioning problem frequency or history, focus on solutions instead
        3. Convert emotional expressions into understanding and collaborative language
        4. Maintain technical accuracy while using warm and supportive language
        5. Emphasize team collaboration and positive improvement
        Response should be in English.\n\n"
                          } else {
                            "以下のGitHub issueの内容を、非常に優しく共感的な表現に書き換えてください。以下のガイドラインに従ってください：
        1. すべての否定的な表現を前向きな改善の機会として言い換える
        2. 問題の回数や頻度への言及を避け、代わりに解決策に焦点を当てる
        3. 感情的な表現を、理解と協力を求める表現に変換する
        4. 技術的な正確性を保ちながら、温かみのある言葉遣いを心がける
        5. チームの協力と前向きな改善を強調する
        回答は日本語でお願いします。\n\n"
                          },
                          "professional" = if(language == "english") {
                            "Please rewrite the following GitHub issue content in a professional and concise manner, maintaining technical accuracy. Response should be in English.\n\n"
                          } else {
                            "以下のGitHub issueの内容を、専門的で簡潔な表現に書き換えてください。技術的な正確性を維持してください。回答は日本語でお願いします。\n\n"
                          },
                          "detailed" = if(language == "english") {
                            "Please rewrite the following GitHub issue content with detailed explanations and context. Response should be in English.\n\n"
                          } else {
                            "以下のGitHub issueの内容を、詳細な説明とコンテキストを含めて書き換えてください。回答は日本語でお願いします。\n\n"
                          }
    )
    paste0(base_prompt, text)
  }
  
  # メッセージ変換の実行
  converted <- eventReactive(input$convert, {
    req(input$api_key, input$original_text)
    
    setAPI(input$api_key)
    
    prompt <- get_style_prompt(input$style, input$original_text, input$output_language)
    
    withProgress(
      message = 'Converting...',
      value = 0.5,
      {
        tryCatch({
          response <- gemini(
            prompt = prompt,
            model = input$model,
            temperature = input$temperature
          )
          response
        }, error = function(e) {
          paste("Error occurred:", e$message)
        })
      }
    )
  })
  
  # 変換結果の表示
  output$converted_text <- renderText({
    converted()
  })
  
  # コピーボタンの処理
  observeEvent(input$copy, {
    req(converted())
    writeClipboardString(converted())
    showNotification("Copied to clipboard", type = "message")
  })
}

# アプリの起動
shinyApp(ui = ui, server = server)