File size: 6,627 Bytes
fe6855c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
import requests
import json
from app.models.request_type_model import RequestTypeModel
from config import settings

MODEL_NAME = settings.settings.MODEL_NAME  # e.g., "tiiuae/falcon-7b-instruct"
HF_TOKEN = settings.settings.HUGGINGFACE_API_TOKEN  # Hugging Face token

if not HF_TOKEN or HF_TOKEN == "YOUR_HUGGINGFACE_API_TOKEN":
    print("Error: Hugging Face API token is missing. Please ensure you have a valid config.")
    exit()

API_URL = f"https://router.huggingface.co/hf-inference/models/{MODEL_NAME}/v1/chat/completions"
HEADERS = {"Authorization": f"Bearer {HF_TOKEN}"}

PROMPT_OBJECTIVE_CLASSIFICATION_RULES = """
### Task: Email Classification 

#### **Objective:** 
Analyze the given email and classify it into the most appropriate **Request Type** and **Sub Request Type** based on its primary intent.

#### **Instructions:**
- Identify the key intent of the email.
- Match it with one of the **Request Types** from the predefined categories.
- Select the most relevant **Sub Request Type** for the classification.
- If no exact match is found, choose the closest category.

Only return a JSON object with the classification results.
"""
PROMPT_CATEGORIES = f"""
#### **Classification Categories & Definitions:** 
{json.dumps(RequestTypeModel.requests_datasets, indent=2)}
"""

PROMPT_OUTPUT_FORMAT = """
#### **Output Format:** 
Return the classification result in **pure JSON format** (without extra text or markdown).

Example Output:
{
  "request_type": "Commitment Change",
  "sub_request_type": "Increase",
  "confidence_score": 0.95,
  "email_subject": "Request for Credit Line Increase"
}
"""
PROMPT_TEMPLATE = """ 
### Task: Email Classification  
#### **Objective:**  
Analyze the given email and classify it into the most appropriate **Request Type** and **Sub Request Type** based on its primary intent. Ensure the response is strictly in JSON format with the specified fields.  

#### **Classification Categories:**  
Each email must be categorized under one of the following **Request Types** and corresponding **Sub Request Types**:  

| Request Type              | Sub Request Type                                      |  
|---------------------------|------------------------------------------------------|  
| Adjustment                | N/A                                                  |  
| AU Transfer               | N/A                                                  |  
| Closing Notice            | Reallocation Fees, Amendment Fees, Reallocation Principal |  
| Commitment Change         | Cashless Roll, Decrease, Increase                    |  
| Fee Payment               | Ongoing Fee, Letter of Credit Fee                    |  
| Money Movement - Inbound  | Principal, Interest, Principal + Interest, Principal + Interest + Fee |  
| Money Movement - Outbound | Timebound, Foreign Currency                          |  

#### **Output Format:**  
Return the classification result strictly in **JSON format** with the following fields:  
```json
{
  "request_type": "Request Type",
  "sub_request_type": "Sub Request Type",
  "confidence_score": Confidence Score (between 0 and 1),
  "email_subject": "Email Subject"
}
### **🔹 Email for Classification:**  
```email
{{
QQA Bank, N.A.
Loan Agency Services


 Date: 05-Feb-2025
    TO: ABC BANK, NATIONAL ASSOCIATION
ATTN: RAMAKRISHNA KUNCHALA
    Fax: 877-606-9426
      Re: ABB MID-ATLANTIC LLC $171.3MM 11-4-2022, TERM LOAN A-2

Description: Facility Lender Share Adjustment

BORROWER: ABB MID-ATLANTIC LIC
DEAL NAME: ABB MID-ATLANTIC LIC $171. 3MM 11-4-2022

Effective 04-Feb-2025, the Lender Shares of facility TERM LOAN A-2 have been adjusted.
Your share of the commitment was USD 5,518,249.19. It has been Increased to USD 5,542,963.55.

For: ABC BANK, NA

Reference: ABIB MID-ATLANTIC LIC $171.3MM 11-4-2022,

If you have any questions, please call the undersigned.
********************************************COMMENT***************************************
PLEASE FUND YOUR SHARE OF $24,714.36


Bank Name: QQA Bank NA
ABA   #   011500120
Account #: 0026693011
Account Name: LIQ CLO Operating Account
Ref: ABTB Mid-Atlantic LLC

********************************************************************************************
Regards,

SCOTT WALLACE
Telephone #:
Fax #:

QQA Commercial Banking is a brand name of QQA Bank, N.A. Member FDIC

}}

"""

def extract_json_from_response(response_text):
    """Extract JSON response from model output."""
    try:
        json_start = response_text.find('{')
        json_end = response_text.rfind('}') + 1
        json_string = response_text[json_start:json_end]
        return json.loads(json_string)
    except (ValueError, json.JSONDecodeError):
        return {"error": "Could not extract JSON from model output"}

def send_to_huggingface_api(prompt):
    """Send the prompt to Hugging Face API and get the response."""
    try:
        payload = {
            "messages": [
                {"role": "system", "content": PROMPT_OBJECTIVE_CLASSIFICATION_RULES + PROMPT_CATEGORIES + PROMPT_OUTPUT_FORMAT},
                {"role": "user", "content": prompt}
            ],
            "max_tokens": 700,
            "temperature": 0.2,
            "top_p": 0.8,
            "model": MODEL_NAME
        }
        response = requests.post(API_URL, headers=HEADERS, json=payload)
        response.raise_for_status()
        result = response.json()
        
        if "choices" in result and result["choices"]:
            return result["choices"][0]["message"]["content"]
        return {"error": "Unexpected API response format"}
    
    except requests.exceptions.RequestException as e:
        return {"error": f"API request failed: {e}"}


def classify_email_with_prompt(email_text):


    final_response = send_to_huggingface_api(email_text)
    
    try:
        classification = extract_json_from_response(final_response)
        request_type = classification.get("request_type", "").strip()
        if request_type:
            valid_sub_types = RequestTypeModel.get_sub_types(request_type)
            sub_request_type = classification.get("sub_request_type", "").strip()
            if sub_request_type not in valid_sub_types:
                classification["sub_request_type"] = valid_sub_types[0]
        return classification
    except Exception as e:
        return {"error": str(e)}

# Example Usage
if __name__ == "__main__":
    email_text = """
    QQA Bank, N.A.
    Loan Agency Services
    Date: 05-Feb-2025
    Description: Facility Lender Share Adjustment
    """
    classification = classify_email_with_prompt(email_text)
    print(classification)