I want to write a python program with gradio that can let the LLM generate excel file with the process as follow:
1. LLM will generate the csv format text as user required
2. The program will detect the LLM generated output, then convert to excel format
3. Have a convert to excel button that can let the user to choose to convert the llm output to excel file if he want

My original program for running the llm with multiturn conversation and chat with pdf:
"
# Pdf, work

import os
import time
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer, BitsAndBytesConfig
import gradio as gr
from threading import Thread
from PyPDF2 import PdfReader  # Import PyPDF2 for PDF text extraction

MODEL_PATH = r"C:\Users\shermanhonsf\Desktop\Python\llama_develop\model\Llama3.2-1B-Instruct-HF-Model"  # Your model path

TITLE = """
Chat with Llama 3.2 1B
"""

PLACEHOLDER = """
Hi, I'm Llama. Ask me anything or upload a PDF to chat about its content.
"""

CSS = """
.duplicate-button {
    margin: auto !important;
    color: white !important;
    background: black !important;
    border-radius: 100vh !important;
}
h3 {
    text-align: center;
}
"""

# Set the device to "cuda" if you have a compatible GPU, otherwise "cpu"
device = "cuda" if torch.cuda.is_available() else "cpu"

# Configure quantization if needed (optional)
quantization_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4"
)

# Load the tokenizer and model from the local directory
tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH)
model = AutoModelForCausalLM.from_pretrained(
    MODEL_PATH,
    torch_dtype=torch.bfloat16,
    device_map="auto",
    # quantization_config=quantization_config
)

# Move the model to the appropriate device
model.to(device)


def extract_pdf_text(pdf_path):
    """Extract all text from a PDF file."""
    try:
        reader = PdfReader(pdf_path)
        text = ""
        for page in reader.pages:
            text += page.extract_text()
        return text
    except Exception as e:
        return f"Error reading PDF: {e}"


def stream_chat(message: str, history: list, system_prompt: str ="You are a helpful assistant. When asked to generate tabular data, please follow these rules:\n"
                    "1. Produce the specified data as a CSV table with a header row.\n"
                    "2. Ensure that fields in the CSV are separated by commas (',').\n"
                    "3. Enclose the CSV output with markers: \n"
                    "   - Begin with `#START_CSV`.\n"
                    "   - End with `#END_CSV`.\n",
                temperature: float = 0.8, max_new_tokens: int = 1024, top_p: float = 1.0, top_k: int = 20, penalty: float = 1.2, pdf_text: str = ""):
    print(f'message: {message}')
    print(f'history: {history}')
    print(f'system_prompt: {system_prompt}')
    print(f'temperature: {temperature}')
    print(f'max_new_tokens: {max_new_tokens}')
    print(f'top_p: {top_p}')
    print(f'top_k: {top_k}')
    print(f'penalty: {penalty}')
    print(f'Message: {message}')
    print(f'History: {history}')
    print(f'PDF Text: {pdf_text}')

    conversation = [
        {"role": "system", "content": system_prompt}
    ]

    # Add PDF content to the system prompt if provided
    if pdf_text.strip():
        pdf_summary = f"The user uploaded a PDF with the following content:\n{pdf_text[:2000]}...\n(This is a truncated summary if the text is too long.)"
        conversation.append({"role": "system", "content": pdf_summary})

    for prompt, answer in history:
        conversation.extend([
            {"role": "user", "content": prompt},
            {"role": "assistant", "content": answer},
        ])

    conversation.append({"role": "user", "content": message})

    # Prepare input IDs
    input_ids = tokenizer.apply_chat_template(
        conversation,
        # tokenize=True,
        add_generation_prompt=True,
        return_tensors="pt"
    ).to(device)

    streamer = TextIteratorStreamer(
        tokenizer,
        timeout=60.0,
        skip_prompt=True,
        skip_special_tokens=True
    )

    generate_kwargs = dict(
        input_ids=input_ids,
        max_new_tokens=max_new_tokens,
        do_sample=False if temperature == 0 else True,
        top_p=top_p,
        top_k=top_k,
        temperature=temperature,
        eos_token_id=[128001, 128008, 128009],
        streamer=streamer,
    )

    # Generate the response in a background thread
    with torch.no_grad():
        thread = Thread(target=model.generate, kwargs=generate_kwargs)
        thread.start()

    # Stream the response back to the user
    buffer = ""
    for new_text in streamer:
        buffer += new_text
        yield buffer


# Create the Gradio interface
chatbot = gr.Chatbot(height=600, show_copy_button=True, layout="panel", placeholder=PLACEHOLDER)

with gr.Blocks(css=CSS) as demo:
    gr.HTML(TITLE)
    
    # Add file uploader for PDF input
    pdf_file = gr.File(label="Upload PDF", type="filepath")
    pdf_textbox = gr.Textbox(label="Extracted PDF Text", placeholder="PDF content will appear here after upload.", lines=10, interactive=False)
    
    def process_pdf(file):
        if file is not None:
            pdf_text = extract_pdf_text(file.name)
            return pdf_text
        return "No PDF uploaded."

    pdf_file.change(process_pdf, inputs=pdf_file, outputs=pdf_textbox)
    
    gr.ChatInterface(
        fn=stream_chat,
        chatbot=chatbot,
        fill_height=True,
        additional_inputs_accordion=gr.Accordion(
            label="⚙️ Parameters",
            open=False,
            render=False
        ),
        additional_inputs=[
            gr.Textbox(
                value="You are a helpful assistant. When asked to generate tabular data, please follow these rules:\n"
                    "1. Produce the specified data as a CSV table with a header row.\n"
                    "2. Ensure that fields in the CSV are separated by commas (',').\n"
                    "3. Enclose the CSV output with markers: \n"
                    "   - Begin with `#START_CSV`.\n"
                    "   - End with `#END_CSV`.\n",
                label="System Prompt",
                render=False,
            ),
            gr.Slider(
                minimum=0,
                maximum=1,
                step=0.1,
                value=0.8,
                label="Temperature",
                render=False,
            ),
            gr.Slider(
                minimum=128,
                maximum=8192,
                step=1,
                value=1024,
                label="Max new tokens",
                render=False,
            ),
            gr.Slider(
                minimum=0.0,
                maximum=1.0,
                step=0.1,
                value=1.0,
                label="Top_p",
                render=False,
            ),
            gr.Slider(
                minimum=1,
                maximum=20,
                step=1,
                value=20,
                label="Top_k",
                render=False,
            ),
            gr.Slider(
                minimum=0.0,
                maximum=2.0,
                step=0.1,
                value=1.2,
                label="Repetition penalty",
                render=False,
            ),
            pdf_textbox  # Pass the extracted PDF text as an additional input
        ],
        examples=[
            ["What are the main themes explored in the movie 'Dune', and how do they reflect contemporary issues? "],
            ["What are 3 practical techniques I can use to prioritize tasks more effectively in a busy work schedule? "],
            ["How does blockchain technology work, and what are its potential applications beyond cryptocurrencies? "],
            ["Show me a code snippet of a website's sticky header in CSS and JavaScript."],
        ],
        cache_examples=False,
    )

if __name__ == "__main__":
    demo.launch(debug=True)
"
The sample code of detecting the llm csv output then convert to excel format (For your reference):
"
import pandas as pd
import re

def extract_csv_data(llm_output):
    # Find the start and end markers for the CSV content
    start_marker = "#START_CSV"
    end_marker = "#END_CSV"
    
    # Get the content between the markers
    start_index = llm_output.find(start_marker)
    end_index = llm_output.find(end_marker)

    if start_index == -1 or end_index == -1:
        print("CSV markers not found in the output.")
        return None
    
    # Extract the CSV data
    csv_content = llm_output[start_index + len(start_marker):end_index].strip()
    return csv_content

def convert_to_excel(llm_output, output_file='output.xlsx'):
    csv_data = extract_csv_data(llm_output)
    
    # If there's no CSV data found, we could return or raise an error
    if not csv_data:
        print("No CSV data found.")
        return

    # Read the CSV data into a DataFrame
    from io import StringIO
    df = pd.read_csv(StringIO(csv_data), sep=",")

    # Save the DataFrame to an Excel file
    df.to_excel(output_file, index=False)

# Example usage:
llm_output = """
```csv
#START_CSV
Product,SalesDate,Quantity,QuantityPerUnit,Revenue
Product A,2023-01-01,10,100.00
Product A,2023-01-02,15,150.00
Product A,2023-01-03,20,200.00
Product A,2023-01-04,25,250.00
Product A,2023-01-05,30,300.00
Product A,2023-01-06,35,350.00
Product A,2023-01-07,40,400.00
Product A,2023-01-08,45,450.00
Product A,2023-01-09,50,500.00
Product A,2023-01-10,55,550.00
#END_CSV
```

Note: 
- The SalesDate is a random date in January 2023, which can be generated using the `datetime` module in Python.
- The Quantity and QuantityPerUnit are random values within the specified range.
- The Revenue is a random value within the specified range (100.00 to 550.00).
- The Product names are also random values.
"""

convert_to_excel(llm_output, 'sales_data.xlsx')
"
Integrate the convert to excel function with my above code and keep all my original functions. Show added or modified code.