From 6e277be22bd9df6f9f488ab4b5eca29d66faf517 Mon Sep 17 00:00:00 2001 From: Hyeongjun Ham Date: Tue, 18 Nov 2025 20:00:32 +0900 Subject: [PATCH 01/12] =?UTF-8?q?chore:=20=EC=9D=B4=EC=A0=84=20=EB=B2=84?= =?UTF-8?q?=EC=A0=84=EC=9D=98=20=EB=A1=9C=EC=BB=AC=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test_local.py | 70 ----------------------------------------------- 1 file changed, 70 deletions(-) delete mode 100644 src/test_local.py diff --git a/src/test_local.py b/src/test_local.py deleted file mode 100644 index d00417e..0000000 --- a/src/test_local.py +++ /dev/null @@ -1,70 +0,0 @@ - -from lambda_function import lambda_handler - -def create_test_event(url: str, body: str) -> dict: - """테스트용 event 객체 생성""" - return { - 'queryStringParameters': { - 'url': url - }, - 'body': body, - } - - -def run_test(): - """Lambda 함수 로컬 테스트 실행""" - - # 테스트 데이터 - test_url = "https://example.com/terms" - test_body = """ - - -

서비스 약관

-

이용자는 본 약관에 동의함으로써 당 서비스를 이용할 수 있습니다.

-

당 회사는 이용자의 개인정보를 보호하기 위해 최선을 다합니다.

-

서비스 이용 중 발생하는 문제에 대해 당 회사는 책임을 지지 않습니다.

- - - """ - - # Event와 Context 생성 - event = create_test_event(test_url, test_body) - context = None - - print("=" * 60) - print("lambda_function 로컬 테스트 실행") - print("=" * 60) - - print("요청 데이터:") - print("-" * 60) - print(f"URL: {event['queryStringParameters']['url']}") - print(f"Body 크기: {len(test_body)} bytes") - print() - - try: - print("lambda_handler 실행 중...") - print() - response = lambda_handler(event, context) - - print("응답 데이터:") - print("-" * 60) - print(f"Status Code: {response.get('statusCode')}") - print() - - print("Body:") - print(response.get('body')) - - print() - print("=" * 60) - - except Exception as e: - print() - print(f"에러: {type(e).__name__}") - print(f" {str(e)}") - print() - import traceback - traceback.print_exc() - - -if __name__ == '__main__': - run_test() From 8beaa9eaed60deb2be7a4f5c5451507cc40e2271 Mon Sep 17 00:00:00 2001 From: Hyeongjun Ham Date: Tue, 18 Nov 2025 20:01:07 +0900 Subject: [PATCH 02/12] =?UTF-8?q?chore:=20=EB=A1=9C=EC=BB=AC=20=ED=99=98?= =?UTF-8?q?=EA=B2=BD=EC=97=90=EC=84=9C=EC=9D=98=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EB=A5=BC=20=EC=9C=84=ED=95=9C=20localstack=20?= =?UTF-8?q?=EB=B0=8F=20awscli=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 8f97f3e..85e9a62 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,4 @@ boto3 -markdownify \ No newline at end of file +markdownify +localstack +awscli-local[ver1] \ No newline at end of file From b39a452067f3d8290c82b6f272e0e0a3f776b356 Mon Sep 17 00:00:00 2001 From: Hyeongjun Ham Date: Thu, 20 Nov 2025 13:34:55 +0900 Subject: [PATCH 03/12] =?UTF-8?q?chore:=20gemini=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20google-genai=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80=20bedrock=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=A0=84=ED=99=98=ED=95=98=EB=A9=B0=20gemini?= =?UTF-8?q?=EB=A5=BC=20=EC=A0=9C=EA=B1=B0=ED=96=88=EC=9C=BC=EB=82=98,=20?= =?UTF-8?q?=EB=A1=9C=EC=BB=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=ED=99=98?= =?UTF-8?q?=EA=B2=BD=EC=97=90=EC=84=9C=EB=8A=94=20key=20=EB=B0=9C=EA=B8=89?= =?UTF-8?q?=EC=9D=B4=20=EB=B6=88=EA=B0=80=EB=8A=A5=ED=95=B4=20bedrock=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=EC=9D=B4=20=EC=96=B4=EB=A0=A4=EC=9B=8C=20?= =?UTF-8?q?=EB=A1=9C=EC=BB=AC=20=ED=99=98=EA=B2=BD=EC=97=90=EC=84=9C?= =?UTF-8?q?=EB=A7=8C=ED=81=BC=EC=9D=80=20gemini=EB=A1=9C=20=EB=8C=80?= =?UTF-8?q?=EC=B2=B4=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements.txt b/requirements.txt index 85e9a62..d403cc1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ boto3 +google-genai markdownify localstack awscli-local[ver1] \ No newline at end of file From 5b79977076061c4f59ef6466fc25a7627dea56e2 Mon Sep 17 00:00:00 2001 From: Hyeongjun Ham Date: Thu, 20 Nov 2025 13:36:25 +0900 Subject: [PATCH 04/12] =?UTF-8?q?feat:=20gemini=EC=99=80=20bedrock?= =?UTF-8?q?=EC=9D=84=20=EC=9E=90=EB=8F=99=EC=9C=BC=EB=A1=9C=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=ED=95=98=EB=8A=94=20LLMClient=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=B6=94=EA=B0=80=20LLM=5FPROVIDER=20=ED=99=98?= =?UTF-8?q?=EA=B2=BD=20=EB=B3=80=EC=88=98=EC=9D=98=20=EA=B0=92=EC=9D=B4=20?= =?UTF-8?q?GEMINI=EC=9D=B4=EB=A9=B4=20gemini=EB=A5=BC,=20=EC=95=84?= =?UTF-8?q?=EB=8B=8C=20=EA=B2=BD=EC=9A=B0=20bedrock=EC=97=90=EC=84=9C=20cl?= =?UTF-8?q?aude=EB=A5=BC=20=ED=98=B8=EC=B6=9C=ED=95=A9=EB=8B=88=EB=8B=A4.?= =?UTF-8?q?=20claude=EC=9D=98=20=EA=B2=BD=EC=9A=B0=20=EA=B8=B0=EC=A1=B4=20?= =?UTF-8?q?sonnet=204.5=EA=B0=80=20=EC=86=8D=EB=8F=84=EA=B0=80=20=EB=8B=A4?= =?UTF-8?q?=EC=86=8C=20=EB=8A=90=EB=A0=A4=203.5=20haiku=EB=A1=9C=20?= =?UTF-8?q?=EB=AA=A8=EB=8D=B8=EC=9D=84=20=EB=B3=80=EA=B2=BD=ED=95=98?= =?UTF-8?q?=EC=98=80=EC=8A=B5=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/llm_client.py | 70 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 src/llm_client.py diff --git a/src/llm_client.py b/src/llm_client.py new file mode 100644 index 0000000..0fbe7c8 --- /dev/null +++ b/src/llm_client.py @@ -0,0 +1,70 @@ + +# 로컬 테스트 환경에서는 gemini 사용 +# AWS Lambda 환경에서는 Bedrock의 Claude 사용 + +# temperature, top_p는 기본값 temperature 0.2, top_p 0.9로 사용 +# 환각 억제 목적 + +import os +from google import genai +from google.genai import types +import boto3 + +class LLMClient: + + # 환경에 따라 LLM 모델 선정 및 클라이언트 초기화 + def __init__(self, temperature: float = 0.2, top_p: float = 0.9): + + self.temperature = temperature + self.top_p = top_p + + self.provider = os.getenv("LLM_PROVIDER") + if (self.provider == "GEMINI"): + # 로컬 테스트 환경 - gemini + self.client = genai.Client() + else: + # AWS Lambda 환경 - Bedrock Claude + self.client = boto3.client( + service_name="bedrock-runtime", + region_name="us-west-2" + ) + + # 응답 생성 + # gemini와 bedrock claude 분기 처리 + def generate_response(self, system_instruction: str, message: str) -> str: + + if (self.provider == "GEMINI"): + return self._generate_response_gemini(system_instruction, message) + else: + return self._generate_response_bedrock_claude(system_instruction, message) + + # gemini로부터 응답 생성 + def _generate_response_gemini(self, system_instruction: str, message: str) -> str: + + response = self.client.models.generate_content( + model="gemini-2.5-flash-lite", + config=types.GenerateContentConfig( + temperature=self.temperature, + top_p=self.top_p, + system_instruction=system_instruction + ), + contents=message + ) + + return response.text + + # bedrock Claude로부터 응답 생성 + # claude 모델은 3.5 haiku 사용. 테스트에 걸리는 시간 줄이기 위함 + def _generate_response_bedrock_claude(self, system_instruction: str, message: str) -> str: + + response = self.client.converse( + modelId="us.anthropic.claude-3-5-haiku-20241022-v1:0", + inferenceConfig={ + "temperature": self.temperature, + "topP": self.top_p + }, + system=[{"text": system_instruction}], + messages=[{"role": "user", "content": [{"text": message}]}] + ) + + return response['output']['message']['content'][0]['text'] From 66fe7d7e78daf037c43c9b4ab28ce33f3f47a685 Mon Sep 17 00:00:00 2001 From: Hyeongjun Ham Date: Thu, 20 Nov 2025 13:42:23 +0900 Subject: [PATCH 05/12] =?UTF-8?q?refactor:=20=EC=9A=94=EC=95=BD=20?= =?UTF-8?q?=EB=B0=8F=20=ED=8F=89=EA=B0=80=20=EA=B3=BC=EC=A0=95=EC=97=90?= =?UTF-8?q?=EC=84=9C=20LLMClient=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95=20=EC=9D=B4=EC=A0=9C=20?= =?UTF-8?q?tos=5Fsummarize=EC=99=80=20tos=5Fevaluate=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=EA=B0=80=20=EC=A7=81=EC=A0=91=20bedrock=EC=9D=84=20?= =?UTF-8?q?=ED=98=B8=EC=B6=9C=ED=95=98=EC=A7=80=20=EC=95=8A=EA=B3=A0=20LLM?= =?UTF-8?q?Client=EB=A5=BC=20=ED=86=B5=ED=95=B4=20=EA=B0=84=EC=A0=91?= =?UTF-8?q?=EC=A0=81=EC=9C=BC=EB=A1=9C=20=EB=AA=A8=EB=8D=B8=EC=9D=84=20?= =?UTF-8?q?=ED=98=B8=EC=B6=9C=ED=95=A9=EB=8B=88=EB=8B=A4.=20client?= =?UTF-8?q?=EB=A5=BC=20=EA=B0=81=20=ED=95=A8=EC=88=98=EB=B3=84=EB=A1=9C=20?= =?UTF-8?q?=EC=B4=88=EA=B8=B0=ED=99=94=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EA=B3=A0,=20lambda=5Fhandler=EC=97=90=EC=84=9C=20=EB=A7=8C?= =?UTF-8?q?=EB=93=A0=20client=EB=A5=BC=20=EB=B0=9B=EC=95=84=EC=84=9C=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=A9=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/tos_evaluate.py | 33 ++++++++------------------------- src/tos_summarize.py | 29 ++++++----------------------- 2 files changed, 14 insertions(+), 48 deletions(-) diff --git a/src/tos_evaluate.py b/src/tos_evaluate.py index 054eb2f..0fe45cf 100644 --- a/src/tos_evaluate.py +++ b/src/tos_evaluate.py @@ -1,8 +1,8 @@ import json -import boto3 +from llm_client import LLMClient -def tos_evaluate(summarized_tos): - system_instruction=[{"text": """ +def tos_evaluate(summarized_tos, client: LLMClient) -> dict: + system_instruction=""" 당신은 전문적인 약관 분석 AI입니다. 주어진 약관 내용 및 각 조항을 평가합니다. 주어진 약관은 주요 조항을 위주로 요약된 내용입니다. JSON 양식으로, 다음의 key값을 사용합니다. @@ -39,33 +39,16 @@ def tos_evaluate(summarized_tos): } ] } -"""}] - 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 = client.generate_response(system_instruction, summarized_tos) print("TOS Evaluation Response:") print(response) - text = response['output']['message']['content'][0]['text'] - start = text.find('{') - end = text.rfind('}') + 1 - json_text = text[start:end] + start = response.find('{') + end = response.rfind('}') + 1 + json_text = response[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 8263f67..d013d58 100644 --- a/src/tos_summarize.py +++ b/src/tos_summarize.py @@ -1,32 +1,15 @@ -import boto3 +from llm_client import LLMClient -def tos_summarize(tos_content): - system_instruction=[{"text": """ +def tos_summarize(tos_content, client: LLMClient) -> str: + system_instruction=""" 당신은 약관 분석 전문가입니다. 주어진 텍스트에서 주요 약관 내용을 요약합니다. 한국어로 응답합니다. -"""}] - - 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": tos_content} - ] - }] - - response = client.converse( - modelId=model_id, - system=system_instruction, - messages=messages, - ) + response = client.generate_response(system_instruction, tos_content) print("TOS Summarization Response:") print(response) - return response['output']['message']['content'][0]['text'] + return response From 2c50da990716e3a167cebb536b858ec1b1abe13f Mon Sep 17 00:00:00 2001 From: Hyeongjun Ham Date: Thu, 20 Nov 2025 13:43:54 +0900 Subject: [PATCH 06/12] =?UTF-8?q?refactor:=20LLMClient=20=EC=9D=B8?= =?UTF-8?q?=EC=8A=A4=ED=84=B4=EC=8A=A4=EB=A5=BC=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=ED=95=98=EC=97=AC=20tos=5Fsummarize=20=EB=B0=8F=20tos=5Fevalua?= =?UTF-8?q?te=EC=97=90=20=EC=A0=84=EB=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lambda_function.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lambda_function.py b/src/lambda_function.py index bbaec90..4638949 100644 --- a/src/lambda_function.py +++ b/src/lambda_function.py @@ -3,6 +3,7 @@ from tos_summarize import tos_summarize from tos_evaluate import tos_evaluate +from llm_client import LLMClient def lambda_handler(event, context): # url이 없거나 빈 문자열인 경우 @@ -40,11 +41,13 @@ def lambda_handler(event, context): # TODO: 기존 URL 기반 캐싱 로직 구현 + client = LLMClient() + # tos_content 문자열에서 중요 조항 위주로 약관 요약 - summarized_tos = tos_summarize(tos_content) + summarized_tos = tos_summarize(tos_content, client) # 약관 조항에 대해 분석 수행 - evaluation_result = tos_evaluate(summarized_tos) + evaluation_result = tos_evaluate(summarized_tos, client) return { 'statusCode': 200, From 54ae58e5bdcc7baf282774c7089a1215b2cee434 Mon Sep 17 00:00:00 2001 From: Hyeongjun Ham Date: Thu, 20 Nov 2025 15:55:31 +0900 Subject: [PATCH 07/12] =?UTF-8?q?chore:=20=EC=9E=98=EB=AA=BB=EB=90=9C=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A0=9C=EA=B1=B0=20localstack,?= =?UTF-8?q?=20awscli-local=EC=9D=80=20=EC=8B=A4=ED=96=89=EC=9A=A9=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=84=A4=EC=B9=98=ED=95=98=EB=8A=94=20=EA=B2=83?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20=ED=94=84=EB=A1=9C=EC=A0=9D=ED=8A=B8?= =?UTF-8?q?=EC=97=90=20=ED=8F=AC=ED=95=A8=EB=90=98=EC=96=B4=EC=95=BC=20?= =?UTF-8?q?=ED=95=A0=20=EB=AA=A8=EB=93=88=EC=9D=B4=20=EC=95=84=EB=8B=99?= =?UTF-8?q?=EB=8B=88=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- requirements.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index d403cc1..6cf392f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,3 @@ boto3 google-genai -markdownify -localstack -awscli-local[ver1] \ No newline at end of file +markdownify \ No newline at end of file From f809b302b854120a6018919f5c3ddaddc2f0a4a9 Mon Sep 17 00:00:00 2001 From: Hyeongjun Ham Date: Fri, 21 Nov 2025 15:39:06 +0900 Subject: [PATCH 08/12] =?UTF-8?q?chore:=20=EB=A1=9C=EC=BB=AC=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EC=9A=A9=20=EC=9E=84=EC=8B=9C=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=EC=9D=84=20git=EC=9C=BC=EB=A1=9C=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8F=84=EB=A1=9D=20gitignore=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=EC=97=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f462c4d..12e6ee1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ /venv/ -src/__pycache__/ \ No newline at end of file +src/__pycache__/ +build/ +test-package.zip +output.json \ No newline at end of file From c4815be811f761fb6279c4c67ccde59f43cb4c02 Mon Sep 17 00:00:00 2001 From: Hyeongjun Ham Date: Fri, 21 Nov 2025 16:01:54 +0900 Subject: [PATCH 09/12] =?UTF-8?q?docs:=20README.md=EC=97=90=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EA=B4=80=EB=A0=A8=20=EB=82=B4=EC=9A=A9=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 56 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index d2aed78..e0836e4 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,56 @@ # TermLens_BE 약관 요약과 중요 조항에 대한 평가를 제공합니다. - # 아키텍처 AWS Lambda - +AWS Bedrock # Getting Started -## 개발환경 구축 -bash를 기준으로 작성됨 - +## 테스트 +LocalStack의 실행을 위해 docker 설치가 필요합니다. +### LocalStack 설치 ```bash -sudo apt install python3.12-venv -python3 -m venv venv # 가상환경 생성 -source venv/bin/activate # 가상환경 사용 +# pipx 설치 +sudo apt update +sudo apt install pipx +# 잘 설치되었는지 확인 +pipx --version + +# LocalStack, awslocal 설치 +pipx install localstack --include-deps +pipx install awscli-local[ver1] --include-deps +source ~/.bashrc +# 잘 설치되었는지 확인 +localstack --version +awslocal --version ``` +wsl 환경에서 `pip install` 명령을 전역으로 쓸 수 없어 pipx를 사용합니다. +### 로컬 테스트 +docker가 실행된 상태에서 `localstack start` 명령으로 LocalStack을 구동합니다. 이후 터미널에 `Ready`가 나타나면 다른 터미널 창을 열고, 프로젝트 디렉토리에서 아래 명령을 수행합니다. +```bash +pip install -r requirements.txt -t build/ --upgrade +cp src/*.py build/ +cd build +zip -r ../test-package.zip . +cd .. -이후부터 작업 시 `source venv/bin/activate` 명령으로 가상환경을 실행한 후 작업 -- `(venv) 사용자명@컴퓨터명:~/.../TermLens_BE` 처럼 앞에 `(venv)`가 붙는지 확인 +# LoaclStack에 Lambda 함수 생성 +awslocal lambda create-function \ + --function-name analyzeTermsOfServices \ + --runtime python3.12 \ + --timeout 120 \ + --zip-file fileb://test-package.zip \ + --handler lambda_function.lambda_handler \ + --role arn:aws:iam::000000000000:role/lambda-role \ + --environment Variables="{GEMINI_API_KEY=여기에_KEY값을_넣어주세요,LLM_PROVIDER=GEMINI}" +# LocalStack에서 람다 함수 호출 +awslocal lambda invoke --function-name analyzeTermsOfServices \ + --payload '{"queryStringParameters": {"url" : "www.example.com"}, "body" : "약관 텍스트" }' output.json +``` +이후 `output.json` 파일에서 응답을 확인할 수 있습니다. +### AWS 환경에서 테스트 +로컬에서는 작동만을 확인하고, 답변 품질에 대한 테스트는 AWS Lambda에, 테스트용 함수에 배포하여 수행합니다. ## 컨벤션 ### 커밋 메시지 커밋 메시지의 작성법은 [컨벤셔널 커밋](https://www.conventionalcommits.org/ko/v1.0.0/)을 따릅니다. `feat: `, `fix: `, `test: ` 등의 접두사 뒤에 설명을 덧붙이는 방식입니다. 한국어로 작성합니다. - ### 브랜칭 전략 [깃허브 플로우](https://docs.github.com/ko/get-started/using-github/github-flow)와 유사하게, 개별 작업마다 연관된 새로운 브랜치를 생성하고, 해당 브랜치에서 작업 후 main 브랜치에 병합하는 방식으로 개발을 진행합니다. 이때 브랜치의 이름은 `작업 종류/이슈번호-짧은-설명` 으로 합니다. - -# 테스트 -로컬에서 `lambda_handler()` 메서드를 테스트해야하는 경우 `test_local.py`를 통해 실행 From da7030987c98e3b3fe2384aa49aaae4f63a87d4c Mon Sep 17 00:00:00 2001 From: Hyeongjun Ham <94438522+hjham0856@users.noreply.github.com> Date: Fri, 21 Nov 2025 16:42:02 +0900 Subject: [PATCH 10/12] =?UTF-8?q?docs:=20README=EC=97=90=20LoaclStack?= =?UTF-8?q?=EC=9D=98=20=EB=9E=8C=EB=8B=A4=20=ED=95=A8=EC=88=98=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=EC=97=90=20=EB=8C=80=ED=95=9C=20?= =?UTF-8?q?=EB=82=B4=EC=9A=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index e0836e4..2e22e62 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,11 @@ # TermLens_BE 약관 요약과 중요 조항에 대한 평가를 제공합니다. # 아키텍처 -AWS Lambda -AWS Bedrock -# Getting Started -## 테스트 +- AWS Lambda +- AWS Bedrock +# 테스트 LocalStack의 실행을 위해 docker 설치가 필요합니다. -### LocalStack 설치 +## LocalStack 설치 ```bash # pipx 설치 sudo apt update @@ -23,16 +22,20 @@ localstack --version awslocal --version ``` wsl 환경에서 `pip install` 명령을 전역으로 쓸 수 없어 pipx를 사용합니다. -### 로컬 테스트 -docker가 실행된 상태에서 `localstack start` 명령으로 LocalStack을 구동합니다. 이후 터미널에 `Ready`가 나타나면 다른 터미널 창을 열고, 프로젝트 디렉토리에서 아래 명령을 수행합니다. +## 로컬 테스트 +**docker가 실행된 상태에서** `localstack start` 명령으로 LocalStack을 구동합니다. 이후 터미널에 `Ready`가 나타나면 다른 터미널 창을 열고, 프로젝트 디렉토리에서 아래 작업을 수행합니다. + +우선, LocalStack에 업로드할 zip파일을 생성합니다. ```bash pip install -r requirements.txt -t build/ --upgrade cp src/*.py build/ cd build zip -r ../test-package.zip . cd .. +``` -# LoaclStack에 Lambda 함수 생성 +그 다음 아래의 명령을 통해 람다 함수를 생성합니다. +```bash awslocal lambda create-function \ --function-name analyzeTermsOfServices \ --runtime python3.12 \ @@ -41,16 +44,25 @@ awslocal lambda create-function \ --handler lambda_function.lambda_handler \ --role arn:aws:iam::000000000000:role/lambda-role \ --environment Variables="{GEMINI_API_KEY=여기에_KEY값을_넣어주세요,LLM_PROVIDER=GEMINI}" +``` -# LocalStack에서 람다 함수 호출 +생성된 함수의 호출은 다음과 같이 할 수 있습니다. +```bash awslocal lambda invoke --function-name analyzeTermsOfServices \ --payload '{"queryStringParameters": {"url" : "www.example.com"}, "body" : "약관 텍스트" }' output.json ``` 이후 `output.json` 파일에서 응답을 확인할 수 있습니다. -### AWS 환경에서 테스트 + +함수가 생성된 상태에서 변경하기 위해서는 `update-function-code`를 사용합니다. +```bash +awslocal lambda update-function-code \ + --function-name analyzeTermsOfServices \ + --zip-file fileb://test-package.zip +``` +## AWS 환경에서 테스트 로컬에서는 작동만을 확인하고, 답변 품질에 대한 테스트는 AWS Lambda에, 테스트용 함수에 배포하여 수행합니다. -## 컨벤션 -### 커밋 메시지 +# 컨벤션 +## 커밋 메시지 커밋 메시지의 작성법은 [컨벤셔널 커밋](https://www.conventionalcommits.org/ko/v1.0.0/)을 따릅니다. `feat: `, `fix: `, `test: ` 등의 접두사 뒤에 설명을 덧붙이는 방식입니다. 한국어로 작성합니다. -### 브랜칭 전략 +## 브랜칭 전략 [깃허브 플로우](https://docs.github.com/ko/get-started/using-github/github-flow)와 유사하게, 개별 작업마다 연관된 새로운 브랜치를 생성하고, 해당 브랜치에서 작업 후 main 브랜치에 병합하는 방식으로 개발을 진행합니다. 이때 브랜치의 이름은 `작업 종류/이슈번호-짧은-설명` 으로 합니다. From f890b6d31b89293f8f4681e41c83fe8400df8254 Mon Sep 17 00:00:00 2001 From: Hyeongjun Ham <94438522+hjham0856@users.noreply.github.com> Date: Fri, 21 Nov 2025 16:48:39 +0900 Subject: [PATCH 11/12] =?UTF-8?q?refactor:=20tos=5Fcontent=EC=97=90=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=ED=9E=8C=ED=8A=B8=20`str`=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/tos_summarize.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tos_summarize.py b/src/tos_summarize.py index d013d58..a14859b 100644 --- a/src/tos_summarize.py +++ b/src/tos_summarize.py @@ -1,6 +1,6 @@ from llm_client import LLMClient -def tos_summarize(tos_content, client: LLMClient) -> str: +def tos_summarize(tos_content: str, client: LLMClient) -> str: system_instruction=""" 당신은 약관 분석 전문가입니다. 주어진 텍스트에서 주요 약관 내용을 요약합니다. From 02542abc0d1e9193d24e59a05ec4ad5ca209c94e Mon Sep 17 00:00:00 2001 From: Hyeongjun Ham <94438522+hjham0856@users.noreply.github.com> Date: Tue, 25 Nov 2025 16:01:05 +0900 Subject: [PATCH 12/12] =?UTF-8?q?docs:=20arm=20=ED=99=98=EA=B2=BD=20?= =?UTF-8?q?=ED=98=B8=ED=99=98=EC=84=B1=20=EB=AA=85=EB=A0=B9=EC=96=B4=20?= =?UTF-8?q?=EC=98=88=EC=8B=9C=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20zsh=20?= =?UTF-8?q?=ED=98=B8=ED=99=98=EC=84=B1=20=EA=B3=A0=EB=A0=A4=20=EB=AA=85?= =?UTF-8?q?=EB=A0=B9=EC=96=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arm환경에서 pip install로 설치하는 경우 arm용 바이너리가 설치되어, aws lambda와 동일하게 amd64 기반으로 작동하는 localstack에서 인식하지 못해 docker를 사용하여 amd64 환경을 현재 디렉토리에서 시뮬레이션하여 설치하도록 하는 명령어를 예시에 추가했습니다. zsh 호환성을 고려하여 람다함수 생성 시 환경변수 설정에 큰따옴표 대신 작은따옴표를 사용합니다. --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2e22e62..35f10f1 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ source ~/.bashrc localstack --version awslocal --version ``` -wsl 환경에서 `pip install` 명령을 전역으로 쓸 수 없어 pipx를 사용합니다. +wsl 환경에서 `pip install` 명령을 전역으로 쓸 수 없어 pipx를 사용합니다. 전역으로 localstack 및 awslocal을 설치하여 사용 가능한 경우 pipx의 설치가 필요하지 않습니다. ## 로컬 테스트 **docker가 실행된 상태에서** `localstack start` 명령으로 LocalStack을 구동합니다. 이후 터미널에 `Ready`가 나타나면 다른 터미널 창을 열고, 프로젝트 디렉토리에서 아래 작업을 수행합니다. @@ -34,6 +34,11 @@ zip -r ../test-package.zip . cd .. ``` +ARM 환경에서는 `pip install...` 명령 대신 아래의 명령을 사용해주세요. LocalStack 및 AWS Lambda 환경에서는 amd64(x86-64)을 기반으로 작동하나, ARM 기반 기기에서 해당 명령으로 설치하게 되면 ARM용 바이너리를 받아와 LocalStack에서 실행하지 못합니다. 아래 명령으로 생성된 `build/` 디렉토리 및 `test-package.zip` 파일은 삭제 시 root 권한이 필요합니다. +```bash +docker run --platform linux/amd64 --rm -v "$(pwd)":/var/task --entrypoint "" public.ecr.aws/lambda/python:3.12 /bin/sh -c "pip install -r requirements.txt -t build/ --upgrade && cp src/*.py build/ && cd build && dnf install -y zip && zip -r ../test-package.zip . && cd .." +``` + 그 다음 아래의 명령을 통해 람다 함수를 생성합니다. ```bash awslocal lambda create-function \ @@ -43,7 +48,7 @@ awslocal lambda create-function \ --zip-file fileb://test-package.zip \ --handler lambda_function.lambda_handler \ --role arn:aws:iam::000000000000:role/lambda-role \ - --environment Variables="{GEMINI_API_KEY=여기에_KEY값을_넣어주세요,LLM_PROVIDER=GEMINI}" + --environment Variables='{GEMINI_API_KEY=여기에_KEY값을_넣어주세요,LLM_PROVIDER=GEMINI}' ``` 생성된 함수의 호출은 다음과 같이 할 수 있습니다.