File size: 4,203 Bytes
3198de9
 
 
622fdfa
3198de9
 
 
 
 
53c0aaf
3198de9
7233ebd
 
 
 
 
 
 
 
 
 
 
 
 
bec5b9b
e5b907c
 
 
 
 
 
53c0aaf
 
e5b907c
 
 
bec5b9b
622fdfa
 
 
 
 
 
 
fba796c
75b116b
 
a1a38a3
 
0c14d50
622fdfa
dda63af
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
622fdfa
 
 
af081bd
 
3198de9
75b116b
0c14d50
af081bd
0c14d50
af081bd
622fdfa
 
af081bd
622fdfa
 
 
 
3133187
af081bd
0c14d50
 
 
 
622fdfa
53c0aaf
e87d54d
23237f8
e5b907c
 
 
 
 
10f6cc3
 
 
 
 
 
 
53c0aaf
 
 
 
 
 
622fdfa
10f6cc3
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
import os
import re
from langchain.chains import RetrievalQA
from langchain.llms import OpenAI as LangchainOpenAI
from langchain.document_loaders import PyPDFLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
import panel as pn
from panel.template import VanillaTemplate

CSS = """
#header {
    height: 0;
    padding: 0;
}

.pn-busy-container {
    visibility: hidden;
}
"""

pn.extension(raw_css=[CSS])

# Custom CSS to use Lato font
lato_font_style = """
.bk, .bk-root {
    font-family: 'Lato', sans-serif !important;
}
"""

# Create a custom template
template = VanillaTemplate(
    raw_css=[lato_font_style],
    css_files=['https://fonts.googleapis.com/css2?family=Lato:wght@400;700&display=swap']
)

# Set global sizing mode
pn.config.sizing_mode = 'stretch_width'

# Panel extension
pn.extension()

class LangchainConversation:
    def __init__(self):
        self.file_input = pn.widgets.FileInput(height=45)
        self.openaikey = pn.widgets.PasswordInput(value="", placeholder="Enter your OpenAI API Key here...", height=45)
        self.chatbox = pn.widgets.ChatBox(height=300, primary_name="User")
        self.chatbox.param.watch(self._chat, 'value')
        self.chat_history = []  # Chat history to store previous queries and responses

    def _chat(self, event):
        user_message = event.new[-1]
        input = user_message.get("User")
        if input is None:
            return
        os.environ["OPENAI_API_KEY"] = self.openaikey.value
        if self.file_input.value is not None:
            file_path = "/.cache/temp.pdf"
            self.file_input.save(file_path)
            # Check if the uploaded file is a PDF
            if self.file_input.filename.lower().endswith('.pdf'):
                prompt_text = self.remove_empty_lines(input)
                if prompt_text:
                    result = self.qa(file=file_path, query=prompt_text)
                    self.chatbox.append({"AI": result})
            else:
                # Delete the non-PDF file from cache
                os.remove(file_path)
                # Display an error message in the chatbox
                self.chatbox.append({"AI": "Error: Only PDF files are allowed. Please upload a valid PDF file."})

    @staticmethod
    def remove_empty_lines(text):
        lines = re.split(r'\\r\\n|\\r|\\n', text)
        return '\\n'.join([line.strip() for line in lines if line.strip()])

    def qa(self, file, query):
        # Consider chat history when processing new queries
        chat_history_str = "\\n".join([f"User: {q}\\nAI: {a}" for q, a in self.chat_history])

        # Load, split, and analyze the document using the default text splitter
        loader = PyPDFLoader(file)
        documents = loader.load()
        text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)  # Default text splitting
        texts = text_splitter.split_documents(documents)
        embeddings = OpenAIEmbeddings()
        db = Chroma.from_documents(texts, embeddings)
        retriever = db.as_retriever(search_type="similarity", search_kwargs={"k": 3})
        qa = RetrievalQA.from_chain_type(llm=LangchainOpenAI(), chain_type="stuff", retriever=retriever, return_source_documents=True)
        result = qa({"query": query + "\\n" + chat_history_str})

        # Update chat history
        self.chat_history.append((query, result['result']))

        return result['result']


    def view(self):
        custom_link_style = {
            'color': '#1b9aaa',
            'font-weight': 'bold'
        }

        layout = pn.Column(
            pn.pane.Markdown(""" 
            Built by <a href="https://www.mckenzielloydsmith.com/home?utm_source=HuggingFace&utm_medium=PDF+Analyzer" target="_blank">McKenzie</a>.
            """),  # Closing parenthesis for pn.pane.Markdown
            pn.Row(self.file_input, self.openaikey), self.chatbox
        )

        # Add layout to the template
        template.main.append(layout)

        # Serve the template
        return template.servable()

langchain_conversation = LangchainConversation()
langchain_conversation.view()