Files
ExperionCrawler/.rooBackup/2026-05-05-152500/test_dxf_extract_pid1.py
2026-05-08 17:22:10 +09:00

141 lines
3.9 KiB
Python

#!/usr/bin/env python3
"""
DXF 파일에서 P&ID 태그 추출 스크립트
ezdxf + OpenAI API 사용 (청크 단위 3회 호출)
"""
import ezdxf
import json
import re
from ezdxf.tools.text import plain_mtext
from openai import OpenAI
# DXF 파일 경로
filepath = '/home/windpacer/projects/ExperionCrawler/src/Web/uploads/pid/p-9100.dxf'
# DXF 파일 읽기
doc = ezdxf.readfile(filepath)
msp = doc.modelspace()
# 텍스트 추출
texts = []
for entity in msp:
if entity.dxftype() == 'TEXT':
texts.append(entity.dxf.text)
elif entity.dxftype() == 'MTEXT':
try:
plain = plain_mtext(entity.dxf.text)
if plain.strip():
texts.append(plain)
except Exception:
pass
text = '\n'.join(texts)
print(f'총 텍스트: {len(text)}')
# OpenAI 클라이언트 생성 (타임아웃 1800초 = 30분)
llm = OpenAI(
base_url='http://localhost:8000/v1',
api_key='dummy',
timeout=1800
)
# 청크별 프롬프트
chunks = [
{
'name': 'Field Instruments - Sensors',
'system': (
'You are a P&ID expert. Extract sensor tags only.\n'
'Return ONLY a JSON array.\n'
'\n'
'Instrument types to extract: FT, FIT, LT, PT, TE, PG, LG, TG\n'
'Format: [{"tagNo":"FT-10101","confidence":0.95},...]\n'
),
'user': 'Extract ALL tags of FT, FIT, LT, PT, TE, PG, LG, TG from the text below:\n\n{text}'
}
]
# 결과 저장
all_tags = []
seen_tags = set()
for chunk in chunks:
print(f'\n=== {chunk["name"]} ===')
# 프롬프트 생성
system = chunk['system']
user = chunk['user'].format(text=text[:100000])
# LLM 호출
resp = llm.chat.completions.create(
model='Qwen3.6-27B-FP8',
messages=[
{'role': 'system', 'content': system},
{'role': 'user', 'content': user},
],
max_tokens=65536,
temperature=0.1,
extra_body={'chat_template_kwargs': {'enable_thinking': False}},
)
raw = (resp.choices[0].message.content or '').strip()
finish = resp.choices[0].finish_reason
print(f'응답 길이: {len(raw)}자, finish_reason: {finish}')
# 잘린 경우 복구
if finish == 'length' and not raw.rstrip().endswith(']'):
last = raw.rfind('}')
if last != -1:
raw = raw[:last+1] + ']'
print('잘린 JSON 복구')
# 배열 추출
depth = 0
start = -1
best = ''
for i, c in enumerate(raw):
if c == '[':
if depth == 0:
start = i
depth += 1
elif c == ']':
depth -= 1
if depth == 0 and start >= 0:
cand = raw[start:i+1]
if len(cand) > len(best):
best = cand
# JSON 파싱 및 결과 저장
try:
data = json.loads(best) if best else []
print(f'추출된 태그 수: {len(data)}')
for item in data:
tag_no = item.get('tagNo')
if tag_no and tag_no not in seen_tags:
seen_tags.add(tag_no)
all_tags.append({
'tagNo': tag_no,
'confidence': item.get('confidence', 0.95)
})
print(f'중복 제거 후 총 태그 수: {len(all_tags)}')
except json.JSONDecodeError as e:
print(f'파싱 실패: {e}')
print(repr(best[-300:] if best else ''))
# 최종 결과
print(f'\n=== 최종 결과 ===')
print(f'총 추출 태그 수: {len(all_tags)}')
print()
for t in all_tags[:30]:
print(f' {t["tagNo"]}')
if len(all_tags) > 30:
print(f' ... (총 {len(all_tags)}개)')
# JSON 파일로 저장
output_path = '/home/windpacer/projects/ExperionCrawler/src/Web/uploads/pid/p-9100_extracted1.json'
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(all_tags, f, indent=2, ensure_ascii=False)
print(f'\n결과 저장: {output_path}')