diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..0a8642f
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,10 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Zeppelin ignored files
+/ZeppelinRemoteNotebooks/
diff --git a/.idea/_AI.iml b/.idea/_AI.iml
new file mode 100644
index 0000000..f5cf686
--- /dev/null
+++ b/.idea/_AI.iml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..4f33453
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..bd13592
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..cff07f0
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/pipeline/analysis_pipeline.py b/app/pipeline/analysis_pipeline.py
index 5b85d38..e92bbc3 100644
--- a/app/pipeline/analysis_pipeline.py
+++ b/app/pipeline/analysis_pipeline.py
@@ -52,29 +52,20 @@ def run_analysis_pipeline(payload: AnalyzeRequest) -> Dict[str, object]:
for message in conversation
if message.sender.strip().upper() == "OTHER" and message.content.strip()
]
- logger.info(
- "Pipeline start: %d turns (other=%d)",
- len(conversation),
- len(other_contents),
- )
# 1. 입력에서 대화 유형 수신 (유형별 신호 범위 결정을 위함)
conversation_type = payload.type
- logger.info("Step 1 conversation_type(from input): %s", conversation_type)
# 2. 규칙 기반 신호 추출 (유형 기반 + 공통 신호) (위험 신호 후보 추출)
allowed_signals = resolve_risk_signals(conversation_type)
rule_signals = analyze_conversation(other_contents, allowed_signals=allowed_signals)
- logger.info("Step 2 signals: %s", rule_signals)
# 3. RAG 쿼리 보강 (근거 자료 확보를 위한 검색 품질 향상)
signal_terms = signal_query_terms(rule_signals)
matched_phrases = extract_signal_phrases(other_contents, allowed_signals=allowed_signals)
- logger.info("Step 3 query_terms=%s matched_phrases=%s", signal_terms, matched_phrases)
# 4. 결정 오케스트레이터 (위험 단계 산출)
risk_stage = decide_risk_stage(rule_signals)
- logger.info("Step 4 risk_stage: %s", risk_stage)
# 5. RAG 검색 (근거 자료 확보)
retrieval_request = RetrievalRequest(
@@ -85,7 +76,6 @@ def run_analysis_pipeline(payload: AnalyzeRequest) -> Dict[str, object]:
matched_phrases=matched_phrases,
)
references = retrieve_evidence(retrieval_request)
- logger.info("Step 5 references: %d", len(references))
# 6. 안전 행동 생성 (LLM: references + 대화 발췌 사용) (최종 응답 생성)
conversation_lines = _build_conversation_excerpt(
@@ -94,7 +84,6 @@ def run_analysis_pipeline(payload: AnalyzeRequest) -> Dict[str, object]:
safe_actions = generate_safe_actions(
risk_stage, conversation_type, references, conversation_lines, payload.platform
)
- logger.info("Step 6 safe_actions generated")
rag_references = [
{"source": reference.source, "summary": reference.note} for reference in references
diff --git a/app/schemas/request.py b/app/schemas/request.py
index b4af952..5e98e80 100644
--- a/app/schemas/request.py
+++ b/app/schemas/request.py
@@ -1,7 +1,7 @@
from datetime import datetime
-from typing import List, Literal
+from typing import List, Literal, Optional
-from pydantic import BaseModel, Field
+from pydantic import BaseModel, Field, field_validator
class Message(BaseModel):
@@ -11,6 +11,20 @@ class Message(BaseModel):
content: str = Field(..., description="Message content")
sender: str = Field(..., description="Message sender (e.g. ME, OTHER)")
timestamp: datetime = Field(..., description="Message timestamp in ISO 8601")
+
+ @field_validator("type", mode="before")
+ @classmethod
+ def uppercase_type(cls, v):
+ if isinstance(v, str):
+ return v.upper()
+ return v
+
+ @field_validator("sender", mode="before")
+ @classmethod
+ def uppercase_sender(cls, v):
+ if isinstance(v, str):
+ return v.upper()
+ return v
class AnalyzeRequest(BaseModel):
@@ -19,9 +33,16 @@ class AnalyzeRequest(BaseModel):
platform: Literal["INSTAGRAM", "TELEGRAM"] = Field(
..., description="Platform name (INSTAGRAM or TELEGRAM)"
)
- type: Literal["구직", "중고거래", "재테크", "부업"] = Field(
- ..., description="Conversation type (구직, 중고거래, 재테크, 부업)"
+ type: Optional[Literal["구직", "중고거래", "재테크", "부업"]] = Field(
+ None, description="Conversation type (구직, 중고거래, 재테크, 부업)"
)
+
+ @field_validator("platform", mode="before")
+ @classmethod
+ def uppercase_platform(cls, v):
+ if isinstance(v, str):
+ return v.upper()
+ return v
class ReportRequest(BaseModel):