tags of input representation into a Python list. Give me the names of catalysts ONLY. Only output the Python list(like string).\n\n"],
17 | "2_list": ["json", "Question 2. Please tell me the names of catalysts from the input json provided by me into a Python list. Only output the Python list(like string).\n\n"],
18 | "3_list": ["None", "Question 3. Based on the answer to Question 1, modify or remove any catalysts from the answer to Question 2 and provide the updated list in Python. Give me the names of catalysts ONLY. Only output the Python list.(like string)\n\n"]
19 | }
20 |
21 | # Questions related to performance
22 | self.questions_for_performance = {
23 | "1_list": ["json", "Question 1. Inform me about what performance type does {catalyst_name} have in the input json I provided? Only output the Python list.(like string)\n\n"]
24 | }
25 |
26 | # Questions related to properties
27 | self.questions_for_property = {
28 | "1_both": ["json", "Question 1. Provide detailed information about all sublayers of the {element} of {catalyst_name} in input json. Remove keys from the dictionary that do not have a value. Present it in either Python list or JSON format. If the {element} is not 'loading', strictly provide it in Python list or JSON format.(like string not ```python and not ```json)\n\n"],
29 | "2_str": ["None", "Question 2. If there is any occurrence of 'NA', 'na', 'unknown', or similar content in your recent response, Respond with yes or no. You must answer strictly with yes or no.\n\n"],
30 | "3_dict": ["None", "Question 3. In the answer to question 1, remove any parts corresponding to 'NA', 'na', 'unknown', or similar contents. Show the modified JSON. Only display the JSON. (like string not ```json)\n\n"],
31 | "4_list": ["representation", "Question 4. Based on the input representation, provide values of the {element} of the {catalyst_name} as a Python list. If there is a unit, please provide strictly the value including the unit. The elements of a Python list must be composed of value plus unit. Only output the Python list.(like string not ```python)\n\n"],
32 | "5_list": ["None", "Question 5. Based on the answer to question 3, provide values of the '''value''' key of the sublayers of the {element} as a Python list. Only output the Python list.(like string not ```python)\n\n"],
33 | "6_list": ["None", "Question 6. Based on only numerical values, provide a list of elements that exist in the answer to Question 5 but are not present in the the answer to Question 4. Note that unit differences can be ignored if the numbers match. Only output the Python list.(like string not ```python)\n\n"],
34 | "7_dict": ["json", "Question 7. If elements included in the list that is the answer to question 6 are in the answer to question 1, remove the sub-dictionary containing those elements from the json I provided. If the answer to 6 is a list containing elements, be sure to delete it from json. Show the modified JSON after removal. Only display the JSON. (like string not ```json)\n\n"],
35 | "8_dict": ["json", "Question 8. Please tell me the final modified json of {catalyst_name} by reflecting the answer to question 7 in the json I provided. Only output the JSON of {catalyst_name}. the catalyst_name is {catalyst_name}. The first key of the dictionary should be {catalyst_name}. Remove keys from the dictionary that do not have a value. (like string not ```json)"]
36 | }
37 |
38 | # Questions related to electrolyte, reaction_type, substrate
39 | self.questions_for_representation = {
40 | "1_str": ["representation_title", "Question 1. If there is any occurrence of 'OER', 'HER', 'oxygen evolution reaction', 'hydrogen evolution reaction' or similar contents in input representation, respond with yes or no. Please answer with either yes or no.\n\n"],
41 | "2_str": ["representation_table_caption", "Question 2. If there is any occurrence of 'OER', 'HER', 'oxygen evolution reaction', 'hydrogen evolution reaction' or similar contents in input representation, respond with yes or no. Please answer with either yes or no.\n\n"],
42 | "3_str": ["representation_title", "Question 3. Does the input representation contain information corresponding to substrate? Please answer with either yes or no\n\n"],
43 | "4_str": ["representation_table_caption", "Question 4. Does the input representation contain information corresponding to substrate? Please answer with either yes or no\n\n"],
44 | "5_str": ["representation_title", "Question 5. Does the input representation contain information corresponding to electrolyte? Please answer with either yes or no\n\n"],
45 | "6_str": ["representation_table_caption", "Question 6. Does the input representation contain information corresponding to electrolyte? Please answer with either yes or no\n\n"]
46 | }
47 |
48 | # system prompt
49 | self.system_prompt = {"role": "system", "content": "You need to modify the JSON representing the table presenter.\n\n JSON templete : {'catalyst_name' : {'performance_name' : \{property templete\}}}\n property templete : {'electrolyte': '', 'reaction_type': '', 'value': '', 'current_density': '', 'overpotential': '', 'potential': '', 'substrate': '', 'versus': '', 'condition': ''}\n performance_list = [overpotential, tafel_slope, Rct, stability, Cdl, onset_potential, potential, TOF, ECSA, water_splitting_potential, mass_activity, exchange_current_density, Rs, specific_activity, onset_overpotential, BET, surface_area, loading, apparent_activation_energy]\n In the JSON template, 'catalyst_name' and 'performance_name' should be replaced with the actual names present in the input representation."}
50 |
51 | def input_prompt(self, representation, json, want_type):
52 | """
53 | Generates a formatted input string based on the type of content requested.
54 |
55 | Parameters:
56 | representation (str): The input representation string containing HTML content.
57 | json (str): The JSON string to be included in the input.
58 | want_type (str): The type of content required ('both', 'representation', 'json', 'representation_title', 'representation_table_caption').
59 |
60 | Returns:
61 | str: The formatted input string.
62 | """
63 |
64 | # Split the representation string at each occurrence of '
'
65 | splitted_strings = representation.split('')
66 | # Determine the format based on the requested type
67 | if want_type == 'both':
68 | format_for_input = "\n" + str(representation) + "\n\n" + str(json) + "\n\n"
69 | elif want_type == 'representation':
70 | format_for_input = "\n" + str(representation) + "\n\n"
71 | elif want_type == 'json':
72 | format_for_input = "\n" + str(json) + "\n\n"
73 | elif want_type == 'representation_title':
74 | title_string = splitted_strings[0] + ''
75 | format_for_input = "\n" + str(title_string) + "\n\n"
76 | elif want_type == 'representation_table_caption':
77 | table_caption_string = splitted_strings[1]
78 | format_for_input = "\n" + str(table_caption_string) + "\n\n"
79 |
80 | return format_for_input
81 |
82 | def load_file(self, file_type, file_path, file_name):
83 | """
84 | Loads the content of a file based on the specified type and path.
85 |
86 | Parameters:
87 | file_type (str): The type of the file (json, html, txt, etc.)
88 | file_path (str): The path to the file
89 | file_name (str): The name of the file
90 |
91 | Returns:
92 | output: The content of the file. The type of the content depends on the file_type.
93 |
94 | Raises:
95 | ValueError: If the file type is unsupported.
96 | """
97 | with open(file_path + file_name, 'r', encoding='utf-8-sig') as f:
98 | # Load JSON files
99 | if file_type == 'json':
100 | output = json.load(f)
101 | # Read text or HTML files
102 | elif file_type in ['html', 'txt']:
103 | output = f.read()
104 | # Raise an error for unsupported file formats
105 | else:
106 | raise ValueError("Unsupported file format.")
107 |
108 | return output
109 |
110 | def formatting_type(self, key, answer):
111 | """
112 | Formats the answer based on the specified key type.
113 |
114 | Parameters:
115 | key (str): The key indicating the type of format required (e.g., '1_list', '2_dict').
116 | answer (str): The answer to be formatted.
117 |
118 | Returns:
119 | The formatted answer, which can be a list or a dictionary based on the key type.
120 | """
121 | # Determine the desired format type from the key
122 | want_type = key.split('_')[1]
123 |
124 | # Handle formatting if the desired type is a list
125 | if want_type == "list":
126 | if answer[0] == '"' and answer[-1] == '"':
127 | answer = answer.strip('"') # Remove surrounding quotes if present
128 | answer = eval(answer) # Evaluate the string as a Python expression (e.g., convert to list)
129 |
130 | # Handle formatting if the desired type is a dictionary
131 | elif want_type == "dict":
132 | if "```" in answer:
133 | answer = answer.replace("```json", "").replace("```", "") # Remove markdown code block formatting
134 | answer = json.loads(answer) # Parse the string as JSON
135 |
136 | return answer
137 |
138 | def check_type(self, key, answer):
139 | """
140 | Checks if the type of the answer matches the expected type based on the key.
141 |
142 | Parameters:
143 | key (str): The key indicating the expected type (e.g., '1_list', '2_dict').
144 | answer (any): The answer whose type needs to be checked.
145 |
146 | Returns:
147 | tuple: A tuple containing the expected type (str) and a boolean indicating whether the types match.
148 | """
149 | # Extract the question number and expected type from the key
150 | question_number = key.split('_')[0]
151 | want_type = key.split('_')[1]
152 |
153 | # Determine the actual type of the answer
154 | answer_type = type(answer).__name__
155 |
156 | # Check if the expected type matches the actual type
157 | type_bool = want_type == answer_type
158 |
159 | return want_type, type_bool
160 |
161 | def prompt(self, Q):
162 | """
163 | Sends a list of messages to the OpenAI ChatCompletion API and returns the response.
164 |
165 | Parameters:
166 | Q (list): A list of message dictionaries to be sent to the API.
167 |
168 | Returns:
169 | tuple: A tuple containing the original list of messages (Q) and the response content.
170 | """
171 | while True:
172 | try:
173 | # Send a request to the OpenAI ChatCompletion API
174 | response = openai.ChatCompletion.create(
175 | model="gpt-4-0125-preview",
176 | messages=Q,
177 | temperature=0,
178 | frequency_penalty=0,
179 | presence_penalty=0
180 | )
181 | break # Exit the loop if the request is successful
182 | except Exception as e:
183 | # Print the error message and retry
184 | print("An error occurred:", e)
185 |
186 | # Return the original messages and the content of the response
187 | return Q, response['choices'][0]['message']['content']
188 |
189 | def run(self, input_type, split_mode):
190 | """
191 | Executes the main process for modifying JSON files based on given questions.
192 |
193 | Parameters:
194 | input_type (str): The type of input files (e.g., 'json', 'txt').
195 | split_mode (str): The mode for handling splits (e.g., 'split', 'no-split').
196 |
197 | Returns:
198 | None
199 | """
200 | json_name_list = os.listdir(self.json_path)
201 | error_file_name = []
202 | transpose_bool = False
203 |
204 | for json_name in json_name_list:
205 | # try:
206 | txt_name = json_name.split('.')[0]
207 | # Load input files
208 | input_json = self.load_file('json', self.json_path, json_name)
209 | input_representation = self.load_file(input_type, self.representation_path, txt_name + '.txt')
210 |
211 | # Initialize messages with system prompt
212 | messages = [self.system_prompt]
213 |
214 | # Catalyst check
215 | catalyst_result = {}
216 | question_list = []
217 | answer_list = []
218 | question_token_list = []
219 | answer_token_list = []
220 | final_result = []
221 | final_json = {"catalysts": []}
222 |
223 | # Iterate through catalyst questions
224 | for key, value in self.questions_for_catalyst.items():
225 | if value[0] != "None":
226 | messages.append({"role": "user", "content": self.input_prompt(input_representation, input_json, value[0])})
227 | messages.append({"role": "user", "content": value[1]})
228 | messages, answer = self.prompt(messages)
229 | question_token_list.append(messages)
230 | answer_token_list.append(answer)
231 |
232 | try:
233 | mod_answer = self.formatting_type(key, answer)
234 | except Exception as e:
235 | try:
236 | messages, answer = self.prompt(messages)
237 | question_token_list.append(messages)
238 | answer_token_list.append(answer)
239 | question_list.append("Throwing the same message once again")
240 | answer_list.append("Throwing the same message once again")
241 | except Exception as e:
242 | error_file_name.append(json_name)
243 | print(json_name)
244 | break
245 |
246 | catalyst_result[key[0]] = mod_answer
247 | question_list.append(value[1])
248 | answer_list.append(mod_answer)
249 |
250 | print('--------------------------')
251 | print(self.questions_for_catalyst[key])
252 | print(mod_answer)
253 | print(catalyst_result)
254 | print('--------------------------')
255 |
256 | messages.append({"role": "assistant", "content": answer})
257 | if key[0] == '2' and catalyst_result["1"] == catalyst_result["2"]:
258 | print("GO TO THE PERFORMANCE STAGE !!")
259 | break
260 |
261 | # Performance check
262 | performance_result = {}
263 | mod_catalyst_list = answer_list[-1]
264 |
265 | if len(mod_catalyst_list) > 1:
266 | transpose_bool = True
267 |
268 | for i in range(len(mod_catalyst_list)):
269 | messages = [self.system_prompt]
270 | for key, value in self.questions_for_performance.items():
271 | if value[0] != "None":
272 | messages.append({"role": "user", "content": self.input_prompt(input_representation, input_json, value[0])})
273 | question = value[1].format(catalyst_name = '"""'+ mod_catalyst_list[i] +'"""')
274 | messages.append({"role": "user", "content": question})
275 | messages, answer = self.prompt(messages)
276 | question_token_list.append(messages)
277 | answer_token_list.append(answer)
278 |
279 | try:
280 | mod_answer = self.formatting_type(key, answer)
281 | except:
282 | try:
283 | messages, answer = self.prompt(messages)
284 | question_token_list.append(messages)
285 | answer_token_list.append(answer)
286 | except:
287 | error_file_name.append(json_name)
288 |
289 | break
290 |
291 | performance_result[f'{mod_catalyst_list[i]}_{key[0]}'] = mod_answer
292 | question_list.append(question)
293 | answer_list.append(mod_answer)
294 |
295 | messages.append({"role": "assistant", "content": answer})
296 | if key[0] == '3' and performance_result[f'{mod_catalyst_list[i]}_3'] == []:
297 | print("GO TO THE PROPERTY STAGE !!")
298 | break
299 |
300 | if isinstance(answer_list[-1], list):
301 | mod_performance_list = performance_result[f'{mod_catalyst_list[i]}_1']
302 | else:
303 | while not isinstance(answer_list[-1], list):
304 | messages.pop()
305 | messages, answer = self.prompt(messages)
306 | question_token_list.append(messages)
307 | answer_token_list.append(answer)
308 | mod_answer = self.formatting_type("1_list", answer)
309 | question_list.append(question)
310 | answer_list.append(mod_answer)
311 | mod_performance_list = answer
312 |
313 | # Property check
314 | property_result = {}
315 | skip_questions = False
316 | print("#####################")
317 | print(mod_performance_list)
318 |
319 | if mod_performance_list == []:
320 | mod_answer = {str(mod_catalyst_list[i]): {}}
321 | else:
322 | for j in range(len(mod_performance_list)):
323 | messages = []
324 | messages.append(self.system_prompt)
325 | print("@@@@@@@@@@@@")
326 | print(mod_performance_list[j])
327 | # system prompt 넣어주고, input 표현자, json 넣어주는 코드
328 | # messages = []
329 | # messages.append(self.system_prompt)
330 |
331 | skip_questions = False
332 | anwer3_no = False
333 | for key, value in self.questions_for_property.items():
334 | # 질문 2의 답변이 "no"일 때 질문 3번과 4번 skip하기 위한 조건문
335 | if key[0] in ['3','7'] and skip_questions:
336 | print("SKIP THE NEXT QUESTIONS")
337 | question_list.append("SKIP THE NEXT QUESTIONS")
338 | answer_list.append("SKIP THE NEXT QUESTIONS")
339 | if key[0] in ['3','7']:
340 | skip_questions = False
341 | continue # 질문 3번과 4번 건너뛰기
342 |
343 | if value[0] != "None":
344 | messages.append({"role": "user", "content": self.input_prompt(input_representation, input_json, value[0])})
345 |
346 | question = value[1].format(catalyst_name = '"""'+ mod_catalyst_list[i] +'"""', element = '"""'+ mod_performance_list[j] +'"""')
347 | messages.append({"role": "user", "content": question})
348 | messages, answer = self.prompt(messages)
349 | question_token_list.append(messages)
350 | answer_token_list.append(answer)
351 | try:
352 | mod_answer = self.formatting_type(key, answer)
353 | except:
354 | try:
355 | messages, answer = self.prompt(messages)
356 | question_token_list.append(messages)
357 | answer_token_list.append(answer)
358 | except:
359 | print(json_name)
360 | error_file_name.append(json_name)
361 | break
362 |
363 | property_result[mod_catalyst_list[i] + '_' + mod_performance_list[j] + '_' + key[0]] = answer
364 | question_list.append(question)
365 | answer_list.append(mod_answer)
366 |
367 | print('--------------------------')
368 | print(question)
369 | print(mod_answer)
370 | print('--------------------------')
371 |
372 | messages.append({"role": "assistant", "content": answer})
373 |
374 | if key[0] == '2' and mod_answer.lower() == "no":
375 | question_list.append("Question 3. Based on the answer to question 2, remove any parts corresponding to 'NA', 'na', 'unknown', or similar content from the answer to question 1. Show the modified JSON. Only display the JSON. (like string not ```json)")
376 | answer_list.append(str(property_result[mod_catalyst_list[i] + '_' + mod_performance_list[j] + '_1']))
377 | messages.append({"role": "user", "content": "Question 3. Based on the answer to question 2, remove any parts corresponding to 'NA', 'na', 'unknown', or similar content from the answer to question 1. Show the modified JSON. Only display the JSON. (like string not ```json)"})
378 | messages.append({"role": "assistant", "content": property_result[mod_catalyst_list[i] + '_' + mod_performance_list[j] + '_1']})
379 | skip_questions = True
380 | anwer3_no = True
381 |
382 | if key[0] == '6' and mod_answer == []:
383 | if anwer3_no:
384 | question_list.append("Question 7. If the answer to question 6 is an empty list, just provide the answer to question 1 as it is.")
385 | answer_list.append(str(property_result[mod_catalyst_list[i] + '_' + mod_performance_list[j] + '_1']))
386 | messages.append({"role": "user", "content": "Question 7. If the answer to question 6 is an empty list, just provide the answer to question 1 as it is."})
387 | messages.append({"role": "assistant", "content": property_result[mod_catalyst_list[i] + '_' + mod_performance_list[j] + '_1']})
388 | skip_questions = True
389 | else:
390 | question_list.append("Question 7. If the answer to question 6 is an empty list, just provide the answer to question 3 as it is.")
391 | answer_list.append(str(property_result[mod_catalyst_list[i] + '_' + mod_performance_list[j] + '_3']))
392 | messages.append({"role": "user", "content": "Question 7. If the answer to question 6 is an empty list, just provide the answer to question 3 as it is."})
393 | messages.append({"role": "assistant", "content": property_result[mod_catalyst_list[i] + '_' + mod_performance_list[j] + '_3']})
394 | skip_questions = True
395 |
396 | if isinstance(mod_answer, dict):
397 | input_json = mod_answer
398 | else:
399 | count = 0
400 | while not isinstance(mod_answer, dict) and count < 3:
401 | messages.pop()
402 | messages.append({"role": "user", "content": self.input_prompt(input_representation, input_json, 'json')})
403 | messages, answer = self.prompt(messages)
404 | question_token_list.append(messages)
405 | answer_token_list.append(answer)
406 | try:
407 | mod_answer = self.formatting_type(key, answer)
408 | except:
409 | try:
410 | messages, answer = self.prompt(messages)
411 | question_token_list.append(messages)
412 | answer_token_list.append(answer)
413 | except:
414 | print('#$@%@#%@#%#@%@#%@#')
415 | print(json_name)
416 | print('#$@%@#%@#%#@%@#%@#')
417 | error_file_name.append(json_name)
418 | break
419 |
420 | count += 1
421 |
422 | property_result[mod_catalyst_list[i] + '_' + mod_performance_list[j] + '_' + key[0]] = answer
423 | question_list.append(question)
424 | answer_list.append(mod_answer)
425 |
426 | print('--------------------------')
427 | print(question)
428 | print(mod_answer)
429 | print('--------------------------')
430 |
431 | messages.append({"role": "assistant", "content": answer})
432 |
433 | if len(mod_catalyst_list) == 1 and split_mode == 'split':
434 | final_result.append(mod_answer)
435 | else:
436 | input_json = self.load_file(input_type, self.json_path, json_name)
437 | final_json["catalysts"].append(mod_answer)
438 |
439 | if transpose_bool:
440 | final_result.append(final_json)
441 |
442 | # Final JSON after property modifications
443 | if final_result[0] == []:
444 | input_json = self.load_file('json', self.json_path, json_name)
445 | new_json = input_json
446 | else:
447 | new_json = final_result[0]
448 |
449 | # Handle representation questions
450 | remove_elements = []
451 | representation_result = {}
452 | for key, value in self.questions_for_representation.items():
453 | messages = []
454 | if value[0] == "None":
455 | pass
456 | else:
457 | messages.append({"role": "user", "content": self.input_prompt(input_representation, new_json, value[0])})
458 |
459 | question = value[1]
460 | messages.append({"role": "user", "content": question})
461 | messages, answer = self.prompt(messages)
462 | question_token_list.append(messages)
463 | answer_token_list.append(answer)
464 |
465 | mod_answer = self.formatting_type(key, answer)
466 |
467 | question_list.append(question)
468 | answer_list.append(mod_answer)
469 |
470 | print('--------------------------')
471 | print(question)
472 | print(mod_answer)
473 | print('--------------------------')
474 |
475 | messages.append({"role": "assistant", "content": answer})
476 | representation_result[key[0]] = mod_answer.replace(".", "").lower()
477 |
478 | if representation_result['1'] == 'no' and representation_result['2'] == 'no':
479 | remove_elements.append('reaction_type')
480 | if representation_result['3'] == 'no' and representation_result['4'] == 'no':
481 | remove_elements.append('substrate')
482 | if representation_result['5'] == 'no' and representation_result['6'] == 'no':
483 | remove_elements.append('electrolyte')
484 |
485 | remove_elements = list(set(remove_elements))
486 |
487 | if remove_elements != []:
488 | for delete_element in remove_elements:
489 | messages = []
490 | messages.append({"role": "user", "content": self.input_prompt(input_representation, new_json, 'json')})
491 | question = "Remove all elements with the key name {delete_element} from the input JSON and display it in only JSON format. Other explanation is not allowed. Show me only JSON result. Only display the JSON. (like string not ```json)".format(delete_element="'''"+delete_element+"'''")
492 | messages.append({"role": "user", "content": question})
493 | messages, answer = self.prompt(messages)
494 | question_token_list.append(messages)
495 | answer_token_list.append(answer)
496 | try:
497 | mod_answer = self.formatting_type('1_dict', answer)
498 | except:
499 | try:
500 | messages, answer = self.prompt(messages)
501 | question_token_list.append(messages)
502 | answer_token_list.append(answer)
503 | except:
504 | print('#$@%@#%@#%#@%@#%@#')
505 | print(json_name)
506 | print('#$@%@#%@#%#@%@#%@#')
507 | error_file_name.append(json_name)
508 | break
509 |
510 | question_list.append(question)
511 | answer_list.append(mod_answer)
512 | print('--------------------------')
513 | print(question)
514 | print('answer')
515 | print(answer)
516 | print('mod answer')
517 | print(mod_answer)
518 | print('--------------------------')
519 |
520 | if not isinstance(mod_answer, dict):
521 | count = 0
522 | while not isinstance(mod_answer, dict) and count < 3:
523 | # 원래 했던 질문 제거하고 다시
524 | messages, answer = self.prompt(messages)
525 | question_token_list.append(messages)
526 | answer_token_list.append(answer)
527 | try:
528 | mod_answer = self.formatting_type('1_dict', answer)
529 | except:
530 | try:
531 | messages, answer = self.prompt(messages)
532 | question_token_list.append(messages)
533 | answer_token_list.append(answer)
534 | except:
535 | print('#$@%@#%@#%#@%@#%@#')
536 | print(json_name)
537 | print('#$@%@#%@#%#@%@#%@#')
538 | error_file_name.append(json_name)
539 | break
540 |
541 | count += 1
542 | question_list.append(question)
543 | answer_list.append(mod_answer)
544 |
545 | print('--------------------------')
546 | print(question)
547 | print(mod_answer)
548 | print('--------------------------')
549 |
550 | if not isinstance(mod_answer, dict):
551 | new_json = new_json
552 | else:
553 | new_json = mod_answer
554 | else:
555 | mod_answer = new_json
556 |
557 | # Ensure the necessary directories exist
558 | os.makedirs(os.path.join(self.save_path, 'log'), exist_ok=True)
559 | os.makedirs(os.path.join(self.save_path, 'token'), exist_ok=True)
560 | os.makedirs(os.path.join(self.save_path, 'json'), exist_ok=True)
561 |
562 | # Save the modified JSON and log
563 | if json_name not in error_file_name:
564 | log_path = self.save_path + 'log/'+ txt_name
565 | df = pd.DataFrame({'Question': question_list, 'GPT answer': answer_list})
566 | df.to_csv(log_path+'.csv', index=False)
567 |
568 | token_path = self.save_path + 'token/'+ txt_name
569 | token_df = pd.DataFrame({'Question': question_token_list, 'GPT answer': answer_token_list})
570 | token_df.to_csv(token_path+'.csv', index=False)
571 |
572 | new_json_path = self.save_path + 'json/'+ json_name
573 | if mod_answer == [] :
574 | input_json = self.load_file('json', self.json_path, json_name)
575 | with open(new_json_path, "w") as json_file:
576 | json.dump(input_json, json_file, indent=4)
577 | else:
578 | if isinstance(mod_answer, list):
579 | with open(new_json_path, "w") as json_file:
580 | json.dump(new_json, json_file, indent=4)
581 |
582 | elif isinstance(mod_answer, str):
583 | with open(new_json_path, "w") as json_file:
584 | json.dump(new_json, json_file, indent=4)
585 | else:
586 | with open(new_json_path, "w") as json_file:
587 | json.dump(mod_answer, json_file, indent=4)
588 |
589 |
590 | if __name__ == "__main__":
591 | representation_path = 'table representer path'
592 | json_path = 'gpt prediction'
593 | save_path = 'save path'
594 |
595 | assistant = FollowQ(json_path, representation_path, save_path)
596 | assistant.run('txt', 'split')
597 |
598 |
599 |
--------------------------------------------------------------------------------
/GPT_models/models.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 | import openai
4 | import time
5 | from ast import literal_eval
6 | from copy import copy
7 |
8 | def fine_tuning(input_path, output_path):
9 | """
10 | Test fine_tuning model, generates the prediction of table data extraction in json format.
11 | You can use OPENAI PLAYGROUND for training the model.
12 |
13 | Parameters:
14 | input_path : TSV or JSON table representation path
15 | output_path : The path where the prediction is saved
16 |
17 | Returns:
18 | json : prediction of table data extraction
19 | """
20 |
21 | openai.api_key = "YOUR OPENAI KEY"
22 | file_list = os.listdir(input_path)
23 |
24 | response = []
25 | for file in file_list:
26 | file_path = ''.join([output_path, file])
27 | file_name = os.path.basename(file_path)
28 | with open( input_path + file, 'r', encoding='utf-8-sig') as file:
29 | loaded_data_string = json.load(file)
30 |
31 | completion = openai.ChatCompletion.create(
32 | model="FINE TUNED MODEL",
33 | temperature=0,
34 | messages=[
35 | {"role": "system", "content": "this task is to take a string as input and convert it to json format. I want to extract the performance below. [reaction_type, versus, overpotential, substrate, loading, tafel_slope, onset_potential, current_density, BET, specific_activity, mass_activity, surface_area, ECSA, apparent_activation_energy, water_splitting_potential, potential, Rs, Rct, Cdl, TOF, stability, electrolyte, exchange_current_density, onset_overpotential]. If there is information about overpotential and Tafel slope in the input, the output should be generated as follows.\n\n{\n\u201dcatalyst_name\": {\n\"overpotential\": {\n\"electrolyte\": \"1.0 M KOH\",\n\"reaction_type\": \"OER\",\n\"value\": \"230 mV\",\n\"current_density\": \"50 mA/cm2\"\n},\n\"tafel_slope\": {\n\"electrolyte\": \"1.0 M KOH\",\n\"reaction_type\": \"OER\",\n\"value\": \"54 mV/dec\"\n}\n\n}\n\n}\n\nIf information regarding the reaction_type or electrolyte cannot be found in the input, they should not be included in the output as follows.\n\n{\n\u201dcatalyst_name\": {\n\"overpotential\": {\n\"value\": \"230 mV\",\n\"current_density\": \"50 mA/cm2\"\n},\n\"tafel_slope\": {\n\"value\": \"54 mV/dec\"\n}\n\n}\n\n}\n\nIf the string is missing certain information such as 'mass_activity', ‘reaction_type’, ‘value’ or 'current_density', your output should not include those keys.\n\nIf there are no values corresponding to the mentioned performance metrics in the input, simply extract the catalyst name as shown below.\n\n{\n\u201dcatalyst_name\": {}\n}\n\nNote: The output should be a JSON object with keys for only the present metrics."},
36 | {"role": "user", "content": str(loaded_data_string)}
37 | ]
38 | )
39 | result = completion.choices[0].message['content']
40 | response.append(result)
41 | try:
42 | dict_1 = literal_eval(result)
43 | json_file_path = os.path.join(output_path, file_name)
44 | with open(file_path[:-5]+'.json', "w", encoding="utf-8-sig") as json_file:
45 | json.dump(dict_1, json_file, indent=4)
46 | except:
47 | with open(file_path[:-5]+'.txt', "w", encoding="utf-8-sig") as file:
48 | file.write(result)
49 |
50 |
51 |
52 | def few_shot(input_path, output_path) :
53 | """
54 | Test few shot model, generates the prediction of table data extraction in json format.
55 | You need to give several I/O pairs.
56 |
57 | Parameters:
58 | input_path : TSV or JSON table representation path
59 | output_path : The path where the prediction is saved
60 |
61 | Returns:
62 | json : prediction of table data extraction
63 | """
64 | client = OpenAI(api_key= "YOUR OPENAI KEY")
65 | file_list = os.listdir(input_path)
66 | for file in file_list :
67 | with open(input_path + file, 'r', encoding='utf-8') as file:
68 | text = file.read()
69 | response = client.chat.completions.create(
70 | model="gpt-4-1106-preview",
71 | temperature=0,
72 | frequency_penalty=0,
73 | presence_penalty=0,
74 | messages=[
75 | {"role": "system", "content": "I will extract the performance information of the catalyst from the table and create a JSON format. The types of performance to be extracted will be given as a list: performance_list = [overpotential, tafel_slope, Rct, stability, Cdl, onset_potential, current_density, potential, TOF, ECSA, water_splitting_potential, mass_activity, exchange_current_density, Rs, specific_activity, onset_overpotential, BET, surface_area, loading, apparent_activation_energy]. You can only use the names as they are in the performance_list, and any changes to the names in the performance_list, no matter how slight, are not allowed. The JSON format will have performance within the catalyst, and each performance will include elements present in the table: reaction type, value, electrolyte, condition, current density, versus(ex: RHE) and substrate. Other elements must not be included in performance. Be very strict. The output must contain only json dictionary. Other sentences or opinion must not be in output."},
76 |
77 | # X I/O PAIRS
78 | {"role": "user", "content":''},
79 | {"role": "assistant", "content": ''},
80 |
81 | {"role": "user", "content": text}
82 | ]
83 | )
84 | prediction = response.choices[0].message.content.strip()
85 | output_filename = output_path + '/' + name
86 | try :
87 | json_data = json.loads(prediction)
88 | with open(output_filename + '.json', 'w', encoding='utf-8-sig') as json_file:
89 | json.dump(json_data, json_file, ensure_ascii = False, indent = 4)
90 |
91 | except :
92 | json_data = prediction
93 | with open(output_filename + '.txt', "w", encoding="utf-8-sig") as txt_file:
94 | txt_file.write(json_data)
95 |
96 |
97 | def prompt(messages) :
98 | response = client.chat.completions.create(
99 | model="gpt-4-1106-preview",
100 | temperature=0,
101 | frequency_penalty=0,
102 | presence_penalty=0,
103 | messages= messages)
104 |
105 | return messages, response.choices[0].message.content
106 |
107 |
108 | def zero_shot(input_path, output_path) :
109 | """
110 | Test zero shot model, generates the prediction of table data extraction in json format.
111 |
112 | Parameters:
113 | input_path : TSV or JSON table representation path
114 | output_path : The path where the prediction is saved
115 |
116 | Returns:
117 | json : prediction of table data extraction
118 | """
119 |
120 | client = OpenAI(api_key = 'YOUR OPENAI KEY')
121 | file_list = os.listdir(input_path)
122 |
123 | for file in file_list :
124 | data = {'question': [], 'answer': []}
125 |
126 | with open(input_path + file, 'r', encoding='utf-8') as file:
127 | table_representer = file.read()
128 |
129 | table_name = file.split('.')[0]
130 |
131 | instruction = "I'm going to convert the information in the table representer into JSON format.\n CATALYST_TEMPLATE = {'catalyst_name' : {'performance_name' : {PROPERTY_TEMPLATE}}\n PROPERTY_TEMPLATE = {'electrolyte': '', 'reaction_type': '', 'value': '', 'current_density': '', 'overpotential': '', 'potential': '','substrate': '', 'versus':''}\n performance_list = [overpotential, tafel_slope, Rct, stability, Cdl, onset_potential, current_density, potential, TOF, ECSA, water_splitting_potential, mass_activity, exchange_current_density, Rs, specific_activity, onset_overpotential, BET, surface_area, loading, apparent_activation_energy]\n. Table representer is in below \n\n "
132 | result = {"catalysts":[]}
133 |
134 | message_ = [{"role": "system", "content": instruction + table_representer}]
135 |
136 | catalyst_q = "Show the catalysts present in the table representer as a Python list. Answer must be ONLY python list. Not like '''python ''' Be very very very strict. Other sentences or explanation is not allowed.\n"
137 | question = catalyst_q
138 | message_.append({"role": "user", "content": question})
139 | _, cata_answer = prompt(message_)
140 | catalyst_list = eval(cata_answer)
141 | data['question'].append(copy(message_))
142 | data['answer'].append(cata_answer)
143 |
144 | message_.append({"role": "assistant", "content": cata_answer}) # 다음 prompt에 이전 답 추가
145 |
146 | for catalyst in catalyst_list :
147 |
148 | performance_template_q = "Create a CATALYST_TEMPLATE filling in the performance of {catalyst} from the table representer, strictly adhering to the following 3 rules:\n\n Rule 1: Only include the actual existing performances from the Performance_list in the CATALYST_TEMPLATE.\n Rule 2: Set all values of the keys in PROPERTY_TEMPLATE to be " ". DO NOT INSERT ANY VALUE. BE VERY STRICT.\n Rule 3: Answer must be ONLY json format. Only display the JSON (like string not ```json). Other sentences or explanation is not allowed.".format(catalyst="'''"+catalyst+"'''")
149 | question = performance_template_q
150 | message_.append({"role": "user", "content": question})
151 | _, perfo_answer = prompt(message_)
152 |
153 | data['question'].append(copy(message_))
154 | data['answer'].append(perfo_answer)
155 |
156 | message_.append({"role": "assistant", "content": perfo_answer})
157 | property_q = 'In PROPERTY_TEMPLATE, maintain all keys, and fill in values that exist in the table representer. If there are more than two "values" for the same performance, fill in each "value" with the property template and make it into a list. If there is unit information, never create or modify additional keys, but reflect the units in the value.'
158 | question = property_q
159 | message_.append({"role": "user", "content": question})
160 | _, property_answer1 = prompt(message_)
161 |
162 | data['question'].append(copy(message_))
163 | data['answer'].append(property_answer1)
164 |
165 | message_.append({"role": "assistant", "content": property_answer1})
166 | property_title_caption_q = "Modify the previous version of CATALYST_TEMPLATE based solely on the title, caption according to the rules below. Only refer to the title and caption part in table representer. Strictly adhere to the following rules. \n Rule 1: If there is reaction type information in title or caption, reflect the reaction type in previous version of CATALYST_TEMPLATE accordingly. But if there isn't reaction type information in title or caption part, leave CATALYST_TEMPLATE as previous version. Be strict. \n Rule 2: If there is electrolyte information in title or caption part, reflect the electrolyte in previous version of CATALYST_TEMPLATE. But if there isn't electrolyte information in title or caption part, leave CATALYST_TEMPLATE as previous version. Be strict. \n Rule 3: Never modify the keys. \n Rule 4: Never fill in values for any other keys except reaction_type, electrolyte. Never delete any other keys or value."
167 | question = property_title_caption_q
168 | message_.append({"role": "user", "content": question})
169 | _, property_answer2 = prompt(message_)
170 |
171 | data['question'].append(copy(message_))
172 | data['answer'].append(property_answer2)
173 |
174 | message_.append({"role": "assistant", "content": property_answer1})
175 | delete_q ='Remove keys with no values from previous version of CATALYST_TEMPLATE.'
176 | question = delete_q
177 | message_.append({"role": "user", "content": question})
178 | _, delete_answer = prompt(message_)
179 |
180 | data['question'].append(copy(message_))
181 | data['answer'].append(delete_answer)
182 |
183 | catalyst_template = json.loads(delete_answer)
184 | result["catalysts"].append(catalyst_template)
185 |
186 | message_ = [{"role": "system", "content": instruction + table_representer}]
187 | message_.append({"role": "user", "content": catalyst_q})
188 | message_.append({"role": "assistant", "content": cata_answer})
189 |
190 | if len(result["catalysts"]) == 1 :
191 | final_result = result["catalysts"][0]
192 |
193 | elif len(result["catalysts"]) > 1 :
194 | final_result = result
195 | try :
196 | with open(output_path + table_name + ".json", "w") as json_file:
197 | json.dump(final_result, json_file, indent = 4)
198 | except :
199 | with open(output_path + table_name + ".txt", "w", encoding="utf-8-sig") as txt_file:
200 | txt_file.write(final_result)
201 |
202 |
203 |
204 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MaTableGPT: GPT-based Table Data Extractor from Materials Science Literature
2 |
3 | ## Introduction
4 | ### 1) Overall workflow of MaTableGPT
5 | 1. Generate customized TSV, JSON representation for HTML format of table and split the table.
6 | 2. Test 3 models (fine tuning, few shot, zero shot) and go through the follow up questions process.
7 | 
8 |
9 | ### 2) GPT modeling process
10 | 
11 |
12 | ## User Manual
13 | ### 1) Installation
14 |
15 | **Using conda**
16 | ```bash
17 | conda env create -f requirements_conda.txt
18 | ```
19 | **Using pip**
20 | ```bash
21 | pip install -r requirements_paper.txt
22 | ```
23 | ### 2) Download data files
24 | ```
25 | git clone https://github.com/KIST-CSRC/MaTableGPT.git
26 | git lfs pull
27 | ```
28 | ## 3) Script architecture
29 | ```
30 | MaTableGPT
31 | ├── data
32 | │ └── non_split
33 | │ └── split
34 | │ └── pickle_folder
35 | │ └── result
36 | ├── GPT_models
37 | │ └── models.py
38 | │ └── follow_up_q.py.py
39 | ├── model_evaluation
40 | │ └── utils
41 | │ └── evaluation.py
42 | ├── table_representation
43 | │ └── table_representer.py
44 | │ └── table2json.py
45 | ├── table_splitting
46 | │ └── split_table.py
47 | │
48 | └── run.py
49 | ```
50 | ### 4) Code usage (run.py)
51 | **Examples : Input generation (split, tsv)**
52 | > ```python
53 | > input_guneration("split", "TSV")
54 | > ```
55 |
56 | **Examples : Data extraction (few shot, follow_up questions)**
57 | > ```python
58 | > model_test("few_shot", True)
59 | > ```
60 | ## Benefit
61 | Using MaTableGPT, we achieved a table data extraction accuracy of 96.8% and proposed the optimal solution for each situation through the Pareto-front solution.
62 | ## Reference
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/data/non_split/table_html/example_tbl01.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/split/table_split_json/example_tbl01_01.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts",
3 | "caption": "",
4 | "tag": "
catalyst
electrolyte
η at 10 mA cm–2 (mV)
Tafel slope (mV/decade)
durability (h)
ref
Co-BPDC/Co-BDC heterojunction
1 M KOH
335
72.1
80
this work
"
5 | }
--------------------------------------------------------------------------------
/data/split/table_split_json/example_tbl01_02.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts",
3 | "caption": "",
4 | "tag": "
catalyst
electrolyte
η at 10 mA cm–2 (mV)
Tafel slope (mV/decade)
durability (h)
ref
Co-BDC
1 M KOH
392
77.2
28
this work
"
5 | }
--------------------------------------------------------------------------------
/data/split/table_split_json/example_tbl01_03.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts",
3 | "caption": "",
4 | "tag": "
catalyst
electrolyte
η at 10 mA cm–2 (mV)
Tafel slope (mV/decade)
durability (h)
ref
Co-BPDC
1 M KOH
428
78.8
28
this work
"
5 | }
--------------------------------------------------------------------------------
/data/split/table_split_json/example_tbl01_04.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts",
3 | "caption": "",
4 | "tag": "
catalyst
electrolyte
η at 10 mA cm–2 (mV)
Tafel slope (mV/decade)
durability (h)
ref
Co/MIL-101(Cr)-O
0.1 M KOH
570
17
–
(40)
"
5 | }
--------------------------------------------------------------------------------
/data/split/table_split_json/example_tbl01_05.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts",
3 | "caption": "",
4 | "tag": "
catalyst
electrolyte
η at 10 mA cm–2 (mV)
Tafel slope (mV/decade)
durability (h)
ref
Fe2Ni-BPTC/CC
0.1 M KOH
365
77.2
15
(41)
"
5 | }
--------------------------------------------------------------------------------
/data/split/table_split_json/example_tbl01_06.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts",
3 | "caption": "",
4 | "tag": "
catalyst
electrolyte
η at 10 mA cm–2 (mV)
Tafel slope (mV/decade)
durability (h)
ref
UTSA-16
1 M KOH
408
77
7
(42)
"
5 | }
--------------------------------------------------------------------------------
/data/split/table_split_json/example_tbl01_07.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts",
3 | "caption": "",
4 | "tag": "
catalyst
electrolyte
η at 10 mA cm–2 (mV)
Tafel slope (mV/decade)
durability (h)
ref
2D Co–MOF UNS
1 M KOH
263
74
3.3
(18)
"
5 | }
--------------------------------------------------------------------------------
/data/split/table_split_json/example_tbl01_08.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts",
3 | "caption": "",
4 | "tag": "
catalyst
electrolyte
η at 10 mA cm–2 (mV)
Tafel slope (mV/decade)
durability (h)
ref
Co-OBA/C
0.1 M KOH
590
85.7
–
(43)
"
5 | }
--------------------------------------------------------------------------------
/data/split/table_split_json/example_tbl01_09.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts",
3 | "caption": "",
4 | "tag": "
catalyst
electrolyte
η at 10 mA cm–2 (mV)
Tafel slope (mV/decade)
durability (h)
ref
Co2(μ–OH)2(bbta)
1 M KOH
387
60
24
(44)
"
5 | }
--------------------------------------------------------------------------------
/data/split/table_split_json/example_tbl01_10.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts",
3 | "caption": "",
4 | "tag": "
catalyst
electrolyte
η at 10 mA cm–2 (mV)
Tafel slope (mV/decade)
durability (h)
ref
3D Gr/Ni-MOF
0.1 M KOH
370
91
20
(25)
"
5 | }
--------------------------------------------------------------------------------
/data/split/table_split_json/example_tbl01_11.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts",
3 | "caption": "",
4 | "tag": "
catalyst
electrolyte
η at 10 mA cm–2 (mV)
Tafel slope (mV/decade)
durability (h)
ref
Co0.6Fe0.4-MOF-74
1 M KOH
280
56
12
(3)
"
5 | }
--------------------------------------------------------------------------------
/data/split/table_split_json/example_tbl01_12.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts",
3 | "caption": "",
4 | "tag": "
catalyst
electrolyte
η at 10 mA cm–2 (mV)
Tafel slope (mV/decade)
durability (h)
ref
Ti3C2Tx-CoBDC
0.1 M KOH
410
48.2
2.8
(23)
"
5 | }
--------------------------------------------------------------------------------
/data/split/table_split_json/example_tbl01_13.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts",
3 | "caption": "",
4 | "tag": "
catalyst
electrolyte
η at 10 mA cm–2 (mV)
Tafel slope (mV/decade)
durability (h)
ref
Co-MOF
1 M KOH
360
89
–
(45)
"
5 | }
--------------------------------------------------------------------------------
/data/split/tsv_representation/example_tbl01_01.txt:
--------------------------------------------------------------------------------
1 | Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts
catalyst\telectrolyte\tη at 10 mA cm–2 (mV)\tTafel slope (mV/decade)\tdurability (h)\tref\t\nCo-BPDC/Co-BDC heterojunction\t1 M KOH\t335\t72.1\t80\tthis work\t\n
--------------------------------------------------------------------------------
/data/split/tsv_representation/example_tbl01_02.txt:
--------------------------------------------------------------------------------
1 | Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts
catalyst\telectrolyte\tη at 10 mA cm–2 (mV)\tTafel slope (mV/decade)\tdurability (h)\tref\t\nCo-BDC\t1 M KOH\t392\t77.2\t28\tthis work\t\n
--------------------------------------------------------------------------------
/data/split/tsv_representation/example_tbl01_03.txt:
--------------------------------------------------------------------------------
1 | Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts
catalyst\telectrolyte\tη at 10 mA cm–2 (mV)\tTafel slope (mV/decade)\tdurability (h)\tref\t\nCo-BPDC\t1 M KOH\t428\t78.8\t28\tthis work\t\n
--------------------------------------------------------------------------------
/data/split/tsv_representation/example_tbl01_04.txt:
--------------------------------------------------------------------------------
1 | Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts
catalyst\telectrolyte\tη at 10 mA cm–2 (mV)\tTafel slope (mV/decade)\tdurability (h)\tref\t\nCo/MIL-101(Cr)-O\t0.1 M KOH\t570\t17\t–\t (40)\t\n
--------------------------------------------------------------------------------
/data/split/tsv_representation/example_tbl01_05.txt:
--------------------------------------------------------------------------------
1 | Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts
catalyst\telectrolyte\tη at 10 mA cm–2 (mV)\tTafel slope (mV/decade)\tdurability (h)\tref\t\nFe2Ni-BPTC/CC\t0.1 M KOH\t365\t77.2\t15\t (41)\t\n
--------------------------------------------------------------------------------
/data/split/tsv_representation/example_tbl01_06.txt:
--------------------------------------------------------------------------------
1 | Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts
catalyst\telectrolyte\tη at 10 mA cm–2 (mV)\tTafel slope (mV/decade)\tdurability (h)\tref\t\nUTSA-16\t1 M KOH\t408\t77\t7\t (42)\t\n
--------------------------------------------------------------------------------
/data/split/tsv_representation/example_tbl01_07.txt:
--------------------------------------------------------------------------------
1 | Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts
catalyst\telectrolyte\tη at 10 mA cm–2 (mV)\tTafel slope (mV/decade)\tdurability (h)\tref\t\n2D Co–MOF UNS\t1 M KOH\t263\t74\t3.3\t (18)\t\n
--------------------------------------------------------------------------------
/data/split/tsv_representation/example_tbl01_08.txt:
--------------------------------------------------------------------------------
1 | Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts
catalyst\telectrolyte\tη at 10 mA cm–2 (mV)\tTafel slope (mV/decade)\tdurability (h)\tref\t\nCo-OBA/C\t0.1 M KOH\t590\t85.7\t–\t (43)\t\n
--------------------------------------------------------------------------------
/data/split/tsv_representation/example_tbl01_09.txt:
--------------------------------------------------------------------------------
1 | Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts
catalyst\telectrolyte\tη at 10 mA cm–2 (mV)\tTafel slope (mV/decade)\tdurability (h)\tref\t\nCo2(μ–OH)2(bbta)\t1 M KOH\t387\t60\t24\t (44)\t\n
--------------------------------------------------------------------------------
/data/split/tsv_representation/example_tbl01_10.txt:
--------------------------------------------------------------------------------
1 | Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts
catalyst\telectrolyte\tη at 10 mA cm–2 (mV)\tTafel slope (mV/decade)\tdurability (h)\tref\t\n3D Gr/Ni-MOF\t0.1 M KOH\t370\t91\t20\t (25)\t\n
--------------------------------------------------------------------------------
/data/split/tsv_representation/example_tbl01_11.txt:
--------------------------------------------------------------------------------
1 | Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts
catalyst\telectrolyte\tη at 10 mA cm–2 (mV)\tTafel slope (mV/decade)\tdurability (h)\tref\t\nCo0.6Fe0.4-MOF-74\t1 M KOH\t280\t56\t12\t (3)\t\n
--------------------------------------------------------------------------------
/data/split/tsv_representation/example_tbl01_12.txt:
--------------------------------------------------------------------------------
1 | Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts
catalyst\telectrolyte\tη at 10 mA cm–2 (mV)\tTafel slope (mV/decade)\tdurability (h)\tref\t\nTi3C2Tx-CoBDC\t0.1 M KOH\t410\t48.2\t2.8\t (23)\t\n
--------------------------------------------------------------------------------
/data/split/tsv_representation/example_tbl01_13.txt:
--------------------------------------------------------------------------------
1 | Table 1. Comparison of OER Performance for Several MOFs Electrocatalysts
catalyst\telectrolyte\tη at 10 mA cm–2 (mV)\tTafel slope (mV/decade)\tdurability (h)\tref\t\nCo-MOF\t1 M KOH\t360\t89\t–\t (45)\t\n