Add pydantic Object for llm response and rework decision making
This commit is contained in:
@ -7,6 +7,10 @@ from dto.requests import GameStartRequestDTO, GameDecisionRequestDTO
|
|||||||
from services.extractor import extract_profile, extract_passport, extract_description, extract_account
|
from services.extractor import extract_profile, extract_passport, extract_description, extract_account
|
||||||
from services.julius_baer_api_client import JuliusBaerApiClient
|
from services.julius_baer_api_client import JuliusBaerApiClient
|
||||||
from utils.storage.game_files_manager import store_game_round_data
|
from utils.storage.game_files_manager import store_game_round_data
|
||||||
|
from langchain_google_genai import ChatGoogleGenerativeAI
|
||||||
|
from validation.llm_validate import AssistantDecision
|
||||||
|
from langchain_core.prompts import ChatPromptTemplate
|
||||||
|
from langchain_core.output_parsers import PydanticOutputParser
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@ -71,31 +75,73 @@ class Player:
|
|||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
def make_decision(self, client_data: Dict[str, Any]) -> Literal["Accept", "Reject"]:
|
def make_decision(self, client_data: Dict[str, Any]) -> Literal["Accept", "Reject"]:
|
||||||
# Data extraction
|
# 1. Extraction des données
|
||||||
profile = extract_profile(client_data)
|
profile = extract_profile(client_data)
|
||||||
passport = extract_passport(client_data)
|
passport = extract_passport(client_data)
|
||||||
description = extract_description(client_data)
|
description = extract_description(client_data)
|
||||||
account = extract_account(client_data)
|
account = extract_account(client_data)
|
||||||
|
|
||||||
prompt_template = (
|
# 2. Création du parser
|
||||||
"You are a helpful assistant at a private bank.\n"
|
parser = PydanticOutputParser(pydantic_object=AssistantDecision)
|
||||||
"Your task is to accept or reject a new client's application for private banking.\n\n"
|
format_instructions = parser.get_format_instructions()
|
||||||
"Only reject the application if there is an inconsistency in the data provided.\n"
|
|
||||||
"Inconsistencies include:\n"
|
# 3. Prompt enrichi
|
||||||
"- Incorrect data (e.g., mismatched or invalid information)\n"
|
prompt = ChatPromptTemplate.from_template(
|
||||||
"- Incomplete data (e.g., missing required fields)\n\n"
|
"""You are a compliance analyst in a private bank.
|
||||||
"Return only JSON matching this format:\n"
|
You are given structured data extracted from four different documents of a new client application.
|
||||||
"{format_instructions}\n\n"
|
|
||||||
"Here is the extracted passport text:\n"
|
Your task is to accept or reject the client's application for private banking.
|
||||||
"{processed_text}\n\n"
|
|
||||||
"Use the extracted profile, description, and account details to check consistency."
|
Only reject the application if there is an inconsistency in the data provided.
|
||||||
|
Inconsistencies include:
|
||||||
|
- Incorrect data (e.g., mismatched or invalid information)
|
||||||
|
- Incomplete data (e.g., missing required fields)
|
||||||
|
- Implausible or suspicious details
|
||||||
|
|
||||||
|
Use the extracted profile, description, and account details to cross-check the information in the passport and other documents.
|
||||||
|
|
||||||
|
Be highly critical. Reject if there's any doubt or if anything feels wrong.
|
||||||
|
|
||||||
|
Return only JSON matching this format:
|
||||||
|
{format_instructions}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Document: Passport**
|
||||||
|
{passport}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Document: Profile**
|
||||||
|
{profile}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Document: Description**
|
||||||
|
{description}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Document: Account**
|
||||||
|
{account}"""
|
||||||
)
|
)
|
||||||
|
|
||||||
# You'd insert the format instructions and passport text here before calling the LLM
|
# 4. Chaîne LLM
|
||||||
# For example:
|
chain = prompt | ChatGoogleGenerativeAI(model="gemini-pro") | parser
|
||||||
# final_prompt = prompt_template.format(
|
|
||||||
# format_instructions=your_format_instructions,
|
|
||||||
# processed_text=passport['text']
|
|
||||||
# )
|
|
||||||
|
|
||||||
return 'Accept' # Replace me!!
|
# 5. Invocation
|
||||||
|
result: AssistantDecision = chain.invoke({
|
||||||
|
"passport": passport.json(),
|
||||||
|
"profile": profile.json(),
|
||||||
|
"description": description.json(),
|
||||||
|
"account": account.json(),
|
||||||
|
"format_instructions": format_instructions,
|
||||||
|
})
|
||||||
|
|
||||||
|
# 6. Logs et retour
|
||||||
|
if result.decision == "Reject":
|
||||||
|
log.warning(f"Client rejected. Reason: {result.reason}")
|
||||||
|
else:
|
||||||
|
log.info("Client accepted.")
|
||||||
|
|
||||||
|
return result.decision
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
# TODO
|
from pydantic import BaseModel
|
||||||
# account.reference_currency corresponds to passport.country
|
from typing import Literal, Optional
|
||||||
|
|
||||||
# account.country ~ passport.country
|
class AssistantDecision(BaseModel):
|
||||||
# account.country ~ description.nationality
|
decision: Literal["Accept", "Reject"]
|
||||||
|
reason: Optional[str] = None
|
||||||
# account.city is in account.country
|
|
Reference in New Issue
Block a user