-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrequirement_extractor.py
More file actions
186 lines (156 loc) · 6 KB
/
requirement_extractor.py
File metadata and controls
186 lines (156 loc) · 6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
"""
코드 ID: REQ_EXTRACTOR_001
연결 요구사항: AI-REQ-F-001 (문서 분석 및 요구사항 자동 추출)
작성자: AI System
작성일: 2025-09-01
설명: AI 모델을 사용하여 텍스트에서 요구사항을 추출하는 모듈
"""
import openai
import json
from typing import List, Dict, Optional
import logging
from dataclasses import dataclass
# 코드 ID: REQ_EXTRACTOR_001
@dataclass
class ExtractedRequirement:
"""추출된 요구사항 데이터 클래스"""
id: str
text: str
type: str # 기능/비기능
priority: str # 상/중/하
category: str
confidence_score: float
class RequirementExtractor:
"""
AI 기반 요구사항 추출 클래스
- OpenAI GPT 모델 사용
- 요구사항 ID: AI-REQ-F-001과 연결
"""
def __init__(self, api_key: Optional[str] = None):
if api_key:
openai.api_key = api_key
self.logger = logging.getLogger(__name__)
# 요구사항 추출을 위한 프롬프트 템플릿
self.extraction_prompt = """
다음 텍스트에서 요구사항을 추출해주세요.
각 요구사항은 다음 형식으로 반환해주세요:
{
"requirements": [
{
"id": "REQ-001",
"text": "사용자는 로그인할 수 있어야 한다",
"type": "기능",
"priority": "상",
"category": "인증",
"confidence_score": 0.85
}
]
}
분석할 텍스트:
{text}
"""
def extract_requirements(self, text: str, max_requirements: int = 20) -> List[ExtractedRequirement]:
"""
텍스트에서 요구사항 추출
Args:
text (str): 분석할 텍스트
max_requirements (int): 최대 추출 개수
Returns:
List[ExtractedRequirement]: 추출된 요구사항 리스트
"""
try:
# OpenAI API 호출
response = self._call_openai_api(text)
# 응답 파싱
requirements_data = json.loads(response)
# ExtractedRequirement 객체로 변환
requirements = []
for i, req_data in enumerate(requirements_data.get('requirements', [])[:max_requirements]):
requirement = ExtractedRequirement(
id=req_data.get('id', f'REQ-{i+1:03d}'),
text=req_data.get('text', ''),
type=req_data.get('type', '기능'),
priority=req_data.get('priority', '중'),
category=req_data.get('category', '일반'),
confidence_score=req_data.get('confidence_score', 0.5)
)
requirements.append(requirement)
self.logger.info(f"요구사항 {len(requirements)}개 추출 완료")
return requirements
except Exception as e:
self.logger.error(f"요구사항 추출 오류: {e}")
# 폴백: 규칙 기반 추출
return self._fallback_extraction(text, max_requirements)
def _call_openai_api(self, text: str) -> str:
"""OpenAI API 호출"""
try:
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "당신은 소프트웨어 요구사항 분석 전문가입니다."},
{"role": "user", "content": self.extraction_prompt.format(text=text)}
],
max_tokens=2000,
temperature=0.3
)
return response.choices[0].message.content
except Exception as e:
self.logger.warning(f"OpenAI API 호출 실패: {e}")
raise
def _fallback_extraction(self, text: str, max_requirements: int) -> List[ExtractedRequirement]:
"""폴백: 규칙 기반 요구사항 추출"""
requirements = []
sentences = text.split('.')
requirement_patterns = [
r'.*는.*할\s+수\s+있다',
r'시스템.*제공.*한다',
r'사용자.*요청.*처리',
r'.*기능.*구현.*한다'
]
req_id = 1
for sentence in sentences[:max_requirements]:
sentence = sentence.strip()
if len(sentence) < 10:
continue
for pattern in requirement_patterns:
if re.search(pattern, sentence):
requirement = ExtractedRequirement(
id=f'REQ-{req_id:03d}',
text=sentence,
type='기능',
priority='중',
category='일반',
confidence_score=0.6
)
requirements.append(requirement)
req_id += 1
break
return requirements
def validate_requirements(self, requirements: List[ExtractedRequirement]) -> List[ExtractedRequirement]:
"""
추출된 요구사항 검증 및 필터링
Args:
requirements: 추출된 요구사항 리스트
Returns:
List[ExtractedRequirement]: 검증된 요구사항 리스트
"""
valid_requirements = []
for req in requirements:
# 최소 길이 체크
if len(req.text) < 10:
continue
# 중복 체크
is_duplicate = any(
self._calculate_similarity(req.text, valid_req.text) > 0.8
for valid_req in valid_requirements
)
if not is_duplicate and req.confidence_score >= 0.5:
valid_requirements.append(req)
return valid_requirements
def _calculate_similarity(self, text1: str, text2: str) -> float:
"""텍스트 유사도 계산 (간단한 Jaccard 유사도)"""
set1 = set(text1.split())
set2 = set(text2.split())
intersection = len(set1.intersection(set2))
union = len(set1.union(set2))
return intersection / union if union > 0 else 0.0