File size: 7,090 Bytes
38a637f
 
 
 
bbdde00
 
38a637f
bbdde00
9014715
bbdde00
38a637f
bbdde00
38a637f
 
 
3790afa
38a637f
 
3790afa
 
38a637f
 
 
3790afa
fe17826
9014715
bbdde00
38a637f
bbdde00
9014715
bbdde00
38a637f
bbdde00
fe17826
38a637f
3790afa
38a637f
3790afa
9014715
3790afa
 
 
38a637f
3790afa
fe17826
38a637f
bbdde00
 
 
 
 
 
3790afa
38a637f
3790afa
 
 
 
 
 
38a637f
fe17826
 
38a637f
 
 
 
fe17826
38a637f
fe17826
38a637f
3790afa
38a637f
3790afa
9014715
ae11c94
3790afa
bbdde00
38a637f
bbdde00
3790afa
bbdde00
38a637f
bbdde00
3790afa
38a637f
 
 
3790afa
 
bbdde00
 
38a637f
bbdde00
3790afa
38a637f
 
 
 
3790afa
38a637f
9014715
ae11c94
38a637f
3790afa
38a637f
 
9014715
38a637f
 
9014715
38a637f
 
9014715
38a637f
9014715
 
 
 
 
ae11c94
38a637f
3790afa
 
 
 
 
 
38a637f
 
 
 
 
3790afa
38a637f
3790afa
38a637f
 
 
3790afa
38a637f
 
9014715
38a637f
9014715
 
 
 
 
 
 
 
3790afa
38a637f
3790afa
 
207d39c
 
 
 
 
 
38a637f
207d39c
 
 
 
 
 
 
 
 
 
38a637f
207d39c
 
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# Loading required libraries
import gradio as gr              # Gradio: A library for building web interfaces
import requests                  # requests: A library for sending HTTP requests.
from openai import OpenAI        # OpenAI: Clients compatible with the Upstage Solar API

# ------------------------------
# πŸ” Defining a document parsing function
# ------------------------------
def parse_document(file, api_key):
    """
    Function to convert uploaded PDF document to HTML (using Upstage Document Parse API)
    """
    url = "https://api.upstage.ai/v1/document-ai/document-parse"  # API request URL
    headers = {'Authorization': f'Bearer {api_key}'}              # Authentication header settingsμ •
    files = {"document": open(file.name, "rb")}                   # read file
    data = {
        "base64_encoding": "['table']",  # Table data is encoded in base64
        "model": "document-parse"        # Specify usage model
    }

    response = requests.post(url, headers=headers, files=files, data=data)  # POST request
    result = response.json()                                                # Parsing response results
    html_text = result.get("content", {}).get("html", "")                  # HTML Extraction
    return html_text


# ------------------------------
# πŸ’¬ Defining a document-based Q&A function
# ------------------------------
def chat_with_document(history, html_text, user_question, api_key):
    """
    Solar LLM functions to answer user questions based on document content
    """
    if not html_text.strip():
        return history, history, "⚠️ Please convert the document first."  # Guidance if there is no document

    # OpenAI client initialization (Upstage Solar LLM)
    client = OpenAI(
        api_key=api_key,
        base_url="https://api.upstage.ai/v1"
    )

    # Reset previous conversation history
    history = history or []

    # System prompt: Request a response based on the contents of the HTML document
    system_prompt = f"""The following is a financial statement document extracted in HTML format.
                    Please answer user questions accurately and concisely in Korean, based on the text within HTML tags.
                    
                    Document:
                    {html_text}
                    """

    # Message composition (System β†’ User/bot conversation β†’ Current question)
    messages = [{"role": "system", "content": system_prompt}]
    for user, bot in history:
        messages.append({"role": "user", "content": user})
        messages.append({"role": "assistant", "content": bot})
    messages.append({"role": "user", "content": user_question})

    # Solar LLM Call
    try:
        response = client.chat.completions.create(
            model="solar-pro",     # Model name to use
            messages=messages,     # Deliver the entire message
            temperature=0,         # Minimize creativity
            max_tokens=1024        # maximum response length
        )
        bot_reply = response.choices[0].message.content  # Extract response message
    except Exception as e:
        bot_reply = f"⚠️ An error occurred: {str(e)}"  # Error handling

    # Return after updating conversation history
    history.append((user_question, bot_reply))
    return history, history, ""


# ------------------------------
# πŸ” HTML View Toggle Function
# ------------------------------
def toggle_html_view(current_html, is_visible):
    """
    Function to toggle the HTML view/hide state
    """
    return (
        gr.update(value=current_html, visible=not is_visible),  # Hide/Show Text Box
        gr.update(value=current_html, visible=is_visible),      # HTML rendering opposite behavior
        not is_visible                                          # state inversion
    )


# ------------------------------
# πŸ“¦ Gradio UI configuration
# ------------------------------
with gr.Blocks() as demo:
    # Show title and description
    gr.Markdown("# πŸ“„ Financial Statement Analysis Chatbot")
    gr.Markdown("1. Convert PDF documents to HTML using the Document Parse API.\n"
                "2. Answer document-based questions with Solar LLM.")

    # πŸ”‘ API Key input window (entered directly by the user)
    api_key_input = gr.Textbox(label="πŸ”‘ Upstage API Key", type="password", placeholder="Paste your API key here")

    # πŸ“Ž File Upload + Document Conversion Button
    with gr.Row():
        file_input = gr.File(label="πŸ“Ž Upload financial statements")
        parse_btn = gr.Button("Document HTML conversion")

    # πŸ“˜ HTML output area (text + HTML toggle view)
    html_output = gr.Textbox(label="πŸ“˜ document content", lines=10, visible=True, elem_id="scrollable-html")
    html_display = gr.HTML(visible=False, elem_id="scrollable-html-display")
    toggle_html_btn = gr.Button("πŸ” Switch HTML views")
    html_visible_state = gr.State(False)  # Save view state

    # Click the Convert Document button β†’ Generate HTML
    parse_btn.click(
        fn=parse_document,
        inputs=[file_input, api_key_input],
        outputs=html_output
    )

    # When clicking the HTML view switch button β†’ Execute the toggle action
    toggle_html_btn.click(
        fn=toggle_html_view,
        inputs=[html_output, html_visible_state],
        outputs=[html_output, html_display, html_visible_state]
    )

    # πŸ’¬ Chatbot Interface
    chatbot = gr.Chatbot(label="πŸ’¬ Document-based Q&A", height=400)
    user_question = gr.Textbox(label="❓ Please enter your question", lines=2)
    answer_btn = gr.Button("Generate Answer")
    chat_state = gr.State([])  # Save conversation state

    # πŸ’‘ Example Question Button Configuration
    with gr.Row():
        gr.Markdown("πŸ’‘example questions:")
        ex1 = gr.Button("Which company's financial statements are these?")
        ex2 = gr.Button("What was the total net sales for the third quarter?")

    # Click the example question button β†’ Run question + answer
    for btn, question in [(ex1, "Which company's financial statements are these?"), (ex2, "What was the total net sales for the first quarter?")]:
        btn.click(
            fn=lambda q=question: q,        # Pass question text
            inputs=[],
            outputs=user_question
        ).then(
            fn=chat_with_document,
            inputs=[chat_state, html_output, user_question, api_key_input],
            outputs=[chatbot, chat_state, user_question],
            show_progress=True
        )

    # Submit a User Question β†’ Solar LLM Answers
    answer_btn.click(
        fn=chat_with_document,
        inputs=[chat_state, html_output, user_question, api_key_input],
        outputs=[chatbot, chat_state, user_question],
        show_progress=True
    )

# ------------------------------
# 🎨 Styling a scrollable HTML box
# ------------------------------
demo.css = """
#scrollable-html, #scrollable-html-display {
    max-height: 400px;
    overflow: auto;
    border: 1px solid #ccc;
    padding: 10px;
}
"""

# πŸš€ run app
if __name__ == "__main__":
    demo.launch()