-
Notifications
You must be signed in to change notification settings - Fork 0
[FEATURE] CV 분석 결과를 바탕으로 OpenAI에 설명 요청 #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bb4eb0a
38eaf14
db90904
e885d49
022e9f3
0541d27
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| from app.core.config import settings | ||
| from openai import OpenAI | ||
| import json | ||
|
|
||
| client = OpenAI(api_key=settings.OPENAI_KEY) | ||
|
|
||
| class PregnancySafetyChecker: | ||
| def __init__(self, client: OpenAI): | ||
| self.client = client | ||
|
|
||
| """ | ||
| - isSafe: 안전하면 1, 안전하지 않으면 0 | ||
| - description: 복용 가능 여부 설명 | ||
| """ | ||
| def ask_chatgpt_about_pregnancy_safety(self, pill_name: str) -> tuple[str, int]: | ||
| prompt = f""" | ||
| 약 이름: {pill_name} | ||
| 질문: 이 약은 임산부가 복용해도 안전한가요? 복용 가능 여부와 주의사항을 알려주세요. | ||
| description 안에는 문장마다 \\n 을 적용하세요. | ||
| 결과를 JSON 형식으로 정확히 반환하세요. 설명이나 다른 텍스트를 절대 덧붙이지 마세요. | ||
| 스키마: | ||
| {{ | ||
| "description": "복용 가능 여부 및 주의사항에 대한 설명", | ||
| "isSafe": 1 또는 0 | ||
| }} | ||
| """ | ||
|
Comment on lines
+16
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| response = self.client.chat.completions.create( | ||
| model="gpt-4o-mini", | ||
| messages=[{"role": "user", "content": prompt}], | ||
| temperature=0, | ||
| max_tokens=600, | ||
| response_format={"type": "json_object"} | ||
| ) | ||
| print("GPT Asking 성공...") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| raw = response.choices[0].message.content.strip() | ||
|
|
||
| try: | ||
| data = json.loads(raw) | ||
| except json.JSONDecodeError: | ||
| start = raw.find("{") | ||
| end = raw.rfind("}") | ||
| if start != -1 and end != -1 and start < end: | ||
| data = json.loads(raw[start:end+1]) | ||
| else: | ||
| # 디버깅 | ||
| preview = raw[:200].replace("\n", "\\n") | ||
| raise ValueError(f"응답이 유효한 JSON이 아닙니다. preview='{preview}'") | ||
|
|
||
| description = data.get("description") | ||
| isSafe = data.get("isSafe") | ||
|
|
||
| if isinstance(isSafe, bool): | ||
| isSafe = 1 if isSafe else 0 | ||
| elif isinstance(isSafe, str): | ||
| isSafe = 1 if isSafe.strip() in {"1", "true", "True"} else 0 | ||
| elif not isinstance(isSafe, int): | ||
| isSafe = 0 | ||
|
Comment on lines
+53
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| if not isinstance(description, str): | ||
| description = "" # 안전장치 | ||
|
|
||
| return description, int(isSafe) | ||
|
|
||
|
|
||
| checker = PregnancySafetyChecker(client) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,27 +1,15 @@ | ||
|
|
||
| import boto3 | ||
| from botocore.config import Config as BotoConfig | ||
| import requests | ||
| from io import BytesIO | ||
|
|
||
| from app.core.config import settings | ||
|
|
||
| class S3Service: | ||
| def __init__(self): | ||
| self.client = boto3.client( | ||
| "s3", | ||
| region_name=settings.S3_REGION, | ||
| config=BotoConfig( | ||
| retries={"max_attempts": 5, "mode": "standard"}, | ||
| read_timeout=30, | ||
| connect_timeout=5, | ||
| ), | ||
| ) | ||
| pass | ||
|
|
||
| def download_file_from_presigned_url(self, presigned_url: str) -> BytesIO: | ||
| response = requests.get(presigned_url) | ||
| response.raise_for_status() | ||
|
|
||
| return BytesIO(response.content) # response 안의 content Stream으로 처리 | ||
| # response의 content를 BytesIO로 감싸 반환 | ||
| return BytesIO(response.content) | ||
|
|
||
| s3_service = S3Service() |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |||||
|
|
||||||
| from app.core.config import settings | ||||||
| from app.schemas.job import ImageJob, JobResult | ||||||
| from app.services.openai_service import checker | ||||||
| from app.services.predictor_service import predictor_service | ||||||
| from app.services.s3_service import s3_service | ||||||
|
|
||||||
|
|
@@ -27,11 +28,8 @@ async def process_image_scan(job: ImageJob, redis_client: redis.Redis): | |||||
| predictor_service.predict, | ||||||
| stream_file | ||||||
| ) | ||||||
|
|
||||||
| # TODO: ChatGPT에 요청 결과 출력 | ||||||
|
|
||||||
| isSafe = 0 | ||||||
| description = "일단은 테스트입니다. 추후에 GPT 부분 추가할 예정" | ||||||
| print(f"[task] Start Asking GPT for job_id={correlationId}") | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 디버깅 및 로깅을 위해
Suggested change
|
||||||
| description, isSafe = checker.ask_chatgpt_about_pregnancy_safety(pillName) | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이미 실행 중인 이벤트 루프가 비동기적으로 동작하므로, 별도의 스레드를 두는 대신 동기 방식 처리를 선택 |
||||||
| finishedAt = datetime.utcnow().isoformat() | ||||||
|
|
||||||
| result = JobResult( | ||||||
|
|
||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현재
ask_chatgpt_about_pregnancy_safety메서드는 동기적으로 작동합니다. 이 애플리케이션은asyncio를 기반으로 하므로,openai라이브러리의AsyncOpenAI클라이언트를 사용하여 이 메서드를async로 구현하는 것이 더 자연스럽고 효율적입니다. 이렇게 하면 호출부에서asyncio.to_thread를 사용할 필요가 없어지고, 코드 전체의 비동기 일관성을 유지할 수 있습니다.