Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions agents/sns_analyzer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# SNS 분석기 (SNS Analyzer)

## 개요

이 모듈은 Act 1: Entertainment의 SNS 성과 분석을 담당하는 LangGraph Workflow입니다. Instagram API를 통한 데이터 수집 및 월간 성과 분석을 제공하여 인플루언서의 콘텐츠 성과를 종합적으로 분석합니다.

## 주요 노드

### InstagramDataCollectorNode
**목적**: Instagram API를 통한 데이터 수집 및 메트릭 계산
- **입력**: InstagramAnalysisState (instagram_user_id, access_token, analysis_period)
- **처리**:
- 계정 인사이트 수집 (월간/일간 reach, 팔로워 수, 프로필 조회수)
- 미디어 목록 및 개별 인사이트 수집
- 참여율, 팔로워 성장률, 콘텐츠 타입별 성과 계산
- **출력**: 수집된 데이터 요약 및 상태 업데이트
- **에러 처리**: 재시도 로직 및 상세한 에러 분류

## 구조

```
sns_analyzer/
├── modules/ # 모듈 구성 요소
│ ├── __init__.py
│ ├── errors.py # 커스텀 예외 클래스들
│ ├── nodes.py # Workflow 노드 (InstagramDataCollectorNode)
│ ├── state.py # 상태 정의 (InstagramAnalysisState)
│ └── tools.py # Instagram API 호출 및 메트릭 계산 함수
├── pyproject.toml # 프로젝트 의존성
├── README.md # 이 문서
└── workflow.py # Instagram 분석 Workflow 정의
```

## 사용 방법

SNS 분석 Workflow는 다음과 같이 사용할 수 있습니다:

```python
from agents.sns_analyzer.workflow import instagram_analysis_workflow

# 초기 상태 설정
initial_state = {
"instagram_user_id": "your_user_id",
"access_token": "your_access_token",
"analysis_period": "2024-01",
"request_type": "monthly_analysis",
"response": []
}

# Workflow 실행
result = instagram_analysis_workflow.build().invoke(initial_state)
```

## 확장 방법

이 모듈은 확장성을 고려하여 설계되었습니다. 새로운 기능(백로그)을 추가하려면:

1. `modules/nodes.py`에 새로운 노드 클래스 추가
2. 필요에 따라 `modules/state.py`에 상태 관리 추가
3. 필요에 따라 `model.py`, `chain.py` 등의 해당 노드에서 사용되는 관련 모듈을 수정/추가하세요.
4. `workflow.py`에서 Workflow에 새 노드를 엣지로 연결

## 라이센스

이 모듈은 Proact0의 Act 1: Entertainment의 내부 프로젝트로, 그룹 정책에 따른 라이센스가 적용됩니다.
9 changes: 9 additions & 0 deletions agents/sns_analyzer/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"""
Management 패키지 초기화 모듈

이 모듈은 Management Workflow를 외부에 노출시키는 역할을 합니다.
"""

from agents.sns_analyzer.workflow import management_workflow

__all__ = ["management_workflow"]
Empty file.
67 changes: 67 additions & 0 deletions agents/sns_analyzer/modules/chains.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""LangChain 체인을 설정하는 함수 모듈

LCEL(LangChain Expression Language)을 사용하여 체인을 구성합니다.
기본적으로 modules.prompt 템플릿과 modules.models 모듈을 사용하여 LangChain 체인을 생성합니다.

"""

from langchain.schema.runnable import RunnablePassthrough, RunnableSerializable
from langchain_core.output_parsers import StrOutputParser

from agents.sns_analyzer.modules.models import get_openai_model
from agents.sns_analyzer.modules.prompts import get_resource_planning_prompt


def set_resource_planning_chain() -> RunnableSerializable:
"""
리소스 계획 수립에 사용할 LangChain 체인을 생성합니다.

이 함수는 LCEL(LangChain Expression Language)을 사용하여 체인을 구성합니다.
체인은 다음 단계로 구성됩니다:
1. 입력에서 project_id, request_type, query, team_members 등을 추출하여 프롬프트에 전달
2. 프롬프트 템플릿에 값을 삽입하여 최종 프롬프트 생성
3. LLM을 호출하여 리소스 계획 생성 수행
4. 결과를 문자열로 변환

이 함수는 리소스 관리 노드에서 사용됩니다.

Returns:
RunnableSerializable: 실행 가능한 체인 객체
"""
# 리소스 계획을 위한 프롬프트 가져오기
prompt = get_resource_planning_prompt()
# OpenAI 모델 가져오기
model = get_openai_model()

# LCEL을 사용하여 체인 구성
return (
# 입력에서 필요한 필드 추출 및 프롬프트에 전달
RunnablePassthrough.assign(
project_id=lambda x: x["project_id"], # 프로젝트 ID 추출
request_type=lambda x: x["request_type"], # 요청 유형 추출
query=lambda x: x["query"], # 사용자 쿼리 추출
team_members=lambda x: x.get("team_members", []), # 팀 구성원 추출
resources_available=lambda x: x.get(
"resources_available", {}
), # 가용 리소스 추출
)
| prompt # 프롬프트 적용
| model # LLM 모델 호출
| StrOutputParser() # 결과를 문자열로 변환
)


def set_instagram_data_collection_chain() -> RunnableSerializable:
"""
Instagram 데이터 수집 결과를 단순히 반환하는 체인을 생성합니다.

Instagram 데이터 수집 자체는 노드에서 수행하고,
이 체인은 수집된 데이터를 그대로 전달하는 역할만 합니다.

나중에 수집된 데이터를 LLM으로 분석하는 체인을 추가할 예정입니다.

Returns:
RunnableSerializable: Instagram 데이터 수집 체인 객체
"""
# 현재는 입력을 그대로 전달 (패스스루)
return RunnablePassthrough()
64 changes: 64 additions & 0 deletions agents/sns_analyzer/modules/conditions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""
조건부 라우팅 함수 모듈

이 모듈은 LangGraph Workflow에서 조건부 라우팅을 처리하는 함수들을 제공합니다.
조건부 라우팅은 Workflow의 다음 단계를 동적으로 결정하는 데 사용됩니다.

현재는 주석 처리된 예시 코드만 포함되어 있으며, 필요에 따라 실제 구현을 추가할 수 있습니다.
이 예시 코드는 ReAct 패턴에서 LLM의 출력에 따라 다음 노드를 결정하는 라우터 함수를 보여줍니다.

Workflow가 확장됨에 따라 다양한 조건부 라우팅 함수를 이 모듈에 추가할 수 있습니다.
예를 들어, 콘텐츠 유형에 따른 라우팅, 사용자 요청 유형에 따른 라우팅 등을 구현할 수 있습니다.
"""

# from typing import Literal


# def router(state) -> Literal["__end__", "tools"]:
# """
# 모델의 출력을 기반으로 다음 노드를 결정하는 라우터 함수
#
# 이 함수는 LLM의 마지막 메시지를 검사하여 도구 호출이 포함되어 있는지 확인하고,
# 그 결과에 따라 Workflow의 다음 단계를 결정합니다.
#
# 도구 호출이 있으면 "tools" 노드로 라우팅하고, 그렇지 않으면 Workflow를 종료합니다.
# 이는 ReAct 패턴의 일반적인 구현 방식으로, LLM이 도구를 사용해야 할지 또는
# 최종 응답을 생성해야 할지를 결정하게 합니다.
#
# Args:
# state (State): 현재 Workflow 상태 객체 (메시지 기록 포함)
#
# Returns:
# str: 다음에 실행할 노드의 이름 ("__end__" 또는 "tools")
#
# Raises:
# ValueError: 마지막 메시지가 AIMessage 타입이 아닌 경우
#
# 예시:
# ```python
# # Workflow에 조건부 에지 추가
# builder.add_conditional_edges(
# "call_model", # 소스 노드
# router, # 라우터 함수
# {
# "__end__": "__end__", # 종료 조건
# "tools": "execute_tools" # 도구 실행 조건
# }
# )
# ```
# """
# # 상태에서 마지막 메시지 가져오기
# last_message = state.messages[-1]
#
# # 메시지 타입 검증
# if not isinstance(last_message, AIMessage):
# raise ValueError(
# f"Expected AIMessage in output edges, but got {type(last_message).__name__}"
# )
#
# # 도구 호출 여부에 따른 라우팅 결정
# if not last_message.tool_calls:
# return "__end__" # 도구 호출이 없으면 Workflow 종료
#
# # 도구 호출이 있으면 도구 실행 노드로 라우팅
# return "tools"
Loading