cella110n commited on
Commit
ffaba02
1 Parent(s): b5780f2

Upload app_v1_0.R

Browse files
Files changed (1) hide show
  1. old_versions/app_v1_0.R +643 -0
old_versions/app_v1_0.R ADDED
@@ -0,0 +1,643 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ # UIを定義
29
+ ui <- fluidPage(
30
+ # アプリケーションのタイトル
31
+ titlePanel("SDtagEditoR"),
32
+
33
+ uiOutput("notDRmode"),
34
+
35
+ # CSSを追加
36
+ tags$style(type = "text/css",
37
+ "#image_captions { white-space: pre-wrap; }",
38
+ ".shiny-action-button { margin-bottom: 50px; }"
39
+ ),
40
+
41
+ # JavaScript関数を追加
42
+ tags$head(tags$script(HTML("
43
+ function copyToClipboard(text) {
44
+ var dummy = document.createElement('textarea');
45
+ document.body.appendChild(dummy);
46
+ dummy.value = text;
47
+ dummy.select();
48
+ document.execCommand('copy');
49
+ document.body.removeChild(dummy);
50
+ }
51
+ "))),
52
+
53
+ tags$script(HTML("
54
+ function handleCaptionClick(caption, source) {
55
+ var operationModeElement = document.getElementById('notDRmode');
56
+ if (operationModeElement && operationModeElement.innerText === 'FALSE') {
57
+ if (source === 'frequency') {
58
+ Shiny.setInputValue('clicked_caption_frequency', caption, {priority: 'event'});
59
+ } else {
60
+ Shiny.setInputValue('clicked_caption', caption, {priority: 'event'});
61
+ }
62
+ } else {
63
+ copyToClipboard(caption);
64
+ }
65
+ }
66
+ ")),
67
+
68
+
69
+ # ユーザー入力を受け付ける部分
70
+ sidebarLayout(
71
+ sidebarPanel(
72
+ # ディレクトリパスを入力するテキストボックス
73
+ textInput("directory_path", "Enter the directory path:", value = ""),
74
+
75
+ # キャプションデータを読み込むボタン
76
+ actionButton("load_data", "Load Captions Data"),
77
+ tags$br(),
78
+ tags$br(),
79
+
80
+ conditionalPanel(
81
+ condition = "output.dataLoaded",
82
+
83
+ # 画像の選択
84
+ selectInput("selected_image", "Choose an image:", choices = NULL),
85
+
86
+ # 前後の画像に移動するボタン
87
+ actionButton("prev_image", "Prev"),
88
+ actionButton("next_image", "Next"),
89
+ tags$br(),
90
+ tags$br(),
91
+
92
+ # Direct Removerボタンの追加
93
+ actionButton("direct_remover", "Direct Remover"),
94
+ conditionalPanel(
95
+ condition = "output.notDRmode === 'FALSE'", # notDRmodeがfalseの場合
96
+ actionButton("exit_direct_remover", "Exit Direct Remover")
97
+ ),
98
+ tags$br(),
99
+ tags$br(),
100
+ conditionalPanel(
101
+ condition = "output.notDRmode === 'TRUE'",
102
+
103
+ # タブセット
104
+ actionButton("shuffle_single", "Shuffle Order for Current Image"),
105
+ actionButton("shuffle_all", "Shuffle Order for All Images"),
106
+ tags$br(),
107
+ tags$br(),
108
+ numericInput("frequency_threshold", "Frequency Threshold:", value = 5, min = 1),
109
+ actionButton("remove_low_freq", "Remove Low Frequency Captions"),
110
+ tags$br(),
111
+ tags$br(),
112
+ textInput("edit_caption", "Caption to Edit:", ""),
113
+ actionButton("remove_single", "Remove from Single"),
114
+ actionButton("remove_from_all", "Remove from All"),
115
+ # actionButton("edit_interactively", "Edit Interactively"),
116
+ tags$br(),
117
+ actionButton("add_single", "Add to Single"),
118
+ actionButton("add_to_all", "Add to All"),
119
+ tags$br(),
120
+ actionButton("move_caption", "Move Caption"),
121
+ actionButton("move_caption_all", "Move Caption of All"),
122
+ tags$br(),
123
+ actionButton("remove_related_single", "Remove Related from Single"),
124
+ actionButton("remove_related_all", "Remove Related from all"),
125
+ orderInputPanel(),
126
+ textInputPanel(), # ここで関数を呼び出しています
127
+ tags$br(),
128
+ ),
129
+ tags$br(),
130
+ tags$br(),
131
+ actionButton("output_captions", "Output Edited Captions")
132
+ )
133
+ ),
134
+
135
+ mainPanel(
136
+ fluidRow(
137
+ column(6,
138
+ imageOutput("image_display", width = "100%", height = "50%"),
139
+ tags$br(),
140
+ uiOutput("image_captions")
141
+ ),
142
+ column(6,
143
+ verbatimTextOutput("log_output"), # ログの表示領域を追加
144
+ fluidRow( # この行を追加
145
+ column(6, tableOutput("selected_image_captions")),
146
+ column(6, tableOutput("caption_frequency_table_with_links"))
147
+ )
148
+ )
149
+ )
150
+ )
151
+ )
152
+ )
153
+
154
+
155
+ # サーバーロジックを定義
156
+ server <- function(input, output, session) {
157
+ # リアクティブな変数を定義
158
+ directory_path <- reactiveVal()
159
+ captions_data <- reactiveVal()
160
+ caption_frequency <- reactiveVal()
161
+ operation_mode <- reactiveVal("normal")
162
+ log_text <- reactiveVal("Log:\n")
163
+
164
+ # ログを追加する関数
165
+ add_log <- function(message) {
166
+ current_log <- log_text()
167
+ new_log <- paste(current_log, message, "\n")
168
+ log_text(new_log)
169
+ }
170
+
171
+ # ログを更新する関数
172
+ update_log <- function(message) {
173
+ log_text(message)
174
+ }
175
+
176
+ # 読み込み確認
177
+ output$dataLoaded <- reactive({
178
+ !is.null(captions_data())
179
+ })
180
+ outputOptions(output, "dataLoaded", suspendWhenHidden=FALSE)
181
+
182
+ # パネルの表示/非表示を制御するリアクティブ出力
183
+ output$notDRmode <- renderText({
184
+ if (operation_mode() != "direct remove") {
185
+ return("TRUE")
186
+ } else {
187
+ return("FALSE")
188
+ }
189
+ })
190
+ outputOptions(output, "notDRmode", suspendWhenHidden=FALSE)
191
+
192
+ ## Load Data
193
+ observeEvent(input$load_data, {
194
+ update_log("Loading captions data...")
195
+
196
+ # ボタンが押されたときに実行されるコード
197
+ temp_directory_path <- isolate(input$directory_path)
198
+ temp_captions_data <- read_captions_from_directory(temp_directory_path)
199
+ temp_caption_frequency <- get_caption_frequency(temp_captions_data)
200
+
201
+ # リアクティブな変数を更新
202
+ directory_path(temp_directory_path)
203
+ captions_data(temp_captions_data)
204
+ caption_frequency(temp_caption_frequency)
205
+
206
+ # 画像の選択のための選択肢を更新
207
+ unique_images <- unique(captions_data()$image_path)
208
+ updateSelectInput(session, "selected_image", choices = unique_images, selected = unique_images[1])
209
+
210
+ update_log("Captions data loaded.")
211
+ })
212
+
213
+ # 画像の移動
214
+ observeEvent(input$prev_image, {
215
+ current_index <- which(unique(captions_data()$image_path) == input$selected_image)
216
+ if (current_index > 1) {
217
+ updateSelectInput(session, "selected_image", selected = unique(captions_data()$image_path)[current_index - 1])
218
+ }
219
+ })
220
+
221
+ observeEvent(input$next_image, {
222
+ current_index <- which(unique(captions_data()$image_path) == input$selected_image)
223
+ if (current_index < length(unique(captions_data()$image_path))) {
224
+ updateSelectInput(session, "selected_image", selected = unique(captions_data()$image_path)[current_index + 1])
225
+ }
226
+ })
227
+
228
+ # Direct Removerボタンの動作
229
+ observeEvent(input$direct_remover, {
230
+ operation_mode("direct remove")
231
+ update_log("DIRECT REMOVER MODE.")
232
+ })
233
+
234
+ observeEvent(input$exit_direct_remover, {
235
+ operation_mode("normal")
236
+ update_log("Exited Direct Remover mode.")
237
+ })
238
+
239
+ # Shuffle Order for Current Image
240
+ observeEvent(input$shuffle_single, {
241
+ if (operation_mode() != "normal") {
242
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
243
+ return()
244
+ }
245
+
246
+ current_image <- input$selected_image
247
+ updated_data <- captions_data()
248
+ captions_for_current_image <- filter(updated_data, image_path == current_image)
249
+
250
+ # Orderをランダムにする
251
+ new_order <- sample(1:nrow(captions_for_current_image), nrow(captions_for_current_image))
252
+ captions_for_current_image$caption_order <- new_order
253
+
254
+ # データを更新
255
+ updated_data[updated_data$image_path == current_image, ] <- captions_for_current_image
256
+ captions_data(updated_data)
257
+
258
+ update_log("captions of this image was shauffled.")
259
+ })
260
+
261
+ # Shuffle Order for All Images
262
+ observeEvent(input$shuffle_all, {
263
+ if (operation_mode() != "normal") {
264
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
265
+ return()
266
+ }
267
+
268
+ updated_data <- captions_data()
269
+ unique_images <- unique(updated_data$image_path)
270
+
271
+ for (image in unique_images) {
272
+ captions_for_image <- filter(updated_data, image_path == image)
273
+ new_order <- sample(1:nrow(captions_for_image), nrow(captions_for_image))
274
+ captions_for_image$caption_order <- new_order
275
+ updated_data[updated_data$image_path == image, ] <- captions_for_image
276
+ }
277
+
278
+ captions_data(updated_data)
279
+ update_log("captions of all images was shauffled.")
280
+ })
281
+
282
+ # remove_low_freqボタンが押されたときの処理
283
+ observeEvent(input$remove_low_freq, {
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
+ if (!is.null(captions_data())) {
290
+ threshold <- input$frequency_threshold
291
+ updated_data <- remove_low_frequency_captions(captions_data(), threshold)
292
+ captions_data(updated_data)
293
+
294
+ # キャプションの頻度を更新
295
+ updated_caption_frequency <- get_caption_frequency(updated_data)
296
+ caption_frequency(updated_caption_frequency)
297
+ }
298
+
299
+ update_log("Low frequency captions removed.")
300
+ })
301
+
302
+ # Remove Captions from All Images
303
+ observeEvent(input$remove_from_all, {
304
+ if (operation_mode() != "normal") {
305
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
306
+ return()
307
+ }
308
+
309
+ # 指定されたキャプションをすべての画像から削除
310
+ target_caption <- input$edit_caption
311
+ updated_data <- captions_data()
312
+ unique_images <- unique(updated_data$image_path[updated_data$caption == target_caption])
313
+ for (image in unique_images) {
314
+ updated_data <- remove_caption_and_adjust_order(updated_data, image, target_caption)
315
+ }
316
+ captions_data(updated_data)
317
+
318
+ # キャプションの頻度を更新
319
+ updated_caption_frequency <- get_caption_frequency(updated_data)
320
+ caption_frequency(updated_caption_frequency)
321
+
322
+ update_log("Caption removed from all images.")
323
+ })
324
+
325
+ # Remode/Add Single/Add all/move captionの処理
326
+ showOrderInput <- reactiveVal(FALSE)
327
+ showTextInput <- reactiveVal(FALSE)
328
+
329
+ observeEvent(input$remove_single, {
330
+ if (operation_mode() != "normal") {
331
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
332
+ return()
333
+ }
334
+ target_caption <- input$edit_caption
335
+ if (target_caption %in% captions_data()$caption[captions_data()$image_path == input$selected_image]) {
336
+ updated_data <- remove_caption_and_adjust_order(captions_data(), input$selected_image, target_caption)
337
+ captions_data(updated_data)
338
+ update_log("Caption removed from this image.")
339
+ } else {
340
+ showNotification("Error: Caption not found in the selected image.", type = "error")
341
+ }
342
+ })
343
+
344
+ observeEvent(input$add_single, {
345
+ if (operation_mode() != "normal") {
346
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
347
+ return()
348
+ }
349
+ operation_mode("add_single")
350
+ showOrderInput(TRUE)
351
+ update_log("ADD SINGLE MODE.")
352
+ })
353
+
354
+ observeEvent(input$add_to_all, {
355
+ if (operation_mode() != "normal") {
356
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
357
+ return()
358
+ }
359
+ operation_mode("add_all")
360
+ showOrderInput(TRUE)
361
+ update_log("ADD ALL MODE.")
362
+ })
363
+
364
+ observeEvent(input$move_caption, {
365
+ if (operation_mode() != "normal") {
366
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
367
+ return()
368
+ }
369
+ target_caption <- input$edit_caption
370
+ if (target_caption %in% captions_data()$caption[captions_data()$image_path == input$selected_image]) {
371
+ operation_mode("move_caption")
372
+ showOrderInput(TRUE)
373
+ update_log("MOVE CAPTION SINGLE MODE.")
374
+ } else {
375
+ showNotification("Error: Caption not found in the selected image.", type = "error")
376
+ }
377
+ })
378
+
379
+ observeEvent(input$move_caption_all, {
380
+ if (operation_mode() != "normal") {
381
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
382
+ return()
383
+ }
384
+ operation_mode("move_caption_all")
385
+ showOrderInput(TRUE)
386
+ update_log("MOVE CAPTION ALL MODE.")
387
+ })
388
+
389
+ observeEvent(input$remove_related_single, {
390
+ if (operation_mode() != "normal") {
391
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
392
+ return()
393
+ }
394
+ if (!is.null(captions_data())) {
395
+ selected_image_path <- input$selected_image
396
+ target_caption <- input$edit_caption
397
+
398
+ # target_captionが選択された画像に紐づいているか確認
399
+ if (any(captions_data()$image_path == selected_image_path & captions_data()$caption == target_caption)) {
400
+ operation_mode("remove_related_single")
401
+ showTextInput(TRUE)
402
+ update_log("RELATIVE REMOVE SINGLE MODE.")
403
+ } else {
404
+ showNotification("Error: Caption not found in the selected image.", type = "error")
405
+ }
406
+ }
407
+ })
408
+
409
+ observeEvent(input$remove_related_all, {
410
+ if (operation_mode() != "normal") {
411
+ showNotification("Another operation is in progress. Please finish or cancel it first.", type = "error")
412
+ return()
413
+ }
414
+ operation_mode("remove_related_all")
415
+ showTextInput(TRUE)
416
+ update_log("RELATIVE REMOVE ALL MODE.")
417
+ })
418
+
419
+ observeEvent(input$confirm_order, {
420
+ switch(operation_mode(),
421
+ "add_single" = {
422
+ # Add to Singleの処理
423
+ target_caption <- input$edit_caption
424
+ target_order <- max(1, floor(input$target_order))
425
+ updated_data <- add_caption_at_order(captions_data(), input$selected_image, target_caption, target_order)
426
+ captions_data(updated_data)
427
+ update_log("Caption added to target order.")
428
+ },
429
+ "add_all" = {
430
+ target_caption <- input$edit_caption
431
+ target_order <- target_order <- max(1, floor(input$target_order))
432
+ updated_data <- captions_data()
433
+ unique_images <- unique(updated_data$image_path)
434
+ for (image in unique_images) {
435
+ updated_data <- add_caption_at_order(updated_data, image, target_caption, target_order)
436
+ }
437
+ captions_data(updated_data)
438
+ update_log("Caption added to all images.")
439
+ },
440
+ "move_caption" = {
441
+ # Move Captionの処理
442
+ target_caption <- input$edit_caption
443
+ target_order <- target_order <- max(1, floor(input$target_order))
444
+ updated_data <- move_caption_order(captions_data(), input$selected_image, target_caption, target_order)
445
+ captions_data(updated_data)
446
+ update_log("Caption moved to target order.")
447
+ },
448
+ "move_caption_all" = {
449
+ # Move Caption Allの処理
450
+ target_caption <- input$edit_caption
451
+ target_order <- target_order <- max(1, floor(input$target_order))
452
+ updated_data <- captions_data()
453
+ unique_images <- unique(updated_data$image_path[updated_data$caption == target_caption])
454
+ for (image in unique_images) {
455
+ updated_data <- move_caption_order(updated_data, image, target_caption, target_order)
456
+ }
457
+ captions_data(updated_data)
458
+ update_log("Caption moved to target order from all images.")
459
+ }
460
+ )
461
+
462
+ # キャプションの頻度を更新
463
+ updated_caption_frequency <- get_caption_frequency(updated_data)
464
+ caption_frequency(updated_caption_frequency)
465
+ operation_mode("normal")
466
+ showOrderInput(FALSE)
467
+ })
468
+
469
+
470
+ observeEvent(input$confirm_text, {
471
+ switch(operation_mode(),
472
+ "remove_related_single" = {
473
+ # Remove Related captions of Singleの処理
474
+ related_captions <- unlist(strsplit(input$related_captions_input, ","))
475
+ related_captions <- trimws(related_captions) # スペースを削除
476
+ representative_caption <- input$edit_caption
477
+
478
+ updated_data <- remove_related_captions_except_representative(captions_data(), related_captions, representative_caption, input$selected_image)
479
+ captions_data(updated_data)
480
+ update_log("Relative captions were removed from this image.")
481
+ },
482
+ "remove_related_all" = {
483
+ # Remove Related captions from All Imagesの処理
484
+ related_captions <- unlist(strsplit(input$related_captions_input, ","))
485
+ related_captions <- trimws(related_captions) # スペースを削除
486
+ representative_caption <- input$edit_caption
487
+
488
+ updated_data <- captions_data()
489
+ # representative_captionを持つすべての画像を検索
490
+ images_with_rep_caption <- unique(updated_data$image_path[updated_data$caption == representative_caption])
491
+
492
+ for (image_path in images_with_rep_caption) {
493
+ updated_data <- remove_related_captions_except_representative(updated_data, related_captions, representative_caption, image_path)
494
+ }
495
+
496
+ captions_data(updated_data)
497
+ update_log("Relative captions were removed from all images.")
498
+ }
499
+ )
500
+
501
+ # キャプションの頻度を更新
502
+ updated_caption_frequency <- get_caption_frequency(updated_data)
503
+ caption_frequency(updated_caption_frequency)
504
+ operation_mode("normal")
505
+ showTextInput(FALSE)
506
+ })
507
+
508
+
509
+ observeEvent(input$cancel_order, {
510
+ operation_mode("normal")
511
+ showOrderInput(FALSE)
512
+ update_log("Operation was canceled.")
513
+ })
514
+
515
+ observeEvent(input$cancel_text, {
516
+ operation_mode("normal")
517
+ showTextInput(FALSE)
518
+ update_log("Operation was canceled.")
519
+ })
520
+
521
+ output$showOrderInput <- reactive({
522
+ showOrderInput()
523
+ })
524
+
525
+ outputOptions(output, "showOrderInput", suspendWhenHidden=FALSE)
526
+
527
+ output$showTextInput <- reactive({
528
+ showTextInput()
529
+ })
530
+
531
+ outputOptions(output, "showTextInput", suspendWhenHidden=FALSE)
532
+
533
+ # Direct Remove MODE
534
+ observeEvent(input$clicked_caption, {
535
+ target_caption <- input$clicked_caption
536
+
537
+ # 単一画像のキャプションを削除
538
+ updated_data <- remove_caption_and_adjust_order(captions_data(), input$selected_image, target_caption)
539
+ captions_data(updated_data)
540
+
541
+ # キャプションの頻度を更新
542
+ updated_caption_frequency <- get_caption_frequency(updated_data)
543
+ caption_frequency(updated_caption_frequency)
544
+
545
+ update_log("Caption removed from this image.")
546
+ })
547
+
548
+ observeEvent(input$clicked_caption_frequency, {
549
+ target_caption <- input$clicked_caption_frequency
550
+
551
+ # 指定されたキャプションをすべての画像から削除
552
+ updated_data <- captions_data()
553
+ unique_images <- unique(updated_data$image_path[updated_data$caption == target_caption])
554
+ for (image in unique_images) {
555
+ updated_data <- remove_caption_and_adjust_order(updated_data, image, target_caption)
556
+ }
557
+ captions_data(updated_data)
558
+
559
+ # キャプションの頻度を更新
560
+ updated_caption_frequency <- get_caption_frequency(updated_data)
561
+ caption_frequency(updated_caption_frequency)
562
+
563
+ update_log("Caption removed from all images.")
564
+ })
565
+
566
+ # 書き出し
567
+
568
+ observeEvent(input$output_captions, {
569
+ # 出力ディレクトリを確認し、存在しない場合は作成
570
+ if (!dir.exists("./output")) {
571
+ dir.create("./output")
572
+ }
573
+
574
+ # 各画像に対応するキャプションをCSV形式で書き出す
575
+ unique_images <- unique(captions_data()$image_path)
576
+ for (image_path in unique_images) {
577
+ # ファイル名を生成
578
+ image_name <- basename(image_path)
579
+ output_filename <- paste0("./output/", tools::file_path_sans_ext(image_name), ".txt")
580
+
581
+ # キャプションをCSV形式で取得
582
+ csv_captions <- capture.output(print_image_captions_as_csv(captions_data(), image_path))
583
+
584
+ # データをファイルに書き出す
585
+ writeLines(csv_captions, con = output_filename)
586
+ }
587
+
588
+ # ログに書き出し完了のメッセージを追加
589
+ update_log("Captions data written to ./output/ directory.")
590
+ })
591
+
592
+ # レンダリング
593
+ output$image_display <- renderImage({
594
+ list(src = file.path(input$selected_image), alt = "Selected Image", width = "80%")
595
+ }, deleteFile = FALSE)
596
+
597
+ output$image_captions <- renderUI({
598
+ if (!is.null(captions_data())) {
599
+ selected_image_path <- input$selected_image
600
+ captions <- filter(captions_data(), image_path == selected_image_path) %>%
601
+ arrange(caption_order) %>%
602
+ pull(caption)
603
+
604
+ # キャプションをリンク付きのHTMLに変換
605
+ linked_captions <- lapply(captions, function(caption) {
606
+ sprintf("<a href='javascript:void(0);' onclick='handleCaptionClick(\"%s\", \"image\");'>%s</a>", caption, caption)
607
+ })
608
+
609
+ HTML(paste(linked_captions, collapse = ", "))
610
+ }
611
+ })
612
+
613
+ output$log_output <- renderText({
614
+ log_text()
615
+ })
616
+
617
+ output$selected_image_captions <- renderTable({
618
+ if (!is.null(captions_data())) {
619
+ selected_image_path <- input$selected_image
620
+ selected_captions <- filter(captions_data(), image_path == selected_image_path) %>%
621
+ select(caption, caption_order) %>%
622
+ arrange(caption_order)
623
+
624
+ # caption列の各エントリにリンクを追加
625
+ selected_captions$caption <- sprintf("<a href='javascript:void(0);' onclick='handleCaptionClick(\"%s\", \"image\");'>%s</a>", selected_captions$caption, selected_captions$caption)
626
+
627
+ return(selected_captions)
628
+ }
629
+ }, sanitize.text.function = function(x) x) # HTMLをエスケープしないようにする
630
+
631
+ output$caption_frequency_table_with_links <- renderTable({
632
+ if (!is.null(caption_frequency())) {
633
+ freq_data <- caption_frequency()
634
+ freq_data$caption <- sprintf("<a href='javascript:void(0);' onclick='handleCaptionClick(\"%s\", \"frequency\");'>%s</a>", freq_data$caption, freq_data$caption)
635
+ freq_data
636
+ }
637
+ }, sanitize.text.function = function(x) x, rownames = TRUE)
638
+
639
+ }
640
+
641
+ # アプリを実行
642
+ shinyApp(ui = ui, server = server)
643
+