diff --git a/README.md b/README.md index 79ae96c..d2aed78 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ # 아키텍처 AWS Lambda -Gemini # Getting Started ## 개발환경 구축 @@ -13,7 +12,6 @@ bash를 기준으로 작성됨 sudo apt install python3.12-venv python3 -m venv venv # 가상환경 생성 source venv/bin/activate # 가상환경 사용 -pip install -q -U google-genai ``` 이후부터 작업 시 `source venv/bin/activate` 명령으로 가상환경을 실행한 후 작업 diff --git a/requirements.txt b/requirements.txt index 4175144..1db657b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -google-genai \ No newline at end of file +boto3 \ No newline at end of file diff --git a/src/lambda_function.py b/src/lambda_function.py index 9f1009b..d8a3955 100644 --- a/src/lambda_function.py +++ b/src/lambda_function.py @@ -1,14 +1,9 @@ import json -import os -from google import genai from tos_summarize import tos_summarize from tos_evaluate import tos_evaluate def lambda_handler(event, context): - GEMINI_API_KEY = os.getenv('GEMINI_API_KEY') - client = genai.Client(api_key=GEMINI_API_KEY) - # url이 없거나 빈 문자열인 경우 if ('queryStringParameters' not in event or 'url' not in event['queryStringParameters'] @@ -36,11 +31,10 @@ def lambda_handler(event, context): # TODO: 기존 URL 기반 캐싱 로직 구현 # text_html 문자열에서 중요 조항 위주로 약관 요약 - summarized_tos = tos_summarize(text_html, client) + summarized_tos = tos_summarize(text_html) # 약관 조항에 대해 분석 수행 - # gemini api의 rate limit 문제로, 여러 조항을 한 번에 보내지 않고 하나씩 처리 - evaluation_result = tos_evaluate(summarized_tos, client) + evaluation_result = tos_evaluate(summarized_tos) return { 'statusCode': 200, diff --git a/src/test_local.py b/src/test_local.py index 75abe22..d00417e 100644 --- a/src/test_local.py +++ b/src/test_local.py @@ -1,4 +1,3 @@ -import os from lambda_function import lambda_handler @@ -15,13 +14,6 @@ def create_test_event(url: str, body: str) -> dict: def run_test(): """Lambda 함수 로컬 테스트 실행""" - # GEMINI_API_KEY 확인 - api_key = os.getenv('GEMINI_API_KEY') - if not api_key: - print("GEMINI_API_KEY 환경변수가 설정되지 않았습니다.") - print() - return - # 테스트 데이터 test_url = "https://example.com/terms" test_body = """ diff --git a/src/tos_evaluate.py b/src/tos_evaluate.py index 64f23cd..054eb2f 100644 --- a/src/tos_evaluate.py +++ b/src/tos_evaluate.py @@ -1,48 +1,71 @@ -import enum import json -from google import genai -from google.genai import types +import boto3 -def tos_evaluate(summarized_tos, client): - response = client.models.generate_content( - model="gemini-2.5-flash-lite", - config=types.GenerateContentConfig( - system_instruction= - """ - 당신은 약관 분석 전문가입니다. 주어진 약관 및 각 조항을 평가합니다. - 각 약관 조항은 good, neutral, bad 중 하나로 평가합니다. - 'good'은 이용자에게 유리한 조항, 'neutral'은 중립적인 조항, 'bad'는 이용자에게 불리한 조항을 의미합니다. - A, B, C, D, E 등급 중 하나로 전체 약관을 평가합니다. - A는 매우 우수한 약관, E는 매우 불리한 약관을 의미합니다. - 한국어로 응답합니다. - """, - response_mime_type="application/json", - response_schema={ - "type": "object", - "properties": { - "overall_evaluation": { - "type": "string" - }, - "evaluation_for_each_clause": { - "type": "array", - "items": { - "type": "object", - "properties": { - "evaluation": { - "type": "string" - }, - "summarized_clause": { - "type": "string" - } - } - } - } - } - } - ), - contents=summarized_tos, +def tos_evaluate(summarized_tos): + system_instruction=[{"text": """ +당신은 전문적인 약관 분석 AI입니다. 주어진 약관 내용 및 각 조항을 평가합니다. +주어진 약관은 주요 조항을 위주로 요약된 내용입니다. +JSON 양식으로, 다음의 key값을 사용합니다. +"overall_evaluation": "A|B|C|D|E", +"evaluation_for_each_clause": [ + "evaluation": "good|neutral|bad", + "summarized_clause": "조항 요약 내용" +] +"overall_evaluation"은 전체 약관의 등급을 나타냅니다. A는 가장 우수한 약관, E는 가장 불리한 약관입니다. +"evaluation_for_each_clause"는 각 조항에 대한 평가를 포함하는 리스트입니다. +"evaluation"은 각 조항이 소비자에게 유리한지(good)/중립적인지(neutral)/불리한지(bad)를 나타냅니다. +"summarized_clause"는 각 조항의 요약된 내용을 포함합니다. +JSON 형식 이외에 서론이나 결론, 코드 블럭 따위는 절대로 포함하지 마십시오. +응답은 곧바로 json.loads()를 통해 파싱되기 때문에 반드시 여는 중괄호(`{`})로 시작하고 닫는 중괄호(`}`)로 끝나야 합니다. +예시 응답: +{ + "overall_evaluation": "D", + "evaluation_for_each_clause": [ + { + "evaluation": "neutral", + "summarized_clause": "AWS 사이트 콘텐츠의 저작권은 AWS 또는 제공자에게 있으며, 관련 법률에 의해 보호됨을 명시합니다." + }, + { + "evaluation": "neutral", + "summarized_clause": "AWS 상표 및 트레이드 드레스는 허가 없이 사용할 수 없으며, 타사 상표는 해당 소유자에게 있음을 명시합니다." + }, + { + "evaluation": "bad", + "summarized_clause": "개인적인 사이트 이용 목적 외 상업적 재판매, 복제, 변경 등은 사전 서면 동의 없이는 금지됨을 명시하며, 이는 일반적인 내용이나 명확한 제한을 둠." + }, + { + "evaluation": "bad", + "summarized_clause": "이용자의 계정 및 비밀번호 관리 책임을 명시하고, 계정 활동에 대한 책임을 이용자에게 부과합니다. 또한 AWS는 일방적으로 서비스 거절 및 계정 해지 권한을 가집니다." + } + ] +} +"""}] + client = boto3.client( + service_name="bedrock-runtime", + region_name="us-west-2" +) + + model_id = "us.anthropic.claude-sonnet-4-5-20250929-v1:0" + messages = [{ + "role": "user", + "content": [ + {"text": summarized_tos} + ] + }] + + response = client.converse( + modelId=model_id, + system=system_instruction, + messages=messages, ) - # response에서 JSON 파싱 후 반환 + print("TOS Evaluation Response:") + print(response) - return json.loads(response.text) + text = response['output']['message']['content'][0]['text'] + start = text.find('{') + end = text.rfind('}') + 1 + json_text = text[start:end] + + # response에서 JSON 파싱 후 반환 + return json.loads(json_text) \ No newline at end of file diff --git a/src/tos_summarize.py b/src/tos_summarize.py index 41086a5..892bed2 100644 --- a/src/tos_summarize.py +++ b/src/tos_summarize.py @@ -1,18 +1,32 @@ -import json -from google import genai -from google.genai import types +import boto3 -def tos_summarize(text_html, client): - response = client.models.generate_content( - model="gemini-2.5-flash-lite", - config=types.GenerateContentConfig( - system_instruction=""" - 당신은 약관 분석 전문가입니다. - 주어진 html 페이지에서 주요 약관 내용을 요약합니다. - 한국어로 응답합니다. - """, - ), - contents=text_html, +def tos_summarize(text_html): + system_instruction=[{"text": """ +당신은 약관 분석 전문가입니다. +주어진 html 페이지에서 주요 약관 내용을 요약합니다. +한국어로 응답합니다. +"""}] + + client = boto3.client( + service_name="bedrock-runtime", + region_name="us-west-2" ) - return response.text + model_id = "us.anthropic.claude-sonnet-4-5-20250929-v1:0" + messages = [{ + "role": "user", + "content": [ + {"text": text_html} + ] + }] + + response = client.converse( + modelId=model_id, + system=system_instruction, + messages=messages, + ) + + print("TOS Summarization Response:") + print(response) + + return response['output']['message']['content'][0]['text']