1
+ from langchain_text_splitters import RecursiveCharacterTextSplitter
2
+ from langchain_community .document_loaders import WebBaseLoader , PyPDFLoader
3
+ from langchain_huggingface import HuggingFaceEmbeddings , HuggingFacePipeline
4
+ from langchain .prompts import PromptTemplate
5
+ from langchain .chains import RetrievalQA
6
+ from langchain_chroma import Chroma
7
+ from optimum .intel import OVModelForCausalLM
8
+ from transformers import AutoTokenizer , pipeline
9
+ import openvino as ov
1
10
import os
2
11
os .environ ['USER_AGENT' ] = "SummarizeBot"
3
12
4
- import openvino as ov
5
- from transformers import AutoTokenizer , pipeline
6
- from optimum .intel import OVModelForCausalLM
7
- from langchain_chroma import Chroma
8
- from langchain .chains import RetrievalQA
9
- from langchain .prompts import PromptTemplate
10
- from langchain_huggingface import HuggingFaceEmbeddings , HuggingFacePipeline
11
- from langchain_community .document_loaders import WebBaseLoader , PyPDFLoader
12
- from langchain_text_splitters import RecursiveCharacterTextSplitter
13
13
14
14
def get_device ():
15
15
core = ov .Core ()
@@ -23,11 +23,11 @@ def get_device():
23
23
class TextSummarizerEngine :
24
24
"""
25
25
A class for managing text summarization and Q&A operations using LLMs and vector stores.
26
-
26
+
27
27
This class encapsulates the functionality for loading LLMs, processing documents,
28
28
and generating summaries and answers for both web content and PDFs.
29
29
"""
30
-
30
+
31
31
# Prompt Templates for Summarization & QA Bot
32
32
SUMMARY_TEMPLATE = """Write a concise summary of the following: "{context}" CONCISE SUMMARY: """
33
33
QUERY_TEMPLATE = """Use the following pieces of context to answer the question at the end.
@@ -37,41 +37,41 @@ class TextSummarizerEngine:
37
37
{context}
38
38
Question: {question}
39
39
Helpful Answer:"""
40
-
40
+
41
41
# Embedding model name
42
42
EMBEDDING_MODEL = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
43
-
43
+
44
44
def __init__ (self ):
45
45
"""Initialize the TextSummarizerEngine with empty attributes."""
46
46
self .model_id = None
47
47
self .model_path = None
48
48
self .llm = None
49
49
self .tokenizer = None
50
-
50
+
51
51
# Vector store for document processing
52
52
self .vectorstore = None
53
-
53
+
54
54
# Initialize embeddings
55
55
self .embeddings = HuggingFaceEmbeddings (model_name = self .EMBEDDING_MODEL )
56
-
56
+
57
57
def load_model (self , model_id ):
58
58
"""
59
59
Load and initialize the specified LLM model using OpenVINO optimization.
60
60
"""
61
61
self .model_id = model_id
62
-
62
+
63
63
if model_id == "Meta LLama 2" :
64
64
self .model_path = "../models/ov_llama_2"
65
65
elif model_id == "Qwen 7B Instruct" :
66
66
self .model_path = "../models/ov_qwen7b"
67
67
else :
68
68
raise ValueError (f"Unsupported model ID: { model_id } " )
69
-
69
+
70
70
# Load the model with OpenVINO optimization
71
71
device = get_device ()
72
72
model = OVModelForCausalLM .from_pretrained (self .model_path , device = device )
73
73
self .tokenizer = AutoTokenizer .from_pretrained (self .model_path )
74
-
74
+
75
75
# Create a text generation pipeline
76
76
pipe = pipeline (
77
77
"text-generation" ,
@@ -80,10 +80,10 @@ def load_model(self, model_id):
80
80
max_new_tokens = 4096 ,
81
81
device = model .device ,
82
82
)
83
-
83
+
84
84
# Create a LangChain compatible model
85
85
self .llm = HuggingFacePipeline (pipeline = pipe )
86
-
86
+
87
87
def _process_document (self , loader ):
88
88
"""
89
89
Process document content from a loader and create a vector store.
@@ -94,36 +94,36 @@ def _process_document(self, loader):
94
94
chunk_size = 1000 , chunk_overlap = 20
95
95
)
96
96
all_splits = text_splitter .split_documents (page_data )
97
-
97
+
98
98
# Create and return a vector store from the document chunks
99
99
vectorstore = Chroma .from_documents (
100
- documents = all_splits ,
100
+ documents = all_splits ,
101
101
embedding = self .embeddings
102
102
)
103
103
return vectorstore
104
-
104
+
105
105
async def process_document (self , source , is_url = True ):
106
106
"""
107
107
Process a document (URL or PDF) to generate a summary of its content.
108
108
"""
109
109
if not self .llm :
110
110
raise ValueError ("Model not loaded. Call load_model first." )
111
-
111
+
112
112
# Create the appropriate loader based on the document type
113
113
if is_url :
114
114
loader = WebBaseLoader (source )
115
115
else :
116
116
loader = PyPDFLoader (source , extract_images = False )
117
-
117
+
118
118
# Process the document content
119
119
self .vectorstore = self ._process_document (loader )
120
-
120
+
121
121
# Create a prompt for summarization
122
122
prompt = PromptTemplate (
123
- template = self .SUMMARY_TEMPLATE ,
123
+ template = self .SUMMARY_TEMPLATE ,
124
124
input_variables = ["context" ]
125
125
)
126
-
126
+
127
127
# Create a retrieval QA chain
128
128
qa_chain = RetrievalQA .from_chain_type (
129
129
llm = self .llm ,
@@ -132,7 +132,7 @@ async def process_document(self, source, is_url=True):
132
132
chain_type_kwargs = {"prompt" : prompt },
133
133
return_source_documents = False ,
134
134
)
135
-
135
+
136
136
# Generate a summary
137
137
question = "Please summarize the entire content in one paragraph of 100 words"
138
138
summary = qa_chain .invoke (question )["result" ]
@@ -142,20 +142,20 @@ async def process_document(self, source, is_url=True):
142
142
else :
143
143
summary = "No summary found."
144
144
return summary
145
-
145
+
146
146
async def answer_question (self , query ):
147
147
"""
148
148
Answer a question about previously processed document content.
149
149
"""
150
150
if not self .llm or not self .vectorstore :
151
151
raise ValueError ("Document content not processed or model not loaded." )
152
-
152
+
153
153
# Create a prompt for Q&A
154
154
prompt = PromptTemplate (
155
- template = self .QUERY_TEMPLATE ,
155
+ template = self .QUERY_TEMPLATE ,
156
156
input_variables = ["context" , "question" ]
157
157
)
158
-
158
+
159
159
# Create a retrieval QA chain
160
160
reduce_chain = RetrievalQA .from_chain_type (
161
161
llm = self .llm ,
@@ -164,7 +164,7 @@ async def answer_question(self, query):
164
164
chain_type_kwargs = {"prompt" : prompt },
165
165
return_source_documents = False ,
166
166
)
167
-
167
+
168
168
# Generate an answer
169
169
response = reduce_chain .invoke ({"query" : query })['result' ]
170
170
start_idx = response .find ("Helpful Answer:" )
@@ -173,7 +173,7 @@ async def answer_question(self, query):
173
173
else :
174
174
response = "No answer found."
175
175
return response
176
-
176
+
177
177
def cleanup (self ):
178
178
"""Clean up resources when done."""
179
179
if self .vectorstore :
@@ -182,12 +182,12 @@ def cleanup(self):
182
182
except Exception :
183
183
print ("Failed to delete vector store collection" )
184
184
185
+
185
186
if __name__ == "__main__" :
186
187
# Example usage
187
188
engine = TextSummarizerEngine ()
188
189
engine .load_model ("Qwen 7B Instruct" )
189
-
190
+
190
191
# Process a document (URL or PDF)
191
192
engine .process_document ("https://example.com/document" , is_url = True )
192
193
engine .cleanup ()
193
-
0 commit comments