Spaces:
Sleeping
Sleeping
| """ | |
| ์ปค์คํ ์ฌ์ฌ ๊ธฐ์ค ์์ฑ ๋ชจ๋ | |
| ์ฌ์ฉ์ ์ ๋ ฅ ๊ธฐ์ค์ ๋ฐํ์ผ๋ก LLM์ด ํ๊ฐ ํ๋กฌํํธ๋ฅผ ์๋ ์์ฑ | |
| """ | |
| import json | |
| from typing import Dict, Any, List, Optional | |
| from openai import OpenAI | |
| import os | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| class CustomCriteriaGenerator: | |
| """์ฌ์ฉ์ ์ ์ ์ฌ์ฌ ๊ธฐ์ค์ผ๋ก LLM ํ๋กฌํํธ๋ฅผ ์์ฑํ๋ ํด๋์ค""" | |
| def __init__(self, api_key: Optional[str] = None): | |
| self.api_key = api_key or os.getenv("OPENAI_API_KEY") | |
| if not self.api_key: | |
| raise ValueError("OPENAI_API_KEY๊ฐ ์ค์ ๋์ง ์์์ต๋๋ค.") | |
| self.client = OpenAI(api_key=self.api_key) | |
| self.model = "gpt-4o" | |
| def generate_evaluation_prompt( | |
| self, | |
| criteria_name: str, | |
| criteria_description: str, | |
| sub_criteria: List[Dict[str, Any]], | |
| total_points: int, | |
| evaluation_target: str = "workflow" # "workflow" or "project_description" | |
| ) -> str: | |
| """ | |
| ์ฌ์ฉ์ ์ ์ ์ฌ์ฌ ๊ธฐ์ค์ ๋ฐํ์ผ๋ก LLM ํ๊ฐ ํ๋กฌํํธ ์์ฑ | |
| Args: | |
| criteria_name: ์ฌ์ฌ ๊ธฐ์ค ์ด๋ฆ (์: "๊ธฐ์ ์ ์์ฑ๋") | |
| criteria_description: ์ฌ์ฌ ๊ธฐ์ค ์ ์ฒด ์ค๋ช | |
| sub_criteria: ์ธ๋ถ ๊ธฐ์ค ๋ฆฌ์คํธ [{"name": "์ด๋ฆ", "description": "์ค๋ช ", "points": ์ ์}, ...] | |
| total_points: ์ด์ | |
| evaluation_target: ํ๊ฐ ๋์ ์ ํ ("workflow" ๋๋ "project_description") | |
| Returns: | |
| ์์ฑ๋ ํ๊ฐ ํ๋กฌํํธ ๋ฌธ์์ด | |
| """ | |
| # ์ธ๋ถ ๊ธฐ์ค ํฌ๋งทํ | |
| sub_criteria_text = "" | |
| json_output_structure = {} | |
| for idx, sub in enumerate(sub_criteria, 1): | |
| sub_name = sub.get("name", f"๊ธฐ์ค{idx}") | |
| sub_desc = sub.get("description", "") | |
| sub_points = sub.get("points", 0) | |
| sub_details = sub.get("details", []) | |
| sub_criteria_text += f"\n### {criteria_name[:2]}-{idx}. {sub_name} ({sub_points}์ )\n\n" | |
| sub_criteria_text += f"**์ค๋ช :** {sub_desc}\n\n" | |
| if sub_details: | |
| sub_criteria_text += "**์ธ๋ถ ํ๊ฐ ํญ๋ชฉ:**\n" | |
| detail_json = {} | |
| for detail in sub_details: | |
| detail_name = detail.get("name", "") | |
| detail_points = detail.get("points", 0) | |
| detail_desc = detail.get("description", "") | |
| sub_criteria_text += f"- {detail_name} ({detail_points}์ ): {detail_desc}\n" | |
| # JSON ํค๋ฅผ ํ๊ธ๋ก ์ ์งํ๋ ํน์๋ฌธ์ ์ ๊ฑฐ | |
| safe_key = detail_name.replace(" ", "_").replace("/", "_").replace("ยท", "_") | |
| detail_json[safe_key] = f"<0-{detail_points}>" | |
| detail_json["์๊ณ"] = f"<0-{sub_points}>" | |
| detail_json["ํ๊ฐ"] = "<๊ตฌ์ฒด์ ํ๊ฐ>" | |
| else: | |
| detail_json = { | |
| "์ ์": f"<0-{sub_points}>", | |
| "ํ๊ฐ": "<๊ตฌ์ฒด์ ํ๊ฐ>" | |
| } | |
| # JSON ํค๋ฅผ ํ๊ธ๋ก ์ ์ง | |
| safe_sub_name = sub_name.replace(" ", "_").replace("/", "_").replace("ยท", "_") | |
| json_output_structure[safe_sub_name] = detail_json | |
| json_output_structure["์ด์ "] = f"<0-{total_points}>" | |
| json_output_structure["์ข ํฉ_ํ๊ฐ"] = "<์ ์ฒด์ ์ธ ํ๊ฐ ์์ฝ>" | |
| # ํ๊ฐ ๋์์ ๋ฐ๋ฅธ ์๋ด ๋ฌธ๊ตฌ | |
| if evaluation_target == "workflow": | |
| target_instruction = "์ํฌํ๋ก์ฐ JSON ํ์ผ์ ๋ถ์ํ์ฌ ๋ค์ ๊ธฐ์ค์ผ๋ก ํ๊ฐํ์ญ์์ค." | |
| else: | |
| target_instruction = "์ ์ถ๋ ํ๋ก์ ํธ ์ค๋ช ์ ๋ถ์ํ์ฌ ๋ค์ ๊ธฐ์ค์ผ๋ก ํ๊ฐํ์ญ์์ค." | |
| # ์ต์ข ํ๋กฌํํธ ์์ฑ | |
| prompt = f"""# {criteria_name} ์ฌ์ฌ ๊ธฐ์ค ({total_points}์ ) | |
| โ ๏ธ **์ค์: ์๊ฒฉํ ํ๊ฐ ์์น** | |
| - ์ ์๋ ๋งค์ฐ ์๊ฒฉํ๊ฒ ๋ถ์ฌํ์ญ์์ค. ์๋ฒฝํ์ง ์์ผ๋ฉด ๊ฐ์ ํ์ญ์์ค. | |
| - "๊ฑฐ์ ์์ฑ" ๋๋ "๋๋ถ๋ถ ์ข์"์ ์ถฉ๋ถํ์ง ์์ต๋๋ค. ๊ธฐ์ค์ ์ ํํ ์ถฉ์กฑํด์ผ๋ง ์ ์๋ฅผ ๋ถ์ฌํ์ญ์์ค. | |
| - ๋ถํ์คํ๊ฑฐ๋ ๋ช ํํ์ง ์์ ๊ฒฝ์ฐ๋ ๋ฎ์ ์ ์๋ฅผ ๋ถ์ฌํ์ญ์์ค. | |
| - ๊ธฐ์ค์ ์์ ํ ์ถฉ์กฑํ์ง ์์ผ๋ฉด ํด๋น ํญ๋ชฉ์ ๋ํ ์ ์๋ฅผ ๋ถ์ฌํ์ง ๋ง์ญ์์ค. | |
| {target_instruction} | |
| ## ์ฌ์ฌ ๊ธฐ์ค ์ค๋ช | |
| {criteria_description} | |
| ## ํ๊ฐ ํญ๋ชฉ: | |
| {sub_criteria_text} | |
| ## ์ถ๋ ฅ ํ์: | |
| JSON ํ์์ผ๋ก ๋ค์๊ณผ ๊ฐ์ด ์ถ๋ ฅํ์ญ์์ค: | |
| {json.dumps(json_output_structure, ensure_ascii=False, indent=4)} | |
| """ | |
| return prompt | |
| def generate_prompt_with_llm( | |
| self, | |
| criteria_name: str, | |
| criteria_description: str, | |
| sub_criteria: List[Dict[str, Any]], | |
| total_points: int, | |
| evaluation_target: str = "workflow", | |
| additional_context: str = "" | |
| ) -> str: | |
| """ | |
| LLM์ ์ฌ์ฉํ์ฌ ๋ ์ ๊ตํ ํ๊ฐ ํ๋กฌํํธ ์์ฑ | |
| Args: | |
| criteria_name: ์ฌ์ฌ ๊ธฐ์ค ์ด๋ฆ | |
| criteria_description: ์ฌ์ฌ ๊ธฐ์ค ์ค๋ช | |
| sub_criteria: ์ธ๋ถ ๊ธฐ์ค ๋ฆฌ์คํธ | |
| total_points: ์ด์ | |
| evaluation_target: ํ๊ฐ ๋์ | |
| additional_context: ์ถ๊ฐ ์ปจํ ์คํธ (์ ํ) | |
| Returns: | |
| LLM์ด ์์ฑํ ์ ๊ตํ ํ๊ฐ ํ๋กฌํํธ | |
| """ | |
| user_input = f""" | |
| ๋ค์ ์ฌ์ฌ ๊ธฐ์ค์ ๋ฐํ์ผ๋ก n8n ์ํฌํ๋ก์ฐ ํ๊ฐ์ฉ ํ๋กฌํํธ๋ฅผ ์์ฑํด์ฃผ์ธ์. | |
| ## ์ฌ์ฌ ๊ธฐ์ค ์ ๋ณด | |
| - ๊ธฐ์ค ์ด๋ฆ: {criteria_name} | |
| - ์ด์ : {total_points}์ | |
| - ํ๊ฐ ๋์: {"์ํฌํ๋ก์ฐ JSON ํ์ผ" if evaluation_target == "workflow" else "ํ๋ก์ ํธ ์ค๋ช ์"} | |
| ## ๊ธฐ์ค ์ค๋ช | |
| {criteria_description} | |
| ## ์ธ๋ถ ๊ธฐ์ค | |
| {json.dumps(sub_criteria, ensure_ascii=False, indent=2)} | |
| ## ์ถ๊ฐ ์ปจํ ์คํธ | |
| {additional_context if additional_context else "์์"} | |
| ์ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก LLM์ด ํ๊ฐํ ๋ ์ฌ์ฉํ ์์ธํ๊ณ ๊ตฌ์ฒด์ ์ธ ํ๊ฐ ํ๋กฌํํธ๋ฅผ ์์ฑํด์ฃผ์ธ์. | |
| ํ๋กฌํํธ์๋ ๋ค์์ด ํฌํจ๋์ด์ผ ํฉ๋๋ค: | |
| 1. ์๊ฒฉํ ํ๊ฐ ์์น | |
| 2. ๊ฐ ์ธ๋ถ ๊ธฐ์ค๋ณ ๊ตฌ์ฒด์ ์ธ ํ๊ฐ ํฌ์ธํธ | |
| 3. JSON ํ์์ ์ถ๋ ฅ ํ์ ์ง์ | |
| 4. ํ๊ฐ ์ ์ฃผ์์ฌํญ | |
| """ | |
| try: | |
| response = self.client.chat.completions.create( | |
| model=self.model, | |
| messages=[ | |
| { | |
| "role": "system", | |
| "content": """๋น์ ์ n8n ์ํฌํ๋ก์ฐ ํ๊ฐ ํ๋กฌํํธ๋ฅผ ์ค๊ณํ๋ ์ ๋ฌธ๊ฐ์ ๋๋ค. | |
| ์ฌ์ฉ์๊ฐ ์ ๊ณตํ๋ ์ฌ์ฌ ๊ธฐ์ค์ ๋ฐํ์ผ๋ก, LLM์ด ์ํฌํ๋ก์ฐ๋ ํ๋ก์ ํธ๋ฅผ ์๊ฒฉํ๊ณ ๊ณต์ ํ๊ฒ ํ๊ฐํ ์ ์๋ | |
| ์์ธํ ํ๊ฐ ํ๋กฌํํธ๋ฅผ ์์ฑํฉ๋๋ค. | |
| ํ๋กฌํํธ ์์ฑ ์ ๋ค์ ์์น์ ๋ฐ๋ฅด์ธ์: | |
| 1. ๊ฐ ํ๊ฐ ํญ๋ชฉ๋ณ๋ก ๊ตฌ์ฒด์ ์ธ ํ๋จ ๊ธฐ์ค ์ ์ | |
| 2. JSON ํ์์ผ๋ก ์ ์์ ํ๊ฐ๋ฅผ ์ถ๋ ฅํ๋๋ก ์ง์ | |
| 3. ์๊ฒฉํ ํ๊ฐ ์์น ๋ช ์ | |
| 4. ์ํฌํ๋ก์ฐ JSON์์ ํ์ธํ ์ ์๋ ๊ตฌ์ฒด์ ์ธ ์ ํธ(signal) ์ ์ | |
| 5. ํ๊ฐ์๊ฐ ์ผ๊ด๋๊ฒ ์ ์๋ฅผ ๋ถ์ฌํ ์ ์๋๋ก ๋ช ํํ ๊ธฐ์ค ์ ๊ณต""" | |
| }, | |
| { | |
| "role": "user", | |
| "content": user_input | |
| } | |
| ], | |
| temperature=0.3 | |
| ) | |
| return response.choices[0].message.content | |
| except Exception as e: | |
| print(f"LLM ํ๋กฌํํธ ์์ฑ ์คํจ: {e}") | |
| # ์คํจ ์ ๊ธฐ๋ณธ ํ๋กฌํํธ ์์ฑ ๋ฉ์๋ ์ฌ์ฉ | |
| return self.generate_evaluation_prompt( | |
| criteria_name, criteria_description, sub_criteria, | |
| total_points, evaluation_target | |
| ) | |
| def validate_criteria(self, sub_criteria: List[Dict[str, Any]], total_points: int) -> Dict[str, Any]: | |
| """ | |
| ์ฌ์ฌ ๊ธฐ์ค์ ์ ํจ์ฑ ๊ฒ์ฌ | |
| Args: | |
| sub_criteria: ์ธ๋ถ ๊ธฐ์ค ๋ฆฌ์คํธ | |
| total_points: ๋ช ์๋ ์ด์ | |
| Returns: | |
| ๊ฒ์ฆ ๊ฒฐ๊ณผ {"valid": bool, "message": str, "calculated_total": int} | |
| """ | |
| calculated_total = 0 | |
| for sub in sub_criteria: | |
| sub_points = sub.get("points", 0) | |
| details = sub.get("details", []) | |
| if details: | |
| detail_total = sum(d.get("points", 0) for d in details) | |
| if detail_total != sub_points: | |
| return { | |
| "valid": False, | |
| "message": f"'{sub.get('name', '?')}'์ ์ธ๋ถ ์ ์ ํฉ๊ณ({detail_total})๊ฐ ์๊ณ({sub_points})์ ์ผ์นํ์ง ์์ต๋๋ค.", | |
| "calculated_total": calculated_total | |
| } | |
| calculated_total += sub_points | |
| if calculated_total != total_points: | |
| return { | |
| "valid": False, | |
| "message": f"์ธ๋ถ ๊ธฐ์ค ์ ์ ํฉ๊ณ({calculated_total})๊ฐ ์ด์ ({total_points})๊ณผ ์ผ์นํ์ง ์์ต๋๋ค.", | |
| "calculated_total": calculated_total | |
| } | |
| return { | |
| "valid": True, | |
| "message": "์ฌ์ฌ ๊ธฐ์ค์ด ์ ํจํฉ๋๋ค.", | |
| "calculated_total": calculated_total | |
| } | |
| # ๊ธฐ๋ณธ ํ ํ๋ฆฟ ์ ๊ณต (๊ณ ์ ํ ํ๋ฆฟ - ๋ฐฐ์ ๋ง ์กฐ์ ๊ฐ๋ฅ) | |
| FIXED_CRITERIA_TEMPLATES = { | |
| "๊ธฐ์ ์ _์์ฑ๋": { | |
| "name": "๊ธฐ์ ์ ์์ฑ๋", | |
| "description": "์ํฌํ๋ก์ฐ์ ๊ตฌ์กฐ์ ์์ฑ๋, ๋ฐ์ดํฐ ์ฒ๋ฆฌ์ ์ผ๊ด์ฑ, ์์ธ ์ฒ๋ฆฌ๋ฅผ ํ๊ฐํฉ๋๋ค.", | |
| "evaluation_target": "workflow", | |
| "structure": [ | |
| { | |
| "name": "๊ตฌ์กฐ ์๊ฒฐ์ฑ & ๋ชจ๋ํ", | |
| "description": "TriggerโOutput๊น์ง ๊ฒฝ๋ก ์์ฑ, dead node ์์, ์ญํ ๊ธฐ๋ฐ ๋ค์ด๋ฐยท๋ชจ๋ํ", | |
| "ratio": 0.4 # 40% | |
| }, | |
| { | |
| "name": "๋ฐ์ดํฐยท์คํค๋ง ์ผ๊ด์ฑ", | |
| "description": "key ์ผ๊ด์ฑ, ๋ถํ์ํ overwrite ์์, merge ์ ํฉ์ฑ", | |
| "ratio": 0.4 # 40% | |
| }, | |
| { | |
| "name": "๋ถ๊ธฐ/์์ธ ์ฒ๋ฆฌ", | |
| "description": "์๋ฏธ ์๋ ์กฐ๊ฑด ๋ถ๊ธฐ, fallback/default ๊ฒฝ๋ก ์กด์ฌ", | |
| "ratio": 0.2 # 20% | |
| } | |
| ] | |
| }, | |
| "์ ์คํ ์ด์ง_ํ์ฉ๋": { | |
| "name": "์ ์คํ ์ด์ง ์ ํ ํ์ฉ๋", | |
| "description": "์ ์คํ ์ด์ง API์ ์ ์ ํ ์ฌ์ฉ, ํ๋กฌํํธ ์ค๊ณ, ๊ธฐ๋ฅ ์กฐํฉ์ ํ๊ฐํฉ๋๋ค.", | |
| "evaluation_target": "workflow", | |
| "structure": [ | |
| { | |
| "name": "API ์ฌ์ฉ ์ ํฉ์ฑ", | |
| "description": "๊ณต์ ์๋ํฌ์ธํธ, credential ๋ณด์, ๋ชฉ์ ์ ํฉ API ์ ํ", | |
| "ratio": 0.33 # 33% | |
| }, | |
| { | |
| "name": "Prompt/System ์ค๊ณ", | |
| "description": "๋ช ํํ ์ญํ ์ ์, ์ถ๋ ฅ ํฌ๋งท ๊ฐ์ ๋ ฅ, ๊น๋ํ ํ๋กฌํํธ", | |
| "ratio": 0.33 # 33% | |
| }, | |
| { | |
| "name": "๊ธฐ๋ฅ ์กฐํฉยท์ค์ผ์คํธ๋ ์ด์ ", | |
| "description": "๋ค๋จ๊ณ ํ์ดํ๋ผ์ธ, ์ /ํ์ฒ๋ฆฌ, ํจ์จ์ ํธ์ถ", | |
| "ratio": 0.34 # 34% | |
| } | |
| ] | |
| } | |
| } | |
| # ์ปค์คํฐ๋ง์ด์ง ๊ฐ๋ฅํ ํ ํ๋ฆฟ | |
| DEFAULT_CRITERIA_TEMPLATES = { | |
| "์ค์ฉ์ฑ": { | |
| "name": "์ค์ฉ์ฑ", | |
| "description": "์ค์ ์ ๋ฌด ์ ์ฉ ๊ฐ๋ฅ์ฑ, ์ฌ์ฌ์ฉ์ฑยทํ์ฅ์ฑ, ์ฌ์ฉ์ ํธ์์ฑ์ ํ๊ฐํฉ๋๋ค.", | |
| "total_points": 30, | |
| "evaluation_target": "project_description", | |
| "sub_criteria": [ | |
| { | |
| "name": "์ ๋ฌด ์ ์ฉ ๊ฐ๋ฅ์ฑ", | |
| "description": "๋ฐ๋ณต ์ ๋ฌด ์ ๊ฑฐ, ์ค์ ์ฌ์ฉ ์๋๋ฆฌ์ค ์ ๋ช , ์๊ฐ ์ ๊ฐ ํจ๊ณผ ๋ช ํ", | |
| "points": 10, | |
| "details": [ | |
| {"name": "๋ฐ๋ณต ์ ๋ฌด ์ ๊ฑฐ", "points": 3, "description": "๋งค์ผ/๋งค์ฃผ ๋ฐ๋ณต๋๋ ์์ ์ ์๋ํ"}, | |
| {"name": "์ค์ ์ฌ์ฉ ์๋๋ฆฌ์ค ์ ๋ช ", "points": 4, "description": "๋๊ฐ/์ธ์ /์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ๊ตฌ์ฒด์ "}, | |
| {"name": "์๊ฐ ์ ๊ฐ ํจ๊ณผ ๋ช ํ", "points": 3, "description": "์ ๋์ /์ง์ ํจ๊ณผ ์ ์"} | |
| ] | |
| }, | |
| { | |
| "name": "์ฌ์ฌ์ฉ์ฑยทํ์ฅ์ฑ", | |
| "description": "๋ค๋ฅธ ๋ฐ์ดํฐยท์กฐ์ง์๋ ์ ์ฉ ๊ฐ๋ฅํ ์ผ๋ฐํ ๊ตฌ์กฐ", | |
| "points": 10, | |
| "details": [ | |
| {"name": "๋ค๋ฅธ ๋ฐ์ดํฐยท์กฐ์ง ์ ์ฉ ๊ฐ๋ฅ", "points": 5, "description": "ํน์ ํ์ฌ/ํ ์ข ์ ์ต์ํ"}, | |
| {"name": "ํ์ฅ ๊ฐ๋ฅํ ์ค๊ณ", "points": 5, "description": "์๋ก์ด ์๊ตฌ์ฌํญ ์ถ๊ฐ ์ ์ต์ ์์ "} | |
| ] | |
| }, | |
| { | |
| "name": "์ฌ์ฉ์ ํธ์์ฑ", | |
| "description": "์ต์ข ์ฌ์ฉ์ ์ ์ฅ์์ ์ง๊ด์ ์ผ๋ก ์ธ ์ ์๋๊ฐ?", | |
| "points": 10, | |
| "details": [ | |
| {"name": "์ง๊ด์ ์ธ ์ ๋ ฅ ๋ฐฉ์", "points": 4, "description": "๊ฐ๋จํ๊ณ ๋ช ํํ ์ ๋ ฅ"}, | |
| {"name": "๋ช ํํ ์ถ๋ ฅ ๋ฐ ํผ๋๋ฐฑ", "points": 3, "description": "์ดํดํ๊ธฐ ์ฌ์ด ๊ฒฐ๊ณผ๋ฌผ"}, | |
| {"name": "์๋ฌ ์ฒ๋ฆฌ ๋ฐ ๊ฐ์ด๋", "points": 3, "description": "์ฌ์ฉ์ ์นํ์ ๋ฉ์์ง"} | |
| ] | |
| } | |
| ] | |
| }, | |
| "๋ฌธ์ ํด๊ฒฐ": { | |
| "name": "๋ฌธ์ ํด๊ฒฐ ์ ๊ทผ๋ฒ", | |
| "description": "๋ฌธ์ ์ ์์ ๋ ์ฐฝ์ฑ๊ณผ ์๋ฃจ์ ์ ์ฐธ์ ์ฑ์ ํ๊ฐํฉ๋๋ค.", | |
| "total_points": 30, | |
| "evaluation_target": "project_description", | |
| "sub_criteria": [ | |
| { | |
| "name": "๋ฌธ์ ์ ์์ ๋ ์ฐฝ์ฑ", | |
| "description": "์๋ํ ๋์ ์ ์ ์ด ์๋กญ๊ฑฐ๋, ์ค์ง์ ๋ฌธ์ ๋ฅผ ์ ํฌ์ฐฉํ๋๊ฐ? ๊ธฐ์กด ๋ฐฉ๋ฒ๊ณผ ์ฐจ๋ณํ๋ ์ ๊ทผ์ ํ๋๊ฐ?", | |
| "points": 15, | |
| "details": [ | |
| {"name": "์ค์ง์ ๋ฌธ์ ํฌ์ฐฉ", "points": 8, "description": "๊ตฌ์ฒด์ ๋ฌธ์ ์ํฉ ์ ์, ๋ช ํํ pain point"}, | |
| {"name": "์ฐจ๋ณํ๋ ๊ด์ ๋ฐ ๋ ์ฐฝ์ฑ", "points": 7, "description": "๊ธฐ์กด ๋ฐฉ์์ ํ๊ณ ๋ถ์, ์๋ก์ด ์๊ฐ"} | |
| ] | |
| }, | |
| { | |
| "name": "์๋ฃจ์ ์ฐธ์ ์ฑ", | |
| "description": "๋จ์ API ๋์ด์ด ์๋, ์๋ก์ด ์ ๊ทผยท์ ๋ต ๊ธฐ๋ฐ ์ค๊ณ", | |
| "points": 15, | |
| "details": [ | |
| {"name": "์ ๋ต์ ์กฐํฉ ๋ฐ ๋ณต์ก๋", "points": 8, "description": "๋ค๋จ๊ณ ๋ก์ง, ๋ ผ๋ฆฌ์ ์ฐ๊ฒฐ"}, | |
| {"name": "์ฐฝ์์ ์ค๊ณ", "points": 7, "description": "๋ฌธ์ ํด๊ฒฐ ํนํ ์ค๊ณ, ๋ ํนํ ํจํด"} | |
| ] | |
| } | |
| ] | |
| } | |
| } | |
| def get_fixed_template_with_points(template_name: str, total_points: int) -> Optional[Dict[str, Any]]: | |
| """ | |
| ๊ณ ์ ํ ํ๋ฆฟ์ ๋ฐฐ์ ์ ๋ง๊ฒ ์์ฑ | |
| Args: | |
| template_name: "๊ธฐ์ ์ _์์ฑ๋" ๋๋ "์ ์คํ ์ด์ง_ํ์ฉ๋" | |
| total_points: ์ด ๋ฐฐ์ | |
| Returns: | |
| ๋ฐฐ์ ์ด ์ ์ฉ๋ ํ ํ๋ฆฟ ๋์ ๋๋ฆฌ | |
| """ | |
| template = FIXED_CRITERIA_TEMPLATES.get(template_name) | |
| if not template: | |
| return None | |
| # ๋น์จ์ ๋ฐ๋ผ ๋ฐฐ์ ๊ณ์ฐ | |
| sub_criteria = [] | |
| remaining_points = total_points | |
| for idx, item in enumerate(template["structure"]): | |
| # ๋ง์ง๋ง ํญ๋ชฉ์ ๋จ์ ์ ์ ๋ชจ๋ ํ ๋น (๋ฐ์ฌ๋ฆผ ์ค์ฐจ ๋ฐฉ์ง) | |
| if idx == len(template["structure"]) - 1: | |
| points = remaining_points | |
| else: | |
| points = round(total_points * item["ratio"]) | |
| remaining_points -= points | |
| sub_criteria.append({ | |
| "name": item["name"], | |
| "description": item["description"], | |
| "points": points, | |
| "details": [] | |
| }) | |
| return { | |
| "name": template["name"], | |
| "description": template["description"], | |
| "total_points": total_points, | |
| "evaluation_target": template["evaluation_target"], | |
| "sub_criteria": sub_criteria | |
| } | |
| def get_default_template(template_name: str) -> Optional[Dict[str, Any]]: | |
| """๊ธฐ๋ณธ ํ ํ๋ฆฟ ๊ฐ์ ธ์ค๊ธฐ""" | |
| return DEFAULT_CRITERIA_TEMPLATES.get(template_name) | |
| def list_default_templates() -> List[str]: | |
| """์ฌ์ฉ ๊ฐ๋ฅํ ๊ธฐ๋ณธ ํ ํ๋ฆฟ ๋ชฉ๋ก""" | |
| return list(DEFAULT_CRITERIA_TEMPLATES.keys()) | |
| def list_fixed_templates() -> List[str]: | |
| """๊ณ ์ ํ ํ๋ฆฟ ๋ชฉ๋ก""" | |
| return list(FIXED_CRITERIA_TEMPLATES.keys()) | |