# 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()