context
生成 (question, answer, context) pair
question
生成 (question, answer, context) pairdata
資料夾, data
下包含了今天會用到的 pdf 檔案import os
SOURCE_DIR = 'data'
print(os.listdir(SOURCE_DIR))
['108-1_精神科與社區衛生護理.pdf', '110-1_基礎醫學.pdf', '104-2_內外科護理學.pdf']
import fitz # pip install PyMuPDF
import pdfplumber # pip install pdfplumber
import re
DEST_DIR = 'parsed_txt'
os.makedirs(DEST_DIR, exist_ok=True)
SYMBOL_MAPPING = {
"": "A. ", "": "B. ", "": "C. ", "": "D. "
}
pattern = re.compile("|".join(map(re.escape, SYMBOL_MAPPING.keys())))
def replace_symbol(match):
return SYMBOL_MAPPING[match.group(0)]
def pdf2txt_fitz(source_file_path):
text = []
with fitz.open(source_file_path) as doc:
for page in doc:
page_txt = page.get_text("text")
replace_txt = pattern.sub(replace_symbol, page_txt)
text.append(replace_txt) # 取得純文字
return "\n\n".join(text)
def pdf2txt_pdfplumber(source_file_path):
text = []
with pdfplumber.open(source_file_path) as doc:
for page in doc.pages:
page_txt = page.extract_text()
replace_txt = pattern.sub(replace_symbol, page_txt)
text.append(replace_txt) # 取得純文字
return "\n\n".join(text)
def txt_dump(file_path, data):
print("write result to: " + file_path)
with open(file_path, 'w') as f:
f.write(data)
file_names = os.listdir(SOURCE_DIR)
for file_name in file_names:
file_path = os.path.join(SOURCE_DIR, file_name)
base_name, _ext = os.path.splitext(os.path.basename(file_path))
txt_fitz = pdf2txt_fitz(file_path)
txt_pdfplumber = pdf2txt_pdfplumber(file_path)
txt_dump(os.path.join(DEST_DIR, f"{base_name}_fitz.txt"), txt_fitz)
txt_dump(os.path.join(DEST_DIR, f"{base_name}_pdfplumber.txt"), txt_pdfplumber)
re
parse 成 json 檔案就是容易的事情19
腔隙症候群所要觀察的6P,不包括下列那一項?
Petechiae
A.
Paralysis
B.
Paresthesia
C.
Pulselessness
D.
20
下列何者不屬於皮膚牽引?
A. 勃克氏牽引(Buck’s traction)
B. 環圈式顱骨牽引(Halo traction)
C. 骨盆牽引(Pelvic traction)
D. 勒塞爾氏牽引(Russell’s traction)
第 19 題的選項與選項內容的順序是反過來的,但第 20 題又一切正常,這個會非常不利於我們後面的 parser
再看一個例子是 110-1 基礎醫學.txt
原始的 pdf 長這樣
但 parser 出來的 txt 在對應的部分如下:
20
二氧化碳在血液中運送的各種形式,其中比例最高的形式是下列何者?
A. 氣態二氧化碳
B. 溶於血漿中之二氧化碳
C. 碳醯胺基血紅素(carbaminohemoglobin)
D. 碳酸氫根離子(
_
3
HCO )
21
下列何者在小腸液中的含量最低?
A. 蔗糖酶(sucrase)
B. 肝醣酶(glycogenase)
C. 乳糖酶(lactase)
D. 麥芽糖酶(maltase)
這是典型的「PDF 不是文件、是畫布」問題。簡單說:PDF 只保證畫面上長得像印出來的樣子,但不保證文字的邏輯順序。於是像「2°A-V block」這種有上標/符號/連字的組合,常被拆成多個獨立的繪圖指令,抽取時順序就亂了,最後像你看到的那樣把「°、2、°、3」丟到段落尾端。
pip install mistralai
pip install llama-index
pip install llama-parse
from dotenv import find_dotenv, load_dotenv
_ = load_dotenv(find_dotenv())
from llama_parse import LlamaParse
parser = LlamaParse(
# api_key="llx-...", # if you did not create an environmental variable you can set the API key here
result_type="text", # "markdown" and "text" are available
language = 'ch_tra',
)
file_name = 'data/104-2_內外科護理學.pdf'
extra_info = {"file_name": file_name}
with open(f"./{file_name}", "rb") as f:
# must provide extra_info with file_name key with passing file object
documents = parser.load_data(f, extra_info=extra_info)
with open("parsed_txt/104-2_內外科護理學_llama-parse.txt", "w", encoding="utf-8") as f:
for doc in documents:
f.write(doc.text)
繁體中文(ch_tra)
,這個在 pdf 都是圖片的時候變得很重要化學式的部分:
20 二氧化碳在血液中運送的各種形式,其中比例最高的形式是下列何者?
氣態二氧化碳 溶於血漿中之二氧化碳
碳醯胺基血紅素(carbaminohemoglobin) 碳酸氫根離子( HCO₃_ )
全文圖片的部分:
108年第一次專門職業及技術人員高等考試中醫師考試分階段 代號:5106
考試、營養師、心理師、護理師、社會工作師考試試題 頁次:8-1
等 別:高等考試
類 科:護理師
科 目:精神科與社區衛生護理學
考試時間:1小時 座號:
注意:(一)本試題為單一選擇題,請選出一個正確或最適當的答案,複選作答者,該題不予計分。
(二)本科目共80題,每題1.25分,須用2B鉛筆在試卡上依題號清楚劃記,於本試題上作答者,不予計分。
(三)禁止使用電子計算器。
世界衛生組織強調對精神病人基本人權的尊重,下列何者正確?
(A)病人應有權利在社區,而非機構化照顧
(B)全球心理衛生治療的趨勢是從急性醫院轉換為慢性機構療養
(C)精神生物醫學的進步,藥物治療的成效佳,故不需要心理社會的整合性照護
(D)慢性精神病人宜在偏遠地區的療養機構接受治療與安置
2 關於心理防衛機轉(defense mechanism),「把自己無法接受的想法與情緒,推給其他人,認為是
別人擁有這樣的想法,而不是他自己。」指的是下列何種心理防衛機轉?
(A)合理化(rationalization) (B)壓抑(suppression)
(C)反向行為(reactionformation) (D)投射(projection)
from mistralai import Mistral
from dotenv import load_dotenv
load_dotenv()
api_key = os.getenv("MISTRAL_API_KEY")
client = Mistral(api_key=api_key)
from pathlib import Path
from mistralai import DocumentURLChunk, ImageURLChunk, TextChunk
import json
# Verify PDF file exists
pdf_file = Path(file_path)
assert pdf_file.is_file()
# Upload PDF file to Mistral's OCR service
uploaded_file = client.files.upload(
file={
"file_name": pdf_file.stem,
"content": pdf_file.read_bytes(),
},
purpose="ocr",
)
# Get URL for the uploaded file
signed_url = client.files.get_signed_url(file_id=uploaded_file.id, expiry=1)
# Process PDF with OCR, including embedded images
pdf_response = client.ocr.process(
document=DocumentURLChunk(document_url=signed_url.url),
model="mistral-ocr-latest",
include_image_base64=True
)
# Convert response to JSON format
response_dict = json.loads(pdf_response.model_dump_json())
with open('mistral.json', 'w', encoding="utf-8") as f:
f.write(json.dumps(response_dict, indent=2, ensure_ascii=False))