์ธ์ ๊ธฐ๋ฐ ์ฑํ ์คํฌ๋ฆฐ์ท OCR ๋ฐ ๋ํ ๋ถ์ API
์นด์นด์คํก ๋ฑ์ ์ฑํ ์คํฌ๋ฆฐ์ท์ ์ ๋ก๋ํ๋ฉด OCR์ ํตํด ๋ฉ์์ง๋ฅผ ์ถ์ถํ๊ณ , ์ธ๋ถ AI API๋ฅผ ํตํด ๋ํ ๋ด์ฉ์ ๋ถ์ํ๋ ์์คํ ์ ๋๋ค. ์ฌ๋ฌ ์ฅ์ ์คํฌ๋ฆฐ์ท์ ์ ๋ก๋ํ๋ฉด ์๋์ผ๋ก ๊ฒน์น๋ ๋ถ๋ถ์ ์ฐพ์ ๋ณํฉํ๊ณ , ์ ์ฒด ๋ํ ํ๋ฆ์ ๋ถ์ํฉ๋๋ค.
- ๋ค์ค ์คํฌ๋ฆฐ์ท ์ ๋ก๋ ๋ฐ ์๋ ๋ณํฉ
- ์ฑํ ๋งํ์ ๊ฐ์ง ๋ฐ OCR
- ์ธ๋ถ AI API ์ฐ๋์ ํตํ ๋ํ ๋ถ์
- ์คํฌ๋ฆฐ์ท ๊ธฐ๋ฐ ๋ฉ์์ง ๊ฒ์
- ๋ค์ ๋ํ ์์ธก
- ๋ํ ์๋ฎฌ๋ ์ด์ ํ๋ก์
์๋ก์ด ๋ถ์ ์ธ์ ์ ์์ฑํฉ๋๋ค.
Endpoint: POST /sessions
Request Body: ์์
Response:
{
"session_id": "2ea688cf-315f-4dcb-9580-59262fbe5888",
"created_at": "2025-01-15T10:30:00.123456",
"status": "processing"
}์์ฑ๋ ์ธ์ ์ ์คํฌ๋ฆฐ์ท์ ์ ๋ก๋ํฉ๋๋ค. ์ฌ๋ฌ ๋ฒ ํธ์ถํ์ฌ ์ฌ๋ฌ ์ฅ ์ ๋ก๋ ๊ฐ๋ฅํฉ๋๋ค.
Endpoint: POST /sessions/{session_id}/upload
Request:
- Content-Type:
multipart/form-data - Body:
file: ์ด๋ฏธ์ง ํ์ผ (JPG, PNG)
Response:
{
"screenshot_id": "abc123-def456",
"session_id": "2ea688cf-315f-4dcb-9580-59262fbe5888",
"upload_order": 1,
"processed": false,
"message": "Screenshot uploaded successfully (order: 1)"
}์ ๋ก๋๋ ์คํฌ๋ฆฐ์ท๋ค์ OCR ์ฒ๋ฆฌํ๊ณ ๋ณํฉํ ํ, ์ธ๋ถ AI API๋ฅผ ํธ์ถํ์ฌ ๋ถ์ํฉ๋๋ค.
Endpoint: POST /sessions/{session_id}/process
Query Parameters:
relationship(required): ๋ํ ์๋์์ ๊ด๊ณ (์: "FRIEND", "SUPERIOR", "LOVER")relationship_info(required): ๊ด๊ณ์ ๋ํ ์ถ๊ฐ ์ ๋ณด (์: "2๋ ์ง๊ธฐ", "ํ์ฌ ์์ฌ")
Request:
POST /sessions/2ea688cf-315f-4dcb-9580-59262fbe5888/process?relationship=FRIEND&relationship_info=2๋
%20์ง๊ธฐ
Response:
{
"session_id": "2ea688cf-315f-4dcb-9580-59262fbe5888",
"status": "completed",
"total_screenshots": 2,
"total_messages": 22,
"merge_info": {
"merge_history": [
{
"step": 1,
"overlap_found": true,
"overlap_length": 5
}
],
"total_merged": 22
},
"external_api_called": true
}์ธ์ ์ ๋ชจ๋ ๋ฉ์์ง๋ฅผ ์กฐํํฉ๋๋ค. AI ๋ถ์ ๊ฒฐ๊ณผ๊ฐ ํฌํจ๋ฉ๋๋ค.
Endpoint: GET /sessions/{session_id}/messages
Response:
{
"session_id": "2ea688cf-315f-4dcb-9580-59262fbe5888",
"total_messages": 22,
"total_screenshots": 2,
"messages": [
{
"message_id": "msg-001",
"text": "์ค๋ ์ ๋
๋ญ ๋จน์๊น?",
"speaker": "user",
"confidence": 0.95,
"position": {
"x": 150.0,
"y": 200.0,
"width": 180.0,
"height": 50.0
},
"group_id": 1,
"score": 85.0,
"emotional_tone": "POSITIVE",
"impact_score": 2.0,
"ai_message": "์น๊ทผํ๊ณ ์ ์ ํ ์ง๋ฌธ์
๋๋ค.",
"suggested_alternative": null
},
{
"message_id": "msg-002",
"text": "์๋ฌด๊ฑฐ๋ ๊ด์ฐฎ์",
"speaker": "interlocutor",
"confidence": 0.92,
"position": {
"x": 50.0,
"y": 270.0,
"width": 160.0,
"height": 45.0
},
"group_id": 2,
"score": null,
"emotional_tone": null,
"impact_score": null,
"ai_message": null,
"suggested_alternative": null
}
]
}Response Fields:
message_id: ๋ฉ์์ง ๊ณ ์ IDtext: ๋ฉ์์ง ๋ด์ฉspeaker: ๋ฐํ์ ("user" ๋๋ "interlocutor")confidence: OCR ์ ๋ขฐ๋ (0.0 ~ 1.0)position: ์คํฌ๋ฆฐ์ท ๋ด ์์น ์ ๋ณดgroup_id: ์ฐ์๋ ๋ฉ์์ง ๊ทธ๋ฃน IDscore: AI ํ๊ฐ ์ ์ (0 ~ 100, user ๋ฉ์์ง๋ง ํด๋น)emotional_tone: ๊ฐ์ ํค (user ๋ฉ์์ง๋ง ํด๋น)impact_score: ์ํฅ ์ ์ (-3 ~ 3, user ๋ฉ์์ง๋ง ํด๋น)ai_message: AI ํผ๋๋ฐฑ (user ๋ฉ์์ง๋ง ํด๋น)suggested_alternative: AI ์ถ์ฒ ๋์ ํํ (user ๋ฉ์์ง๋ง ํด๋น)
๊ธฐ์กด ์ธ์ ์์ ํน์ ์คํฌ๋ฆฐ์ท์ ํฌํจ๋ ๋ฉ์์ง๋ฅผ ๊ฒ์ํฉ๋๋ค.
Endpoint: POST /sessions/{session_id}/search
Request:
- Content-Type:
multipart/form-data - Body:
file: ๊ฒ์ํ ์ด๋ฏธ์ง ํ์ผ
Response:
{
"matched": true,
"message": "Found 3 matching messages",
"results": [
{
"message_id": "msg-001",
"text": "์ค๋ ์ ๋
๋ญ ๋จน์๊น?",
"speaker": "user",
"confidence": 0.95,
"position": {...},
"group_id": 1
}
]
}์ฌ๋ฌ ์ฅ์ ์คํฌ๋ฆฐ์ท์ ์ ๋ก๋ํ์ฌ ํด๋น ๋ฉ์์ง๋ค์ ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ์กฐํํฉ๋๋ค. Fuzzy matching์ ์ง์ํ๋ฏ๋ก OCR ๊ฒฐ๊ณผ๊ฐ ์ฝ๊ฐ ๋ฌ๋ผ๋ ๋งค์นญ๋ฉ๋๋ค.
Endpoint: POST /sessions/{session_id}/view
Request:
- Content-Type:
multipart/form-data - Body:
files: ์ด๋ฏธ์ง ํ์ผ ๋ฐฐ์ด (์ฌ๋ฌ ์ฅ ์ ๋ก๋ ๊ฐ๋ฅ)
Response:
{
"session_id": "2ea688cf-315f-4dcb-9580-59262fbe5888",
"matched": true,
"total_matched": 15,
"total_ocr_extracted": 18,
"messages": [
{
"message_id": "msg-001",
"text": "์ค๋ ์ ๋
๋ญ ๋จน์๊น?",
"speaker": "user",
"confidence": 0.95,
"position": {...},
"group_id": 1,
"score": 85.0,
"emotional_tone": "POSITIVE",
"impact_score": 2.0,
"ai_message": "์น๊ทผํ๊ณ ์ ์ ํ ์ง๋ฌธ์
๋๋ค.",
"suggested_alternative": null
}
]
}ํ์ฌ ๋ํ ๋งฅ๋ฝ์ ๋ถ์ํ์ฌ ๋ค์์ ๋ณด๋ผ ๋ฉ์์ง๋ฅผ 3๊ฐ์ง ์คํ์ผ๋ก ์ ์ํฉ๋๋ค.
Endpoint: POST /sessions/{session_id}/predict-next
Request Body: ์์ (์ธ์ ์ ๋ณด ์๋ ์ฌ์ฉ)
Response:
{
"session_id": "2ea688cf-315f-4dcb-9580-59262fbe5888",
"relationship": "FRIEND",
"relationship_info": "2๋
์ง๊ธฐ",
"total_messages": 22,
"suggestions": [
{
"style": "๊ณต๊ฐํ",
"text": "์, ๊ทธ ๋ถ๋ถ ๊ถ๊ธํ์
จ๊ฒ ์ด์. ์ ๊ฐ ๋จผ์ ๋ง์๋๋ ธ์ด์ผ ํ๋ค์.",
"expected_impact": 2,
"explanation": "์๋์ ๊ถ๊ธ์ฆ์ ์ธ์ ํ๊ณ ๋ถ๋๋ฝ๊ฒ ์ฌ๊ณผํ๋ ์๋ต"
},
{
"style": "ํด๊ฒฐํ",
"text": "ํน์ ๊ธํ์ ๊ฐ์? ์ง๊ธ ๋ฐ๋ก ํ์ธํด๋ณผ๊ฒ์.",
"expected_impact": 1,
"explanation": "์ฆ๊ฐ์ ์ธ ํด๊ฒฐ ์์ง๋ฅผ ๋ณด์ด๋ ์๋ต"
},
{
"style": "๊ด๊ณํ",
"text": "์, ์ ๊ฐ ๋ฏธ๋ฆฌ ๊ณต์ ๋ฅผ ๋ชป ๋๋ ธ๋ค์. ๋ฐ๋ก ์งํ ์ํฉ ๊ณต์ ๋๋ฆฌ๊ฒ ์ต๋๋ค!",
"expected_impact": 3,
"explanation": "์ฑ
์๊ฐ์ ๋ณด์ด๋ฉฐ ์ ๊ทน์ ์ผ๋ก ์ํตํ๋ ค๋ ์์ธ๋ฅผ ๋ณด์ด๋ ์๋ต"
}
]
}์ธ๋ถ AI์ ์๋ก์ด ๋ํ๋ฅผ ์์ํฉ๋๋ค. AI๊ฐ ๊ด๊ณ์ ๋ง๋ ์ฒซ ๋ฉ์์ง๋ฅผ ๋ณด๋ ๋๋ค.
Endpoint: POST /start-conversation
Request Body:
{
"relationship": "์ฐ์ธ"
}Response:
{
"message": "์์ฆ ๋๋ ๋ณด๋ด๋ ์๊ฐ ์ด๋? ์ข ๋ ํจ๊ป ํ๊ณ ์ถ์ด.",
"thread_id": "thread_W2z3FfcGAB3b7vLPJWrwREaF"
}์งํ ์ค์ธ ๋ํ์ ์ฌ์ฉ์ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๊ณ AI์ ์๋ต๊ณผ ํ๊ฐ๋ฅผ ๋ฐ์ต๋๋ค.
Endpoint: POST /continue-conversation
Request Body:
{
"message": "์์ฆ ์ข ๋ฐ๋น ",
"thread_id": "thread_W2z3FfcGAB3b7vLPJWrwREaF"
}Response:
{
"message": "๋ฐ์ ๊ฑด ์ดํดํด. ๊ทธ๋๋ ๋ค ๋ง์์ด ๊ถ๊ธํ๋ฐ ์กฐ๊ธ๋ง ์๊ฐ ๋ด์ค ์ ์์๊น?",
"response": {
"emotional_tone": "NEUTRAL",
"appropriateness_rating": 60,
"impact_score": 0,
"review_comment": "์ํฉ์ ์ค๋ช
ํ๋ ํํ์ด์ง๋ง ์๋๋ฐฉ์ ๊ฐ์ ์ ๊ณ ๋ คํ ์ถ๊ฐ ์ค๋ช
์ด ์์ผ๋ฉด ์ข๊ฒ ์ต๋๋ค.",
"suggested_alternative": "์์ฆ ์ผ์ด ๋ง์์ ์๊ฐ์ด ๋ถ์กฑํด. ๋ฏธ์ํด, ์กฐ๊ธ๋ง ๊ธฐ๋ค๋ ค์ค ์ ์์๊น?"
}
}Response Fields:
message: AI์ ์๋ต ๋ฉ์์งresponse.emotional_tone: ์ฌ์ฉ์ ๋ฉ์์ง์ ๊ฐ์ ํคresponse.appropriateness_rating: ์ ์ ์ฑ ํ๊ฐ (0 ~ 100)response.impact_score: ๊ด๊ณ์ ๋ฏธ์น๋ ์ํฅ (-3 ~ 3)response.review_comment: AI ํผ๋๋ฐฑresponse.suggested_alternative: ์ถ์ฒ ๋์ ํํ
# 1. ์ธ์
์์ฑ
curl -X POST http://server/sessions
# 2. ์คํฌ๋ฆฐ์ท ์
๋ก๋ (์ฌ๋ฌ ์ฅ)
curl -X POST http://server/sessions/{session_id}/upload \
-F "file=@screenshot1.jpg"
curl -X POST http://server/sessions/{session_id}/upload \
-F "file=@screenshot2.jpg"
# 3. ์ธ์
์ฒ๋ฆฌ (OCR + ๋ณํฉ + AI ๋ถ์)
curl -X POST "http://server/sessions/{session_id}/process?relationship=FRIEND&relationship_info=2๋
%20์ง๊ธฐ"
# 4. ๊ฒฐ๊ณผ ์กฐํ
curl -X GET http://server/sessions/{session_id}/messages
# 5. ๋ค์ ๋ํ ์์ธก
curl -X POST http://server/sessions/{session_id}/predict-next# 1. ๋ํ ์์
curl -X POST http://server/start-conversation \
-H "Content-Type: application/json" \
-d '{"relationship": "์ฐ์ธ"}'
# 2. ๋ํ ์ด์ด๊ฐ๊ธฐ
curl -X POST http://server/continue-conversation \
-H "Content-Type: application/json" \
-d '{"message": "์ค๋ ํ๋ ํ๋ฃจ์์ด", "thread_id": "thread_xxx"}'python test_client.py# ๊ฐ๋จํ ๋ํ ํ
์คํธ
python test_conversation.py simple
# ์ฌ๋ฌ ๊ด๊ณ ์ ํ ํ
์คํธ
python test_conversation.py multiple
# ๊ธด ๋ํ ํ
์คํธ
python test_conversation.py longpip install -r requirements.txtpython main.py์๋ฒ๋ ๊ธฐ๋ณธ์ ์ผ๋ก 0.0.0.0:80์์ ์คํ๋ฉ๋๋ค.
main.py์ Configuration ์น์
์์ ์ธ๋ถ AI API URL์ ์ค์ ํฉ๋๋ค:
EXTERNAL_API_URL = "http://localhost:8080/analyze-messages"
SUGGESTION_API_URL = "http://localhost:8080/suggestion-messages"
START_CONVERSATION_URL = "http://localhost:8080/start-conversation"
SEND_MESSAGE_URL = "http://localhost:8080/send-message"์ธ๋ถ API๊ฐ ์์ผ๋ฉด ๋๋ฏธ ๋ฐ์ดํฐ๋ก ๋์ํฉ๋๋ค.
SQLite๋ฅผ ์ฌ์ฉํ๋ฉฐ, chat_sessions.db ํ์ผ์ ์ ์ฅ๋ฉ๋๋ค.
sessions: ์ธ์ ์ ๋ณด
- session_id (TEXT, PK)
- created_at (TEXT)
- updated_at (TEXT)
- status (TEXT)
- total_screenshots (INTEGER)
- total_messages (INTEGER)
- relationship (TEXT)
- relationship_info (TEXT)
screenshots: ์ ๋ก๋๋ ์คํฌ๋ฆฐ์ท
- screenshot_id (TEXT, PK)
- session_id (TEXT, FK)
- file_path (TEXT)
- upload_order (INTEGER)
- uploaded_at (TEXT)
- processed (INTEGER)
- image_width (INTEGER)
- image_height (INTEGER)
messages: OCR ์ถ์ถ ๋ฉ์์ง
- message_id (TEXT, PK)
- session_id (TEXT, FK)
- screenshot_id (TEXT, FK)
- text (TEXT)
- speaker (TEXT)
- confidence (REAL)
- position_x, position_y, position_width, position_height (REAL)
- group_id (INTEGER)
- sequence_order (INTEGER)
- score (REAL)
- emotional_tone (TEXT)
- impact_score (REAL)
- review_comment (TEXT)
- suggested_alternative (TEXT)
- created_at (TEXT)
์ฌ๋ฌ ์ฅ์ ์คํฌ๋ฆฐ์ท์ ์ ๋ก๋ํ๋ฉด ๊ฒน์น๋ ๋ฉ์์ง๋ฅผ ์๋์ผ๋ก ๊ฐ์งํ์ฌ ๋ณํฉํฉ๋๋ค.
- ์ต์ 2๊ฐ ์ด์์ ๋ฉ์์ง๊ฐ ๊ฒน์น๋ฉด ๋ณํฉ
- ๊ฒน์น๋ ๋ถ๋ถ ์ดํ์ ๋ฉ์์ง๋ง ์ถ๊ฐ
- ๊ฒน์น์ง ์์ผ๋ฉด ์์๋๋ก ์ด์ด๋ถ์
/view ์๋ํฌ์ธํธ์์๋ SequenceMatcher๋ฅผ ์ฌ์ฉํ ํ
์คํธ ์ ์ฌ๋ ๋น๊ต๋ฅผ ์ํํฉ๋๋ค.
- ์ ์ฌ๋ ์๊ณ๊ฐ: 85%
- OCR ์ค์ฐจ๋ฅผ ๊ณ ๋ คํ ์ ์ฐํ ๋งค์นญ
๋ชจ๋ ์๋ํฌ์ธํธ๋ ์คํจ ์ ์ ์ ํ HTTP ์ํ ์ฝ๋์ ์๋ฌ ๋ฉ์์ง๋ฅผ ๋ฐํํฉ๋๋ค:
- 400: ์๋ชป๋ ์์ฒญ (์ธ์ ์ด ์ฒ๋ฆฌ๋์ง ์์, ๋ฉ์์ง ์์ ๋ฑ)
- 404: ๋ฆฌ์์ค๋ฅผ ์ฐพ์ ์ ์์ (์ธ์ ์์)
- 500: ์๋ฒ ๋ด๋ถ ์ค๋ฅ
- 502: ์ธ๋ถ API ์ค๋ฅ
- 504: ์ธ๋ถ API ํ์์์
{
"detail": "Session not found"
}