LLMlight 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
LLMlight/RAG.py ADDED
@@ -0,0 +1,441 @@
1
+ import pymupdf
2
+ import os
3
+ import numpy as np
4
+ import json
5
+ import re
6
+ from sentence_transformers import SentenceTransformer
7
+ import logging
8
+
9
+ from . import utils
10
+ # import utils
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ class SimpleVectorStore:
15
+ """
16
+ A lightweight vector store implementation using NumPy.
17
+ """
18
+ def __init__(self, dimension=1536):
19
+ """
20
+ Initialize the vector store.
21
+
22
+ Args:
23
+ dimension (int): Dimension of embeddings
24
+ """
25
+ self.dimension = dimension
26
+ self.vectors = []
27
+ self.documents = []
28
+ self.metadata = []
29
+
30
+ def add_documents(self, documents, vectors=None, metadata=None):
31
+ """
32
+ Add documents to the vector store.
33
+
34
+ Args:
35
+ documents (List[str]): List of document chunks
36
+ vectors (List[List[float]], optional): List of embedding vectors
37
+ metadata (List[Dict], optional): List of metadata dictionaries
38
+ """
39
+ if vectors is None:
40
+ vectors = [None] * len(documents)
41
+
42
+ if metadata is None:
43
+ metadata = [{} for _ in range(len(documents))]
44
+
45
+ for doc, vec, meta in zip(documents, vectors, metadata):
46
+ self.documents.append(doc)
47
+ self.vectors.append(vec)
48
+ self.metadata.append(meta)
49
+
50
+ def search(self, query_vector, top_k=5):
51
+ """
52
+ Search for most similar documents.
53
+
54
+ Args:
55
+ query_vector (List[float]): Query embedding vector
56
+ top_k (int): Number of results to return
57
+
58
+ Returns:
59
+ List[Dict]: List of results with documents, scores, and metadata
60
+ """
61
+ if not self.vectors or not self.documents:
62
+ return []
63
+
64
+ # Convert query vector to numpy array
65
+ query_array = np.array(query_vector)
66
+
67
+ # Compute similarity
68
+ # similarities = cosine_similarity(query_vector, chunk_vectors)[0]
69
+ # # Get top scoring chunks
70
+ # if top_chunks is None: top_chunks = len(similarities)
71
+ # top_indices = np.argsort(similarities)[-top_chunks:][::-1]
72
+ # # Join relevant chunks and send as prompt
73
+ # relevant_chunks = [chunks[i] for i in top_indices]
74
+ # relevant_scores = [similarities[i] for i in top_indices]
75
+
76
+ # Calculate similarities
77
+ similarities = []
78
+ for i, vector in enumerate(self.vectors):
79
+ if vector is not None:
80
+ # Compute cosine similarity
81
+ similarity = np.dot(query_array, vector) / (
82
+ np.linalg.norm(query_array) * np.linalg.norm(vector)
83
+ )
84
+ similarities.append((i, similarity))
85
+
86
+ # Sort by similarity (descending)
87
+ similarities.sort(key=lambda x: x[1], reverse=True)
88
+
89
+ # Get top-k results
90
+ results = []
91
+ for i, score in similarities[:top_k]:
92
+ results.append({
93
+ "document": self.documents[i],
94
+ "score": float(score),
95
+ "metadata": self.metadata[i]
96
+ })
97
+
98
+ return results
99
+
100
+
101
+ def RAG_with_RSE(context, query, label=None, chunk_size=800, irrelevant_chunk_penalty=0.2, embedding_method='bert', device='cpu', batch_size=16):
102
+ """
103
+ Complete RAG pipeline with Relevant Segment Extraction.
104
+
105
+ Args:
106
+ text (str):
107
+ Text (context)
108
+ Path to the PDF document
109
+ query (str): User query
110
+ chunk_size (int): Size of chunks
111
+ irrelevant_chunk_penalty (float): Penalty for irrelevant chunks
112
+ embedding_method:
113
+ "bge": The large retrieval-optimized embedding model for search or ranking
114
+ "bge-small": The small retrieval-optimized embedding model for search or ranking
115
+ "bert": General-purpose sentence embedding model
116
+
117
+ Returns:
118
+ Dict: Result with query, segments, and response
119
+ """
120
+ print("\n=== STARTING RAG WITH RELEVANT SEGMENT EXTRACTION ===")
121
+ print(f"Query: {query}")
122
+
123
+ if embedding_method == 'bge':
124
+ embedding_method = "BAAI/bge-en-icl"
125
+ elif embedding_method == 'bge-small':
126
+ embedding_method = "BAAI/bge-small-en"
127
+ elif embedding_method == 'bert':
128
+ embedding_method = "all-MiniLM-L6-v2"
129
+ else:
130
+ raise Exception(f'The embedding method [{embedding_method}] is not valid.')
131
+
132
+ # Process the document to extract text, chunk it, and create embeddings
133
+ chunks, vector_store, doc_info = process_document(context, label=label, chunk_size=chunk_size, embedding_method=embedding_method, device=device, batch_size=batch_size)
134
+
135
+ # Calculate relevance scores and chunk values based on the query
136
+ print("\nCalculating relevance scores and chunk values...")
137
+ chunk_values = calculate_chunk_values(query, chunks, vector_store, irrelevant_chunk_penalty)
138
+
139
+ # Find the best segments of text based on chunk values
140
+ best_segments, scores = find_best_segments(chunk_values, max_segment_length=20, total_max_length=30, min_segment_value=0.2)
141
+
142
+ # Reconstruct text segments from the best chunks
143
+ print("\nReconstructing text segments from chunks...")
144
+ segments = reconstruct_segments(chunks, best_segments)
145
+
146
+ # Format the segments into a context string for the language model
147
+ context = format_segments_for_context(segments)
148
+
149
+ return context
150
+
151
+ # # Generate a response from the language model using the context
152
+ # response = generate_response(query, context)
153
+ # # Compile the result into a dictionary
154
+ # result = {
155
+ # "query": query,
156
+ # "segments": segments,
157
+ # "response": response
158
+ # }
159
+ # print("\n=== FINAL RESPONSE ===")
160
+ # print(response)
161
+ # return result
162
+
163
+
164
+ def create_embeddings(texts, model_path="BAAI/bge-small-en", batch_size=32, device="cpu"):
165
+ """
166
+ Generate embeddings using a local model.
167
+
168
+ Args:
169
+ texts (List[str]): List of texts to embed
170
+ model_path (str): Path or name of the local embedding model
171
+ batch_size: int : 16 when you run out of memory. Default: 32
172
+ embedding_method:
173
+ "BAAI/bge-en-icl": The large version of retrieval-optimized embedding model for search or ranking.
174
+ "BAAI/bge-small-en": The smaller version of retrieval-optimized embedding model for search or ranking.
175
+ "all-MiniLM-L6-v2": general-purpose sentence embedding model
176
+ device: str: "cuda" or 'cpu'
177
+
178
+ Returns:
179
+ List[List[float]]: List of embedding vectors
180
+ """
181
+ if not texts:
182
+ return []
183
+
184
+ # Load the model once and reuse it
185
+ model = SentenceTransformer(model_path, device=device)
186
+
187
+ # Compute embeddings
188
+ embeddings = model.encode(texts, batch_size=batch_size, convert_to_list=True)
189
+
190
+ # Return the list of all embeddings
191
+ return embeddings
192
+
193
+ # def create_embeddings(texts, model="BAAI/bge-en-icl"):
194
+ # """
195
+ # Generate embeddings for texts.
196
+
197
+ # Args:
198
+ # texts (List[str]): List of texts to embed
199
+ # model (str): Embedding model to use
200
+
201
+ # Returns:
202
+ # List[List[float]]: List of embedding vectors
203
+ # """
204
+ # if not texts:
205
+ # return [] # Return an empty list if no texts are provided
206
+
207
+ # # Process in batches if the list is long
208
+ # batch_size = 100 # Adjust based on your API limits
209
+ # all_embeddings = [] # Initialize a list to store all embeddings
210
+
211
+ # for i in range(0, len(texts), batch_size):
212
+ # batch = texts[i:i + batch_size] # Get the current batch of texts
213
+
214
+ # # Create embeddings for the current batch using the specified model
215
+ # response = client.embeddings.create(
216
+ # input=batch,
217
+ # model=model
218
+ # )
219
+
220
+ # # Extract embeddings from the response
221
+ # batch_embeddings = [item.embedding for item in response.data]
222
+ # all_embeddings.extend(batch_embeddings) # Add the batch embeddings to the list
223
+
224
+ # return all_embeddings # Return the list of all embeddings
225
+
226
+ def extract_text_from_pdf(pdf_path):
227
+ """
228
+ Extracts text from a PDF file and prints the first `num_chars` characters.
229
+
230
+ Args:
231
+ pdf_path (str): Path to the PDF file.
232
+
233
+ Returns:
234
+ str: Extracted text from the PDF.
235
+ """
236
+ # Open the PDF file
237
+ mypdf = pymupdf.open(pdf_path)
238
+ all_text = "" # Initialize an empty string to store the extracted text
239
+
240
+ # Iterate through each page in the PDF
241
+ for page_num in range(mypdf.page_count):
242
+ page = mypdf[page_num] # Get the page
243
+ text = page.get_text("text") # Extract text from the page
244
+ all_text += text # Append the extracted text to the all_text string
245
+
246
+ return all_text # Return the extracted text
247
+
248
+ def process_document(context, label=None, chunk_size=800, embedding_method="all-MiniLM-L6-v2", batch_size=16, device='cpu'):
249
+ """
250
+ Process a document for use with RSE.
251
+
252
+ Args:
253
+ context (str):
254
+ Text (context)
255
+ The Path to the PDF document
256
+ label (str):
257
+ Add label to identify where the specific text originates from.
258
+ chunk_size (int): Size of each chunk in characters
259
+ embedding_method:
260
+ "BAAI/bge-en-icl": The large version of retrieval-optimized embedding model for search or ranking.
261
+ "BAAI/bge-small-en": The smaller version of retrieval-optimized embedding model for search or ranking.
262
+ "all-MiniLM-L6-v2": bert: general-purpose sentence embedding model
263
+
264
+ Returns:
265
+ Tuple[List[str], SimpleVectorStore, Dict]: Chunks, vector store, and document info
266
+ """
267
+ print("Extracting context from document...")
268
+ # Extract text from the PDF file
269
+ if os.path.isfile(context):
270
+ label = context
271
+ context = extract_text_from_pdf(context)
272
+ # text = utils.read_pdf(pdf_path, return_type='string')
273
+
274
+ print("Chunking context into non-overlapping segments...")
275
+ # Chunk the extracted text into non-overlapping segments
276
+ chunks = utils.chunk_text(context, chunk_size=chunk_size, overlap=0, method='chars')
277
+ print(f"Created {len(chunks)} chunks")
278
+
279
+ print("Generating embeddings for chunks...")
280
+ # Generate embeddings for the context chunks
281
+ chunk_embeddings = create_embeddings(chunks, model_path=embedding_method, batch_size=batch_size, device=device)
282
+
283
+ # Create an instance of the SimpleVectorStore
284
+ vector_store = SimpleVectorStore()
285
+
286
+ # Add documents with metadata (including chunk index for later reconstruction)
287
+ metadata = [{"chunk_index": i, "source": label} for i in range(len(chunks))]
288
+ vector_store.add_documents(chunks, chunk_embeddings, metadata)
289
+
290
+ # Track original document structure for segment reconstruction
291
+ doc_info = {
292
+ "chunks": chunks,
293
+ "source": label,
294
+ }
295
+
296
+ return chunks, vector_store, doc_info
297
+
298
+
299
+ def calculate_chunk_values(query, chunks, vector_store, irrelevant_chunk_penalty=0.2):
300
+ """
301
+ Calculate chunk values by combining relevance and position.
302
+
303
+ Args:
304
+ query (str): Query text
305
+ chunks (List[str]): List of document chunks
306
+ vector_store (SimpleVectorStore): Vector store containing the chunks
307
+ irrelevant_chunk_penalty (float): Penalty for irrelevant chunks
308
+
309
+ Returns:
310
+ List[float]: List of chunk values
311
+ """
312
+ # Create query embedding
313
+ query_embedding = create_embeddings([query])[0]
314
+
315
+ # Get all chunks with similarity scores
316
+ num_chunks = len(chunks)
317
+ results = vector_store.search(query_embedding, top_k=num_chunks)
318
+
319
+ # Create a mapping of chunk_index to relevance score
320
+ relevance_scores = {result["metadata"]["chunk_index"]: result["score"] for result in results}
321
+
322
+ # Calculate chunk values (relevance score minus penalty)
323
+ chunk_values = []
324
+ for i in range(num_chunks):
325
+ # Get relevance score or default to 0 if not in results
326
+ score = relevance_scores.get(i, 0.0)
327
+ # Apply penalty to convert to a value where irrelevant chunks have negative value
328
+ value = score - irrelevant_chunk_penalty
329
+ chunk_values.append(value)
330
+
331
+ return chunk_values
332
+
333
+
334
+ def find_best_segments(chunk_values, max_segment_length=20, total_max_length=30, min_segment_value=0.2):
335
+ """
336
+ Find the best segments using a variant of the maximum sum subarray algorithm.
337
+
338
+ Args:
339
+ chunk_values (List[float]): Values for each chunk
340
+ max_segment_length (int): Maximum length of a single segment
341
+ total_max_length (int): Maximum total length across all segments
342
+ min_segment_value (float): Minimum value for a segment to be considered
343
+
344
+ Returns:
345
+ List[Tuple[int, int]]: List of (start, end) indices for best segments
346
+ """
347
+ print("Finding optimal continuous text segments...")
348
+
349
+ best_segments = []
350
+ segment_scores = []
351
+ total_included_chunks = 0
352
+
353
+ # Keep finding segments until we hit our limits
354
+ while total_included_chunks < total_max_length:
355
+ best_score = min_segment_value # Minimum threshold for a segment
356
+ best_segment = None
357
+
358
+ # Try each possible starting position
359
+ for start in range(len(chunk_values)):
360
+ # Skip if this start position is already in a selected segment
361
+ if any(start >= s[0] and start < s[1] for s in best_segments):
362
+ continue
363
+
364
+ # Try each possible segment length
365
+ for length in range(1, min(max_segment_length, len(chunk_values) - start) + 1):
366
+ end = start + length
367
+
368
+ # Skip if end position is already in a selected segment
369
+ if any(end > s[0] and end <= s[1] for s in best_segments):
370
+ continue
371
+
372
+ # Calculate segment value as sum of chunk values
373
+ segment_value = sum(chunk_values[start:end])
374
+
375
+ # Update best segment if this one is better
376
+ if segment_value > best_score:
377
+ best_score = segment_value
378
+ best_segment = (start, end)
379
+
380
+ # If we found a good segment, add it
381
+ if best_segment:
382
+ best_segments.append(best_segment)
383
+ segment_scores.append(best_score)
384
+ total_included_chunks += best_segment[1] - best_segment[0]
385
+ print(f"Found segment {best_segment} with score {best_score:.4f}")
386
+ else:
387
+ # No more good segments to find
388
+ break
389
+
390
+ # Sort segments by their starting position for readability
391
+ best_segments = sorted(best_segments, key=lambda x: x[0])
392
+
393
+ return best_segments, segment_scores
394
+
395
+
396
+ def reconstruct_segments(chunks, best_segments):
397
+ """
398
+ Reconstruct text segments based on chunk indices.
399
+
400
+ Args:
401
+ chunks (List[str]): List of all document chunks
402
+ best_segments (List[Tuple[int, int]]): List of (start, end) indices for segments
403
+
404
+ Returns:
405
+ List[str]: List of reconstructed text segments
406
+ """
407
+ reconstructed_segments = [] # Initialize an empty list to store the reconstructed segments
408
+
409
+ for start, end in best_segments:
410
+ # Join the chunks in this segment to form the complete segment text
411
+ segment_text = " ".join(chunks[start:end])
412
+ # Append the segment text and its range to the reconstructed_segments list
413
+ reconstructed_segments.append({
414
+ "text": segment_text,
415
+ "segment_range": (start, end),
416
+ })
417
+
418
+ return reconstructed_segments # Return the list of reconstructed text segments
419
+
420
+
421
+ def format_segments_for_context(segments):
422
+ """
423
+ Format segments into a context string for the LLM.
424
+
425
+ Args:
426
+ segments (List[Dict]): List of segment dictionaries
427
+
428
+ Returns:
429
+ str: Formatted context text
430
+ """
431
+ context = [] # Initialize an empty list to store the formatted context
432
+
433
+ for i, segment in enumerate(segments):
434
+ # Create a header for each segment with its index and chunk range
435
+ segment_header = f"SEGMENT {i+1} (Chunks {segment['segment_range'][0]}-{segment['segment_range'][1]-1}):"
436
+ context.append(segment_header) # Add the segment header to the context list
437
+ context.append(segment['text']) # Add the segment text to the context list
438
+ context.append("-" * 80) # Add a separator line for readability
439
+
440
+ # Join all elements in the context list with double newlines and return the result
441
+ return "\n\n".join(context)
LLMlight/__init__.py ADDED
@@ -0,0 +1,37 @@
1
+ import logging
2
+ from LLMlight.LLMlight import LLMlight
3
+
4
+ __author__ = 'Erdogan Tasksen'
5
+ __email__ = 'erdogant@gmail.com'
6
+ __version__ = '0.1.0'
7
+
8
+ # Setup root logger
9
+ _logger = logging.getLogger('LLMlight')
10
+ _log_handler = logging.StreamHandler()
11
+ _fmt = '[{asctime}] [{name}] [{levelname}] {msg}'
12
+ _formatter = logging.Formatter(fmt=_fmt, style='{', datefmt='%d-%m-%Y %H:%M:%S')
13
+ _log_handler.setFormatter(_formatter)
14
+ _logger.addHandler(_log_handler)
15
+ _log_handler.setLevel(logging.DEBUG)
16
+ _logger.propagate = False
17
+
18
+
19
+
20
+ # module level doc-string
21
+ __doc__ = """
22
+ LLMlight
23
+ =====================================================================
24
+
25
+ LLMlight is for...
26
+
27
+ Example
28
+ -------
29
+ >>> import LLMlight as LLMlight
30
+ >>> model = LLMlight.fit_transform(X)
31
+ >>> fig,ax = LLMlight.plot(model)
32
+
33
+ References
34
+ ----------
35
+ https://github.com/erdogant/LLMlight
36
+
37
+ """
LLMlight/examples.py ADDED
@@ -0,0 +1,175 @@
1
+ # %%
2
+ # import LLMlight as llm
3
+ # print(dir(llm))
4
+ # print(llm.__version__)
5
+
6
+ # %%
7
+ from LLMlight import LLMlight
8
+ model = LLMlight(verbose='debug')
9
+ model.check_logger()
10
+
11
+
12
+ #%% Available models
13
+ from LLMlight import LLMlight
14
+ model = LLMlight(verbose='info')
15
+ modelnames = model.get_available_models(validate=True)
16
+
17
+ # %%
18
+ for modelname in modelnames:
19
+ from LLMlight import LLMlight
20
+ llm = LLMlight(modelname=modelname)
21
+ print(llm.modelname)
22
+
23
+ system_message = "You are a helpful assistant."
24
+ response = llm.run('What is the capital of France?', system=system_message)
25
+ print(response)
26
+
27
+ # %%
28
+ from LLMlight import LLMlight
29
+ model_path = r'C:/Users\beeld/.lmstudio/models/NousResearch/Hermes-3-Llama-3.2-3B-GGUF\Hermes-3-Llama-3.2-3B.Q4_K_M.gguf'
30
+ model = LLMlight(endpoint=model_path, top_p=0.9)
31
+ # model.run('hello, who are you?')
32
+ system_message = "You are a helpful assistant."
33
+ response = model.run('What is the capital of France?', system=system_message)
34
+
35
+
36
+
37
+
38
+
39
+ #%%
40
+ import llama_cpp
41
+ print(llama_cpp.__version__)
42
+ print(llama_cpp.llama_cpp_version()) # Might crash if incompatible
43
+
44
+ # Check your GGUF model's metadata
45
+ model_path = r'C:/Users\beeld/.lmstudio/models/NousResearch/Hermes-3-Llama-3.2-3B-GGUF\Hermes-3-Llama-3.2-3B.Q4_K_M.gguf'
46
+ with open(model_path, 'rb') as f:
47
+ header = f.read(128)
48
+ print(header)
49
+
50
+
51
+ #%%
52
+ import os
53
+ import logging
54
+ import requests
55
+ from tqdm import tqdm
56
+ from llama_cpp import Llama
57
+
58
+ logger = logging.getLogger(__name__)
59
+ logging.basicConfig(level=logging.INFO)
60
+
61
+ def download_and_load_gguf_model(
62
+ url: str,
63
+ model_name: str,
64
+ cache_dir: str = "local_models",
65
+ n_ctx: int = 4096,
66
+ n_threads: int = 8,
67
+ n_gpu_layers: int = 0,
68
+ verbose: bool = True
69
+ ) -> Llama:
70
+ """
71
+ Downloads a GGUF model from a URL (if not already cached) and loads it with llama-cpp-python.
72
+
73
+ Args:
74
+ url (str): Direct URL to the .gguf model file.
75
+ model_name (str): Filename to use for local caching (e.g. 'Hermes.gguf').
76
+ cache_dir (str): Directory to store the model. Default is 'local_models'.
77
+ n_ctx (int): Context window size.
78
+ n_threads (int): CPU threads to use.
79
+ n_gpu_layers (int): GPU layers to offload. Use 0 for CPU-only.
80
+ verbose (bool): Print logs during loading.
81
+
82
+ Returns:
83
+ Llama: Loaded model ready for inference.
84
+ """
85
+ os.makedirs(cache_dir, exist_ok=True)
86
+ model_path = os.path.join(cache_dir, model_name)
87
+
88
+ if not os.path.exists(model_path):
89
+ logger.info(f"Model not found locally. Downloading from:\n{url}")
90
+ try:
91
+ with requests.get(url, stream=True) as r:
92
+ r.raise_for_status()
93
+ total_size = int(r.headers.get("content-length", 0))
94
+ with open(model_path, "wb") as f, tqdm(
95
+ total=total_size, unit='B', unit_scale=True, desc=model_name
96
+ ) as bar:
97
+ for chunk in r.iter_content(chunk_size=8192):
98
+ f.write(chunk)
99
+ bar.update(len(chunk))
100
+ except Exception as e:
101
+ raise RuntimeError(f"Failed to download model: {e}")
102
+
103
+ else:
104
+ logger.info(f"Using cached model at: {model_path}")
105
+
106
+ # Load with llama-cpp
107
+ llm = Llama(
108
+ model_path=model_path,
109
+ n_ctx=n_ctx,
110
+ n_threads=n_threads,
111
+ n_gpu_layers=n_gpu_layers,
112
+ verbose=verbose
113
+ )
114
+
115
+ logger.info("Model loaded successfully.")
116
+ return llm
117
+
118
+ #%%
119
+ url = "https://huggingface.co/TheBloke/Hermes-2-Pro-Llama-3-GGUF/resolve/main/hermes-2-pro-llama-3.Q4_K_M.gguf"
120
+
121
+ model_name = "hermes-2-pro-llama-3.Q4_K_M.gguf"
122
+
123
+ llm = download_and_load_gguf_model(url, model_name)
124
+
125
+ prompt = "<|begin_of_text|><|start_header_id|>user<|end_header_id|>\nWhat is the capital of France?\n<|start_header_id|>assistant<|end_header_id|>\n"
126
+ response = llm(prompt=prompt, max_tokens=20, stop=["<|end_of_text|>"])
127
+ print(response["choices"][0]["text"].strip())
128
+
129
+ #%%
130
+ # Code to inference Hermes with HF Transformers
131
+ # Requires pytorch, transformers, bitsandbytes, sentencepiece, protobuf, and flash-attn packages
132
+
133
+ import torch
134
+ from transformers import AutoTokenizer, AutoModelForCausalLM, LlamaForCausalLM
135
+ import bitsandbytes, flash_attn
136
+
137
+ tokenizer = AutoTokenizer.from_pretrained('NousResearch/Hermes-3-Llama-3.1-8B', trust_remote_code=True)
138
+ model = LlamaForCausalLM.from_pretrained(
139
+ "NousResearch/Hermes-3-Llama-3.1-8B",
140
+ torch_dtype=torch.float16,
141
+ device_map="auto",
142
+ load_in_8bit=False,
143
+ load_in_4bit=True,
144
+ use_flash_attention_2=True
145
+ )
146
+
147
+ prompts = [
148
+ """<|im_start|>system
149
+ You are a sentient, superintelligent artificial general intelligence, here to teach and assist me.<|im_end|>
150
+ <|im_start|>user
151
+ Write a short story about Goku discovering kirby has teamed up with Majin Buu to destroy the world.<|im_end|>
152
+ <|im_start|>assistant""",
153
+ ]
154
+
155
+ for chat in prompts:
156
+ print(chat)
157
+ input_ids = tokenizer(chat, return_tensors="pt").input_ids.to("cuda")
158
+ generated_ids = model.generate(input_ids, max_new_tokens=750, temperature=0.8, repetition_penalty=1.1, do_sample=True, eos_token_id=tokenizer.eos_token_id)
159
+ response = tokenizer.decode(generated_ids[0][input_ids.shape[-1]:], skip_special_tokens=True, clean_up_tokenization_space=True)
160
+ print(f"Response: {response}")
161
+
162
+ #%%
163
+ url = "https://huggingface.co/TheBloke/Hermes-2-Pro-Llama-3-GGUF/resolve/main/hermes-2-pro-llama-3.Q4_K_M.gguf"
164
+ model_name = "hermes-2-pro-llama-3.Q4_K_M.gguf"
165
+
166
+ # Already avoids bitsandbytes
167
+ llm = download_and_load_gguf_model(url, model_name, n_gpu_layers=0)
168
+
169
+
170
+
171
+ from transformers import AutoModelForCausalLM, AutoTokenizer
172
+
173
+ model_id = "meta-llama/Llama-2-7b-hf" # for example
174
+
175
+ model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto") # will crash without CUDA if quantized