cella110n commited on
Commit
310d0b1
·
1 Parent(s): f8dfd01
Files changed (1) hide show
  1. app.R +805 -0
app.R ADDED
@@ -0,0 +1,805 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ rm(list=ls())
2
+
3
+ # 必要なライブラリを読み込む
4
+ library(shiny)
5
+
6
+ # 事前に定義された関数を含むRスクリプトを読み込む
7
+ source("./script.R")
8
+
9
+ # パネル用関数
10
+ orderInputPanel <- function() {
11
+ conditionalPanel(
12
+ condition = "output.showOrderInput",
13
+ numericInput("target_order", "Target Order:", value = 1, min = 1),
14
+ actionButton("confirm_order", "Confirm Order"),
15
+ actionButton("cancel_order", "Cancel")
16
+ )
17
+ }
18
+
19
+ textInputPanel <- function() {
20
+ conditionalPanel(
21
+ condition = "output.showTextInput",
22
+ textInput("related_captions_input", "Enter related captions (comma separated):"),
23
+ actionButton("confirm_text", "Confirm Order"),
24
+ actionButton("cancel_text", "Cancel")
25
+ )
26
+ }
27
+
28
+ # キャプションの並び替え関数
29
+ sort_captions_by_search <- function(data, search_term) {
30
+ if (is.null(search_term) || search_term == "") {
31
+ return(data)
32
+ }
33
+
34
+ # 検索語でのマッチングスコアを計算
35
+ scores <- as.integer(grepl(search_term, data$caption, ignore.case = TRUE))
36
+
37
+ # スコアの降順でデータフレームを並び替え
38
+ return(data[order(-scores), ])
39
+ }
40
+
41
+ # UIを定義
42
+ ui <- fluidPage(
43
+ # アプリケーションのタイトル
44
+ titlePanel("SDtagEditoR"),
45
+
46
+ # CSSを追加
47
+ tags$style(type = "text/css",
48
+ "#image_captions { white-space: pre-wrap; }",
49
+ ".shiny-action-button { margin-bottom: 50px; }"
50
+ ),
51
+
52
+ # JavaScript関数を追加
53
+ tags$head(tags$script(HTML("
54
+ function copyToClipboard(text) {
55
+ var dummy = document.createElement('textarea');
56
+ document.body.appendChild(dummy);
57
+ dummy.value = text;
58
+ dummy.select();
59
+ document.execCommand('copy');
60
+ document.body.removeChild(dummy);
61
+ }
62
+ "))),
63
+
64
+ tags$script(HTML("
65
+ function handleCaptionClick(caption, source) {
66
+ var operationModeElement = document.getElementById('operation_mode_UI');
67
+ if (operationModeElement && operationModeElement.innerText === 'direct remove') {
68
+ if (source === 'frequency') {
69
+ Shiny.setInputValue('clicked_caption_frequency', caption, {priority: 'event'});
70
+ } else {
71
+ Shiny.setInputValue('clicked_caption', caption, {priority: 'event'});
72
+ }
73
+ } else {
74
+ copyToClipboard(caption);
75
+ }
76
+ }
77
+ ")),
78
+
79
+
80
+ # ユーザー入力を受け付ける部分
81
+ sidebarLayout(
82
+ sidebarPanel(
83
+ uiOutput("operation_mode_UI"),
84
+
85
+ # ディレクトリパスを入力するテキストボックス
86
+ textInput("directory_path", "Enter the directory path:", value = ""),
87
+
88
+ # キャプションデータを読み込むボタン
89
+ actionButton("load_data", "Load Captions Data"),
90
+ tags$br(),
91
+ tags$br(),
92
+
93
+ conditionalPanel(
94
+ condition = "output.dataLoaded",
95
+
96
+ # 画像の選択
97
+ selectInput("selected_image", "Choose an image:", choices = NULL),
98
+
99
+ # 前後の画像に移動するボタン
100
+ actionButton("prev_image", "Prev"),
101
+ actionButton("next_image", "Next"),
102
+ tags$br(),
103
+ tags$br(),
104
+
105
+ # Direct Removerボタンの追加
106
+ actionButton("direct_remover", "Direct Remover"),
107
+ conditionalPanel(
108
+ condition = "output.operation_mode_UI === 'direct remove'",
109
+ actionButton("exit_direct_remover", "Exit Direct Remover")
110
+ ),
111
+ tags$br(),
112
+ tags$br(),
113
+ conditionalPanel(
114
+ condition = "output.operation_mode_UI !== 'direct remove'",
115
+
116
+ # タブセット
117
+ actionButton("shuffle_single", "Shuffle Order for Current Image"),
118
+ actionButton("shuffle_all", "Shuffle Order for All Images"),
119
+ tags$br(),
120
+ tags$br(),
121
+ numericInput("frequency_threshold", "Frequency Threshold:", value = 5, min = 1),
122
+ actionButton("remove_low_freq", "Remove Low Frequency Captions"),
123
+ tags$br(),
124
+ tags$br(),
125
+ textInput("edit_caption", "Caption to Edit:", ""),
126
+ actionButton("remove_single", "Remove from Single"),
127
+ actionButton("remove_from_all", "Remove from All"),
128
+ # actionButton("edit_interactively", "Edit Interactively"),
129
+ tags$br(),
130
+ actionButton("add_single", "Add to Single"),
131
+ actionButton("add_to_all", "Add to All"),
132
+ tags$br(),
133
+ actionButton("move_caption", "Move Caption"),
134
+ actionButton("move_caption_all", "Move Caption of All"),
135
+ tags$br(),
136
+ actionButton("remove_related_single", "Remove Related from Single"),
137
+ actionButton("remove_related_all", "Remove Related from all"),
138
+ orderInputPanel(),
139
+ textInputPanel(), # ここで関数を呼び出しています
140
+ tags$br(),
141
+ ),
142
+ tags$br(),
143
+ tags$br(),
144
+ actionButton("restore_captions", "Restore captions"),
145
+ tags$br(),
146
+ actionButton("output_captions", "Output Edited Captions")
147
+ )
148
+ ),
149
+
150
+ mainPanel(
151
+ fluidRow(
152
+ column(6,
153
+ imageOutput("image_display", width = "100%", height = "50%"),
154
+ tags$br(),
155
+ uiOutput("image_captions")
156
+ ),
157
+ column(6,
158
+ verbatimTextOutput("log_output"),
159
+ textInput("search_caption", "Search Caption:", ""),
160
+ actionButton("search_button", "Search"),
161
+ actionButton("clear_search", "Clear"),
162
+ fluidRow(
163
+ column(6, tableOutput("selected_image_captions")),
164
+ column(6, tableOutput("caption_frequency_table_with_links"))
165
+ )
166
+ )
167
+ )
168
+ )
169
+ )
170
+ )
171
+
172
+
173
+ # サーバーロジックを定義
174
+ server <- function(input, output, session) {
175
+ # リアクティブな変数を定義
176
+ directory_path <- reactiveVal()
177
+ captions_data <- reactiveVal()
178
+ caption_frequency <- reactiveVal()
179
+ operation_mode <- reactiveVal("normal")
180
+ log_text <- reactiveVal("Log:\n")
181
+
182
+ ## ログ表示用
183
+ # ログを追加する関数
184
+ add_log <- function(message) {
185
+ current_log <- log_text()
186
+ new_log <- paste(current_log, message, "\n")
187
+ log_text(new_log)
188
+ }
189
+
190
+ # ログを更新する関数
191
+ update_log <- function(message) {
192
+ log_text(message)
193
+ }
194
+
195
+ ## パネルの条件分岐用
196
+ # 読み込み確認
197
+ output$dataLoaded <- reactive({
198
+ !is.null(captions_data())
199
+ })
200
+ outputOptions(output, "dataLoaded", suspendWhenHidden=FALSE)
201
+
202
+ # Operation ModeをUI側に渡す
203
+ output$operation_mode_UI <- renderText({
204
+ return(operation_mode())
205
+ })
206
+ outputOptions(output, "operation_mode_UI", suspendWhenHidden=FALSE)
207
+
208
+ ## 一時保存用
209
+ # 一時保存用のリアクティブ変数を作成
210
+ temp_captions_data <- reactiveVal()
211
+
212
+ # input$selected_imageが変化したときに、現在のcaptions_data()を一時保存
213
+ observeEvent(input$selected_image, {
214
+ temp_captions_data(captions_data())
215
+ }, ignoreNULL = TRUE)
216
+
217
+ ## 検索機能
218
+ searched_caption <- reactiveVal(NULL)
219
+
220
+ observeEvent(input$search_button, {
221
+ searched_caption(input$search_caption)
222
+ })
223
+
224
+ observeEvent(input$clear_search, {
225
+ searched_caption(NULL)
226
+ updateTextInput(session, "search_caption", value = "")
227
+ })
228
+
229
+ ## Load Data
230
+ observeEvent(input$load_data, {
231
+
232
+ # ボタンが押されたときに実行されるコード
233
+ temp_directory_path <- isolate(input$directory_path)
234
+ temp_captions_data <- read_captions_from_directory(temp_directory_path)
235
+
236
+ # エラーが発生した場合、Shiny UI上でエラーメッセージを表示
237
+ if (is.null(temp_captions_data)) {
238
+ showNotification("Error in read_captions_from_directory: No .txt files found in the specified directory.", type = "error")
239
+ return()
240
+ }
241
+
242
+ temp_caption_frequency <- get_caption_frequency(temp_captions_data)
243
+
244
+ # リアクティブな変数を更新
245
+ directory_path(temp_directory_path)
246
+ captions_data(temp_captions_data)
247
+ caption_frequency(temp_caption_frequency)
248
+
249
+ # 画像の選択のための選択肢を更新
250
+ unique_images <- unique(captions_data()$image_path)
251
+ updateSelectInput(session, "selected_image", choices = unique_images, selected = unique_images[1])
252
+
253
+ update_log("Captions data loaded.")
254
+ })
255
+
256
+ # 画像の移動
257
+ observeEvent(input$prev_image, {
258
+ current_index <- which(unique(captions_data()$image_path) == input$selected_image)
259
+ if (current_index > 1) {
260
+ updateSelectInput(session, "selected_image", selected = unique(captions_data()$image_path)[current_index - 1])
261
+ }
262
+ })
263
+
264
+ observeEvent(input$next_image, {
265
+ current_index <- which(unique(captions_data()$image_path) == input$selected_image)
266
+ if (current_index < length(unique(captions_data()$image_path))) {
267
+ updateSelectInput(session, "selected_image", selected = unique(captions_data()$image_path)[current_index + 1])
268
+ }
269
+ })
270
+
271
+ # Direct Removerボタンの動作
272
+ observeEvent(input$direct_remover, {
273
+ operation_mode("direct remove")
274
+ update_log("DIRECT REMOVER MODE.")
275
+ })
276
+
277
+ observeEvent(input$exit_direct_remover, {
278
+ operation_mode("normal")
279
+ update_log("Exited Direct Remover mode.")
280
+ })
281
+
282
+ # Shuffle Order for Current Image
283
+ observeEvent(input$shuffle_single, {
284
+ if (operation_mode() != "normal") {
285
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
286
+ return()
287
+ }
288
+
289
+ current_image <- input$selected_image
290
+ updated_data <- captions_data()
291
+ captions_for_current_image <- filter(updated_data, image_path == current_image)
292
+
293
+ # Orderをランダムにする
294
+ new_order <- sample(1:nrow(captions_for_current_image), nrow(captions_for_current_image))
295
+ captions_for_current_image$caption_order <- new_order
296
+
297
+ # データを更新
298
+ updated_data[updated_data$image_path == current_image, ] <- captions_for_current_image
299
+ captions_data(updated_data)
300
+
301
+ update_log("captions of this image was shauffled.")
302
+ })
303
+
304
+ # Shuffle Order for All Images
305
+ observeEvent(input$shuffle_all, {
306
+ if (operation_mode() != "normal") {
307
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
308
+ return()
309
+ }
310
+
311
+ updated_data <- captions_data()
312
+ unique_images <- unique(updated_data$image_path)
313
+
314
+ for (image in unique_images) {
315
+ captions_for_image <- filter(updated_data, image_path == image)
316
+ new_order <- sample(1:nrow(captions_for_image), nrow(captions_for_image))
317
+ captions_for_image$caption_order <- new_order
318
+ updated_data[updated_data$image_path == image, ] <- captions_for_image
319
+ }
320
+
321
+ captions_data(updated_data)
322
+ update_log("captions of all images was shauffled.")
323
+ })
324
+
325
+ # remove_low_freqボタンが押されたときの処理
326
+ observeEvent(input$remove_low_freq, {
327
+ if (operation_mode() != "normal") {
328
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
329
+ return()
330
+ }
331
+
332
+ if (!is.null(captions_data())) {
333
+ threshold <- input$frequency_threshold
334
+ updated_data <- remove_low_frequency_captions(captions_data(), threshold)
335
+ captions_data(updated_data)
336
+
337
+ # キャプションの頻度を更新
338
+ updated_caption_frequency <- get_caption_frequency(updated_data)
339
+ caption_frequency(updated_caption_frequency)
340
+ }
341
+
342
+ update_log("Low frequency captions removed.")
343
+ })
344
+
345
+ # Remove Captions from All Images
346
+ observeEvent(input$remove_from_all, {
347
+ if (operation_mode() != "normal") {
348
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
349
+ return()
350
+ }
351
+
352
+ # 指定されたキャプションをすべての画像から削除
353
+ target_caption <- input$edit_caption
354
+ updated_data <- captions_data()
355
+ unique_images <- unique(updated_data$image_path[updated_data$caption == target_caption])
356
+ for (image in unique_images) {
357
+ updated_data <- remove_caption_and_adjust_order(updated_data, image, target_caption)
358
+ }
359
+ captions_data(updated_data)
360
+
361
+ # キャプションの頻度を更新
362
+ updated_caption_frequency <- get_caption_frequency(updated_data)
363
+ caption_frequency(updated_caption_frequency)
364
+
365
+ update_log("Caption removed from all images.")
366
+ })
367
+
368
+ # Remode/Add Single/Add all/move captionの処理
369
+ showOrderInput <- reactiveVal(FALSE)
370
+ showTextInput <- reactiveVal(FALSE)
371
+
372
+ observeEvent(input$remove_single, {
373
+ if (operation_mode() != "normal") {
374
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
375
+ return()
376
+ }
377
+ target_caption <- input$edit_caption
378
+ if (target_caption %in% captions_data()$caption[captions_data()$image_path == input$selected_image]) {
379
+ updated_data <- remove_caption_and_adjust_order(captions_data(), input$selected_image, target_caption)
380
+ captions_data(updated_data)
381
+ update_log("Caption removed from this image.")
382
+ } else {
383
+ showNotification("Error: Caption not found in the selected image.", type = "error")
384
+ }
385
+ })
386
+
387
+ observeEvent(input$add_single, {
388
+ if (operation_mode() != "normal") {
389
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
390
+ return()
391
+ }
392
+ operation_mode("add_single")
393
+ showOrderInput(TRUE)
394
+ update_log("ADD SINGLE MODE.")
395
+ })
396
+
397
+ observeEvent(input$add_to_all, {
398
+ if (operation_mode() != "normal") {
399
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
400
+ return()
401
+ }
402
+ operation_mode("add_all")
403
+ showOrderInput(TRUE)
404
+ update_log("ADD ALL MODE.")
405
+ })
406
+
407
+ observeEvent(input$move_caption, {
408
+ if (operation_mode() != "normal") {
409
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
410
+ return()
411
+ }
412
+ target_caption <- input$edit_caption
413
+ if (target_caption %in% captions_data()$caption[captions_data()$image_path == input$selected_image]) {
414
+ operation_mode("move_caption")
415
+ showOrderInput(TRUE)
416
+ update_log("MOVE CAPTION SINGLE MODE.")
417
+ } else {
418
+ showNotification("Error: Caption not found in the selected image.", type = "error")
419
+ }
420
+ })
421
+
422
+ observeEvent(input$move_caption_all, {
423
+ if (operation_mode() != "normal") {
424
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
425
+ return()
426
+ }
427
+ operation_mode("move_caption_all")
428
+ showOrderInput(TRUE)
429
+ update_log("MOVE CAPTION ALL MODE.")
430
+ })
431
+
432
+ observeEvent(input$remove_related_single, {
433
+ if (operation_mode() != "normal") {
434
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
435
+ return()
436
+ }
437
+ if (!is.null(captions_data())) {
438
+ selected_image_path <- input$selected_image
439
+ target_caption <- input$edit_caption
440
+
441
+ # target_captionが選択された画像に紐づいているか確認
442
+ if (any(captions_data()$image_path == selected_image_path & captions_data()$caption == target_caption)) {
443
+ operation_mode("remove_related_single")
444
+ showTextInput(TRUE)
445
+ update_log("RELATIVE REMOVE SINGLE MODE.")
446
+ } else {
447
+ showNotification("Error: Caption not found in the selected image.", type = "error")
448
+ }
449
+ }
450
+ })
451
+
452
+ observeEvent(input$remove_related_all, {
453
+ if (operation_mode() != "normal") {
454
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
455
+ return()
456
+ }
457
+ operation_mode("remove_related_all")
458
+ showTextInput(TRUE)
459
+ update_log("RELATIVE REMOVE ALL MODE.")
460
+ })
461
+
462
+ observeEvent(input$confirm_order, {
463
+ switch(operation_mode(),
464
+ "add_single" = {
465
+ # Add to Singleの処理
466
+ target_caption <- input$edit_caption
467
+ target_order <- max(1, floor(input$target_order))
468
+ updated_data <- add_caption_at_order(captions_data(), input$selected_image, target_caption, target_order)
469
+ captions_data(updated_data)
470
+ update_log("Caption added to target order.")
471
+ },
472
+ "add_all" = {
473
+ target_caption <- input$edit_caption
474
+ target_order <- target_order <- max(1, floor(input$target_order))
475
+ updated_data <- captions_data()
476
+ unique_images <- unique(updated_data$image_path)
477
+ for (image in unique_images) {
478
+ updated_data <- add_caption_at_order(updated_data, image, target_caption, target_order)
479
+ }
480
+ captions_data(updated_data)
481
+ update_log("Caption added to all images.")
482
+ },
483
+ "move_caption" = {
484
+ # Move Captionの処理
485
+ target_caption <- input$edit_caption
486
+ target_order <- target_order <- max(1, floor(input$target_order))
487
+ updated_data <- move_caption_order(captions_data(), input$selected_image, target_caption, target_order)
488
+ captions_data(updated_data)
489
+ update_log("Caption moved to target order.")
490
+ },
491
+ "move_caption_all" = {
492
+ # Move Caption Allの処理
493
+ target_caption <- input$edit_caption
494
+ target_order <- target_order <- max(1, floor(input$target_order))
495
+ updated_data <- captions_data()
496
+ unique_images <- unique(updated_data$image_path[updated_data$caption == target_caption])
497
+ for (image in unique_images) {
498
+ updated_data <- move_caption_order(updated_data, image, target_caption, target_order)
499
+ }
500
+ captions_data(updated_data)
501
+ update_log("Caption moved to target order from all images.")
502
+ }
503
+ )
504
+
505
+ # キャプションの頻度を更新
506
+ updated_caption_frequency <- get_caption_frequency(updated_data)
507
+ caption_frequency(updated_caption_frequency)
508
+ operation_mode("normal")
509
+ showOrderInput(FALSE)
510
+ })
511
+
512
+
513
+ observeEvent(input$confirm_text, {
514
+ switch(operation_mode(),
515
+ "remove_related_single" = {
516
+ # Remove Related captions of Singleの処理
517
+ related_captions <- unlist(strsplit(input$related_captions_input, ","))
518
+ related_captions <- trimws(related_captions) # スペースを削除
519
+ representative_caption <- input$edit_caption
520
+
521
+ updated_data <- remove_related_captions_except_representative(captions_data(), related_captions, representative_caption, input$selected_image)
522
+ captions_data(updated_data)
523
+ update_log("Relative captions were removed from this image.")
524
+ },
525
+ "remove_related_all" = {
526
+ # Remove Related captions from All Imagesの処理
527
+ related_captions <- unlist(strsplit(input$related_captions_input, ","))
528
+ related_captions <- trimws(related_captions) # スペースを削除
529
+ representative_caption <- input$edit_caption
530
+
531
+ updated_data <- captions_data()
532
+ # representative_captionを持つすべての画像を検索
533
+ images_with_rep_caption <- unique(updated_data$image_path[updated_data$caption == representative_caption])
534
+
535
+ for (image_path in images_with_rep_caption) {
536
+ updated_data <- remove_related_captions_except_representative(updated_data, related_captions, representative_caption, image_path)
537
+ }
538
+
539
+ captions_data(updated_data)
540
+ update_log("Relative captions were removed from all images.")
541
+ }
542
+ )
543
+
544
+ # キャプションの頻度を更新
545
+ updated_caption_frequency <- get_caption_frequency(updated_data)
546
+ caption_frequency(updated_caption_frequency)
547
+ operation_mode("normal")
548
+ showTextInput(FALSE)
549
+ })
550
+
551
+
552
+ observeEvent(input$cancel_order, {
553
+ operation_mode("normal")
554
+ showOrderInput(FALSE)
555
+ update_log("Operation was canceled.")
556
+ })
557
+
558
+ observeEvent(input$cancel_text, {
559
+ operation_mode("normal")
560
+ showTextInput(FALSE)
561
+ update_log("Operation was canceled.")
562
+ })
563
+
564
+ output$showOrderInput <- reactive({
565
+ showOrderInput()
566
+ })
567
+
568
+ outputOptions(output, "showOrderInput", suspendWhenHidden=FALSE)
569
+
570
+ output$showTextInput <- reactive({
571
+ showTextInput()
572
+ })
573
+
574
+ outputOptions(output, "showTextInput", suspendWhenHidden=FALSE)
575
+
576
+ # Direct Remove MODE
577
+ observeEvent(input$clicked_caption, {
578
+ target_caption <- input$clicked_caption
579
+
580
+ # 単一画像のキャプションを削除
581
+ updated_data <- remove_caption_and_adjust_order(captions_data(), input$selected_image, target_caption)
582
+ captions_data(updated_data)
583
+
584
+ # キャプションの頻度を更新
585
+ updated_caption_frequency <- get_caption_frequency(updated_data)
586
+ caption_frequency(updated_caption_frequency)
587
+
588
+ update_log("Caption removed from this image.")
589
+ })
590
+
591
+ observeEvent(input$clicked_caption_frequency, {
592
+ target_caption <- input$clicked_caption_frequency
593
+
594
+ # 指定されたキャプションをすべての画像から削除
595
+ updated_data <- captions_data()
596
+ unique_images <- unique(updated_data$image_path[updated_data$caption == target_caption])
597
+ for (image in unique_images) {
598
+ updated_data <- remove_caption_and_adjust_order(updated_data, image, target_caption)
599
+ }
600
+ captions_data(updated_data)
601
+
602
+ # キャプションの頻度を更新
603
+ updated_caption_frequency <- get_caption_frequency(updated_data)
604
+ caption_frequency(updated_caption_frequency)
605
+
606
+ update_log("Caption removed from all images.")
607
+ })
608
+
609
+ ## Restore Captions
610
+ # 3. 「Restore captions」ボタンがクリックされたときの処理
611
+ # observeEvent(input$restore_captions, {
612
+ # # 確認のダイアログを表示
613
+ # if (modalDialog(
614
+ # title = "Confirmation",
615
+ # "Are you sure you want to restore the captions?",
616
+ # footer = tagList(
617
+ # modalButton("Cancel"),
618
+ # actionButton("proceed_restore", "Yes, Restore")
619
+ # )
620
+ # )) {
621
+ # # 復元処理
622
+ # observeEvent(input$proceed_restore, {
623
+ # captions_data(temp_captions_data())
624
+ # removeModal()
625
+ # })
626
+ # }
627
+ # })
628
+
629
+ # yes/no選択dialog
630
+ show_confirmation_dialog <- function() {
631
+ showModal(
632
+ modalDialog(
633
+ title = "Confirmation",
634
+ "Are you sure?",
635
+ footer = tagList(
636
+ modalButton("No"),
637
+ actionButton("yes_button", "Yes")
638
+ )
639
+ )
640
+ )
641
+ }
642
+
643
+ # リアクティブな変数を作成して、ユーザーの選択を保存
644
+ user_choice <- reactiveVal(NULL)
645
+
646
+ # ユーザーの選択に基づいてリアクティブな値を更新
647
+ observeEvent(input$yes_button, {
648
+ user_choice("Yes")
649
+ removeModal()
650
+ })
651
+
652
+ ## Restore captions: calling confirmation dialog
653
+ observeEvent(input$restore_captions, {
654
+ show_confirmation_dialog()
655
+ observeEvent(user_choice(), {
656
+ if (user_choice() == "Yes") {
657
+ captions_data(temp_captions_data())
658
+ }
659
+ # リアクティブな変数をリセット
660
+ user_choice(NULL)
661
+ }, ignoreNULL = TRUE)
662
+ })
663
+
664
+ ## 書き出し
665
+ observeEvent(input$output_captions, {
666
+ show_confirmation_dialog()
667
+
668
+ observeEvent(user_choice(), {
669
+ if (user_choice() == "Yes") {
670
+
671
+ # 出力ディレクトリを確認し、存在しない場合は作成
672
+ if (!dir.exists("./output")) {
673
+ dir.create("./output")
674
+ }
675
+
676
+ # 各画像に対応するキャプションをCSV形式で書き出す
677
+ unique_images <- unique(captions_data()$image_path)
678
+ for (image_path in unique_images) {
679
+ # ファイル名を生成
680
+ image_name <- basename(image_path)
681
+ output_filename <- paste0("./output/", tools::file_path_sans_ext(image_name), ".txt")
682
+
683
+ # キャプションをCSV形式で取得
684
+ csv_captions <- capture.output(print_image_captions_as_csv(captions_data(), image_path))
685
+
686
+ # データをファイルに書き出す
687
+ writeLines(csv_captions, con = output_filename)
688
+ }
689
+
690
+ # ログに書き出し完了のメッセージを追加
691
+ update_log("Captions data written to ./output/ directory.")
692
+
693
+ }
694
+ # リアクティブな変数をリセット
695
+ user_choice(NULL)
696
+ }, ignoreNULL = TRUE)
697
+ })
698
+
699
+ # レンダリング
700
+ output$image_display <- renderImage({
701
+ list(src = file.path(input$selected_image), alt = "Selected Image", width = "80%")
702
+ }, deleteFile = FALSE)
703
+
704
+ # output$image_captions <- renderUI({
705
+ # if (!is.null(captions_data())) {
706
+ # selected_image_path <- input$selected_image
707
+ # captions <- filter(captions_data(), image_path == selected_image_path) %>%
708
+ # arrange(caption_order) %>%
709
+ # pull(caption)
710
+ #
711
+ # # キャプションをリンク付きのHTMLに変換
712
+ # linked_captions <- lapply(captions, function(caption) {
713
+ # sprintf("<a href='javascript:void(0);' onclick='handleCaptionClick(\"%s\", \"image\");'>%s</a>", caption, caption)
714
+ # })
715
+ #
716
+ # HTML(paste(linked_captions, collapse = ", "))
717
+ # }
718
+ # })
719
+ #
720
+ output$image_captions <- renderUI({
721
+ if (!is.null(captions_data())) {
722
+ selected_image_path <- input$selected_image
723
+ captions <- filter(captions_data(), image_path == selected_image_path) %>%
724
+ arrange(caption_order) %>%
725
+ pull(caption)
726
+
727
+ # キャプションをリンク付きのHTMLに変換
728
+ linked_captions <- lapply(captions, function(caption) {
729
+ if (!is.null(searched_caption()) && grepl(searched_caption(), caption)) {
730
+ sprintf("<a href='javascript:void(0);' onclick='handleCaptionClick(\"%s\");' style='background-color: yellow;'>%s</a>", caption, caption)
731
+ } else {
732
+ sprintf("<a href='javascript:void(0);' onclick='handleCaptionClick(\"%s\");'>%s</a>", caption, caption)
733
+ }
734
+ })
735
+
736
+ HTML(paste(linked_captions, collapse = ", "))
737
+ }
738
+ })
739
+
740
+ output$log_output <- renderText({
741
+ log_text()
742
+ })
743
+
744
+ output$selected_image_captions <- renderTable({
745
+ if (!is.null(captions_data())) {
746
+ selected_image_path <- input$selected_image
747
+ selected_captions <- filter(captions_data(), image_path == selected_image_path) %>%
748
+ select(caption, caption_order) %>%
749
+ arrange(caption_order)
750
+
751
+ # キャプションの並び替え
752
+ sorted_captions <- sort_captions_by_search(selected_captions, searched_caption())
753
+
754
+ # caption列の各エントリにリンクを追加
755
+ sorted_captions$caption <- sprintf("<a href='javascript:void(0);' onclick='handleCaptionClick(\"%s\", \"image\");'>%s</a>", sorted_captions$caption, sorted_captions$caption)
756
+
757
+ return(sorted_captions)
758
+ }
759
+ }, sanitize.text.function = function(x) x)
760
+
761
+ output$caption_frequency_table_with_links <- renderTable({
762
+ if (!is.null(caption_frequency())) {
763
+ freq_data <- caption_frequency()
764
+
765
+ # キャプションの並び替え
766
+ sorted_freq_data <- sort_captions_by_search(freq_data, searched_caption())
767
+
768
+ # caption列の各エントリにリンクを追加
769
+ sorted_freq_data$caption <- sprintf("<a href='javascript:void(0);' onclick='handleCaptionClick(\"%s\", \"frequency\");'>%s</a>", sorted_freq_data$caption, sorted_freq_data$caption)
770
+
771
+ return(sorted_freq_data)
772
+ }
773
+ }, sanitize.text.function = function(x) x, rownames = TRUE)
774
+
775
+
776
+
777
+
778
+
779
+ # output$selected_image_captions <- renderTable({
780
+ # if (!is.null(captions_data())) {
781
+ # selected_image_path <- input$selected_image
782
+ # selected_captions <- filter(captions_data(), image_path == selected_image_path) %>%
783
+ # select(caption, caption_order) %>%
784
+ # arrange(caption_order)
785
+ #
786
+ # # caption列の各エントリにリンクを追加
787
+ # selected_captions$caption <- sprintf("<a href='javascript:void(0);' onclick='handleCaptionClick(\"%s\", \"image\");'>%s</a>", selected_captions$caption, selected_captions$caption)
788
+ #
789
+ # return(selected_captions)
790
+ # }
791
+ # }, sanitize.text.function = function(x) x) # HTMLをエスケープしないようにする
792
+ #
793
+ # output$caption_frequency_table_with_links <- renderTable({
794
+ # if (!is.null(caption_frequency())) {
795
+ # freq_data <- caption_frequency()
796
+ # freq_data$caption <- sprintf("<a href='javascript:void(0);' onclick='handleCaptionClick(\"%s\", \"frequency\");'>%s</a>", freq_data$caption, freq_data$caption)
797
+ # freq_data
798
+ # }
799
+ # }, sanitize.text.function = function(x) x, rownames = TRUE)
800
+
801
+ }
802
+
803
+ # アプリを実行
804
+ shinyApp(ui = ui, server = server)
805
+