|
5 | 5 |
|
6 | 6 | """ |
7 | 7 |
|
| 8 | + |
8 | 9 | from langchain_core.output_parsers import StrOutputParser |
9 | 10 | from langchain_core.runnables import ( |
10 | 11 | RunnableLambda, |
| 12 | + RunnableMap, |
11 | 13 | RunnablePassthrough, |
12 | 14 | RunnableSerializable, |
13 | 15 | ) |
14 | 16 |
|
15 | 17 | from agents.text.mcp.mcp_client import scrape_news |
16 | | -from agents.text.modules.models import get_openai_model |
| 18 | +from agents.text.modules.models import get_groq_model, get_openai_model |
17 | 19 | from agents.text.modules.persona import PERSONA |
18 | 20 | from agents.text.modules.prompts import ( |
19 | 21 | get_extraction_prompt, |
20 | 22 | get_instagram_text_prompt, |
21 | 23 | get_news_scraping_query_prompt, |
22 | 24 | get_topic_from_news_prompt, |
| 25 | + get_persona_match_prompt, |
23 | 26 | ) |
24 | 27 |
|
25 | 28 |
|
@@ -119,3 +122,89 @@ def set_instagram_text_chain() -> RunnableSerializable: |
119 | 122 | | model # LLM 모델 호출 |
120 | 123 | | StrOutputParser() # 결과를 문자열로 변환 |
121 | 124 | ) |
| 125 | + |
| 126 | + |
| 127 | +def set_instagram_text_format_check_chain() -> RunnableLambda: |
| 128 | + """ |
| 129 | + 인스타그램 포맷(2200자 이하) 검사를 위한 체인을 반환합니다. |
| 130 | +
|
| 131 | + Returns: |
| 132 | + RunnableLambda: 텍스트 길이를 검사하는 실행 체인 |
| 133 | + """ |
| 134 | + return RunnableLambda(lambda x: len(x["text"]) <= 2200) |
| 135 | + |
| 136 | + |
| 137 | +def set_sensitive_text_check_chain() -> RunnableLambda: |
| 138 | + def is_text_safe(x): |
| 139 | + model = get_groq_model("meta-llama/llama-guard-4-12b") |
| 140 | + try: |
| 141 | + response = model.invoke(x["text"]) |
| 142 | + return "safe" in response.content.lower() |
| 143 | + except Exception as e: |
| 144 | + print(f"[ERROR] llama-guard request failed: {e}") |
| 145 | + return False |
| 146 | + |
| 147 | + return RunnableLambda(is_text_safe) |
| 148 | + |
| 149 | + |
| 150 | +def set_text_persona_match_check_chain() -> RunnableLambda: |
| 151 | + def check_persona_match(x): |
| 152 | + model = get_openai_model() |
| 153 | + |
| 154 | + text = x["text"] |
| 155 | + persona = x.get("persona", {}) |
| 156 | + |
| 157 | + # 다양한 타입의 persona_description 처리: dict, str, list |
| 158 | + if isinstance(persona, dict): |
| 159 | + persona_description = "\n".join([f"{k}: {v}" for k, v in persona.items()]) |
| 160 | + elif isinstance(persona, list): |
| 161 | + persona_description = "\n".join([str(p) for p in persona]) |
| 162 | + else: |
| 163 | + persona_description = str(persona) |
| 164 | + |
| 165 | + prompt_template = get_persona_match_prompt() |
| 166 | + prompt = prompt_template.format( |
| 167 | + persona_description=persona_description, text=text |
| 168 | + ) |
| 169 | + |
| 170 | + try: |
| 171 | + response = model.invoke(prompt).content.strip().upper() |
| 172 | + return "YES" in response |
| 173 | + except Exception as e: |
| 174 | + print(f"[ERROR] Persona check failed: {e}") |
| 175 | + return False |
| 176 | + |
| 177 | + return RunnableLambda(check_persona_match) |
| 178 | + |
| 179 | + |
| 180 | +def set_text_content_check_chain() -> RunnableSerializable: |
| 181 | + return ( |
| 182 | + RunnablePassthrough.assign( |
| 183 | + text=lambda x: x if isinstance(x, str) else x.get("instagram_text", ""), |
| 184 | + persona=lambda x: ( |
| 185 | + x.get("persona_extracted", {}) if isinstance(x, dict) else {} |
| 186 | + ), |
| 187 | + ) |
| 188 | + | RunnableMap( |
| 189 | + { |
| 190 | + "format_check_passed": set_instagram_text_format_check_chain(), |
| 191 | + "safety_check_passed": set_sensitive_text_check_chain(), |
| 192 | + "persona_check_passed": set_text_persona_match_check_chain(), |
| 193 | + } |
| 194 | + ) |
| 195 | + | RunnableLambda( |
| 196 | + lambda results: { |
| 197 | + "text_content_checker_result": { |
| 198 | + "success": all(results.values()), |
| 199 | + "reason": [k for k, v in results.items() if not v], |
| 200 | + "content_check_passed": all(results.values()), |
| 201 | + **results, |
| 202 | + "message": ( |
| 203 | + "Text content is valid." |
| 204 | + if all(results.values()) |
| 205 | + else "Text content failed validation checks." |
| 206 | + ), |
| 207 | + } |
| 208 | + } |
| 209 | + ) |
| 210 | + ) |
0 commit comments