Ephraimmm commited on
Commit
1e4bd2b
·
verified ·
1 Parent(s): 5ed39db

Create handler.py

Browse files
Files changed (1) hide show
  1. handler.py +187 -0
handler.py ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Dict, List, Any
2
+ import torch
3
+ from transformers import AutoModelForCausalLM, AutoTokenizer
4
+
5
+
6
+ class EndpointHandler:
7
+ """
8
+ Custom handler for HuggingFace Inference Endpoints
9
+ Handles Nigerian Pidgin English text generation
10
+ """
11
+
12
+ def __init__(self, path: str = ""):
13
+ """
14
+ Initialize the model and tokenizer
15
+
16
+ Args:
17
+ path: Path to the model directory (provided by HuggingFace)
18
+ """
19
+ # Load model
20
+ self.model = AutoModelForCausalLM.from_pretrained(
21
+ path,
22
+ torch_dtype=torch.float16,
23
+ device_map="auto",
24
+ trust_remote_code=True
25
+ )
26
+
27
+ # Load tokenizer
28
+ self.tokenizer = AutoTokenizer.from_pretrained(
29
+ path,
30
+ trust_remote_code=True
31
+ )
32
+
33
+ # Set default system prompt
34
+ self.default_system_prompt = (
35
+ "You are a helpful assistant that speaks Nigerian Pidgin English. "
36
+ "Respond naturally in Pidgin."
37
+ )
38
+
39
+ print("✓ Model and tokenizer loaded successfully")
40
+
41
+ def __call__(self, data: Dict[str, Any]) -> List[Dict[str, Any]]:
42
+ """
43
+ Handle inference requests
44
+
45
+ Args:
46
+ data: Dictionary containing:
47
+ - inputs (str): The user's prompt/question
48
+ - parameters (dict, optional): Generation parameters
49
+ - system_prompt (str): Custom system prompt
50
+ - max_new_tokens (int): Max tokens to generate (default: 100)
51
+ - temperature (float): Sampling temperature (default: 0.7)
52
+ - top_p (float): Nucleus sampling (default: 0.9)
53
+ - top_k (int): Top-k sampling (default: 50)
54
+ - repetition_penalty (float): Penalty for repetition (default: 1.1)
55
+ - do_sample (bool): Whether to use sampling (default: True)
56
+
57
+ Returns:
58
+ List of dictionaries containing generated text
59
+ """
60
+ # Extract inputs
61
+ inputs_text = data.pop("inputs", data)
62
+ parameters = data.pop("parameters", {})
63
+
64
+ # Get generation parameters with defaults
65
+ system_prompt = parameters.get(
66
+ "system_prompt",
67
+ self.default_system_prompt
68
+ )
69
+ max_new_tokens = parameters.get("max_new_tokens", 100)
70
+ temperature = parameters.get("temperature", 0.7)
71
+ top_p = parameters.get("top_p", 0.9)
72
+ top_k = parameters.get("top_k", 50)
73
+ repetition_penalty = parameters.get("repetition_penalty", 1.1)
74
+ do_sample = parameters.get("do_sample", True)
75
+ return_full_text = parameters.get("return_full_text", False)
76
+
77
+ # Construct full prompt with system prompt
78
+ if system_prompt:
79
+ full_prompt = f"{system_prompt}\n\nUser: {inputs_text}\nAssistant:"
80
+ else:
81
+ full_prompt = inputs_text
82
+
83
+ # Tokenize
84
+ inputs = self.tokenizer(
85
+ full_prompt,
86
+ return_tensors="pt",
87
+ truncation=True,
88
+ max_length=2048
89
+ ).to(self.model.device)
90
+
91
+ # Generate
92
+ with torch.no_grad():
93
+ outputs = self.model.generate(
94
+ **inputs,
95
+ max_new_tokens=max_new_tokens,
96
+ temperature=temperature,
97
+ top_p=top_p,
98
+ top_k=top_k,
99
+ repetition_penalty=repetition_penalty,
100
+ do_sample=do_sample,
101
+ pad_token_id=self.tokenizer.pad_token_id,
102
+ eos_token_id=self.tokenizer.eos_token_id,
103
+ )
104
+
105
+ # Decode
106
+ generated_text = self.tokenizer.decode(
107
+ outputs[0],
108
+ skip_special_tokens=True
109
+ )
110
+
111
+ # Extract only the assistant's response if system prompt was used
112
+ if not return_full_text:
113
+ if "Assistant:" in generated_text:
114
+ generated_text = generated_text.split("Assistant:")[-1].strip()
115
+ else:
116
+ # Remove the input prompt from output
117
+ generated_text = generated_text.replace(full_prompt, "").strip()
118
+
119
+ # Return in HuggingFace expected format
120
+ return [{"generated_text": generated_text}]
121
+
122
+
123
+ # For local testing (optional)
124
+ if __name__ == "__main__":
125
+ # Test the handler locally
126
+ print("Testing handler locally...")
127
+
128
+ # Initialize handler (use "." for current directory in local testing)
129
+ handler = EndpointHandler(path="Ephraimmm/pidgin_finetuned_model")
130
+
131
+ # Test cases
132
+ test_cases = [
133
+ {
134
+ "name": "Simple greeting",
135
+ "data": {
136
+ "inputs": "How you dey?",
137
+ "parameters": {
138
+ "max_new_tokens": 50,
139
+ "temperature": 0.7
140
+ }
141
+ }
142
+ },
143
+ {
144
+ "name": "Without system prompt",
145
+ "data": {
146
+ "inputs": "Wetin you wan chop?",
147
+ "parameters": {
148
+ "system_prompt": "",
149
+ "max_new_tokens": 50
150
+ }
151
+ }
152
+ },
153
+ {
154
+ "name": "Custom system prompt",
155
+ "data": {
156
+ "inputs": "Tell me about Lagos",
157
+ "parameters": {
158
+ "system_prompt": "You are a knowledgeable guide who speaks Pidgin.",
159
+ "max_new_tokens": 100,
160
+ "temperature": 0.8
161
+ }
162
+ }
163
+ },
164
+ {
165
+ "name": "Return full text",
166
+ "data": {
167
+ "inputs": "Wetin be your name?",
168
+ "parameters": {
169
+ "max_new_tokens": 50,
170
+ "return_full_text": True
171
+ }
172
+ }
173
+ }
174
+ ]
175
+
176
+ # Run tests
177
+ for test in test_cases:
178
+ print(f"\n{'='*60}")
179
+ print(f"Test: {test['name']}")
180
+ print(f"{'='*60}")
181
+ print(f"Input: {test['data']['inputs']}")
182
+
183
+ result = handler(test['data'])
184
+ print(f"Output: {result[0]['generated_text']}")
185
+
186
+ print(f"\n{'='*60}")
187
+ print("✓ All tests completed!")