Spaces:
Sleeping
Sleeping
Update src/daily_ra/services/llm_service.py
Browse files
src/daily_ra/services/llm_service.py
CHANGED
|
@@ -1,78 +1,78 @@
|
|
| 1 |
-
from pydantic import BaseModel
|
| 2 |
-
from typing import List
|
| 3 |
-
from openai import OpenAI
|
| 4 |
-
from dotenv import load_dotenv
|
| 5 |
-
import os, json
|
| 6 |
-
|
| 7 |
-
# .env を読み込む
|
| 8 |
-
load_dotenv()
|
| 9 |
-
|
| 10 |
-
# クライアントを初期化
|
| 11 |
-
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
|
| 12 |
-
|
| 13 |
-
# ======== Pydantic スキーマ ========
|
| 14 |
-
class DailyRAInput(BaseModel):
|
| 15 |
-
work_date: str
|
| 16 |
-
work_content: str
|
| 17 |
-
hazard_points: str
|
| 18 |
-
general_comments: str
|
| 19 |
-
risk_identification: str
|
| 20 |
-
mitigation_measures: str
|
| 21 |
-
inspection_items: str
|
| 22 |
-
|
| 23 |
-
class GeneratedRule(BaseModel):
|
| 24 |
-
object1: str
|
| 25 |
-
object2: str
|
| 26 |
-
risk: str
|
| 27 |
-
|
| 28 |
-
# ======== LLM サービス ========
|
| 29 |
-
class LLMService:
|
| 30 |
-
@staticmethod
|
| 31 |
-
def generate_prompt(data: DailyRAInput) -> str:
|
| 32 |
-
return f"""
|
| 33 |
-
以下は日次RAの作業内容です。作業者、重機、クレーンなどの対象物と
|
| 34 |
-
安全ルールを JSON 形式で返してください。出力形式は
|
| 35 |
-
[{{"object1": "対象1", "object2": "対象2", "risk": "リスク"}}] です。
|
| 36 |
-
|
| 37 |
-
作業日: {data.work_date}
|
| 38 |
-
作業内容: {data.work_content}
|
| 39 |
-
作業危険ポイント: {data.hazard_points}
|
| 40 |
-
元請コメント: {data.general_comments}
|
| 41 |
-
危険性・有害性の特定: {data.risk_identification}
|
| 42 |
-
危険性・有害性の低減策: {data.mitigation_measures}
|
| 43 |
-
点検事項: {data.inspection_items}
|
| 44 |
-
"""
|
| 45 |
-
|
| 46 |
-
@staticmethod
|
| 47 |
-
def generate_rules(data: DailyRAInput) -> List[GeneratedRule]:
|
| 48 |
-
prompt = LLMService.generate_prompt(data)
|
| 49 |
-
|
| 50 |
-
try:
|
| 51 |
-
response = client.chat.completions.create(
|
| 52 |
-
model="gpt-4o-mini",
|
| 53 |
-
messages=[
|
| 54 |
-
{"role": "system", "content": "あなたは建設現場の安全ルール生成AIです。"},
|
| 55 |
-
{"role": "user", "content": prompt},
|
| 56 |
-
],
|
| 57 |
-
temperature=0.2,
|
| 58 |
-
)
|
| 59 |
-
text = response.choices[0].message.content.strip()
|
| 60 |
-
|
| 61 |
-
# ✅ コードブロック(````json ... `````)を除去
|
| 62 |
-
if text.startswith("```"):
|
| 63 |
-
text = text.strip("`")
|
| 64 |
-
text = text.replace("json", "").strip()
|
| 65 |
-
|
| 66 |
-
# JSONとしてパース
|
| 67 |
-
rules_raw = json.loads(text)
|
| 68 |
-
return [GeneratedRule(**r) for r in rules_raw]
|
| 69 |
-
|
| 70 |
-
except json.JSONDecodeError as e:
|
| 71 |
-
print(f"⚠️ JSONデコードエラー: {e}\n出力内容: {text}")
|
| 72 |
-
return []
|
| 73 |
-
except Exception as e:
|
| 74 |
-
print(f"⚠️ LLM生成エラー: {e}")
|
| 75 |
-
return []
|
| 76 |
-
|
| 77 |
-
# シングルトンインスタンス
|
| 78 |
-
llm_service = LLMService()
|
|
|
|
| 1 |
+
from pydantic import BaseModel
|
| 2 |
+
from typing import List
|
| 3 |
+
from openai import OpenAI
|
| 4 |
+
from dotenv import load_dotenv
|
| 5 |
+
import os, json
|
| 6 |
+
|
| 7 |
+
# .env を読み込む
|
| 8 |
+
load_dotenv()
|
| 9 |
+
|
| 10 |
+
# クライアントを初期化
|
| 11 |
+
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
|
| 12 |
+
|
| 13 |
+
# ======== Pydantic スキーマ ========
|
| 14 |
+
class DailyRAInput(BaseModel):
|
| 15 |
+
work_date: str
|
| 16 |
+
work_content: str
|
| 17 |
+
hazard_points: str
|
| 18 |
+
general_comments: str
|
| 19 |
+
risk_identification: str
|
| 20 |
+
mitigation_measures: str
|
| 21 |
+
inspection_items: str
|
| 22 |
+
|
| 23 |
+
class GeneratedRule(BaseModel):
|
| 24 |
+
object1: str
|
| 25 |
+
object2: str
|
| 26 |
+
risk: str
|
| 27 |
+
|
| 28 |
+
# ======== LLM サービス ========
|
| 29 |
+
class LLMService:
|
| 30 |
+
@staticmethod
|
| 31 |
+
def generate_prompt(data: DailyRAInput) -> str:
|
| 32 |
+
return f"""
|
| 33 |
+
以下は日次RAの作業内容です。作業者、重機、クレーンなどの対象物と対象物同士の関係性を抽出し、
|
| 34 |
+
安全ルールを JSON 形式で返してください。出力形式は
|
| 35 |
+
[{{"object1": "対象1", "object2": "対象2", "risk": "リスク"}}] です。
|
| 36 |
+
|
| 37 |
+
作業日: {data.work_date}
|
| 38 |
+
作業内容: {data.work_content}
|
| 39 |
+
作業危険ポイント: {data.hazard_points}
|
| 40 |
+
元請コメント: {data.general_comments}
|
| 41 |
+
危険性・有害性の特定: {data.risk_identification}
|
| 42 |
+
危険性・有害性の低減策: {data.mitigation_measures}
|
| 43 |
+
点検事項: {data.inspection_items}
|
| 44 |
+
"""
|
| 45 |
+
|
| 46 |
+
@staticmethod
|
| 47 |
+
def generate_rules(data: DailyRAInput) -> List[GeneratedRule]:
|
| 48 |
+
prompt = LLMService.generate_prompt(data)
|
| 49 |
+
|
| 50 |
+
try:
|
| 51 |
+
response = client.chat.completions.create(
|
| 52 |
+
model="gpt-4o-mini",
|
| 53 |
+
messages=[
|
| 54 |
+
{"role": "system", "content": "あなたは建設現場の安全ルール生成AIです。"},
|
| 55 |
+
{"role": "user", "content": prompt},
|
| 56 |
+
],
|
| 57 |
+
temperature=0.2,
|
| 58 |
+
)
|
| 59 |
+
text = response.choices[0].message.content.strip()
|
| 60 |
+
|
| 61 |
+
# ✅ コードブロック(````json ... `````)を除去
|
| 62 |
+
if text.startswith("```"):
|
| 63 |
+
text = text.strip("`")
|
| 64 |
+
text = text.replace("json", "").strip()
|
| 65 |
+
|
| 66 |
+
# JSONとしてパース
|
| 67 |
+
rules_raw = json.loads(text)
|
| 68 |
+
return [GeneratedRule(**r) for r in rules_raw]
|
| 69 |
+
|
| 70 |
+
except json.JSONDecodeError as e:
|
| 71 |
+
print(f"⚠️ JSONデコードエラー: {e}\n出力内容: {text}")
|
| 72 |
+
return []
|
| 73 |
+
except Exception as e:
|
| 74 |
+
print(f"⚠️ LLM生成エラー: {e}")
|
| 75 |
+
return []
|
| 76 |
+
|
| 77 |
+
# シングルトンインスタンス
|
| 78 |
+
llm_service = LLMService()
|