KyosukeIchikawa commited on
Commit
8df1b32
·
1 Parent(s): cca40b2

refactor: Update file upload and URL extraction tabs for improved clarity and functionality

Browse files
Makefile CHANGED
@@ -165,12 +165,12 @@ pre-commit-run-ci: setup-lint
165
  # Run all tests
166
  test: venv
167
  @echo "Running tests..."
168
- $(VENV_PYTHON) -m pytest tests/ --durations=10 -v
169
 
170
  # Run unit tests only
171
  test-unit: venv
172
  @echo "Running unit tests..."
173
- $(VENV_PYTHON) -m pytest tests/unit/ --durations=10 -v
174
 
175
  # Run E2E tests only
176
  test-e2e: venv
 
165
  # Run all tests
166
  test: venv
167
  @echo "Running tests..."
168
+ $(VENV_PYTHON) -m pytest tests/ --durations=10
169
 
170
  # Run unit tests only
171
  test-unit: venv
172
  @echo "Running unit tests..."
173
+ $(VENV_PYTHON) -m pytest tests/unit/ --durations=10
174
 
175
  # Run E2E tests only
176
  test-e2e: venv
tests/e2e/features/file_upload.feature CHANGED
@@ -6,18 +6,18 @@ Feature: File Upload Functionality
6
  Background:
7
  Given the application is running
8
 
9
- Scenario: Uploading a PDF file with extraction button
10
  Given the user has accessed the application page
11
- When the user uploads a PDF file "sample_paper.pdf"
12
- And the user clicks the "ファイルからテキストを抽出" button
13
  Then text should be extracted
14
  And the file input should be cleared
15
  And the "トーク原稿を生成" button should be active
16
 
17
- Scenario: Uploading a text file with extraction button
18
  Given the user has accessed the application page
19
- When the user uploads a text file "sample_text.txt"
20
- And the user clicks the "ファイルからテキストを抽出" button
21
  Then text should be extracted
22
  And the file input should be cleared
23
  And the "トーク原稿を生成" button should be active
@@ -25,27 +25,28 @@ Feature: File Upload Functionality
25
  Scenario: File extraction appends to existing text with separator
26
  Given the user has accessed the application page
27
  And the user has entered "Existing content" into the extracted text area
28
- When the user uploads a text file "sample_text.txt"
29
- And the user clicks the "ファイルからテキストを抽出" button
30
  Then text should be extracted with source separator
31
  And the extracted text area contains "Existing content"
32
  And the extracted text area contains source information for "sample_text.txt"
 
33
 
34
  Scenario: File extraction without automatic separator
35
  Given the user has accessed the application page
36
  And the user unchecks the "追加時に自動で区切りを挿入" checkbox
37
  And the user has entered "Existing content" into the extracted text area
38
- When the user uploads a text file "sample_text.txt"
39
- And the user clicks the "ファイルからテキストを抽出" button
40
  Then text should be extracted without separator
41
  And the extracted text area contains "Existing content"
 
42
 
43
  Scenario: Multiple file extractions accumulate content
44
  Given the user has accessed the application page
45
- When the user uploads a text file "sample_text.txt"
46
- And the user clicks the "ファイルからテキストを抽出" button
47
  And the user uploads a text file "another_file.txt"
48
- And the user clicks the "ファイルからテキストを抽出" button
49
  Then the extracted text area contains content from both files
50
  And the extracted text area contains source information for "sample_text.txt"
51
  And the extracted text area contains source information for "another_file.txt"
 
6
  Background:
7
  Given the application is running
8
 
9
+ Scenario: Uploading a PDF file in file upload tab
10
  Given the user has accessed the application page
11
+ When the user clicks on the "ファイルアップロード" tab
12
+ And the user uploads a PDF file "sample_paper.pdf"
13
  Then text should be extracted
14
  And the file input should be cleared
15
  And the "トーク原稿を生成" button should be active
16
 
17
+ Scenario: Uploading a text file in file upload tab
18
  Given the user has accessed the application page
19
+ When the user clicks on the "ファイルアップロード" tab
20
+ And the user uploads a text file "sample_text.txt"
21
  Then text should be extracted
22
  And the file input should be cleared
23
  And the "トーク原稿を生成" button should be active
 
25
  Scenario: File extraction appends to existing text with separator
26
  Given the user has accessed the application page
27
  And the user has entered "Existing content" into the extracted text area
28
+ When the user clicks on the "ファイルアップロード" tab
29
+ And the user uploads a text file "sample_text.txt"
30
  Then text should be extracted with source separator
31
  And the extracted text area contains "Existing content"
32
  And the extracted text area contains source information for "sample_text.txt"
33
+ And the file input should be cleared
34
 
35
  Scenario: File extraction without automatic separator
36
  Given the user has accessed the application page
37
  And the user unchecks the "追加時に自動で区切りを挿入" checkbox
38
  And the user has entered "Existing content" into the extracted text area
39
+ When the user clicks on the "ファイルアップロード" tab
40
+ And the user uploads a text file "sample_text.txt"
41
  Then text should be extracted without separator
42
  And the extracted text area contains "Existing content"
43
+ And the file input should be cleared
44
 
45
  Scenario: Multiple file extractions accumulate content
46
  Given the user has accessed the application page
47
+ When the user clicks on the "ファイルアップロード" tab
48
+ And the user uploads a text file "sample_text.txt"
49
  And the user uploads a text file "another_file.txt"
 
50
  Then the extracted text area contains content from both files
51
  And the extracted text area contains source information for "sample_text.txt"
52
  And the extracted text area contains source information for "another_file.txt"
tests/e2e/features/text_management.feature CHANGED
@@ -20,20 +20,26 @@ Feature: Text Management Functionality
20
  When the user checks the "追加時に自動で区切りを挿入" checkbox
21
  Then the automatic separator is enabled
22
 
23
- Scenario: Combining file and URL content with separators
24
  Given the user has accessed the application page
25
- When the user uploads a text file "sample_text.txt"
26
- And the user clicks the "ファイルからテキストを抽出" button
 
 
 
 
 
 
 
27
  And the user enters "https://example.com" into the URL input field
28
  And the user clicks the "URLからテキストを抽出" button
29
- Then the extracted text area contains content from both sources
30
- And the extracted text area contains source information for "sample_text.txt"
31
  And the extracted text area contains source information for "https://example.com"
32
 
33
  Scenario: Manual text input preserved during extractions
34
  Given the user has accessed the application page
35
  And the user has entered "Manual input content" into the extracted text area
36
- When the user uploads a text file "sample_text.txt"
37
- And the user clicks the "ファイルからテキストを抽出" button
38
  Then the extracted text area contains "Manual input content"
39
  And the extracted text area contains content from the file
 
20
  When the user checks the "追加時に自動で区切りを挿入" checkbox
21
  Then the automatic separator is enabled
22
 
23
+ Scenario: File upload tab enables automatic extraction
24
  Given the user has accessed the application page
25
+ When the user clicks on the "ファイルアップロード" tab
26
+ And the user uploads a text file "sample_text.txt"
27
+ Then the extracted text area contains content from the file
28
+ And the extracted text area contains source information for "sample_text.txt"
29
+ And the file input should be cleared
30
+
31
+ Scenario: URL extraction tab requires extraction button
32
+ Given the user has accessed the application page
33
+ When the user clicks on the "Webページ抽出" tab
34
  And the user enters "https://example.com" into the URL input field
35
  And the user clicks the "URLからテキストを抽出" button
36
+ Then the extracted text area contains content from the URL
 
37
  And the extracted text area contains source information for "https://example.com"
38
 
39
  Scenario: Manual text input preserved during extractions
40
  Given the user has accessed the application page
41
  And the user has entered "Manual input content" into the extracted text area
42
+ When the user clicks on the "ファイルアップロード" tab
43
+ And the user uploads a text file "sample_text.txt"
44
  Then the extracted text area contains "Manual input content"
45
  And the extracted text area contains content from the file
tests/e2e/features/url_extraction.feature CHANGED
@@ -9,34 +9,40 @@ Feature: URL extraction functionality
9
 
10
  Scenario: Extract text from a valid URL
11
  Given the user has accessed the application page
12
- When the user enters "https://example.com" into the URL input field
 
13
  And the user clicks the "URLからテキストを抽出" button
14
  Then the extracted text area shows content
15
  And the "トーク原稿を生成" button is enabled
16
 
17
  Scenario: Enter an invalid URL
18
  Given the user has accessed the application page
19
- When the user enters "invalid-url" into the URL input field
 
20
  And the user clicks the "URLからテキストを抽出" button
21
  Then the extracted text area shows an error message
22
  And the "トーク原稿を生成" button remains disabled
23
 
24
  Scenario: Extract text from GitHub README URL
25
  Given the user has accessed the application page
26
- When the user enters a GitHub README URL into the URL input field
 
27
  And the user clicks the "URLからテキストを抽出" button
28
  Then the extracted text area shows GitHub README content
29
 
30
  Scenario: Click extract button with empty URL field
 
31
  Given the user has accessed the application page
32
- When the user leaves the URL input field empty
 
33
  And the user clicks the "URLからテキストを抽出" button
34
  Then the extracted text area shows an error message
35
 
36
  Scenario: URL extraction appends to existing text with separator
37
  Given the user has accessed the application page
38
  And the user has entered "Existing content" into the extracted text area
39
- When the user enters "https://example.com" into the URL input field
 
40
  And the user clicks the "URLからテキストを抽出" button
41
  Then the extracted text area shows content with source separator
42
  And the extracted text area contains "Existing content"
@@ -46,7 +52,8 @@ Feature: URL extraction functionality
46
  Given the user has accessed the application page
47
  And the user unchecks the "追加時に自動で区切りを挿入" checkbox
48
  And the user has entered "Existing content" into the extracted text area
49
- When the user enters "https://example.com" into the URL input field
 
50
  And the user clicks the "URLからテキストを抽出" button
51
  Then the extracted text area shows appended content without separator
52
  And the extracted text area contains "Existing content"
 
9
 
10
  Scenario: Extract text from a valid URL
11
  Given the user has accessed the application page
12
+ When the user clicks on the "Webページ抽出" tab
13
+ And the user enters "https://example.com" into the URL input field
14
  And the user clicks the "URLからテキストを抽出" button
15
  Then the extracted text area shows content
16
  And the "トーク原稿を生成" button is enabled
17
 
18
  Scenario: Enter an invalid URL
19
  Given the user has accessed the application page
20
+ When the user clicks on the "Webページ抽出" tab
21
+ And the user enters "invalid-url" into the URL input field
22
  And the user clicks the "URLからテキストを抽出" button
23
  Then the extracted text area shows an error message
24
  And the "トーク原稿を生成" button remains disabled
25
 
26
  Scenario: Extract text from GitHub README URL
27
  Given the user has accessed the application page
28
+ When the user clicks on the "Webページ抽出" tab
29
+ And the user enters a GitHub README URL into the URL input field
30
  And the user clicks the "URLからテキストを抽出" button
31
  Then the extracted text area shows GitHub README content
32
 
33
  Scenario: Click extract button with empty URL field
34
+ Given the application is running
35
  Given the user has accessed the application page
36
+ When the user clicks on the "Webページ抽出" tab
37
+ And the user leaves the URL input field empty
38
  And the user clicks the "URLからテキストを抽出" button
39
  Then the extracted text area shows an error message
40
 
41
  Scenario: URL extraction appends to existing text with separator
42
  Given the user has accessed the application page
43
  And the user has entered "Existing content" into the extracted text area
44
+ When the user clicks on the "Webページ抽出" tab
45
+ And the user enters "https://example.com" into the URL input field
46
  And the user clicks the "URLからテキストを抽出" button
47
  Then the extracted text area shows content with source separator
48
  And the extracted text area contains "Existing content"
 
52
  Given the user has accessed the application page
53
  And the user unchecks the "追加時に自動で区切りを挿入" checkbox
54
  And the user has entered "Existing content" into the extracted text area
55
+ When the user clicks on the "Webページ抽出" tab
56
+ And the user enters "https://example.com" into the URL input field
57
  And the user clicks the "URLからテキストを抽出" button
58
  Then the extracted text area shows appended content without separator
59
  And the extracted text area contains "Existing content"
tests/e2e/steps/audio_generation_steps.py CHANGED
@@ -16,8 +16,8 @@ def podcast_script_is_generated(page: Page):
16
  page: Playwright page object
17
  """
18
 
19
- # Enter test text in the input field
20
- text_area = page.locator("textarea").first
21
  test_text = """
22
  機械学習の最新研究によれば、大規模言語モデルは自然言語処理タスクにおいて
23
  人間に匹敵する性能を発揮することが可能になっています。
 
16
  page: Playwright page object
17
  """
18
 
19
+ # Enter test text in the extracted text area
20
+ text_area = page.locator('textarea[placeholder*="ファイルをアップロードするか"]')
21
  test_text = """
22
  機械学習の最新研究によれば、大規模言語モデルは自然言語処理タスクにおいて
23
  人間に匹敵する性能を発揮することが可能になっています。
tests/e2e/steps/common_steps.py CHANGED
@@ -74,17 +74,22 @@ def user_has_accessed_application_page(page: Page, app_environment):
74
  heading = page.locator('text="トーク原稿の生成"')
75
  expect(heading).to_be_visible(timeout=10000)
76
 
77
- # Verify file input element is displayed
 
 
 
 
 
 
 
78
  file_input = page.locator('input[type="file"]')
79
  expect(file_input).to_be_attached()
80
 
81
- # Verify URL input element is displayed
82
- url_input = page.locator('textarea[placeholder="https://example.com/page"]')
83
- expect(url_input).to_be_visible()
84
-
85
- # Verify URL extraction button is displayed
86
- extract_button = page.locator('button:has-text("URLからテキストを抽出")')
87
- expect(extract_button).to_be_visible()
88
 
89
  logger.info("All main UI elements are visible and accessible")
90
 
 
74
  heading = page.locator('text="トーク原稿の生成"')
75
  expect(heading).to_be_visible(timeout=10000)
76
 
77
+ # Verify tabs are present
78
+ file_upload_tab = page.get_by_role("tab", name="ファイルアップロード")
79
+ expect(file_upload_tab).to_be_visible()
80
+
81
+ web_extraction_tab = page.get_by_role("tab", name="Webページ抽出")
82
+ expect(web_extraction_tab).to_be_visible()
83
+
84
+ # Verify file input element is available (may be hidden initially due to tabs)
85
  file_input = page.locator('input[type="file"]')
86
  expect(file_input).to_be_attached()
87
 
88
+ # Verify extracted text area is visible
89
+ extracted_text_area = page.locator(
90
+ 'textarea[placeholder*="ファイルをアップロードするか"]'
91
+ )
92
+ expect(extracted_text_area).to_be_visible()
 
 
93
 
94
  logger.info("All main UI elements are visible and accessible")
95
 
tests/e2e/steps/file_upload_steps.py CHANGED
@@ -116,19 +116,62 @@ def user_clicks_file_extract_button(page: Page):
116
  logger.info("File extraction button clicked successfully")
117
 
118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  @then("the file input should be cleared")
120
  def file_input_should_be_cleared(page: Page):
121
- """The file input should be cleared after extraction."""
122
  from tests.utils.logger import test_logger as logger
123
 
124
  logger.info("Checking if file input is cleared")
125
 
126
- file_input = page.locator('input[type="file"]').first
 
 
 
 
 
 
127
 
128
- # Check if the file input has been cleared
129
- # In Gradio, this might show as empty or with a default placeholder
130
- files = file_input.input_value()
131
- assert files == "" or files is None, "File input should be cleared after extraction"
132
 
133
  logger.info("File input is cleared as expected")
134
 
 
116
  logger.info("File extraction button clicked successfully")
117
 
118
 
119
+ @when('the user clicks on the "ファイルアップロード" tab')
120
+ def user_clicks_file_upload_tab(page: Page):
121
+ """The user clicks on the file upload tab."""
122
+ from tests.utils.logger import test_logger as logger
123
+
124
+ logger.info("Clicking file upload tab")
125
+
126
+ # Look for the tab using different possible selectors
127
+ tab_selectors = [
128
+ 'button[role="tab"]:has-text("ファイルアップロード")',
129
+ '.tab-nav button:has-text("ファイルアップロード")',
130
+ 'button:has-text("ファイルアップロード")',
131
+ '*[data-testid*="tab"]:has-text("ファイルアップロード")',
132
+ ]
133
+
134
+ tab_clicked = False
135
+ for selector in tab_selectors:
136
+ tab = page.locator(selector)
137
+ if tab.count() > 0 and tab.first.is_visible():
138
+ tab.first.click()
139
+ tab_clicked = True
140
+ break
141
+
142
+ if not tab_clicked:
143
+ # Fallback: look for any clickable element with the text
144
+ tab = page.get_by_text("ファイルアップロード")
145
+ if tab.count() > 0:
146
+ tab.first.click()
147
+ tab_clicked = True
148
+
149
+ if not tab_clicked:
150
+ raise Exception("File upload tab not found")
151
+
152
+ page.wait_for_timeout(1000)
153
+ logger.info("File upload tab clicked successfully")
154
+
155
+
156
  @then("the file input should be cleared")
157
  def file_input_should_be_cleared(page: Page):
158
+ """The file input should be cleared after upload."""
159
  from tests.utils.logger import test_logger as logger
160
 
161
  logger.info("Checking if file input is cleared")
162
 
163
+ # Look for file input element
164
+ file_input = page.locator('input[type="file"]')
165
+ expect(file_input).to_be_visible()
166
+
167
+ # Check if file input has no value (cleared)
168
+ input_value = file_input.input_value()
169
+ logger.info(f"File input value: '{input_value}'")
170
 
171
+ # File input should be empty after automatic extraction
172
+ assert (
173
+ input_value == "" or input_value is None
174
+ ), "File input should be cleared after extraction"
175
 
176
  logger.info("File input is cleared as expected")
177
 
tests/e2e/steps/script_generation_steps.py CHANGED
@@ -18,8 +18,8 @@ def text_is_entered(page: Page):
18
  page: Playwright page object
19
  """
20
 
21
- # Enter test text in the input field
22
- text_area = page.locator("textarea").first
23
  test_text = """
24
  機械学習の最新研究によれば、大規模言語モデルは自然言語処理タスクにおいて
25
  人間に匹敵する性能を発揮することが可能になっています。
 
18
  page: Playwright page object
19
  """
20
 
21
+ # Enter test text in the extracted text area
22
+ text_area = page.locator('textarea[placeholder*="ファイルをアップロードするか"]')
23
  test_text = """
24
  機械学習の最新研究によれば、大規模言語モデルは自然言語処理タスクにおいて
25
  人間に匹敵する性能を発揮することが可能になっています。
tests/e2e/steps/text_management_steps.py CHANGED
@@ -138,6 +138,76 @@ def user_clicks_clear_text_button(page: Page):
138
  logger.info("Clear text button clicked successfully")
139
 
140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  @when('the user clicks the "ファイルからテキストを抽出" button')
142
  def user_clicks_file_extract_button(page: Page):
143
  """The user clicks the file text extraction button."""
@@ -271,34 +341,21 @@ def text_area_contains_source_info(page: Page, source: str):
271
 
272
  @then("the file input should be cleared")
273
  def file_input_should_be_cleared(page: Page):
274
- """The file input should be cleared after extraction."""
275
  logger.info("Checking if file input is cleared")
276
 
277
- # ファイル入力フィールドを見つける(存在することを確認)
278
  file_input = page.locator('input[type="file"]')
279
- expect(file_input).to_be_attached()
280
-
281
- # Gradioは extraction後に一時的にfile inputを非表示にするため、
282
- # 少し待ってから再度表示されることを確認
283
- page.wait_for_timeout(1000) # 1秒待機
284
-
285
- # ファイル入力が再び利用可能になることを確認
286
- # または非表示状態でもクリアされていることを確認
287
- try:
288
- # まず表示状態を確認
289
- expect(file_input).to_be_visible(timeout=3000)
290
- input_value = file_input.input_value()
291
- logger.info(f"File input value: '{input_value}'")
292
- assert (
293
- input_value == ""
294
- ), f"Expected empty file input, but found: '{input_value}'"
295
- except AssertionError:
296
- # 非表示の場合でも、要素は存在し、クリアされた状態であることを確認
297
- logger.info(
298
- "File input is hidden after extraction, which is expected Gradio behavior"
299
- )
300
- # 代わりに、新しいファイルアップロードが可能であることを確認
301
- expect(file_input).to_be_attached()
302
 
303
  logger.info("File input is cleared as expected")
304
 
@@ -633,6 +690,62 @@ def text_area_contains_existing_content(page: Page):
633
  logger.info("Text area contains 'Existing content' as expected")
634
 
635
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
636
  @then('the extracted text area contains "Manual input content"')
637
  def text_area_contains_manual_input_content(page: Page):
638
  """The extracted text area contains 'Manual input content'."""
 
138
  logger.info("Clear text button clicked successfully")
139
 
140
 
141
+ @when('the user clicks on the "ファイルアップロード" tab')
142
+ def user_clicks_file_upload_tab(page: Page):
143
+ """The user clicks on the file upload tab."""
144
+ logger.info("Clicking file upload tab")
145
+
146
+ # Look for the tab using different possible selectors
147
+ tab_selectors = [
148
+ 'button[role="tab"]:has-text("ファイルアップロード")',
149
+ '.tab-nav button:has-text("ファイルアップロード")',
150
+ 'button:has-text("ファイルアップロード")',
151
+ '*[data-testid*="tab"]:has-text("ファイルアップロード")',
152
+ ]
153
+
154
+ tab_clicked = False
155
+ for selector in tab_selectors:
156
+ tab = page.locator(selector)
157
+ if tab.count() > 0 and tab.first.is_visible():
158
+ tab.first.click()
159
+ tab_clicked = True
160
+ break
161
+
162
+ if not tab_clicked:
163
+ # Fallback: look for any clickable element with the text
164
+ tab = page.get_by_text("ファイルアップロード")
165
+ if tab.count() > 0:
166
+ tab.first.click()
167
+ tab_clicked = True
168
+
169
+ if not tab_clicked:
170
+ raise Exception("File upload tab not found")
171
+
172
+ time.sleep(1)
173
+ logger.info("File upload tab clicked successfully")
174
+
175
+
176
+ @when('the user clicks on the "Webページ抽出" tab')
177
+ def user_clicks_web_extraction_tab(page: Page):
178
+ """The user clicks on the web page extraction tab."""
179
+ logger.info("Clicking web page extraction tab")
180
+
181
+ # Look for the tab using different possible selectors
182
+ tab_selectors = [
183
+ 'button[role="tab"]:has-text("Webページ抽出")',
184
+ '.tab-nav button:has-text("Webページ抽出")',
185
+ 'button:has-text("Webページ抽出")',
186
+ '*[data-testid*="tab"]:has-text("Webページ抽出")',
187
+ ]
188
+
189
+ tab_clicked = False
190
+ for selector in tab_selectors:
191
+ tab = page.locator(selector)
192
+ if tab.count() > 0 and tab.first.is_visible():
193
+ tab.first.click()
194
+ tab_clicked = True
195
+ break
196
+
197
+ if not tab_clicked:
198
+ # Fallback: look for any clickable element with the text
199
+ tab = page.get_by_text("Webページ抽出")
200
+ if tab.count() > 0:
201
+ tab.first.click()
202
+ tab_clicked = True
203
+
204
+ if not tab_clicked:
205
+ raise Exception("Web page extraction tab not found")
206
+
207
+ time.sleep(1)
208
+ logger.info("Web page extraction tab clicked successfully")
209
+
210
+
211
  @when('the user clicks the "ファイルからテキストを抽出" button')
212
  def user_clicks_file_extract_button(page: Page):
213
  """The user clicks the file text extraction button."""
 
341
 
342
  @then("the file input should be cleared")
343
  def file_input_should_be_cleared(page: Page):
344
+ """The file input should be cleared after upload."""
345
  logger.info("Checking if file input is cleared")
346
 
347
+ # Look for file input element
348
  file_input = page.locator('input[type="file"]')
349
+ expect(file_input).to_be_attached() # Check element exists, not visibility
350
+
351
+ # Check if file input has no value (cleared)
352
+ input_value = file_input.input_value()
353
+ logger.info(f"File input value: '{input_value}'")
354
+
355
+ # File input should be empty after automatic extraction
356
+ assert (
357
+ input_value == "" or input_value is None
358
+ ), "File input should be cleared after extraction"
 
 
 
 
 
 
 
 
 
 
 
 
 
359
 
360
  logger.info("File input is cleared as expected")
361
 
 
690
  logger.info("Text area contains 'Existing content' as expected")
691
 
692
 
693
+ @then("the file upload area should be visible")
694
+ def file_upload_area_should_be_visible(page: Page):
695
+ """The file upload area should be visible."""
696
+ logger.info("Checking if file upload area is visible")
697
+
698
+ file_upload = page.locator('input[type="file"]')
699
+ expect(file_upload).to_be_visible()
700
+ logger.info("File upload area is visible")
701
+
702
+
703
+ @then("the file upload area should be hidden")
704
+ def file_upload_area_should_be_hidden(page: Page):
705
+ """The file upload area should be hidden."""
706
+ logger.info("Checking if file upload area is hidden")
707
+
708
+ file_upload = page.locator('input[type="file"]')
709
+ expect(file_upload).to_be_hidden()
710
+ logger.info("File upload area is hidden")
711
+
712
+
713
+ @then("the URL input area should be visible")
714
+ def url_input_area_should_be_visible(page: Page):
715
+ """The URL input area should be visible."""
716
+ logger.info("Checking if URL input area is visible")
717
+
718
+ url_input = page.locator('textarea[placeholder="https://example.com/page"]')
719
+ expect(url_input).to_be_visible()
720
+ logger.info("URL input area is visible")
721
+
722
+
723
+ @then("the URL input area should be hidden")
724
+ def url_input_area_should_be_hidden(page: Page):
725
+ """The URL input area should be hidden."""
726
+ logger.info("Checking if URL input area is hidden")
727
+
728
+ url_input = page.locator('textarea[placeholder="https://example.com/page"]')
729
+ expect(url_input).to_be_hidden()
730
+ logger.info("URL input area is hidden")
731
+
732
+
733
+ @then("the extracted text area contains content from the URL")
734
+ def text_area_contains_url_content(page: Page):
735
+ """The extracted text area contains content from the URL."""
736
+ logger.info("Checking if text area contains URL content")
737
+
738
+ text_area = page.locator(
739
+ 'textarea[placeholder*="ファイルをアップロードするか、URLを入力するか"]'
740
+ )
741
+ expect(text_area).to_be_visible()
742
+
743
+ text_content = text_area.input_value()
744
+ assert len(text_content.strip()) > 0, "Text area should contain URL content"
745
+
746
+ logger.info("Text area contains URL content as expected")
747
+
748
+
749
  @then('the extracted text area contains "Manual input content"')
750
  def text_area_contains_manual_input_content(page: Page):
751
  """The extracted text area contains 'Manual input content'."""
tests/e2e/steps/url_extraction_steps.py CHANGED
@@ -13,6 +13,12 @@ def user_enters_url(page: Page, url: str):
13
  """The user enters a URL into the URL input field."""
14
  logger.info(f"Entering URL: {url}")
15
 
 
 
 
 
 
 
16
  # URL入力フィールドを見つけて入力
17
  url_input = page.locator('textarea[placeholder="https://example.com/page"]')
18
  expect(url_input).to_be_visible()
@@ -29,6 +35,12 @@ def user_enters_github_readme_url(page: Page):
29
  )
30
  logger.info(f"Entering GitHub README URL: {github_readme_url}")
31
 
 
 
 
 
 
 
32
  url_input = page.locator('textarea[placeholder="https://example.com/page"]')
33
  expect(url_input).to_be_visible()
34
  url_input.fill(github_readme_url)
@@ -41,6 +53,12 @@ def user_leaves_url_field_empty(page: Page):
41
  """The user leaves the URL input field empty."""
42
  logger.info("Leaving URL field empty")
43
 
 
 
 
 
 
 
44
  # URL入力フィールドが存在することを確認(何も入力しない)
45
  url_input = page.locator('textarea[placeholder="https://example.com/page"]')
46
  expect(url_input).to_be_visible()
 
13
  """The user enters a URL into the URL input field."""
14
  logger.info(f"Entering URL: {url}")
15
 
16
+ # Make sure the Web page extraction tab is active first
17
+ web_tab = page.get_by_role("tab", name="Webページ抽出")
18
+ if web_tab.is_visible():
19
+ web_tab.click()
20
+ time.sleep(1)
21
+
22
  # URL入力フィールドを見つけて入力
23
  url_input = page.locator('textarea[placeholder="https://example.com/page"]')
24
  expect(url_input).to_be_visible()
 
35
  )
36
  logger.info(f"Entering GitHub README URL: {github_readme_url}")
37
 
38
+ # Make sure the Web page extraction tab is active first
39
+ web_tab = page.get_by_role("tab", name="Webページ抽出")
40
+ if web_tab.is_visible():
41
+ web_tab.click()
42
+ time.sleep(1)
43
+
44
  url_input = page.locator('textarea[placeholder="https://example.com/page"]')
45
  expect(url_input).to_be_visible()
46
  url_input.fill(github_readme_url)
 
53
  """The user leaves the URL input field empty."""
54
  logger.info("Leaving URL field empty")
55
 
56
+ # Make sure the Web page extraction tab is active first
57
+ web_tab = page.get_by_role("tab", name="Webページ抽出")
58
+ if web_tab.is_visible():
59
+ web_tab.click()
60
+ time.sleep(1)
61
+
62
  # URL入力フィールドが存在することを確認(何も入力しない)
63
  url_input = page.locator('textarea[placeholder="https://example.com/page"]')
64
  expect(url_input).to_be_visible()
yomitalk/app.py CHANGED
@@ -335,6 +335,10 @@ class PaperPodcastApp:
335
  session_id = request.session_hash
336
  return UserSession(session_id)
337
 
 
 
 
 
338
  def set_openai_api_key(self, api_key: str, user_session: UserSession):
339
  """Set the OpenAI API key for the specific user session."""
340
  if not api_key or api_key.strip() == "":
@@ -500,6 +504,35 @@ class PaperPodcastApp:
500
  logger.error(error_msg)
501
  return f"Error: {str(e)}", user_session
502
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
503
  def generate_podcast_audio_streaming(
504
  self, text: str, user_session: UserSession, progress=gr.Progress()
505
  ):
@@ -832,25 +865,20 @@ class PaperPodcastApp:
832
  # サポートしているファイル形式の拡張子を取得
833
  supported_extensions = ContentExtractor.SUPPORTED_EXTENSIONS
834
 
835
- # Step 1: Content Extraction (Left: File, Right: URL)
836
- gr.Markdown(
837
- "### 解説対象テキストの作成(ファイル抽出 or Webページ抽出 or テキストを直接編集)"
838
- )
839
- with gr.Row(equal_height=True):
840
- with gr.Column():
841
  file_input = gr.File(
842
  file_types=supported_extensions,
843
  type="filepath",
844
  label=f"ファイルをアップロード({', '.join(supported_extensions)})",
845
  height=120,
846
  )
847
- file_extract_btn = gr.Button(
848
- "ファイルからテキストを抽出",
849
- variant="secondary",
850
- size="lg",
851
- )
852
 
853
- with gr.Column():
854
  url_input = gr.Textbox(
855
  placeholder="https://example.com/page",
856
  label="WebページのURLを入力",
@@ -858,35 +886,29 @@ class PaperPodcastApp:
858
  lines=2,
859
  )
860
  url_extract_btn = gr.Button(
861
- "URLからテキストを抽出", variant="secondary", size="lg"
862
  )
863
 
864
- # Step 2: Text Management Controls
865
  with gr.Row(equal_height=True):
866
- with gr.Column(scale=2, min_width=300):
867
  auto_separator_checkbox = gr.Checkbox(
868
  label="テキスト抽出時に区切りを自動挿入",
869
  value=True,
870
  info="ファイル名やURLの情報を含む区切り線を自動挿入します",
871
  )
872
- with gr.Column(scale=1, min_width=150):
873
- clear_text_btn = gr.ClearButton(
874
- components=[], # 後でextracted_textを設定
875
- value="テキストをクリア",
876
- variant="secondary",
877
- size="lg",
878
  )
879
 
880
- # Step 3: Extracted Text Display
881
  extracted_text = gr.Textbox(
882
  label="解説対象テキスト(トークの元ネタ)",
883
- placeholder="ファイルをアップロードするか、URLを入力するか、直接ここにテキストを貼り付けてください...",
884
  lines=10,
885
  )
886
 
887
- # ClearButtonにextracted_textを設定
888
- clear_text_btn.add([extracted_text])
889
-
890
  with gr.Column(variant="panel"):
891
  gr.Markdown("### プロンプト設定")
892
  document_type_radio = gr.Radio(
@@ -1054,9 +1076,16 @@ class PaperPodcastApp:
1054
  )
1055
 
1056
  # Set up event handlers
1057
- # ファイル抽出ボタンのイベントハンドラー
1058
- file_extract_btn.click(
1059
- fn=self.extract_file_text,
 
 
 
 
 
 
 
1060
  inputs=[
1061
  file_input,
1062
  extracted_text,
 
335
  session_id = request.session_hash
336
  return UserSession(session_id)
337
 
338
+ def clear_extracted_text(self) -> str:
339
+ """Clear the extracted text area."""
340
+ return ""
341
+
342
  def set_openai_api_key(self, api_key: str, user_session: UserSession):
343
  """Set the OpenAI API key for the specific user session."""
344
  if not api_key or api_key.strip() == "":
 
504
  logger.error(error_msg)
505
  return f"Error: {str(e)}", user_session
506
 
507
+ def extract_file_text_auto(
508
+ self,
509
+ file_obj,
510
+ existing_text: str,
511
+ add_separator: bool,
512
+ user_session: UserSession,
513
+ ) -> Tuple[None, str, UserSession]:
514
+ """Extract text from uploaded file automatically (for file upload mode)."""
515
+ if file_obj is None:
516
+ logger.warning("No file provided for automatic extraction")
517
+ return None, existing_text, user_session
518
+
519
+ # Extract new text from file
520
+ new_text = ContentExtractor.extract_text(file_obj)
521
+
522
+ # Get source name from file
523
+ source_name = ContentExtractor.get_source_name_from_file(file_obj)
524
+
525
+ # Append to existing text with source information
526
+ combined_text = ContentExtractor.append_text_with_source(
527
+ existing_text, new_text, source_name, add_separator
528
+ )
529
+
530
+ logger.debug(
531
+ f"Auto file text extraction completed for session {user_session.session_id}"
532
+ )
533
+ # Return None for file_input to clear it after extraction
534
+ return None, combined_text, user_session
535
+
536
  def generate_podcast_audio_streaming(
537
  self, text: str, user_session: UserSession, progress=gr.Progress()
538
  ):
 
865
  # サポートしているファイル形式の拡張子を取得
866
  supported_extensions = ContentExtractor.SUPPORTED_EXTENSIONS
867
 
868
+ # Content extraction tabs
869
+ gr.Markdown("### 解説対象テキストの作成")
870
+
871
+ extraction_tabs = gr.Tabs()
872
+ with extraction_tabs:
873
+ with gr.TabItem("ファイルアップロード"):
874
  file_input = gr.File(
875
  file_types=supported_extensions,
876
  type="filepath",
877
  label=f"ファイルをアップロード({', '.join(supported_extensions)})",
878
  height=120,
879
  )
 
 
 
 
 
880
 
881
+ with gr.TabItem("Webページ抽出"):
882
  url_input = gr.Textbox(
883
  placeholder="https://example.com/page",
884
  label="WebページのURLを入力",
 
886
  lines=2,
887
  )
888
  url_extract_btn = gr.Button(
889
+ "URLからテキストを抽出", variant="primary", size="lg"
890
  )
891
 
892
+ # Auto separator checkbox and clear button in the same row
893
  with gr.Row(equal_height=True):
894
+ with gr.Column(scale=3):
895
  auto_separator_checkbox = gr.Checkbox(
896
  label="テキスト抽出時に区切りを自動挿入",
897
  value=True,
898
  info="ファイル名やURLの情報を含む区切り線を自動挿入します",
899
  )
900
+ with gr.Column(scale=1):
901
+ clear_text_btn = gr.Button(
902
+ "テキストをクリア", variant="secondary", size="sm"
 
 
 
903
  )
904
 
905
+ # Extracted text display
906
  extracted_text = gr.Textbox(
907
  label="解説対象テキスト(トークの元ネタ)",
908
+ placeholder="ファイルをアップロードするか、URLを入力するか、直接ここにテキストを入力してください...",
909
  lines=10,
910
  )
911
 
 
 
 
912
  with gr.Column(variant="panel"):
913
  gr.Markdown("### プロンプト設定")
914
  document_type_radio = gr.Radio(
 
1076
  )
1077
 
1078
  # Set up event handlers
1079
+ # Clear text button
1080
+ clear_text_btn.click(
1081
+ fn=self.clear_extracted_text,
1082
+ outputs=[extracted_text],
1083
+ queue=False,
1084
+ )
1085
+
1086
+ # Auto file extraction when file is uploaded (file upload mode)
1087
+ file_input.change(
1088
+ fn=self.extract_file_text_auto,
1089
  inputs=[
1090
  file_input,
1091
  extracted_text,