Spaces:
Running
Running
yuki.tsutsumi
commited on
Commit
•
31ce9a1
1
Parent(s):
2d2cc52
[update]申請履歴のCSVのカラムを柔軟な形にして、動作確認までした。
Browse files- log_config.json +5 -0
- main.py +4 -4
- requirements.txt +1 -0
- src/aws/s3.py +50 -10
- src/database.py +0 -64
- src/forms/change_request.py +168 -21
- src/forms/change_request_history.py +46 -0
- src/forms/database_check.py +0 -19
log_config.json
CHANGED
@@ -39,6 +39,11 @@
|
|
39 |
"handlers": ["consoleHandler", "fileHandler"],
|
40 |
"propagate": false
|
41 |
},
|
|
|
|
|
|
|
|
|
|
|
42 |
"src.utils": {
|
43 |
"level": "DEBUG",
|
44 |
"handlers": ["consoleHandler", "fileHandler"],
|
|
|
39 |
"handlers": ["consoleHandler", "fileHandler"],
|
40 |
"propagate": false
|
41 |
},
|
42 |
+
"src.aws.s3": {
|
43 |
+
"level": "DEBUG",
|
44 |
+
"handlers": ["consoleHandler", "fileHandler"],
|
45 |
+
"propagate": false
|
46 |
+
},
|
47 |
"src.utils": {
|
48 |
"level": "DEBUG",
|
49 |
"handlers": ["consoleHandler", "fileHandler"],
|
main.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
import streamlit as st
|
2 |
|
3 |
from src.forms.change_request import change_request_form
|
4 |
-
from src.forms.
|
5 |
from src.forms.deviation_occurrence_report import deviation_occurrence_report_form
|
6 |
from src.forms.deviation_report import deviation_report_form
|
7 |
|
@@ -9,7 +9,7 @@ pages = {
|
|
9 |
"変更申請書": change_request_form,
|
10 |
"逸脱発生報告書": deviation_occurrence_report_form,
|
11 |
"逸脱報告書": deviation_report_form,
|
12 |
-
"
|
13 |
}
|
14 |
|
15 |
selected_page = st.sidebar.selectbox(
|
@@ -22,5 +22,5 @@ match selected_page:
|
|
22 |
pages["逸脱発生報告書"]()
|
23 |
case "逸脱報告書":
|
24 |
pages["逸脱報告書"]()
|
25 |
-
case "
|
26 |
-
pages["
|
|
|
1 |
import streamlit as st
|
2 |
|
3 |
from src.forms.change_request import change_request_form
|
4 |
+
from src.forms.change_request_history import change_request_history
|
5 |
from src.forms.deviation_occurrence_report import deviation_occurrence_report_form
|
6 |
from src.forms.deviation_report import deviation_report_form
|
7 |
|
|
|
9 |
"変更申請書": change_request_form,
|
10 |
"逸脱発生報告書": deviation_occurrence_report_form,
|
11 |
"逸脱報告書": deviation_report_form,
|
12 |
+
"変更申請履歴": change_request_history,
|
13 |
}
|
14 |
|
15 |
selected_page = st.sidebar.selectbox(
|
|
|
22 |
pages["逸脱発生報告書"]()
|
23 |
case "逸脱報告書":
|
24 |
pages["逸脱報告書"]()
|
25 |
+
case "変更申請履歴":
|
26 |
+
pages["変更申請履歴"]()
|
requirements.txt
CHANGED
@@ -12,3 +12,4 @@ pandas == 2.2.2
|
|
12 |
boto3 == 1.34.131
|
13 |
pandas-stubs == 2.2.2.240603
|
14 |
boto3-stubs == 1.34.149
|
|
|
|
12 |
boto3 == 1.34.131
|
13 |
pandas-stubs == 2.2.2.240603
|
14 |
boto3-stubs == 1.34.149
|
15 |
+
botocore == 1.34.155
|
src/aws/s3.py
CHANGED
@@ -2,22 +2,62 @@ from io import StringIO
|
|
2 |
|
3 |
import boto3
|
4 |
import pandas as pd
|
|
|
|
|
5 |
|
6 |
-
|
7 |
|
|
|
8 |
|
9 |
-
|
10 |
-
|
11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
) -> pd.DataFrame:
|
13 |
-
|
14 |
-
|
15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
|
17 |
|
18 |
-
def
|
19 |
-
data: pd.DataFrame, bucket_name: str, file_name: str
|
20 |
) -> None:
|
|
|
|
|
21 |
csv_buffer = StringIO()
|
22 |
data.to_csv(csv_buffer, index=False)
|
23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
import boto3
|
4 |
import pandas as pd
|
5 |
+
from botocore.client import BaseClient
|
6 |
+
from botocore.exceptions import NoCredentialsError, PartialCredentialsError
|
7 |
|
8 |
+
from src.utils import setup_logger
|
9 |
|
10 |
+
logger = setup_logger(__name__)
|
11 |
|
12 |
+
trial_bucket_name = "pharma-doc-trials"
|
13 |
+
change_request_history_file_path_in_trial_bucket = "bankyo/change_request_history.csv"
|
14 |
+
csv_extension = ".csv"
|
15 |
+
err_msg_file_is_not_csv = "指定したファイルはcsvではありません。"
|
16 |
+
|
17 |
+
|
18 |
+
def get_client() -> BaseClient:
|
19 |
+
return boto3.client("s3")
|
20 |
+
|
21 |
+
|
22 |
+
def get_csv_as_pd_dataframe_from_s3(
|
23 |
+
client: BaseClient, bucket_name: str, file_name: str
|
24 |
) -> pd.DataFrame:
|
25 |
+
if not file_name.lower().endswith(csv_extension):
|
26 |
+
raise ValueError(err_msg_file_is_not_csv)
|
27 |
+
try:
|
28 |
+
obj = client.get_object(Bucket=bucket_name, Key=file_name)
|
29 |
+
data = pd.read_csv(obj["Body"])
|
30 |
+
return data
|
31 |
+
except client.exceptions.NoSuchKey as e:
|
32 |
+
logger.info(f'No such key: {e.response["Error"]["Key"]}')
|
33 |
+
raise e
|
34 |
+
except NoCredentialsError as e:
|
35 |
+
logger.info("Error: No AWS credentials found.")
|
36 |
+
raise e
|
37 |
+
except PartialCredentialsError as e:
|
38 |
+
logger.info("Error: Incomplete AWS credentials found.")
|
39 |
+
raise e
|
40 |
+
except client.exceptions.ClientError as e:
|
41 |
+
logger.info(f"Unexpected error: {e}")
|
42 |
+
raise e
|
43 |
|
44 |
|
45 |
+
def save_pd_dataframe_as_csv_to_s3(
|
46 |
+
client: BaseClient, data: pd.DataFrame, bucket_name: str, file_name: str
|
47 |
) -> None:
|
48 |
+
if not file_name.lower().endswith(csv_extension):
|
49 |
+
raise ValueError(err_msg_file_is_not_csv)
|
50 |
csv_buffer = StringIO()
|
51 |
data.to_csv(csv_buffer, index=False)
|
52 |
+
try:
|
53 |
+
client.put_object(Bucket=bucket_name, Key=file_name, Body=csv_buffer.getvalue())
|
54 |
+
logger.info(f"Successfully saved {file_name} to {bucket_name}.")
|
55 |
+
except NoCredentialsError as e:
|
56 |
+
logger.info("Error: No AWS credentials found.")
|
57 |
+
raise e
|
58 |
+
except PartialCredentialsError as e:
|
59 |
+
logger.info("Error: Incomplete AWS credentials found.")
|
60 |
+
raise e
|
61 |
+
except client.exceptions.ClientError as e:
|
62 |
+
logger.info(f"Unexpected error: {e}")
|
63 |
+
raise e
|
src/database.py
DELETED
@@ -1,64 +0,0 @@
|
|
1 |
-
from datetime import datetime
|
2 |
-
from typing import List
|
3 |
-
|
4 |
-
import pandas as pd
|
5 |
-
import streamlit as st
|
6 |
-
|
7 |
-
from src.aws.s3 import (
|
8 |
-
download_csv_panda_dataframe_from_s3,
|
9 |
-
save_csv_panda_dataframe_to_s3,
|
10 |
-
)
|
11 |
-
|
12 |
-
bucket_name = "pharma-doc-trials"
|
13 |
-
path_name = "bankyo/change_request_history.csv"
|
14 |
-
|
15 |
-
|
16 |
-
def write_csv(
|
17 |
-
applicant_name: str,
|
18 |
-
change_type: List[str],
|
19 |
-
category: List[str],
|
20 |
-
subcategory: List[str],
|
21 |
-
questions: List[str],
|
22 |
-
input: List[str],
|
23 |
-
output_change_content: str,
|
24 |
-
output_change_reason: str,
|
25 |
-
output_effect: str,
|
26 |
-
) -> None:
|
27 |
-
all_types = []
|
28 |
-
for i in range(len(change_type)):
|
29 |
-
all_type = [i + 1, change_type[i], category[i], subcategory[i]]
|
30 |
-
all_types.append(all_type)
|
31 |
-
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
32 |
-
data = download_csv_panda_dataframe_from_s3(bucket_name, path_name)
|
33 |
-
new_row = [
|
34 |
-
timestamp,
|
35 |
-
applicant_name,
|
36 |
-
all_types,
|
37 |
-
output_change_content,
|
38 |
-
output_change_reason,
|
39 |
-
output_effect,
|
40 |
-
]
|
41 |
-
for change_serial_number in range(len(questions)):
|
42 |
-
new_row.append(questions[change_serial_number])
|
43 |
-
new_row.append(input[change_serial_number])
|
44 |
-
|
45 |
-
max_length = max(len(data.columns), len(new_row))
|
46 |
-
number_of_qeustions = len(questions)
|
47 |
-
column_existed_number_of_question = (len(data.columns) - 6) // 2
|
48 |
-
if len(data.columns) < max_length:
|
49 |
-
for i in range(column_existed_number_of_question, number_of_qeustions):
|
50 |
-
data[f"質問{i+1}"] = None
|
51 |
-
data[f"回答{i+1}"] = None
|
52 |
-
new_columns = data.columns.tolist()
|
53 |
-
while len(new_row) < len(new_columns):
|
54 |
-
new_row.append("")
|
55 |
-
new_data = pd.DataFrame([new_row], columns=new_columns)
|
56 |
-
data = pd.concat([data, new_data], ignore_index=True)
|
57 |
-
save_csv_panda_dataframe_to_s3(data, bucket_name, path_name)
|
58 |
-
|
59 |
-
|
60 |
-
def display_csv(file_path: str) -> None:
|
61 |
-
data = download_csv_panda_dataframe_from_s3(bucket_name, path_name)
|
62 |
-
data.to_csv(file_path, index=False)
|
63 |
-
st.write("**データベース**")
|
64 |
-
st.dataframe(data)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/forms/change_request.py
CHANGED
@@ -1,13 +1,22 @@
|
|
1 |
import json
|
2 |
import os
|
3 |
from datetime import date, datetime
|
|
|
|
|
4 |
|
|
|
5 |
import streamlit as st
|
6 |
from dotenv import load_dotenv
|
7 |
from openai import OpenAI
|
8 |
from pinecone import Pinecone
|
9 |
|
10 |
-
from src.
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
from src.prompts.change_request import (
|
12 |
system_template_review,
|
13 |
systemprompt_template_1,
|
@@ -141,6 +150,11 @@ SUBCATEGORIES = {
|
|
141 |
): ["", "液", "クリーム", "チューブ"],
|
142 |
}
|
143 |
|
|
|
|
|
|
|
|
|
|
|
144 |
logger = setup_logger(__name__)
|
145 |
|
146 |
|
@@ -165,7 +179,6 @@ def change_request_form() -> None:
|
|
165 |
if state not in st.session_state:
|
166 |
st.session_state[state] = False
|
167 |
|
168 |
-
upper_bound_correction: int = 1
|
169 |
with st.form("common_question_form"):
|
170 |
col1, col2 = st.columns(2)
|
171 |
with col1:
|
@@ -179,7 +192,6 @@ def change_request_form() -> None:
|
|
179 |
|
180 |
col2_1, col2_2 = st.columns(2)
|
181 |
minimum_change_number: int = 1
|
182 |
-
maximum_change_number: int = 10
|
183 |
with col2_1:
|
184 |
st.selectbox(
|
185 |
"変更の件数",
|
@@ -207,7 +219,6 @@ def change_request_form() -> None:
|
|
207 |
|
208 |
change_number = int(st.session_state["change_num"])
|
209 |
|
210 |
-
start_from_one: int = 1
|
211 |
for change_serial_number in range(
|
212 |
start_from_one, change_number + upper_bound_correction
|
213 |
):
|
@@ -280,10 +291,10 @@ def change_request_form() -> None:
|
|
280 |
st.session_state[f"category_{change_serial_number}"],
|
281 |
st.session_state[f"subcategory_{change_serial_number}"],
|
282 |
)
|
283 |
-
for
|
284 |
next_question_number = len(question_about_this_change) + 1
|
285 |
question_about_this_change.append(
|
286 |
-
f"Q{change_serial_number}-{next_question_number} : {individual_questions[
|
287 |
)
|
288 |
question_about_this_change.append(
|
289 |
f"Q{change_serial_number}-"
|
@@ -359,11 +370,12 @@ def change_request_form() -> None:
|
|
359 |
)
|
360 |
user_prompt = ""
|
361 |
# db用
|
362 |
-
|
363 |
|
364 |
for change_serial_number in range(
|
365 |
start_from_one, change_number + upper_bound_correction
|
366 |
):
|
|
|
367 |
for question_index in range(
|
368 |
len(questions_of_all_changes[change_serial_number - 1])
|
369 |
):
|
@@ -383,7 +395,8 @@ def change_request_form() -> None:
|
|
383 |
# question は「Q1-12...」などの形式
|
384 |
answer_id = question.split(" : ")[0].replace("Q", "A")
|
385 |
user_prompt += f"{answer_id} : {answer}\n"
|
386 |
-
|
|
|
387 |
|
388 |
system_prompt += systemprompt_template_3
|
389 |
|
@@ -430,31 +443,33 @@ def change_request_form() -> None:
|
|
430 |
|
431 |
output_change_application(st.session_state["contents"])
|
432 |
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
|
437 |
for change_serial_number in range(
|
438 |
start_from_one, change_number + upper_bound_correction
|
439 |
):
|
440 |
-
|
441 |
-
|
442 |
st.session_state[f"category_{change_serial_number}"]
|
443 |
)
|
444 |
-
|
445 |
st.session_state[f"subcategory_{change_serial_number}"]
|
446 |
)
|
447 |
|
448 |
-
|
449 |
st.session_state["applicant_name"],
|
450 |
-
|
451 |
-
|
452 |
-
subcategory,
|
453 |
-
question_about_this_change,
|
454 |
-
user_input,
|
455 |
str(response_data["変更内容"]),
|
456 |
str(response_data["変更理由"]),
|
457 |
str(response_data["品質への影響"]),
|
|
|
|
|
|
|
|
|
|
|
458 |
)
|
459 |
st.session_state["document_generated"] = True
|
460 |
|
@@ -484,7 +499,17 @@ def change_request_form() -> None:
|
|
484 |
st.markdown(f'**備考** : {st.session_state["contents"]["備考"]}')
|
485 |
|
486 |
review_button = st.button("レビューする")
|
487 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
488 |
if review_button:
|
489 |
query_content = st.session_state["contents"]["変更内容"]
|
490 |
query_reason = st.session_state["contents"]["変更理由"]
|
@@ -553,3 +578,125 @@ def change_request_form() -> None:
|
|
553 |
)
|
554 |
logger.info("レビュー結果: " + review)
|
555 |
st.markdown(f"**レビュー結果** : {review}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import json
|
2 |
import os
|
3 |
from datetime import date, datetime
|
4 |
+
from typing import Any, List
|
5 |
+
from zoneinfo import ZoneInfo
|
6 |
|
7 |
+
import pandas as pd
|
8 |
import streamlit as st
|
9 |
from dotenv import load_dotenv
|
10 |
from openai import OpenAI
|
11 |
from pinecone import Pinecone
|
12 |
|
13 |
+
from src.aws.s3 import change_request_history_file_path_in_trial_bucket
|
14 |
+
from src.aws.s3 import get_client as get_s3_client
|
15 |
+
from src.aws.s3 import (
|
16 |
+
get_csv_as_pd_dataframe_from_s3,
|
17 |
+
save_pd_dataframe_as_csv_to_s3,
|
18 |
+
trial_bucket_name,
|
19 |
+
)
|
20 |
from src.prompts.change_request import (
|
21 |
system_template_review,
|
22 |
systemprompt_template_1,
|
|
|
150 |
): ["", "液", "クリーム", "チューブ"],
|
151 |
}
|
152 |
|
153 |
+
change_request_history_file_path = "data/change_request_history.csv"
|
154 |
+
maximum_change_number: int = 10
|
155 |
+
start_from_one: int = 1
|
156 |
+
upper_bound_correction: int = 1
|
157 |
+
|
158 |
logger = setup_logger(__name__)
|
159 |
|
160 |
|
|
|
179 |
if state not in st.session_state:
|
180 |
st.session_state[state] = False
|
181 |
|
|
|
182 |
with st.form("common_question_form"):
|
183 |
col1, col2 = st.columns(2)
|
184 |
with col1:
|
|
|
192 |
|
193 |
col2_1, col2_2 = st.columns(2)
|
194 |
minimum_change_number: int = 1
|
|
|
195 |
with col2_1:
|
196 |
st.selectbox(
|
197 |
"変更の件数",
|
|
|
219 |
|
220 |
change_number = int(st.session_state["change_num"])
|
221 |
|
|
|
222 |
for change_serial_number in range(
|
223 |
start_from_one, change_number + upper_bound_correction
|
224 |
):
|
|
|
291 |
st.session_state[f"category_{change_serial_number}"],
|
292 |
st.session_state[f"subcategory_{change_serial_number}"],
|
293 |
)
|
294 |
+
for i in range(len(individual_questions)):
|
295 |
next_question_number = len(question_about_this_change) + 1
|
296 |
question_about_this_change.append(
|
297 |
+
f"Q{change_serial_number}-{next_question_number} : {individual_questions[i]}"
|
298 |
)
|
299 |
question_about_this_change.append(
|
300 |
f"Q{change_serial_number}-"
|
|
|
370 |
)
|
371 |
user_prompt = ""
|
372 |
# db用
|
373 |
+
answers_of_all_changes = []
|
374 |
|
375 |
for change_serial_number in range(
|
376 |
start_from_one, change_number + upper_bound_correction
|
377 |
):
|
378 |
+
answer_about_this_change = []
|
379 |
for question_index in range(
|
380 |
len(questions_of_all_changes[change_serial_number - 1])
|
381 |
):
|
|
|
395 |
# question は「Q1-12...」などの形式
|
396 |
answer_id = question.split(" : ")[0].replace("Q", "A")
|
397 |
user_prompt += f"{answer_id} : {answer}\n"
|
398 |
+
answer_about_this_change.append(f"{answer_id} : {answer}")
|
399 |
+
answers_of_all_changes.append(answer_about_this_change)
|
400 |
|
401 |
system_prompt += systemprompt_template_3
|
402 |
|
|
|
443 |
|
444 |
output_change_application(st.session_state["contents"])
|
445 |
|
446 |
+
types = []
|
447 |
+
categories = []
|
448 |
+
subcategories = []
|
449 |
|
450 |
for change_serial_number in range(
|
451 |
start_from_one, change_number + upper_bound_correction
|
452 |
):
|
453 |
+
types.append(st.session_state[f"type_{change_serial_number}"])
|
454 |
+
categories.append(
|
455 |
st.session_state[f"category_{change_serial_number}"]
|
456 |
)
|
457 |
+
subcategories.append(
|
458 |
st.session_state[f"subcategory_{change_serial_number}"]
|
459 |
)
|
460 |
|
461 |
+
save_change_request_history(
|
462 |
st.session_state["applicant_name"],
|
463 |
+
supplementary_information,
|
464 |
+
attached_files,
|
|
|
|
|
|
|
465 |
str(response_data["変更内容"]),
|
466 |
str(response_data["変更理由"]),
|
467 |
str(response_data["品質への影響"]),
|
468 |
+
types,
|
469 |
+
categories,
|
470 |
+
subcategories,
|
471 |
+
questions_of_all_changes,
|
472 |
+
answers_of_all_changes,
|
473 |
)
|
474 |
st.session_state["document_generated"] = True
|
475 |
|
|
|
499 |
st.markdown(f'**備考** : {st.session_state["contents"]["備考"]}')
|
500 |
|
501 |
review_button = st.button("レビューする")
|
502 |
+
|
503 |
+
bucket_name = "pharma-doc-trials"
|
504 |
+
|
505 |
+
s3_client = get_s3_client()
|
506 |
+
data = get_csv_as_pd_dataframe_from_s3(
|
507 |
+
s3_client, bucket_name, change_request_history_file_path_in_trial_bucket
|
508 |
+
)
|
509 |
+
data.to_csv(change_request_history_file_path, index=False)
|
510 |
+
st.write("**変更申請履歴**")
|
511 |
+
st.dataframe(data)
|
512 |
+
|
513 |
if review_button:
|
514 |
query_content = st.session_state["contents"]["変更内容"]
|
515 |
query_reason = st.session_state["contents"]["変更理由"]
|
|
|
578 |
)
|
579 |
logger.info("レビュー結果: " + review)
|
580 |
st.markdown(f"**レビュー結果** : {review}")
|
581 |
+
|
582 |
+
|
583 |
+
def save_change_request_history(
|
584 |
+
applicant_name: str,
|
585 |
+
supplementary_information: str,
|
586 |
+
attached_files: str,
|
587 |
+
output_change_content: str,
|
588 |
+
output_change_reason: str,
|
589 |
+
output_effect: str,
|
590 |
+
change_type: List[str],
|
591 |
+
category: List[str],
|
592 |
+
subcategory: List[str],
|
593 |
+
questions: List[List[str]],
|
594 |
+
answers: List[List[str]],
|
595 |
+
) -> None:
|
596 |
+
s3_client = get_s3_client()
|
597 |
+
try:
|
598 |
+
df = get_csv_as_pd_dataframe_from_s3(
|
599 |
+
s3_client,
|
600 |
+
trial_bucket_name,
|
601 |
+
change_request_history_file_path_in_trial_bucket,
|
602 |
+
)
|
603 |
+
except s3_client.exceptions.NoSuchKey:
|
604 |
+
df = pd.DataFrame()
|
605 |
+
|
606 |
+
new_common_headers = generate_headers()
|
607 |
+
question_answer_headers = generate_question_answer_headers(questions)
|
608 |
+
new_common_headers.extend(question_answer_headers)
|
609 |
+
|
610 |
+
existing_headers = df.columns.tolist()
|
611 |
+
new_columns = [
|
612 |
+
header for header in new_common_headers if header not in existing_headers
|
613 |
+
]
|
614 |
+
|
615 |
+
for column in new_columns:
|
616 |
+
df[column] = ""
|
617 |
+
|
618 |
+
new_row_data = create_new_row_data(
|
619 |
+
applicant_name,
|
620 |
+
supplementary_information,
|
621 |
+
attached_files,
|
622 |
+
output_change_content,
|
623 |
+
output_change_reason,
|
624 |
+
output_effect,
|
625 |
+
change_type,
|
626 |
+
category,
|
627 |
+
subcategory,
|
628 |
+
questions,
|
629 |
+
answers,
|
630 |
+
)
|
631 |
+
|
632 |
+
new_row = pd.DataFrame([new_row_data])
|
633 |
+
df = pd.concat([df, new_row], ignore_index=True)
|
634 |
+
|
635 |
+
save_pd_dataframe_as_csv_to_s3(
|
636 |
+
s3_client,
|
637 |
+
df,
|
638 |
+
trial_bucket_name,
|
639 |
+
change_request_history_file_path_in_trial_bucket,
|
640 |
+
)
|
641 |
+
|
642 |
+
|
643 |
+
def generate_headers() -> List[str]:
|
644 |
+
new_headers = [
|
645 |
+
"申請者",
|
646 |
+
"備考",
|
647 |
+
"添付資料",
|
648 |
+
"作成日時",
|
649 |
+
"変更内容",
|
650 |
+
"変更理由",
|
651 |
+
"品質への影響",
|
652 |
+
]
|
653 |
+
for i in range(start_from_one, maximum_change_number + upper_bound_correction):
|
654 |
+
new_headers.extend(
|
655 |
+
[f"変更の種類({i}件目)", f"大分類({i}件目)", f"小分類({i}件目)"]
|
656 |
+
)
|
657 |
+
return new_headers
|
658 |
+
|
659 |
+
|
660 |
+
def generate_question_answer_headers(questions: List[List[str]]) -> List[str]:
|
661 |
+
headers = []
|
662 |
+
for i, question_set in enumerate(questions):
|
663 |
+
for j, _ in enumerate(question_set):
|
664 |
+
headers.append(f"質問{i+1}-{j+1}")
|
665 |
+
headers.append(f"回答{i+1}-{j+1}")
|
666 |
+
return headers
|
667 |
+
|
668 |
+
|
669 |
+
def create_new_row_data(
|
670 |
+
applicant_name: str,
|
671 |
+
supplementary_information: str,
|
672 |
+
attached_files: str,
|
673 |
+
output_change_content: str,
|
674 |
+
output_change_reason: str,
|
675 |
+
output_effect: str,
|
676 |
+
change_type: List[str],
|
677 |
+
category: List[str],
|
678 |
+
subcategory: List[str],
|
679 |
+
questions: List[List[str]],
|
680 |
+
answers: List[List[str]],
|
681 |
+
) -> dict[str, Any]:
|
682 |
+
now = datetime.now(ZoneInfo("Asia/Tokyo"))
|
683 |
+
data = {
|
684 |
+
"申請者": applicant_name,
|
685 |
+
"備考": supplementary_information,
|
686 |
+
"添付資料": attached_files,
|
687 |
+
"作成日時": now,
|
688 |
+
"変更内容": output_change_content,
|
689 |
+
"変更理由": output_change_reason,
|
690 |
+
"品質への影響": output_effect,
|
691 |
+
}
|
692 |
+
for i in range(maximum_change_number):
|
693 |
+
data[f"変更の種類({i+1}件目)"] = change_type[i] if i < len(change_type) else ""
|
694 |
+
data[f"大分類({i+1}件目)"] = category[i] if i < len(category) else ""
|
695 |
+
data[f"小分類({i+1}件目)"] = subcategory[i] if i < len(subcategory) else ""
|
696 |
+
for i, question_set in enumerate(questions):
|
697 |
+
for j, question in enumerate(question_set):
|
698 |
+
data[f"質問{i+1}-{j+1}"] = question
|
699 |
+
data[f"回答{i+1}-{j+1}"] = (
|
700 |
+
answers[i][j] if i < len(answers) and j < len(answers[i]) else ""
|
701 |
+
)
|
702 |
+
return data
|
src/forms/change_request_history.py
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
import streamlit as st
|
4 |
+
|
5 |
+
from src.aws.s3 import (
|
6 |
+
change_request_history_file_path_in_trial_bucket,
|
7 |
+
get_client,
|
8 |
+
get_csv_as_pd_dataframe_from_s3,
|
9 |
+
trial_bucket_name,
|
10 |
+
)
|
11 |
+
from src.forms.change_request import change_request_history_file_path
|
12 |
+
|
13 |
+
|
14 |
+
def change_request_history() -> None:
|
15 |
+
s3_client = get_client()
|
16 |
+
try:
|
17 |
+
data = get_csv_as_pd_dataframe_from_s3(
|
18 |
+
s3_client,
|
19 |
+
trial_bucket_name,
|
20 |
+
change_request_history_file_path_in_trial_bucket,
|
21 |
+
)
|
22 |
+
except s3_client.exceptions.NoSuchKey:
|
23 |
+
st.write("変更履歴がありません。")
|
24 |
+
return
|
25 |
+
except Exception:
|
26 |
+
st.error(
|
27 |
+
"システムの内部エラーにより、申請履歴の表示ができません。システム管理者に問い合わせて下さい。"
|
28 |
+
)
|
29 |
+
return
|
30 |
+
data.to_csv(change_request_history_file_path, index=False)
|
31 |
+
st.write("**変更申請履歴**")
|
32 |
+
st.dataframe(data)
|
33 |
+
file_exists = os.path.isfile(change_request_history_file_path)
|
34 |
+
if file_exists:
|
35 |
+
with open(change_request_history_file_path, "rb") as file:
|
36 |
+
st.download_button(
|
37 |
+
label="ダウンロード",
|
38 |
+
data=file,
|
39 |
+
file_name="change_request_history.csv",
|
40 |
+
mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
41 |
+
)
|
42 |
+
else:
|
43 |
+
st.error(
|
44 |
+
"システムの内部エラーにより、申請履歴の表示ができません。システム管理者に問い合わせて下さい。"
|
45 |
+
)
|
46 |
+
return
|
src/forms/database_check.py
DELETED
@@ -1,19 +0,0 @@
|
|
1 |
-
import os
|
2 |
-
|
3 |
-
import streamlit as st
|
4 |
-
|
5 |
-
from src.database import display_csv
|
6 |
-
|
7 |
-
|
8 |
-
def database_check_form() -> None:
|
9 |
-
file_path = "data/change_request_history.csv"
|
10 |
-
display_csv(file_path)
|
11 |
-
file_exists = os.path.isfile(file_path)
|
12 |
-
if file_exists:
|
13 |
-
with open(file_path, "rb") as file:
|
14 |
-
st.download_button(
|
15 |
-
label="ダウンロード",
|
16 |
-
data=file,
|
17 |
-
file_name="change_request_history.csv",
|
18 |
-
mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
19 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|