Keita Inoue commited on
Commit
ed847cf
2 Parent(s): 173258b 983c863

Merge pull request #5 from EQUES-Inc/develop

Browse files
data/template/template_deviation_investigation.docx ADDED
Binary file (48.2 kB). View file
 
src/forms/deviation_investigation_report.py CHANGED
@@ -1,7 +1,8 @@
1
  import json
2
  import os
3
- from datetime import date, datetime, time
4
- from zoneinfo import ZoneInfo
 
5
 
6
  import streamlit as st
7
  from dotenv import load_dotenv
@@ -11,12 +12,105 @@ from src.prompts.deviation_investigation_report import (
11
  deviation_investigation_systemprompt_output_format_instructions,
12
  deviation_investigation_systemprompt_writing_instructions,
13
  )
14
- from src.utils import output_deviation_investigation_report, setup_logger
15
 
16
  logger = setup_logger(__name__)
17
 
 
 
18
 
19
- # 未完成
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
 
21
 
22
  def deviation_investigation_report_form() -> None:
@@ -26,101 +120,475 @@ def deviation_investigation_report_form() -> None:
26
  open_api_key = os.environ.get("OPENAI_API_KEY")
27
  client = OpenAI(api_key=open_api_key)
28
 
 
 
 
 
 
 
 
 
 
29
  for state in ["form_submitted", "document_generated"]:
30
  if state not in st.session_state:
31
  st.session_state[state] = False
32
 
33
- if "occurrence_time" not in st.session_state:
34
- st.session_state["occurrence_time"] = datetime.now(
35
- ZoneInfo("Asia/Tokyo")
36
- ).time()
37
-
38
- with st.form("my_form_deviation"):
39
- col1, col2 = st.columns(2)
40
- with col1:
41
- reporter_name = st.text_input("報告者")
42
- with col2:
43
- report_date = st.date_input("報告日", date.today())
44
-
45
- col2_1, col2_2 = st.columns(2)
46
- with col2_1:
47
- product_name = st.text_input("品名")
48
- with col2_2:
49
- lot_number = st.text_input("ロットNo.")
50
-
51
- col1, col2, col3 = st.columns([1, 1, 2])
52
- with col1:
53
- occurrence_date = st.date_input("発生日", date.today())
54
- with col2:
55
- st.time_input("発生時間", key="occurrence_time")
56
- with col3:
57
- occurrence_place = st.text_input("発生場所")
58
-
59
- q = [
60
- "Q1 : 逸脱内容を記入してください。(どの手順・規格から逸脱したのか)",
61
- "Q2 : 逸脱の発見の経緯を記入してください。",
62
- "Q3 : 応急処置とその処置の理由を記入してください。",
63
- "Q4 : 品質への影響の調査結果を記入してください。",
64
- "Q5 : 原因調査結果について記入してください",
65
- "Q6 : 是正措置について記入してください",
66
- "Q7 : 予防措置について記入してください",
67
- ]
68
-
69
- q_num = len(q)
70
-
71
- input_values = [""] * q_num
72
- for k in range(q_num):
73
- input_values[k] = st.text_area(q[k], key=f"input_deviatoin_{k}")
74
- st.markdown("***")
75
-
76
- shipping_restriction = st.text_area(
77
- "Q8 : 出荷の制限について記入してください。",
78
- key="shipping_restriction_deviation",
79
- )
80
- no_shipping_restriction = st.checkbox(
81
- "出荷の制限なし", key="check_shipping_restriction"
82
- )
83
- attached_files = st.text_area(
84
- "Q9 : 添付資料名を記入してください。",
85
- key="attached_files_deviation",
86
- )
87
- no_attached_file = st.checkbox("添付資料なし", key="check_attached_file")
88
- supplementary_information = st.text_area(
89
- "Q10 : 備考があれば記入してください。",
90
- key="supplementary_information_deviation",
91
- )
92
- no_supplementary_information = st.checkbox(
93
- "なし", key="check_supplementary_information"
94
- )
95
- submitted = st.form_submit_button("送信")
96
-
97
- if "contents" not in st.session_state:
98
- st.session_state["contents"] = {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
  if submitted:
101
- if no_shipping_restriction:
102
- shipping_restriction = "なし"
103
- if no_attached_file:
104
- attached_files = "なし"
105
- if no_supplementary_information:
106
- supplementary_information = "なし"
107
-
108
- # システムプロンプトを作成する
109
  system_prompt = deviation_investigation_systemprompt_writing_instructions
110
- for k in range(q_num):
111
- system_prompt += q[k]
112
- system_prompt += "\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  system_prompt += (
114
  deviation_investigation_systemprompt_output_format_instructions
115
  )
116
 
117
- # ユーザープロンプトを作成する
118
  user_prompt = ""
119
- for k in range(q_num):
120
- user_prompt += f" A{k+1} : {input_values[k]}"
121
- user_prompt += "\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
- # OpenAIのAPIを使用して応答を生成
124
  client = OpenAI(api_key=open_api_key)
125
  response = client.chat.completions.create(
126
  model="gpt-4-0125-preview",
@@ -131,84 +599,440 @@ def deviation_investigation_report_form() -> None:
131
  response_format={"type": "json_object"},
132
  temperature=0.0,
133
  )
 
 
 
134
  response_text = response.choices[0].message.content
135
 
136
- # 応答をjsonに変換
137
  response_data = (
138
  json.loads(response_text) if response_text is not None else {}
139
  )
140
 
141
- if isinstance(report_date, (date, datetime)):
142
- formatted_date = report_date.strftime("%Y年%m月%d日")
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  else:
144
- formatted_date = "報告日が指定されていません。"
145
 
146
- if isinstance(occurrence_date, date) and isinstance(
147
- st.session_state["occurrence_time"], time
 
148
  ):
149
- print(st.session_state["occurrence_time"])
150
- occurrence_datetime = datetime.combine(
151
- occurrence_date, st.session_state["occurrence_time"]
152
- ).strftime("%Y年%m月%d日%H時%M分")
153
- print(occurrence_datetime)
 
 
 
 
 
154
  else:
155
- st.error(
156
- "発生日または発生時間の入力が無効です。システムエラーのため、管理者に問い合わせてください。"
157
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
 
159
- # jsonデータを作成
160
  st.session_state["contents"] = {
161
- "報告者": reporter_name,
162
- "報告日": formatted_date,
163
- "品名": product_name,
164
- "ロットNo.": lot_number,
165
- "発生日時": occurrence_datetime,
166
- "発生場所": occurrence_place,
167
- "逸脱内容・発見の経緯": str(response_data["逸脱内容・発見の経緯"]),
168
- "応急処置・処置の理由": str(response_data["応急処置・処置の理由"]),
169
- "品質への影響の調査結果": str(response_data["品質への影響の調査結果"]),
170
- "原因調査結果": str(response_data["原因調査結果"]),
171
- "是正措置・予防措置": str(response_data["是正措置・予防措置"]),
172
- "出荷の制限": shipping_restriction,
173
- "添付資料": attached_files,
174
- "備考": supplementary_information,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  }
176
 
177
  output_deviation_investigation_report(st.session_state["contents"])
178
  st.session_state["document_generated"] = True
179
 
180
- if st.session_state["document_generated"]:
181
- st.markdown("以下の内容を記入した逸脱報告書(.docx)を作成しました。")
182
 
183
- with open("data/output_deviation.docx", "rb") as file:
184
- st.download_button(
185
- label="ダウンロード",
186
- data=file,
187
- file_name="output_deviation_investigation.docx",
188
- mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
189
- )
190
 
191
- st.markdown(f'**報告者** : {st.session_state["contents"]["報告者"]}')
192
- st.markdown(f'**報告日** : {st.session_state["contents"]["報告日"]}')
193
- st.markdown(f'**品名** : {st.session_state["contents"]["品名"]}')
194
- st.markdown(f'**ロットNo.** : {st.session_state["contents"]["ロットNo."]}')
195
- st.markdown(f'**発生日時** : {st.session_state["contents"]["発生日時"]}')
196
- st.markdown(f'**発生場所** : {st.session_state["contents"]["発生場所"]}')
197
- st.markdown(
198
- f'**逸脱内容・発見の経緯** : {st.session_state["contents"]["逸脱内容・発見の経緯"]}'
199
- )
200
- st.markdown(
201
- f'**応急処置・処置の理由** : {st.session_state["contents"]["応急処置・処置の理由"]}'
202
- )
203
- st.markdown(
204
- f'**品質への影響の調査結果** : {st.session_state["contents"]["品質への影響の調査結果"]}'
205
- )
206
- st.markdown(
207
- f'**原因調査結果** : {st.session_state["contents"]["原因調査結果"]}'
208
- )
209
- st.markdown(
210
- f'**是正措置・予防措置** : {st.session_state["contents"]["是正措置・予防措置"]}'
211
- )
212
- st.markdown(f'**出荷の制限** : {st.session_state["contents"]["出荷の制限"]}')
213
- st.markdown(f'**添付資料** : {st.session_state["contents"]["添付資料"]}')
214
- st.markdown(f'**備考** : {st.session_state["contents"]["備考"]}')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import json
2
  import os
3
+ from datetime import date, datetime
4
+ from enum import Enum
5
+ from typing import Dict
6
 
7
  import streamlit as st
8
  from dotenv import load_dotenv
 
12
  deviation_investigation_systemprompt_output_format_instructions,
13
  deviation_investigation_systemprompt_writing_instructions,
14
  )
15
+ from src.utils import replace_text_in_docx, setup_logger
16
 
17
  logger = setup_logger(__name__)
18
 
19
+ MIN_REPORT_NUMBER = 1
20
+ MAX_REPORT_NUMBER = 10
21
 
22
+
23
+ class InvestigationOrMethodStatus(Enum):
24
+ NOT_SELECTED = ""
25
+ COMPLETED = "完了"
26
+ PROPOSED_COMPLETION = "完了の提案"
27
+ IN_PROGRESS = "対応中"
28
+ NO_ACTION_NEEDED = "対応不要"
29
+
30
+
31
+ class ValidityAssessmentStatus(Enum):
32
+ NOT_SELECTED = ""
33
+ COMPLETED = "完了"
34
+ PROPOSED_COMPLETION = "完了の提案"
35
+ IN_PROGRESS = "対応中"
36
+ NO_ACTION_NEEDED = "対応不要"
37
+ ON_HOLD = "保留"
38
+
39
+
40
+ class PresenceOrAbsence(Enum):
41
+ NOT_SELECTED = ""
42
+ PRESENCE = "有"
43
+ ABSENCE = "無"
44
+
45
+
46
+ class ActionRequirement(Enum):
47
+ NOT_SELECTED = ""
48
+ REQUIRED = "要"
49
+ NOT_REQUIRED = "不要"
50
+ ON_HOLD = "保留"
51
+
52
+
53
+ class CauseInvestigationClassifications(Enum):
54
+ NOT_SELECTED = ""
55
+ PROCEDURE = "手順"
56
+ EDUCATION_TRAINING = "教育訓練"
57
+ FACILITIES_EQUIPMENT = "設備/機器"
58
+ ENVIRONMENT = "環境"
59
+ PEOPLE_RELATIONSHIPS = "人/関係"
60
+ CONTROL = "管理"
61
+ OTHERS = "その他"
62
+
63
+
64
+ class CauseInvestigationMethods(Enum):
65
+ NOT_SELECTED = ""
66
+ ANALYSIS_5WHY = "5Why分析"
67
+ CHARACTERISTICS_MAP = "特性要因図"
68
+ OTHERS = "その他"
69
+
70
+
71
+ class DeviationSummaryQuestions(Enum):
72
+ DEVIATION_SUMMARY = "逸脱概要を記入してください。(どの手順・規格から逸脱したのか)"
73
+
74
+
75
+ class CauseInvestigationQuestions(Enum):
76
+ CONTENT_RESULT = "原因調査の調査内容・結果を記入してください。"
77
+ DIRECT_CAUSE = "直接原因を記入してください。"
78
+ ROOT_CAUSE = "根本原因を記入してください。"
79
+
80
+
81
+ class ImpactInvestigationQuestions(Enum):
82
+ IMPACT_ON_THE_LOT = "当該ロットへの影響を記入してください。"
83
+ IMPACT_ON_OTHERS = "他製品・他ロットへの影響を記入してください。"
84
+
85
+
86
+ class RecoveryMeasuresQuestions(Enum):
87
+ CONTENT = "回復措置の実施内容を記入してください。"
88
+ RESULT = "回復措置の実施結果を記入してください。"
89
+
90
+
91
+ class ProductMeasuresQuestions(Enum):
92
+ CONTENT = "製品等に対する措置の実施内容を記入してください。"
93
+ RESULT = "製品等に対する措置の実施結果を記入してください。"
94
+
95
+
96
+ class CorrectivePreventiveMeasuresQuestions(Enum):
97
+ CONTENT = "是正措置・予防措置の実施内容を記入してください。"
98
+ RESULT = "是正措置・予防措置の実施結果を記入してください。"
99
+
100
+
101
+ class ValidityAssessmentQuestions(Enum):
102
+ CONTENT = "有効性評価内容、有効性確認方法、有効性予定期間を記入してください。"
103
+ RESULT = "有効性評価結果、有効性実施期間を記入してください。"
104
+
105
+
106
+ class OtherMeasuresQuestions(Enum):
107
+ CONTENT = "その他の措置の実施内容を記入してください。"
108
+ RESULT = "その他の措置の実施結果を記入してください。"
109
+
110
+
111
+ class ExtensionReasonQuestions(Enum):
112
+ INVESTIGATION = "調査延長の理由を記入してください。"
113
+ MEASURES = "措置延長の理由を記入してください。"
114
 
115
 
116
  def deviation_investigation_report_form() -> None:
 
120
  open_api_key = os.environ.get("OPENAI_API_KEY")
121
  client = OpenAI(api_key=open_api_key)
122
 
123
+ if "subject" not in st.session_state:
124
+ st.session_state["subject"] = ""
125
+ if "control_number" not in st.session_state:
126
+ st.session_state["control_number"] = ""
127
+ if "section_name" not in st.session_state:
128
+ st.session_state["section_name"] = ""
129
+ if "report_number" not in st.session_state:
130
+ st.session_state["report_number"] = "1"
131
+
132
  for state in ["form_submitted", "document_generated"]:
133
  if state not in st.session_state:
134
  st.session_state[state] = False
135
 
136
+ col1, col2 = st.columns(2)
137
+ with col1:
138
+ st.text_input("件名", key="subject")
139
+ with col2:
140
+ st.text_input("管理番号", key="control_number")
141
+
142
+ col2_1, col2_2 = st.columns(2)
143
+ with col2_1:
144
+ st.text_input("課名", key="section_name")
145
+ with col2_2:
146
+ st.selectbox(
147
+ "報数",
148
+ [str(i) for i in range(MIN_REPORT_NUMBER, MAX_REPORT_NUMBER + 1)],
149
+ key="report_number",
150
+ )
151
+
152
+ st.markdown("***")
153
+
154
+ st.markdown("**逸脱概要**")
155
+ if "answer_deviation_summary" not in st.session_state:
156
+ st.session_state["answer_deviation_summary"] = ""
157
+
158
+ st.text_area(
159
+ DeviationSummaryQuestions.DEVIATION_SUMMARY.value,
160
+ key="answer_deviation_summary",
161
+ )
162
+ st.markdown("***")
163
+
164
+ st.markdown("**原因調査**")
165
+ if "status_cause_investigation" not in st.session_state:
166
+ st.session_state["status_cause_investigation"] = ""
167
+ if "answer_cause_investigation_content_result" not in st.session_state:
168
+ st.session_state["answer_cause_investigation_content_result"] = ""
169
+ if "answer_cause_investigation_direct_cause" not in st.session_state:
170
+ st.session_state["answer_cause_investigation_direct_cause"] = ""
171
+ if "answer_cause_investigation_root_cause" not in st.session_state:
172
+ st.session_state["answer_cause_investigation_root_cause"] = ""
173
+ if "cause_investigation_classification" not in st.session_state:
174
+ st.session_state["cause_investigation_classification"] = ""
175
+ if "cause_investigation_classification_others" not in st.session_state:
176
+ st.session_state["cause_investigation_classification_others"] = ""
177
+ if "cause_investigation_method" not in st.session_state:
178
+ st.session_state["cause_investigation_method"] = ""
179
+ if "cause_investigation_method_others" not in st.session_state:
180
+ st.session_state["cause_investigation_method_others"] = ""
181
+
182
+ st.selectbox(
183
+ "状況",
184
+ [status.value for status in InvestigationOrMethodStatus],
185
+ key="status_cause_investigation",
186
+ )
187
+
188
+ if (
189
+ st.session_state["status_cause_investigation"]
190
+ != InvestigationOrMethodStatus.NO_ACTION_NEEDED.value
191
+ ):
192
+ st.text_area(
193
+ CauseInvestigationQuestions.CONTENT_RESULT.value,
194
+ key="answer_cause_investigation_content_result",
195
+ )
196
+ st.text_area(
197
+ CauseInvestigationQuestions.DIRECT_CAUSE.value,
198
+ key="answer_cause_investigation_direct_cause",
199
+ )
200
+ st.text_area(
201
+ CauseInvestigationQuestions.ROOT_CAUSE.value,
202
+ key="answer_cause_investigation_root_cause",
203
+ )
204
+
205
+ st.selectbox(
206
+ "分類",
207
+ [status.value for status in CauseInvestigationClassifications],
208
+ key="cause_investigation_classification",
209
+ )
210
+ if st.session_state["cause_investigation_classification"] == "その他":
211
+ st.text_input(
212
+ "分類を記入してください。",
213
+ key="cause_investigation_classification_others",
214
+ )
215
+ st.selectbox(
216
+ "手法",
217
+ [status.value for status in CauseInvestigationMethods],
218
+ key="cause_investigation_method",
219
+ )
220
+ if st.session_state["cause_investigation_method"] == "その他":
221
+ st.text_input(
222
+ "手法を記入してください。", key="cause_investigation_method_others"
223
+ )
224
+ else:
225
+ st.session_state["answer_cause_investigation_content_result"] = "なし"
226
+ st.session_state["answer_cause_investigation_direct_cause"] = "なし"
227
+ st.session_state["answer_cause_investigation_root_cause"] = "なし"
228
+
229
+ st.markdown("***")
230
+
231
+ st.markdown("**製品品質(製品・中間製品・原材料)への影響**")
232
+ if "status_impact_investigation" not in st.session_state:
233
+ st.session_state["status_impact_investigation"] = ""
234
+ if "answer_impact_investigation_impact_on_the_lot" not in st.session_state:
235
+ st.session_state["answer_impact_investigation_impact_on_the_lot"] = ""
236
+ if "answer_impact_investigation_impact_on_others" not in st.session_state:
237
+ st.session_state["answer_impact_investigation_impact_on_others"] = ""
238
+
239
+ st.selectbox(
240
+ "状況",
241
+ [status.value for status in InvestigationOrMethodStatus],
242
+ key="status_impact_investigation",
243
+ )
244
+
245
+ if (
246
+ st.session_state["status_impact_investigation"]
247
+ != InvestigationOrMethodStatus.NO_ACTION_NEEDED.value
248
+ ):
249
+ st.text_area(
250
+ ImpactInvestigationQuestions.IMPACT_ON_THE_LOT.value,
251
+ key="answer_impact_investigation_impact_on_the_lot",
252
+ )
253
+ st.text_area(
254
+ ImpactInvestigationQuestions.IMPACT_ON_OTHERS.value,
255
+ key="answer_impact_investigation_impact_on_others",
256
+ )
257
+ else:
258
+ st.session_state["answer_impact_investigation_impact_on_the_lot"] = "なし"
259
+ st.session_state["answer_impact_investigation_impact_on_others"] = "なし"
260
+ st.markdown("***")
261
+
262
+ st.markdown("**調査の延長申請(原因調査及び製品品質への影響)**")
263
+ if "investigation_extension" not in st.session_state:
264
+ st.session_state["investigation_extension"] = ""
265
+ if "investigation_next_report_date" not in st.session_state:
266
+ st.session_state["investigation_next_report_date"] = date.today()
267
+ if "investigation_extension_reason" not in st.session_state:
268
+ st.session_state["investigation_extension_reason"] = ""
269
+
270
+ st.selectbox(
271
+ "延長申請",
272
+ [status.value for status in PresenceOrAbsence],
273
+ key="investigation_extension",
274
+ )
275
+
276
+ if st.session_state["investigation_extension"] == PresenceOrAbsence.PRESENCE.value:
277
+ st.date_input("次報の報告予定日", key="investigation_next_report_date")
278
+ st.text_area(
279
+ ExtensionReasonQuestions.INVESTIGATION.value,
280
+ key="investigation_extension_reason",
281
+ )
282
+ st.markdown("***")
283
+
284
+ st.markdown("**回復措置**")
285
+ if "status_recovery_measures" not in st.session_state:
286
+ st.session_state["status_recovery_measures"] = ""
287
+ if "answer_recovery_measure_content" not in st.session_state:
288
+ st.session_state["answer_recovery_measure_content"] = ""
289
+ if "answer_recovery_measure_result" not in st.session_state:
290
+ st.session_state["answer_recovery_measure_result"] = ""
291
+
292
+ st.selectbox(
293
+ "状況",
294
+ [status.value for status in InvestigationOrMethodStatus],
295
+ key="status_recovery_measures",
296
+ )
297
+
298
+ if (
299
+ st.session_state["status_recovery_measures"]
300
+ != InvestigationOrMethodStatus.NO_ACTION_NEEDED.value
301
+ ):
302
+ st.text_area(
303
+ RecoveryMeasuresQuestions.CONTENT.value,
304
+ key="answer_recovery_measures_content",
305
+ )
306
+ st.text_area(
307
+ RecoveryMeasuresQuestions.RESULT.value,
308
+ key="answer_recovery_measures_result",
309
+ )
310
+ else:
311
+ st.session_state["answer_recovery_measures_content"] = "なし"
312
+ st.session_state["answer_recovery_measures_result"] = "なし"
313
+ st.markdown("***")
314
+
315
+ st.markdown("**製品等に関する措置**")
316
+ if "status_product_measures" not in st.session_state:
317
+ st.session_state["status_product_measures"] = ""
318
+ if "answer_product_measures_content" not in st.session_state:
319
+ st.session_state["answer_product_measures_content"] = ""
320
+ if "answer_product_measures_result" not in st.session_state:
321
+ st.session_state["answer_product_measures_result"] = ""
322
+ if "special_work_instructions" not in st.session_state:
323
+ st.session_state["special_work_instructions"] = ""
324
+
325
+ st.selectbox(
326
+ "状況",
327
+ [status.value for status in InvestigationOrMethodStatus],
328
+ key="status_product_measures",
329
+ )
330
+
331
+ if (
332
+ st.session_state["status_product_measures"]
333
+ != InvestigationOrMethodStatus.NO_ACTION_NEEDED.value
334
+ ):
335
+ st.text_area(
336
+ ProductMeasuresQuestions.CONTENT.value,
337
+ key="answer_product_measures_content",
338
+ )
339
+ st.text_area(
340
+ ProductMeasuresQuestions.RESULT.value,
341
+ key="answer_product_measures_result",
342
+ )
343
+
344
+ st.selectbox(
345
+ "特別作業指図書の添付",
346
+ [status.value for status in PresenceOrAbsence],
347
+ key="special_work_instructions",
348
+ )
349
+ else:
350
+ st.session_state["answer_product_measures_content"] = "なし"
351
+ st.session_state["answer_product_measures_result"] = "なし"
352
+
353
+ st.markdown("***")
354
+
355
+ st.markdown("**是正措置・予防措置**")
356
+ if "status_corrective_preventive_measures" not in st.session_state:
357
+ st.session_state["status_corrective_preventive_measures"] = ""
358
+ if "corrective_preventive_measures_content" not in st.session_state:
359
+ st.session_state["corrective_preventive_measures_content"] = ""
360
+ if "corrective_preventive_measures_result" not in st.session_state:
361
+ st.session_state["corrective_preventive_measures_result"] = ""
362
+ if "measures_education_training" not in st.session_state:
363
+ st.session_state["measures_education_training"] = ""
364
+ if "measures_education_training_plan" not in st.session_state:
365
+ st.session_state["measures_education_training_plan"] = date.today()
366
+
367
+ st.selectbox(
368
+ "状況",
369
+ [status.value for status in InvestigationOrMethodStatus],
370
+ key="status_corrective_preventive_measures",
371
+ )
372
+
373
+ if (
374
+ st.session_state["status_corrective_preventive_measures"]
375
+ != InvestigationOrMethodStatus.NO_ACTION_NEEDED.value
376
+ ):
377
+ st.text_area(
378
+ CorrectivePreventiveMeasuresQuestions.CONTENT.value,
379
+ key="answer_corrective_preventive_measures_content",
380
+ )
381
+ st.text_area(
382
+ CorrectivePreventiveMeasuresQuestions.RESULT.value,
383
+ key="answer_corrective_preventive_measures_result",
384
+ )
385
+
386
+ st.selectbox(
387
+ "教育訓練",
388
+ [status.value for status in ActionRequirement],
389
+ key="measures_education_training",
390
+ )
391
+ if (
392
+ st.session_state["measures_education_training"]
393
+ == ActionRequirement.REQUIRED.value
394
+ ):
395
+ st.date_input(
396
+ "教育訓練の予定日/実施日",
397
+ key="measures_education_training_plan",
398
+ )
399
+ else:
400
+ st.session_state["answer_corrective_preventive_measures_content"] = "なし"
401
+ st.session_state["answer_corrective_preventive_measures_result"] = "なし"
402
+
403
+ st.markdown("***")
404
+
405
+ st.markdown("**有効性評価**")
406
+ if "status_validity_assessment" not in st.session_state:
407
+ st.session_state["status_validity_assessment"] = ""
408
+ if "validity_assessment_content" not in st.session_state:
409
+ st.session_state["validity_assessment_content"] = ""
410
+ if "validity_assessment_result" not in st.session_state:
411
+ st.session_state["validity_assessment_result"] = ""
412
+
413
+ st.selectbox(
414
+ "状況",
415
+ [status.value for status in ValidityAssessmentStatus],
416
+ key="status_validity_assessment",
417
+ )
418
+
419
+ if (
420
+ st.session_state["status_validity_assessment"]
421
+ != ValidityAssessmentStatus.NO_ACTION_NEEDED.value
422
+ and st.session_state["status_validity_assessment"]
423
+ != ValidityAssessmentStatus.ON_HOLD.value
424
+ ):
425
+ st.text_area(
426
+ ValidityAssessmentQuestions.CONTENT.value,
427
+ key="answer_validity_assessment_content",
428
+ )
429
+ st.text_area(
430
+ ValidityAssessmentQuestions.RESULT.value,
431
+ key="answer_validity_assessment_result",
432
+ )
433
+ else:
434
+ st.session_state["answer_validity_assessment_content"] = "なし"
435
+ st.session_state["answer_validity_assessment_result"] = "なし"
436
+
437
+ st.markdown("***")
438
+
439
+ st.markdown("**その他**")
440
+ if "status_other_measures" not in st.session_state:
441
+ st.session_state["status_other_measures"] = ""
442
+ if "answer_other_measures_content" not in st.session_state:
443
+ st.session_state["answer_other_measures_content"] = ""
444
+ if "answer_other_measures_result" not in st.session_state:
445
+ st.session_state["answer_other_measures_result"] = ""
446
+
447
+ st.selectbox(
448
+ "状況",
449
+ [status.value for status in InvestigationOrMethodStatus],
450
+ key="status_other_measures",
451
+ )
452
+
453
+ if (
454
+ st.session_state["status_other_measures"]
455
+ != InvestigationOrMethodStatus.NO_ACTION_NEEDED.value
456
+ ):
457
+ st.text_area(
458
+ OtherMeasuresQuestions.CONTENT.value, key="answer_other_measures_content"
459
+ )
460
+ st.text_area(
461
+ OtherMeasuresQuestions.RESULT.value, key="answer_other_measures_result"
462
+ )
463
+ else:
464
+ st.session_state["answer_other_measures_content"] = "なし"
465
+ st.session_state["answer_other_measures_result"] = "なし"
466
+ st.markdown("***")
467
+
468
+ st.markdown("**措置の延長申請**")
469
+ if "measures_extension" not in st.session_state:
470
+ st.session_state["measures_extension"] = ""
471
+ if "measures_next_report_date" not in st.session_state:
472
+ st.session_state["measures_next_report_date"] = date.today()
473
+ if "measures_extension_reason" not in st.session_state:
474
+ st.session_state["measures_extension_reason"] = ""
475
+
476
+ st.selectbox(
477
+ "延長申請",
478
+ [status.value for status in PresenceOrAbsence],
479
+ key="measures_extension",
480
+ )
481
+ if st.session_state["measures_extension"] == PresenceOrAbsence.PRESENCE.value:
482
+ st.date_input("次報の報告予定日", key="measures_next_report_date")
483
+ st.text_area(
484
+ ExtensionReasonQuestions.MEASURES.value, key="measures_extension_reason"
485
+ )
486
+ st.markdown("***")
487
+
488
+ st.markdown("**添付資料の有無**")
489
+ if "attachment" not in st.session_state:
490
+ st.session_state["attachment"] = ""
491
+ if "attached_files" not in st.session_state:
492
+ st.session_state["attached_files"] = ""
493
+ st.selectbox(
494
+ "添付資料",
495
+ [status.value for status in PresenceOrAbsence],
496
+ key="attachment",
497
+ )
498
+ if st.session_state["attachment"] == PresenceOrAbsence.PRESENCE.value:
499
+ st.text_area("添付資料名を記入してください。", key="attached_files")
500
+ st.markdown("***")
501
+
502
+ if (
503
+ st.session_state["attachment"] == PresenceOrAbsence.PRESENCE.value
504
+ and st.session_state["attached_files"]
505
+ ) or st.session_state["attachment"] == PresenceOrAbsence.ABSENCE.value:
506
+ submitted = st.button("送信")
507
+
508
+ st.markdown("***")
509
 
510
  if submitted:
511
+
 
 
 
 
 
 
 
512
  system_prompt = deviation_investigation_systemprompt_writing_instructions
513
+ system_prompt += (
514
+ f"Q1-1 : {DeviationSummaryQuestions.DEVIATION_SUMMARY.value}\n"
515
+ )
516
+ system_prompt += (
517
+ f"Q2-1 : {CauseInvestigationQuestions.CONTENT_RESULT.value}\n"
518
+ )
519
+ system_prompt += (
520
+ f"Q2-2 : {CauseInvestigationQuestions.DIRECT_CAUSE.value}\n"
521
+ )
522
+ system_prompt += f"Q2-3 : {CauseInvestigationQuestions.ROOT_CAUSE.value}\n"
523
+ system_prompt += (
524
+ f"Q3-1 : {ImpactInvestigationQuestions.IMPACT_ON_THE_LOT.value}\n"
525
+ )
526
+ system_prompt += (
527
+ f"Q3-2 : {ImpactInvestigationQuestions.IMPACT_ON_OTHERS.value}\n"
528
+ )
529
+ system_prompt += f"Q4-1 : {RecoveryMeasuresQuestions.CONTENT.value}\n"
530
+ system_prompt += f"Q4-2 : {RecoveryMeasuresQuestions.RESULT.value}\n"
531
+ system_prompt += f"Q5-1 : {ProductMeasuresQuestions.CONTENT.value}\n"
532
+ system_prompt += f"Q5-2 : {ProductMeasuresQuestions.RESULT.value}\n"
533
+ system_prompt += (
534
+ f"Q6-1 : {CorrectivePreventiveMeasuresQuestions.CONTENT.value}\n"
535
+ )
536
+ system_prompt += (
537
+ f"Q6-2 : {CorrectivePreventiveMeasuresQuestions.RESULT.value}\n"
538
+ )
539
+ system_prompt += f"Q7-1 : {ValidityAssessmentQuestions.CONTENT.value}\n"
540
+ system_prompt += f"Q7-2 : {ValidityAssessmentQuestions.RESULT.value}\n"
541
+ system_prompt += f"Q8-1 : {OtherMeasuresQuestions.CONTENT.value}\n"
542
+ system_prompt += f"Q8-2 : {OtherMeasuresQuestions.RESULT.value}\n"
543
+ system_prompt += f"Q9-1 : {ExtensionReasonQuestions.INVESTIGATION.value}\n"
544
+ system_prompt += f"Q9-2 : {ExtensionReasonQuestions.MEASURES.value}\n"
545
  system_prompt += (
546
  deviation_investigation_systemprompt_output_format_instructions
547
  )
548
 
 
549
  user_prompt = ""
550
+ user_prompt += f"A1-1: {st.session_state['answer_deviation_summary']}\n"
551
+ user_prompt += f"A2-1: {st.session_state['answer_cause_investigation_content_result']}\n"
552
+ user_prompt += (
553
+ f"A2-2: {st.session_state['answer_cause_investigation_direct_cause']}\n"
554
+ )
555
+ user_prompt += (
556
+ f"A2-3: {st.session_state['answer_cause_investigation_root_cause']}\n"
557
+ )
558
+ user_prompt += f"A3-1: {st.session_state['answer_impact_investigation_impact_on_the_lot']}\n"
559
+ user_prompt += f"A3-2: {st.session_state['answer_impact_investigation_impact_on_others']}\n"
560
+ user_prompt += (
561
+ f"A4-1: {st.session_state['answer_recovery_measures_content']}\n"
562
+ )
563
+ user_prompt += (
564
+ f"A4-2: {st.session_state['answer_recovery_measures_result']}\n"
565
+ )
566
+ user_prompt += (
567
+ f"A5-1: {st.session_state['answer_product_measures_content']}\n"
568
+ )
569
+ user_prompt += (
570
+ f"A5-2: {st.session_state['answer_product_measures_result']}\n"
571
+ )
572
+ user_prompt += f"A6-1: {st.session_state['answer_corrective_preventive_measures_content']}\n"
573
+ user_prompt += f"A6-2: {st.session_state['answer_corrective_preventive_measures_result']}\n"
574
+ user_prompt += (
575
+ f"A7-1: {st.session_state['answer_validity_assessment_content']}\n"
576
+ )
577
+ user_prompt += (
578
+ f"A7-2: {st.session_state['answer_validity_assessment_result']}\n"
579
+ )
580
+ user_prompt += (
581
+ f"A8-1: {st.session_state['answer_other_measures_content']}\n"
582
+ )
583
+ user_prompt += f"A8-2: {st.session_state['answer_other_measures_result']}\n"
584
+ user_prompt += (
585
+ f"A9-1: {st.session_state['investigation_extension_reason']}\n"
586
+ )
587
+ user_prompt += f"A9-2: {st.session_state['measures_extension_reason']}\n"
588
+
589
+ logger.info("システムプロンプト(逸脱調査報告書作成用): " + system_prompt)
590
+ logger.info("ユーザプロンプト(逸脱調査報告書作成用): " + user_prompt)
591
 
 
592
  client = OpenAI(api_key=open_api_key)
593
  response = client.chat.completions.create(
594
  model="gpt-4-0125-preview",
 
599
  response_format={"type": "json_object"},
600
  temperature=0.0,
601
  )
602
+ logger.info(
603
+ "OpenAIからのレスポンス(逸脱調査報告書作成用): " + str(response)
604
+ )
605
  response_text = response.choices[0].message.content
606
 
 
607
  response_data = (
608
  json.loads(response_text) if response_text is not None else {}
609
  )
610
 
611
+ if (
612
+ st.session_state["measures_education_training"]
613
+ == ActionRequirement.REQUIRED.value
614
+ ):
615
+ if isinstance(
616
+ st.session_state["measures_education_training_plan"],
617
+ (date, datetime),
618
+ ):
619
+ formatted_education_training_plan = st.session_state[
620
+ "measures_education_training_plan"
621
+ ].strftime("%Y年%m月%d日")
622
+ else:
623
+ formatted_education_training_plan = (
624
+ "教育訓練計画が指定されていません。"
625
+ )
626
  else:
627
+ formatted_education_training_plan = ""
628
 
629
+ if (
630
+ st.session_state["investigation_extension"]
631
+ == PresenceOrAbsence.PRESENCE.value
632
  ):
633
+ if isinstance(
634
+ st.session_state["investigation_next_report_date"], (date, datetime)
635
+ ):
636
+ formatted_investigation_next_report_date = st.session_state[
637
+ "investigation_next_report_date"
638
+ ].strftime("%Y年%m月%d日")
639
+ else:
640
+ formatted_investigation_next_report_date = (
641
+ "次報の報告予定日が指定されていません。"
642
+ )
643
  else:
644
+ formatted_investigation_next_report_date = ""
645
+
646
+ if (
647
+ st.session_state["measures_extension"]
648
+ == PresenceOrAbsence.PRESENCE.value
649
+ ):
650
+ if isinstance(
651
+ st.session_state["measures_next_report_date"], (date, datetime)
652
+ ):
653
+ formatted_measures_next_report_date = st.session_state[
654
+ "measures_next_report_date"
655
+ ].strftime("%Y年%m月%d日")
656
+ else:
657
+ formatted_measures_next_report_date = (
658
+ "次報の報告予定日が指定されていません。"
659
+ )
660
+ else:
661
+ formatted_measures_next_report_date = ""
662
 
 
663
  st.session_state["contents"] = {
664
+ "件名": st.session_state["subject"],
665
+ "管理番号": st.session_state["control_number"],
666
+ "課名": st.session_state["section_name"],
667
+ "報数": f'第{st.session_state["report_number"]}報',
668
+ "逸脱概要": str(response_data["逸脱概要"]),
669
+ "原因調査の状況": st.session_state["status_cause_investigation"],
670
+ "原因調査の調査内容/結果": str(
671
+ response_data["原因調査の調査内容/結果"]
672
+ ),
673
+ "直接原因": str(response_data["直接原因"]),
674
+ "根本原因": str(response_data["根本原因"]),
675
+ "原因調査の分類": st.session_state[
676
+ "cause_investigation_classification"
677
+ ],
678
+ "原因調査の分類(その他)": st.session_state[
679
+ "cause_investigation_classification_others"
680
+ ],
681
+ "原因調査の手法": st.session_state["cause_investigation_method"],
682
+ "原因調査の手法(その他)": st.session_state[
683
+ "cause_investigation_method_others"
684
+ ],
685
+ "製品品質(製品・中間製品・原材料)への影響調査の状況": st.session_state[
686
+ "status_impact_investigation"
687
+ ],
688
+ "当該ロットへの影響": str(response_data["当該ロットへの影響"]),
689
+ "他製品・他ロットへの影響": str(
690
+ response_data["他製品・他ロットへの影響"]
691
+ ),
692
+ "調査の延長申請(原因調査及び製品品質への影響)": st.session_state[
693
+ "investigation_extension"
694
+ ],
695
+ "調査延長 次報の報告予定日": formatted_investigation_next_report_date,
696
+ "調査延長 延長理由": str(response_data["調査延長の理由"]),
697
+ "回復措置の状況": st.session_state["status_recovery_measures"],
698
+ "回復措置の実施内容": str(response_data["回復措置の実施内容"]),
699
+ "回復措置の実施結果": str(response_data["回復措置の実施結果"]),
700
+ "製品等に対する措置の状況": st.session_state["status_product_measures"],
701
+ "製品等に対する措置の実施内容": str(
702
+ response_data["製品等に対する措置の実施内容"]
703
+ ),
704
+ "製品等に対する措置の実施結果": str(
705
+ response_data["製品等に対する措置の実施結果"]
706
+ ),
707
+ "特別作業指図書の添付": st.session_state["special_work_instructions"],
708
+ "是正措置/予防措置の状況": st.session_state[
709
+ "status_corrective_preventive_measures"
710
+ ],
711
+ "是正措置/予防措置の実施内容": str(
712
+ response_data["是正措置/予防措置の実施内容"]
713
+ ),
714
+ "是正措置/予防措置の実施結果": str(
715
+ response_data["是正措置/予防措置の実施結果"]
716
+ ),
717
+ "教育訓練": st.session_state["measures_education_training"],
718
+ "教育訓練の計画(予定日/実施日)": formatted_education_training_plan,
719
+ "有効性評価の状況": st.session_state["status_validity_assessment"],
720
+ "有効性評価内容、有効性確認方法、有効性予定期間": str(
721
+ response_data["有効性評価内容、有効性確認方法、有効性予定期間"]
722
+ ),
723
+ "有効性評価結果、有効性実施期間": str(
724
+ response_data["有効性評価結果、有効性実施期間"]
725
+ ),
726
+ "その他の措置の状況": st.session_state["status_other_measures"],
727
+ "その他の措置の実施内容": str(response_data["その他の措置の実施内容"]),
728
+ "その他の措置の実施結果": str(response_data["その他の措置の実施結果"]),
729
+ "措置の延長申請": st.session_state["measures_extension"],
730
+ "措置延長 次報の報告予定日": formatted_measures_next_report_date,
731
+ "措置延長 延長理由": str(response_data["措置延長の理由"]),
732
+ "添付資料": st.session_state["attachment"],
733
+ "添付資料名": st.session_state["attached_files"],
734
  }
735
 
736
  output_deviation_investigation_report(st.session_state["contents"])
737
  st.session_state["document_generated"] = True
738
 
739
+ if st.session_state["document_generated"]:
740
+ st.markdown("以下の内容を記入した逸脱調査報告書(.docx)を作成しました。")
741
 
742
+ with open("data/output_deviation_investigation.docx", "rb") as file:
743
+ st.download_button(
744
+ label="ダウンロード",
745
+ data=file,
746
+ file_name="output_deviation_investigation.docx",
747
+ mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
748
+ )
749
 
750
+ for key, value in st.session_state["contents"].items():
751
+ st.markdown(f"**{key}**: {value}")
752
+
753
+
754
+ def output_deviation_investigation_report(contents: Dict[str, str]) -> None:
755
+ template_path = "data/template/template_deviation_investigation.docx"
756
+
757
+ cause_complete = ""
758
+ cause_complete_suggestion = "□"
759
+ cause_currently_supporting = "□"
760
+ cause_no_support_required = ""
761
+ impact_complete = "□"
762
+ impact_complete_suggestion = "□"
763
+ impact_currently_supporting = ""
764
+ impact_no_support_required = "□"
765
+ recovery_measures_complete = "□"
766
+ recovery_measures_complete_suggestion = ""
767
+ recovery_measures_currently_supporting = "□"
768
+ recovery_measures_no_support_required = "□"
769
+ product_measures_complete = ""
770
+ product_measures_complete_suggestion = "□"
771
+ product_measures_currently_supporting = ""
772
+ product_measures_no_support_required = ""
773
+ corrective_preventive_measures_complete = ""
774
+ corrective_preventive_measures_complete_suggestion = "□"
775
+ corrective_preventive_measures_currently_supporting = "□"
776
+ corrective_preventive_measures_no_support_required = "□"
777
+ validity_assessment_complete = "□"
778
+ validity_assessment_complete_suggestion = "□"
779
+ validity_assessment_currently_supporting = "□"
780
+ validity_assessment_no_support_required = "□"
781
+ validity_assessment_reservation = "□"
782
+ ohter_measures_complete = "□"
783
+ ohter_measures_complete_suggestion = "□"
784
+ ohter_measures_currently_supporting = "□"
785
+ ohter_measures_no_support_required = "□"
786
+
787
+ match contents["原因調査の状況"]:
788
+ case InvestigationOrMethodStatus.COMPLETED.value:
789
+ cause_complete = "☑"
790
+ case InvestigationOrMethodStatus.PROPOSED_COMPLETION.value:
791
+ cause_complete_suggestion = "☑"
792
+ case InvestigationOrMethodStatus.IN_PROGRESS.value:
793
+ cause_currently_supporting = "☑"
794
+ case InvestigationOrMethodStatus.NO_ACTION_NEEDED.value:
795
+ cause_no_support_required = "☑"
796
+ match contents["製品品質(製品・中間製品・原材料)への影響調査の状況"]:
797
+ case InvestigationOrMethodStatus.COMPLETED.value:
798
+ impact_complete = "☑"
799
+ case InvestigationOrMethodStatus.PROPOSED_COMPLETION.value:
800
+ impact_complete_suggestion = "☑"
801
+ case InvestigationOrMethodStatus.IN_PROGRESS.value:
802
+ impact_currently_supporting = "☑"
803
+ case InvestigationOrMethodStatus.NO_ACTION_NEEDED.value:
804
+ impact_no_support_required = "☑"
805
+ match contents["回復措置の状況"]:
806
+ case InvestigationOrMethodStatus.COMPLETED.value:
807
+ recovery_measures_complete = "☑"
808
+ case InvestigationOrMethodStatus.PROPOSED_COMPLETION.value:
809
+ recovery_measures_complete_suggestion = "☑"
810
+ case InvestigationOrMethodStatus.IN_PROGRESS.value:
811
+ recovery_measures_currently_supporting = "☑"
812
+ case InvestigationOrMethodStatus.NO_ACTION_NEEDED.value:
813
+ recovery_measures_no_support_required = "☑"
814
+ match contents["製品等に対する措置の状況"]:
815
+ case InvestigationOrMethodStatus.COMPLETED.value:
816
+ product_measures_complete = "☑"
817
+ case InvestigationOrMethodStatus.PROPOSED_COMPLETION.value:
818
+ product_measures_complete_suggestion = "☑"
819
+ case InvestigationOrMethodStatus.IN_PROGRESS.value:
820
+ product_measures_currently_supporting = "☑"
821
+ case InvestigationOrMethodStatus.NO_ACTION_NEEDED.value:
822
+ product_measures_no_support_required = "☑"
823
+ match contents["是正措置/予防措置の状況"]:
824
+ case InvestigationOrMethodStatus.COMPLETED.value:
825
+ corrective_preventive_measures_complete = "☑"
826
+ case InvestigationOrMethodStatus.PROPOSED_COMPLETION.value:
827
+ corrective_preventive_measures_complete_suggestion = "☑"
828
+ case InvestigationOrMethodStatus.IN_PROGRESS.value:
829
+ corrective_preventive_measures_currently_supporting = "☑"
830
+ case InvestigationOrMethodStatus.NO_ACTION_NEEDED.value:
831
+ corrective_preventive_measures_no_support_required = "☑"
832
+ match contents["有効性評価の状況"]:
833
+ case ValidityAssessmentStatus.COMPLETED.value:
834
+ validity_assessment_complete = "☑"
835
+ case ValidityAssessmentStatus.PROPOSED_COMPLETION.value:
836
+ validity_assessment_complete_suggestion = "☑"
837
+ case ValidityAssessmentStatus.IN_PROGRESS.value:
838
+ validity_assessment_currently_supporting = "☑"
839
+ case ValidityAssessmentStatus.NO_ACTION_NEEDED.value:
840
+ validity_assessment_no_support_required = "☑"
841
+ case ValidityAssessmentStatus.ON_HOLD.value:
842
+ validity_assessment_reservation = "☑"
843
+ match contents["その他の措置の状況"]:
844
+ case InvestigationOrMethodStatus.COMPLETED.value:
845
+ ohter_measures_complete = "☑"
846
+ case InvestigationOrMethodStatus.PROPOSED_COMPLETION.value:
847
+ ohter_measures_complete_suggestion = "☑"
848
+ case InvestigationOrMethodStatus.IN_PROGRESS.value:
849
+ ohter_measures_currently_supporting = "☑"
850
+ case InvestigationOrMethodStatus.NO_ACTION_NEEDED.value:
851
+ ohter_measures_no_support_required = "☑"
852
+
853
+ procedure = "□"
854
+ education_training = "□"
855
+ facilities_equipment = "□"
856
+ environment = "□"
857
+ people_relationships = "□"
858
+ control = "□"
859
+ classification_others = "□"
860
+ classification_others_content = ""
861
+ analysis_5why = "□"
862
+ characteristics = "□"
863
+ method_others = "□"
864
+ method_others_content = ""
865
+
866
+ match contents["原因調査の分類"]:
867
+ case CauseInvestigationClassifications.PROCEDURE.value:
868
+ procedure = "☑"
869
+ case CauseInvestigationClassifications.EDUCATION_TRAINING.value:
870
+ education_training = "☑"
871
+ case CauseInvestigationClassifications.FACILITIES_EQUIPMENT.value:
872
+ facilities_equipment = "☑"
873
+ case CauseInvestigationClassifications.ENVIRONMENT.value:
874
+ environment = "☑"
875
+ case CauseInvestigationClassifications.PEOPLE_RELATIONSHIPS.value:
876
+ people_relationships = "☑"
877
+ case CauseInvestigationClassifications.CONTROL.value:
878
+ control = "☑"
879
+ case CauseInvestigationClassifications.OTHERS.value:
880
+ classification_others = "☑"
881
+ classification_others_content = contents["原因調査の分類(その他)"]
882
+
883
+ match contents["原因調査の手法"]:
884
+ case CauseInvestigationMethods.ANALYSIS_5WHY.value:
885
+ analysis_5why = "☑"
886
+ case CauseInvestigationMethods.CHARACTERISTICS_MAP.value:
887
+ characteristics = "☑"
888
+ case CauseInvestigationMethods.OTHERS.value:
889
+ method_others = "☑"
890
+ method_others_content = contents["原因調査の手法(その他)"]
891
+
892
+ presence_special_work_instructions = "□"
893
+ absence_special_work_instructions = "□"
894
+
895
+ if contents["特別作業指図書の添付"] == PresenceOrAbsence.PRESENCE.value:
896
+ presence_special_work_instructions = "☑"
897
+ else:
898
+ absence_special_work_instructions = "☑"
899
+
900
+ presence_education_training = "□"
901
+ absence_education_training = "□"
902
+ hold_education_training = "□"
903
+ training_plan = ""
904
+
905
+ if contents["教育訓練"] == ActionRequirement.REQUIRED.value:
906
+ presence_education_training = "☑"
907
+ training_plan = contents["教育訓練の計画(予定日/実施日)"]
908
+ elif contents["教育訓練"] == ActionRequirement.ON_HOLD.value:
909
+ hold_education_training = "☑"
910
+ else:
911
+ absence_education_training = "☑"
912
+
913
+ presence_investigation_extension = "□"
914
+ absence_investigation_extension = "□"
915
+ investigation_next_report_date = ""
916
+ investigation_extension_reason = ""
917
+
918
+ if (
919
+ contents["調査の延長申請(原因調査及び製品品質への影響)"]
920
+ == PresenceOrAbsence.PRESENCE.value
921
+ ):
922
+ presence_investigation_extension = "☑"
923
+ investigation_next_report_date = contents["調査延長 次報の報告予定日"]
924
+ investigation_extension_reason = contents["調査延長 延長理由"]
925
+ else:
926
+ absence_investigation_extension = "☑"
927
+
928
+ presence_measures_extension = "□"
929
+ absence_measures_extension = "□"
930
+ measures_next_report_date = ""
931
+ measures_extension_reason = ""
932
+
933
+ if contents["措置の延長申請"] == PresenceOrAbsence.PRESENCE.value:
934
+ presence_measures_extension = "☑"
935
+ measures_next_report_date = contents["措置延長 次報の報告予定日"]
936
+ measures_extension_reason = contents["措置延長 延長理由"]
937
+ else:
938
+ absence_measures_extension = "☑"
939
+
940
+ presence_attachment = "□"
941
+ absence_attachment = "□"
942
+ attachment = ""
943
+
944
+ if contents["添付資料"] == PresenceOrAbsence.PRESENCE.value:
945
+ presence_attachment = "☑"
946
+ attachment = contents["添付資料名"]
947
+ else:
948
+ absence_attachment = "☑"
949
+
950
+ replacements = {
951
+ "[subject]": contents["件名"],
952
+ "[control_number]": contents["管理番号"],
953
+ "[section_name]": contents["課名"],
954
+ "[report_number]": contents["報数"],
955
+ "[deviation_summary]": contents["逸脱概要"],
956
+ "[cause_complete]": cause_complete,
957
+ "[cause_complete_suggestion]": cause_complete_suggestion,
958
+ "[cause_currently_supporting]": cause_currently_supporting,
959
+ "[cause_no_support_required]": cause_no_support_required,
960
+ "[investigation_result]": contents["原因調査の調査内容/結果"],
961
+ "[direct_cause]": contents["直接原因"],
962
+ "[root_cause]": contents["根本原因"],
963
+ "[procedure]": procedure,
964
+ "[education_training]": education_training,
965
+ "[facilities_equipment]": facilities_equipment,
966
+ "[environment]": environment,
967
+ "[people_relationships]": people_relationships,
968
+ "[control]": control,
969
+ "[classification_others]": classification_others,
970
+ "[classification_others_content]": classification_others_content,
971
+ "[analysis_5why]": analysis_5why,
972
+ "[characteristics]": characteristics,
973
+ "[method_others]": method_others,
974
+ "[method_others_content]": method_others_content,
975
+ "[impact_complete]": impact_complete,
976
+ "[impact_complete_suggestion]": impact_complete_suggestion,
977
+ "[impact_currently_supporting]": impact_currently_supporting,
978
+ "[impact_no_support_required]": impact_no_support_required,
979
+ "[impact_on_the_lot]": contents["当該ロットへの影響"],
980
+ "[impact_on_others]": contents["他製品・他ロットへの影響"],
981
+ "[presence_investigation_extension]": presence_investigation_extension,
982
+ "[absence_investigation_extension]": absence_investigation_extension,
983
+ "[investigation_next_report_date]": investigation_next_report_date,
984
+ "[investigation_extension_reason]": investigation_extension_reason,
985
+ "[recovery_measures_complete]": recovery_measures_complete,
986
+ "[recovery_measures_complete_suggestion]": recovery_measures_complete_suggestion,
987
+ "[recovery_measures_currently_supporting]": recovery_measures_currently_supporting,
988
+ "[recovery_measures_no_support_required]": recovery_measures_no_support_required,
989
+ "[recovery_measures]": contents["回復措置の実施内容"],
990
+ "[recovery_measures_result]": contents["回復措置の実施結果"],
991
+ "[product_measures_complete]": product_measures_complete,
992
+ "[product_measures_complete_suggestion]": product_measures_complete_suggestion,
993
+ "[product_measures_currently_supporting]": product_measures_currently_supporting,
994
+ "[product_measures_no_support_required]": product_measures_no_support_required,
995
+ "[product_measures]": contents["製品等に対する措置の実施内容"],
996
+ "[product_measures_result]": contents["製品等に対する措置の実施結果"],
997
+ "[presence_special_work_instructions]": presence_special_work_instructions,
998
+ "[absence_special_work_instructions]": absence_special_work_instructions,
999
+ "[corrective_preventive_measures_complete]": corrective_preventive_measures_complete,
1000
+ "[corrective_preventive_measures_complete_suggestion]": corrective_preventive_measures_complete_suggestion,
1001
+ "[corrective_preventive_measures_currently_supporting]": corrective_preventive_measures_currently_supporting,
1002
+ "[corrective_preventive_measures_no_support_required]": corrective_preventive_measures_no_support_required,
1003
+ "[corrective_precautionary_measures]": contents["是正措置/予防措置の実施内容"],
1004
+ "[corrective_precautionary_measures_result]": contents[
1005
+ "是正措置/予防措置の実施結果"
1006
+ ],
1007
+ "[presence_education_training]": presence_education_training,
1008
+ "[absence_education_training]": absence_education_training,
1009
+ "[hold_education_training]": hold_education_training,
1010
+ "[training_plan]": training_plan,
1011
+ "[validity_assessment_complete]": validity_assessment_complete,
1012
+ "[validity_assessment_complete_suggestion]": validity_assessment_complete_suggestion,
1013
+ "[validity_assessment_currently_supporting]": validity_assessment_currently_supporting,
1014
+ "[validity_assessment_no_support_required]": validity_assessment_no_support_required,
1015
+ "[validity_assessment_reservation]": validity_assessment_reservation,
1016
+ "[validity_assessment]": contents[
1017
+ "有効性評価内容、有効性確認方法、有効性予定期間"
1018
+ ],
1019
+ "[validity_assessment_result]": contents["有効性評価結果、有効性実施期間"],
1020
+ "[ohter_measures_complete]": ohter_measures_complete,
1021
+ "[ohter_measures_complete_suggestion]": ohter_measures_complete_suggestion,
1022
+ "[ohter_measures_currently_supporting]": ohter_measures_currently_supporting,
1023
+ "[ohter_measures_no_support_required]": ohter_measures_no_support_required,
1024
+ "[other_measures]": contents["その他の措置の実施内容"],
1025
+ "[other_measures_result]": contents["その他の措置の実施結果"],
1026
+ "[presence_measures_extension]": presence_measures_extension,
1027
+ "[absence_measures_extension]": absence_measures_extension,
1028
+ "[measures_next_report_date]": measures_next_report_date,
1029
+ "[measures_extension_reason]": measures_extension_reason,
1030
+ "[presence_attachment]": presence_attachment,
1031
+ "[absence_attachment]": absence_attachment,
1032
+ "[attachment]": attachment,
1033
+ }
1034
+
1035
+ doc = replace_text_in_docx(template_path, replacements)
1036
+ output_path = "data/output_deviation_investigation.docx"
1037
+ doc.save(output_path)
1038
+ logger.info(f"Document saved to {output_path}")
src/forms/deviation_notification_report.py CHANGED
@@ -228,7 +228,7 @@ def deviation_notification_report_form() -> None:
228
  {"role": "user", "content": user_prompt},
229
  ],
230
  response_format={"type": "json_object"},
231
- temperature=0.85,
232
  )
233
  logger.info("OpenAIからのレスポンス(逸脱連絡書作成用): " + str(response))
234
  response_text = response.choices[0].message.content
@@ -319,8 +319,7 @@ def deviation_notification_report_form() -> None:
319
  )
320
 
321
  for key, value in st.session_state["contents"].items():
322
- if key != "ユーザープロンプト":
323
- st.markdown(f"**{key}**: {value}")
324
 
325
  deviation_notification_user_template_review = f"""
326
  ## 今回の「逸脱概要」:
@@ -343,7 +342,7 @@ def deviation_notification_report_form() -> None:
343
  "content": deviation_notification_user_template_review,
344
  },
345
  ],
346
- temperature=0.7,
347
  )
348
  review = completion.choices[0].message.content
349
 
 
228
  {"role": "user", "content": user_prompt},
229
  ],
230
  response_format={"type": "json_object"},
231
+ temperature=0.0,
232
  )
233
  logger.info("OpenAIからのレスポンス(逸脱連絡書作成用): " + str(response))
234
  response_text = response.choices[0].message.content
 
319
  )
320
 
321
  for key, value in st.session_state["contents"].items():
322
+ st.markdown(f"**{key}**: {value}")
 
323
 
324
  deviation_notification_user_template_review = f"""
325
  ## 今回の「逸脱概要」:
 
342
  "content": deviation_notification_user_template_review,
343
  },
344
  ],
345
+ temperature=0.0,
346
  )
347
  review = completion.choices[0].message.content
348
 
src/prompts/deviation_investigation_report.py CHANGED
@@ -1,14 +1,29 @@
1
  deviation_investigation_systemprompt_writing_instructions = """
2
  ***
3
- 逸脱内容・発見の経緯:
4
- 応急処置・処置の理由:
5
- 品質への影響の調査結果:
6
- 原因調査結果:
7
- 是正措置・予防措置:
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  ***
9
- あなたは、質問に対して入力された情報から、詳しい内容を含んだ逸脱報告書の文章を生成するアシスタントです。\n
10
  上記の形式に従って、入力された情報を当てはめて出力してください。報告書の読みやすさ、明瞭さ、正確さに注意してください。\n
11
- 変更や必要がないという回答に関してはは特にそのことを記述する必要はありません。特別な記述があった場合にのみ記述してください。
 
 
12
  「だ・である」調で出力してください。\n
13
  あなたは返答をすべてJSON形式で出力します。\n
14
  あなたが質問した内容は以下です。\n
@@ -19,12 +34,24 @@ deviation_investigation_systemprompt_output_format_instructions = """
19
  ***
20
  出力は以下のjsonテンプレートに従って出力してください。\n
21
  {
22
- "逸脱内容・発見の経緯":"",
23
- "応急処置・処置の理由":"",
24
- "品質への影響の調査結果": "",
25
- "原因調査結果": "",
26
- "是正措置・予防措置": ""
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  }
28
  ***
29
- 「です・ます」調ではなく「だ・である」調で出力してください。\n
30
  """
 
1
  deviation_investigation_systemprompt_writing_instructions = """
2
  ***
3
+ 逸脱概要:
4
+ 原因調査の調査内容/結果:
5
+ 直接原因:
6
+ 根本原因:
7
+ 当該ロットへの影響:
8
+ 他製品・他ロットへの影響:
9
+ 回復措置の実施内容:
10
+ 回復措置の実施結果:
11
+ 製品等に対する措置の実施内容:
12
+ 製品等に対する措置の実施結果:
13
+ 是正措置/予防措置の実施内容:
14
+ 是正措置/予防措置の実施結果:
15
+ 有効性評価内容、有効性確認方法、有効性予定期間:
16
+ 有効性評価結果、有効性実施期間:
17
+ その他の措置の実施内容:
18
+ その他の措置の実施結果:
19
+ 調査延長の理由:
20
+ 措置延長の理由:
21
  ***
22
+ あなたは、質問に対して入力された情報から、詳しい内容を含んだ逸脱調査報告書の文章を生成するアシスタントです。\n
23
  上記の形式に従って、入力された情報を当てはめて出力してください。報告書の読みやすさ、明瞭さ、正確さに注意してください。\n
24
+ 基本的に質問は項目と一対一で対応しています。\n
25
+ 入力された内容をそのまま記載するのではなく、正しい日本語表現かどうかに注意し、わかりやすく簡潔な表現に直して記載してください。\n
26
+ 回答が「なし」の場合は「なし」と記入してください。\n
27
  「だ・である」調で出力してください。\n
28
  あなたは返答をすべてJSON形式で出力します。\n
29
  あなたが質問した内容は以下です。\n
 
34
  ***
35
  出力は以下のjsonテンプレートに従って出力してください。\n
36
  {
37
+ "逸脱概要": "",
38
+ "原因調査の調査内容/結果": "",
39
+ "直接原因": "",
40
+ "根本原因": "",
41
+ "当該ロットへの影響": "",
42
+ "他製品・他ロットへの影響": "",
43
+ "回復措置の実施内容": "",
44
+ "回復措置の実施結果": "",
45
+ "製品等に対する措置の実施内容": "",
46
+ "製品等に対する措置の実施結果": "",
47
+ "是正措置/予防措置の実施内容": "",
48
+ "是正措置/予防措置の実施結果": "",
49
+ "有効性評価内容、有効性確認方法、有効性予定期間": "",
50
+ "有効性評価結果、有効性実施期間": "",
51
+ "その他の措置の実施内容": "",
52
+ "その他の措置の実施結果": "",
53
+ "調査延長の理由": "",
54
+ "措置延長の理由": "",
55
  }
56
  ***
 
57
  """
src/utils.py CHANGED
@@ -118,54 +118,6 @@ def output_deviation_notification_report(contents: Dict[str, str]) -> None:
118
  logger.info(f"Document saved to {output_path}")
119
 
120
 
121
- def output_deviation_investigation_report(contents: Dict[str, str]) -> None:
122
- template_path = "data/template/template_deviation_investigation.docx"
123
-
124
- if contents["出荷の制限"] == "なし":
125
- yes_sr = "□"
126
- no_sr = "☑"
127
- shipping_restriction = ""
128
- else:
129
- yes_sr = "☑"
130
- no_sr = "□"
131
- shipping_restriction = contents["出荷の制限"]
132
-
133
- if contents["添付資料"] == "なし":
134
- yes_af = "□"
135
- no_af = "☑"
136
- attached_file = ""
137
- else:
138
- yes_af = "☑"
139
- no_af = "□"
140
- attached_file = contents["添付資料"]
141
-
142
- replacements = {
143
- "[reporter_name]": contents["報告者"],
144
- "[report_date]": contents["報告日"],
145
- "[product_name]": contents["品名"],
146
- "[lot_number]": contents["ロットNo."],
147
- "[occurrence_datetime]": contents["発生日時"],
148
- "[occurrence_place]": contents["発生場所"],
149
- "[deviation_discovery]": contents["逸脱内容・発見の経緯"],
150
- "[first_aid_reason]": contents["応急処置・処置の理由"],
151
- "[impact_on_quality]": contents["品質への影響の調査結果"],
152
- "[cause_investigation]": contents["原因調査結果"],
153
- "[corrective_preventive_measures]": contents["是正措置・予防措置"],
154
- "[yes_sr]": yes_sr,
155
- "[no_sr]": no_sr,
156
- "[shipping_restriction]": shipping_restriction,
157
- "[yes_af]": yes_af,
158
- "[no_af]": no_af,
159
- "[attached_file]": attached_file,
160
- "[supplementary_information]": contents["備考"],
161
- }
162
-
163
- doc = replace_text_in_docx(template_path, replacements)
164
- output_path = "data/output_deviation_investigation.docx"
165
- doc.save(output_path)
166
- logger.info(f"Document saved to {output_path}")
167
-
168
-
169
  def replace_text_in_docx(template_path: str, replacements: Dict[str, str]) -> Any:
170
  """
171
  ドキュメント内の指定されたテキストを置き換える
 
118
  logger.info(f"Document saved to {output_path}")
119
 
120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  def replace_text_in_docx(template_path: str, replacements: Dict[str, str]) -> Any:
122
  """
123
  ドキュメント内の指定されたテキストを置き換える