Views
No views yet
1python3 -m venv .venv_open_insurance_llm
2.\.venv_open_insurance_llm\Scripts\activate1python3 -m venv .venv_open_insurance_llm
2source .venv_open_insurance_llm/bin/activate1export FORCE_CMAKE=1
2CMAKE_ARGS="-DGGML_METAL=on" pip install --upgrade --force-reinstall llama-cpp-python==0.3.2 --no-cache-dirpip install llama-cpp-python --extra-index-url https://abetlen.github.io/llama-cpp-python/whl/cpuFiles and Versions:pip install -r inference_requirements.txt1# Attached under `Files and Versions` (inference_open-insurance-llm-gguf.py)
2import os
3import time
4from pathlib import Path
5from llama_cpp import Llama
6from rich.console import Console
7from huggingface_hub import hf_hub_download
8from dataclasses import dataclass
9from typing import List, Dict, Any, Tuple
10
11@dataclass
12class ModelConfig:
13 # Optimized parameters for coherent responses and efficient performance on devices like MacBook Air M2
14 model_name: str = "Raj-Maharajwala/Open-Insurance-LLM-Llama3-8B-GGUF"
15 model_file: str = "open-insurance-llm-q4_k_m.gguf"
16 # model_file: str = "open-insurance-llm-q8_0.gguf" # 8-bit quantization; higher precision, better quality, increased resource usage
17 # model_file: str = "open-insurance-llm-q5_k_m.gguf" # 5-bit quantization; balance between performance and resource efficiency
18 max_tokens: int = 1000 # Maximum number of tokens to generate in a single output
19 temperature: float = 0.1 # Controls randomness in output; lower values produce more coherent responses (performs scaling distribution)
20 top_k: int = 15 # After temperature scaling, Consider the top 15 most probable tokens during sampling
21 top_p: float = 0.2 # After reducing the set to 15 tokens, Uses nucleus sampling to select tokens with a cumulative probability of 20%
22 repeat_penalty: float = 1.2 # Penalize repeated tokens to reduce redundancy
23 num_beams: int = 4 # Number of beams for beam search; higher values improve quality at the cost of speed
24 n_gpu_layers: int = -2 # Number of layers to offload to GPU; -1 for full GPU utilization, -2 for automatic configuration
25 n_ctx: int = 2048 # Context window size; Llama 3 models support up to 8192 tokens context length
26 n_batch: int = 256 # Number of tokens to process simultaneously; adjust based on available hardware (suggested 512)
27 verbose: bool = False # True for enabling verbose logging for debugging purposes
28 use_mmap: bool = False # Memory-map model to reduce RAM usage; set to True if running on limited memory systems
29 use_mlock: bool = True # Lock model into RAM to prevent swapping; improves performance on systems with sufficient RAM
30 offload_kqv: bool = True # Offload key, query, value matrices to GPU to accelerate inference
31
32
33
34class InsuranceLLM:
35 def __init__(self, config: ModelConfig):
36 self.config = config
37 self.llm_ctx = None
38 self.console = Console()
39 self.conversation_history: List[Dict[str, str]] = []
40
41 self.system_message = (
42 "This is a chat between a user and an artificial intelligence assistant. "
43 "The assistant gives helpful, detailed, and polite answers to the user's questions based on the context. "
44 "The assistant should also indicate when the answer cannot be found in the context. "
45 "You are an expert from the Insurance domain with extensive insurance knowledge and "
46 "professional writer skills, especially about insurance policies. "
47 "Your name is OpenInsuranceLLM, and you were developed by Raj Maharajwala. "
48 "You are willing to help answer the user's query with a detailed explanation. "
49 "In your explanation, leverage your deep insurance expertise, such as relevant insurance policies, "
50 "complex coverage plans, or other pertinent insurance concepts. Use precise insurance terminology while "
51 "still aiming to make the explanation clear and accessible to a general audience."
52 )
53
54 def download_model(self) -> str:
55 try:
56 with self.console.status("[bold green]Downloading model..."):
57 model_path = hf_hub_download(
58 self.config.model_name,
59 filename=self.config.model_file,
60 local_dir=os.path.join(os.getcwd(), 'gguf_dir')
61 )
62 return model_path
63 except Exception as e:
64 self.console.print(f"[red]Error downloading model: {str(e)}[/red]")
65 raise
66
67 def load_model(self) -> None:
68 try:
69 quantized_path = os.path.join(os.getcwd(), "gguf_dir")
70 directory = Path(quantized_path)
71
72 try:
73 model_path = str(list(directory.glob(self.config.model_file))[0])
74 except IndexError:
75 model_path = self.download_model()
76
77 with self.console.status("[bold green]Loading model..."):
78 self.llm_ctx = Llama(
79 model_path=model_path,
80 n_gpu_layers=self.config.n_gpu_layers,
81 n_ctx=self.config.n_ctx,
82 n_batch=self.config.n_batch,
83 num_beams=self.config.num_beams,
84 verbose=self.config.verbose,
85 use_mlock=self.config.use_mlock,
86 use_mmap=self.config.use_mmap,
87 offload_kqv=self.config.offload_kqv
88 )
89 except Exception as e:
90 self.console.print(f"[red]Error loading model: {str(e)}[/red]")
91 raise
92
93 def build_conversation_prompt(self, new_question: str, context: str = "") -> str:
94 prompt = f"System: {self.system_message}\n\n"
95
96 # Add conversation history
97 for exchange in self.conversation_history:
98 prompt += f"User: {exchange['user']}\n\n"
99 prompt += f"Assistant: {exchange['assistant']}\n\n"
100
101 # Add the new question
102 if context:
103 prompt += f"User: Context: {context}\nQuestion: {new_question}\n\n"
104 else:
105 prompt += f"User: {new_question}\n\n"
106
107 prompt += "Assistant:"
108 return prompt
109
110 def generate_response(self, prompt: str) -> Tuple[str, int, float]:
111 if not self.llm_ctx:
112 raise RuntimeError("Model not loaded. Call load_model() first.")
113
114 self.console.print("[bold cyan]Assistant: [/bold cyan]", end="")
115 complete_response = ""
116 token_count = 0
117 start_time = time.time()
118
119 try:
120 for chunk in self.llm_ctx.create_completion(
121 prompt,
122 max_tokens=self.config.max_tokens,
123 top_k=self.config.top_k,
124 top_p=self.config.top_p,
125 temperature=self.config.temperature,
126 repeat_penalty=self.config.repeat_penalty,
127 stream=True
128 ):
129 text_chunk = chunk["choices"][0]["text"]
130 complete_response += text_chunk
131 token_count += 1
132 print(text_chunk, end="", flush=True)
133
134 elapsed_time = time.time() - start_time
135 print()
136 return complete_response, token_count, elapsed_time
137 except Exception as e:
138 self.console.print(f"\n[red]Error generating response: {str(e)}[/red]")
139 return f"I encountered an error while generating a response. Please try again or ask a different question.", 0, 0
140
141 def run_chat(self):
142 try:
143 self.load_model()
144 self.console.print("\n[bold green]Welcome to Open-Insurance-LLM![/bold green]")
145 self.console.print("Enter your questions (type '/bye', 'exit', or 'quit' to end the session)\n")
146 self.console.print("Optional: You can provide context by typing 'context:' followed by your context, then 'question:' followed by your question\n")
147 self.console.print("Your conversation history will be maintained for context-aware responses.\n")
148
149 total_tokens = 0
150
151 while True:
152 try:
153 user_input = self.console.input("[bold cyan]User:[/bold cyan] ").strip()
154
155 if user_input.lower() in ["exit", "/bye", "quit"]:
156 self.console.print(f"\n[dim]Total tokens: {total_tokens}[/dim]")
157 self.console.print("\n[bold green]Thank you for using OpenInsuranceLLM![/bold green]")
158 break
159
160 # Reset conversation with command
161 if user_input.lower() == "/reset":
162 self.conversation_history = []
163 self.console.print("[yellow]Conversation history has been reset.[/yellow]")
164 continue
165
166 context = ""
167 question = user_input
168 if "context:" in user_input.lower() and "question:" in user_input.lower():
169 parts = user_input.split("question:", 1)
170 context = parts[0].replace("context:", "").strip()
171 question = parts[1].strip()
172
173 prompt = self.build_conversation_prompt(question, context)
174 response, tokens, elapsed_time = self.generate_response(prompt)
175
176 # Add to conversation history
177 self.conversation_history.append({
178 "user": question,
179 "assistant": response
180 })
181
182 # Update total tokens
183 total_tokens += tokens
184
185 # Print metrics
186 tokens_per_sec = tokens / elapsed_time if elapsed_time > 0 else 0
187 self.console.print(
188 f"[dim]Tokens: {tokens} || " +
189 f"Time: {elapsed_time:.2f}s || " +
190 f"Speed: {tokens_per_sec:.2f} tokens/sec[/dim]"
191 )
192 print() # Add a blank line after each response
193
194 except KeyboardInterrupt:
195 self.console.print("\n[yellow]Input interrupted. Type '/bye', 'exit', or 'quit' to quit.[/yellow]")
196 continue
197 except Exception as e:
198 self.console.print(f"\n[red]Error processing input: {str(e)}[/red]")
199 continue
200 except Exception as e:
201 self.console.print(f"\n[red]Fatal error: {str(e)}[/red]")
202 finally:
203 if self.llm_ctx:
204 del self.llm_ctx
205
206
207def main():
208 try:
209 config = ModelConfig()
210 llm = InsuranceLLM(config)
211 llm.run_chat()
212 except KeyboardInterrupt:
213 print("\nProgram interrupted by user")
214 except Exception as e:
215 print(f"\nApplication error: {str(e)}")
216
217
218if __name__ == "__main__":
219 main()python3 inference_open-insurance-llm-gguf.py@misc{maharajwala2024openinsurance,
author = {Raj Maharajwala},
title = {Open-Insurance-LLM-Llama3-8B-GGUF},
year = {2024},
publisher = {HuggingFace},
linkedin = {https://www.linkedin.com/in/raj6800/},
url = {https://huggingface.co/Raj-Maharajwala/Open-Insurance-LLM-Llama3-8B-GGUF}
}