File size: 3,797 Bytes
f814c93
 
cb51934
f814c93
cb51934
007c634
f814c93
cb51934
 
f814c93
32e01fc
f814c93
cb51934
007c634
 
 
f814c93
 
 
 
 
 
 
007c634
f814c93
 
cb51934
 
f814c93
 
cb51934
f814c93
 
29e5c2f
007c634
f814c93
cb51934
 
f814c93
 
 
 
 
29e5c2f
007c634
cb51934
 
f814c93
 
 
 
 
 
 
cb51934
f814c93
 
 
 
 
 
 
 
 
cb51934
f814c93
 
 
 
 
 
 
 
cb51934
f814c93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cb51934
f814c93
adf7dca
f814c93
 
 
adf7dca
f814c93
adf7dca
f814c93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# model_loader.py
import os
import torch
import gc
import json
from huggingface_hub import login
from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
from peft import PeftModel

# CONFIG - change these if your repo name differs
BASE_MODEL = "meta-llama/Llama-3.2-3B"   # or local path if you prefer
ADAPTER = "iatechaways/crm_model"            # your LoRA adapter on HF

# Get HF token from environment
HF_TOKEN = os.getenv("HF_TOKEN")

# NOTE: For ZeroGPU we LOAD on CPU and move to GPU only during inference.
def load_model_cpu():
    """
    Load base model + adapter into CPU memory (device_map='cpu' or low mem). 
    Return a dict that holds references to model and tokenizer.
    """
    # load tokenizer
    tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, use_fast=True, token=HF_TOKEN)
    if tokenizer.pad_token is None:
        tokenizer.pad_token = tokenizer.eos_token
    tokenizer.padding_side = "right"

    # load base model on CPU to minimize early GPU allocation
    base = AutoModelForCausalLM.from_pretrained(
        BASE_MODEL,
        device_map={"": "cpu"},
        torch_dtype=torch.float32,
        low_cpu_mem_usage=True,
                token=HF_TOKEN
    )

    model = PeftModel.from_pretrained(
        base,
        ADAPTER,
        device_map={"": "cpu"},
        torch_dtype=torch.float32,
        is_trainable=False,
        low_cpu_mem_usage=True,
                token=HF_TOKEN
    )

    # don't create pipeline here; we'll call generate with model directly
    return {
        "tokenizer": tokenizer,
        "model": model,
        "base_name": BASE_MODEL,
        "adapter": ADAPTER
    }

def move_model_to_gpu(info: dict):
    """Move model to GPU and set dtype to float16 for inference speed."""
    if not torch.cuda.is_available():
        return
    model = info["model"]
    # move to cuda
    model.to("cuda")
    # if tokenizer/pipeline required, we keep tokenizer on CPU
    torch.cuda.empty_cache()

def move_model_to_cpu(info: dict):
    """Move model back to CPU & free GPU memory."""
    if not torch.cuda.is_available():
        return
    model = info["model"]
    model.to("cpu")
    torch.cuda.empty_cache()
    gc.collect()

def generate_with_model(info: dict, email_text: str, mail_type: str, client_data: dict, max_new_tokens: int = 200):
    """Run text generation using the loaded model (assumes model on device)."""
    tokenizer = info["tokenizer"]
    model = info["model"]
    device = next(model.parameters()).device

    # Prepare client context
    client_context = (
        f"Client Info:\n"
        f"Name: {client_data.get('name')}\n"
        f"Policy No: {client_data.get('policy_number')}\n"
        f"Plan: {client_data.get('indiafirst_life_insurance_plan')}\n"
        f"Status: {client_data.get('status')}\n"
        f"Premium: ₹{client_data.get('premium_amt')}\n"
        f"Due Date: {client_data.get('premium_due_date')}\n\n"
    )

    prompt = f"""Email Category: {mail_type}

### Instruction:
You are an LIC customer-service assistant. Respond politely and concisely (2–5 sentences).
Do NOT invent facts that are not present in the client data. If data is missing, ask the customer to provide correct details.

{client_context}

### Input:
{email_text}

### Response:
"""

    inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=1024).to(device)
    with torch.no_grad():
        outputs = model.generate(
            **inputs,
            max_new_tokens=max_new_tokens,
            temperature=0.6,
            top_p=0.9,
            do_sample=True,
            pad_token_id=tokenizer.eos_token_id,
            repetition_penalty=1.12,
            num_beams=1
        )
    decoded = tokenizer.decode(outputs[0], skip_special_tokens=True)
    return decoded