ada error
Error: Out of range float values are not JSON compliant: nan
Json saya berikut
{"Year":[2020,2021,2022,2023,2024],"Net Receivables":[1000,1200,1500,1800,2100],"Sales":[5000,6000,7000,8000,9000],"Cost of Goods Sold":[3000,3600,4200,4800,5400],"Current Assets":[2000,2400,2800,3200,3600],"PPE":[8000,8500,9000,9500,10000],"Net PPE":[7000,7400,7800,8200,8600],"Securities":[0,0,0,0,0],"Total Assets":[15000,16000,17000,18000,19000],"Depreciation Expense":[500,550,600,650,700],"SG&A Expenses":[400,450,500,550,600],"Total Debt":[5000,5500,6000,6500,7000],"Income from Continuing Operations":[1000,1100,1200,1300,1400],"Cash from Operations":[800,900,1000,1100,1200]}
main.py
import pandas as pd
import fitz
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import JSONResponse, HTMLResponse
from fastapi.middleware.cors import CORSMiddleware

from lib.Chatbot import Chatbot
from lib.audit.Beneish import BeneishMScoreCalculator

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
    try:
        contents = await file.read()
        with fitz.open(stream=contents, filetype="pdf") as doc:
            text = ""
            for page in doc:
                text += page.get_text()

        chatbot = Chatbot()
        financial_data = chatbot.extract_financial_data(text)
        df = pd.DataFrame(financial_data)

        # Replace NaN values with None
        df = df.where(pd.notnull(df), None)

        calculator = BeneishMScoreCalculator(df)

        results = calculator.get_results()

        # Convert DataFrame and Series to dictionaries or lists for JSON serialization
        if isinstance(results, pd.DataFrame):
            results = results.to_dict(orient='records')  # For DataFrames
        elif isinstance(results, pd.Series):
            results = results.to_dict()       # For Series
        elif isinstance(results, dict):
             # Convert any nested DataFrames/Series within the dictionary
            for key, value in results.items():
                if isinstance(value, (pd.DataFrame, pd.Series)):
                    results[key] = value.to_dict(orient='records' if isinstance(value, pd.DataFrame) else 'dict')

        return JSONResponse(content={"status": "success", "results": results})
    except Exception as e:
        return JSONResponse(content={"status": "error", "message": str(e)})


@app.get("/")
async def read_index():
    with open("static/index.html", "r") as f:
        html_content = f.read()
    return HTMLResponse(content=html_content)


if __name__ == "__main__":
    import uvicorn

    uvicorn.run("main:app", host="localhost", port=1010, reload=True)
index.html
<!DOCTYPE html>
<html>
<head>
    <title>Chatbot Pemrosesan PDF</title>
    <!-- Menyertakan Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
    <!-- Menyertakan jQuery -->
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <style>
    body {
        padding-top: 50px;
    }
    #loading {
        display: none;
    }
    #results {
        display: none;
    }
    </style>
</head>
<body>
<div class="container">
    <h1 class="text-center">Unggah File PDF untuk Diproses</h1>
    <form id="upload-form">
        <div class="form-group">
            <label for="pdfFile">Pilih file PDF:</label>
            <input type="file" class="form-control-file" id="pdfFile" name="pdfFile" accept="application/pdf" required>
        </div>
        <button type="submit" class="btn btn-primary">Unggah dan Proses</button>
    </form>
    <div id="loading" class="text-center mt-3">
        <div class="spinner-border text-primary" role="status">
            <span class="sr-only">Memproses...</span>
        </div>
        <p>File Anda sedang diproses, harap tunggu...</p>
    </div>
    <div id="results" class="mt-3">
        <h3>Hasil:</h3>
        <pre id="results-content"></pre>
    </div>
</div>

<!-- Script JavaScript -->
<script>
$(document).ready(function(){
    $('#upload-form').on('submit', function(e){
        e.preventDefault();
        var formData = new FormData();
        var fileInput = $('#pdfFile')[0];
        if (fileInput.files.length === 0) {
            alert("Silakan pilih file PDF.");
            return;
        }
        formData.append('file', fileInput.files[0]);

        // Menampilkan indikator pemrosesan
        $('#loading').show();
        $('#results').hide();

        $.ajax({
            url: '/upload',
            type: 'POST',
            data: formData,
            processData: false, // Jangan biarkan jQuery memproses data
            contentType: false, // Jangan tetapkan contentType
            success: function(response){
                // Sembunyikan indikator pemrosesan
                $('#loading').hide();
                if (response.status == "success") {
                    $('#results-content').text(JSON.stringify(response.results, null, 2));
                    $('#results').show();
                } else {
                    alert("Error: " + response.message);
                }
            },
            error: function(xhr, status, error){
                // Sembunyikan indikator pemrosesan
                $('#loading').hide();
                alert("Terjadi kesalahan saat memproses file.");
            }
        });
    });
});
</script>
</body>
</html>
Chatbot.py
import json

from llama_cpp import Llama


class Chatbot:
    def __init__(self, n_gpu_layers=-1, n_ctx=4096, verbose=True):
        self.model_path = (
            "./model/llm/14b/aidit-14b-instruct-q4_k_m-00001-of-00003.gguf"
        )
        self.llm = Llama(
            model_path=self.model_path,
            n_gpu_layers=n_gpu_layers,
            n_ctx=n_ctx,
            verbose=verbose,
        )
        self.system_prompt = """
        You are a specialized chatbot designed to convert financial data from PDF documents into a structured JSON format. Your primary function is to extract relevant information from the provided PDF content and organize it into the following JSON structure:
            {
                "Year":<array of years>,
                "Net Receivables": <array of net receivables>,
                "Sales": <array of sales>,
                "Cost of Goods Sold": <array of cost of goods sold>,
                "Current Assets": <array of current assets>,
                "PPE": <array of PPE>,
                "Net PPE": <array of net PPE>,
                "Securities": <array of securities, if not available, use 0>,
                "Total Assets": <array of total assets>,
                "Depreciation Expense": <array of depreciation expenses>,
                "SG&A Expenses": <array of SG&A expenses>,
                "Total Debt": <array of total debt>,
                "Income from Continuing Operations": <array of income from continuing operations>,
                "Cash from Operations": <array of cash from operations>
            }
        Write ONLY JSON data without codeblock to the standard output. The JSON data should be formatted as a single line without any leading or trailing whitespaces.
        write "END" in new line to finish the conversation.
        """

    def extract_financial_data(self, text):
        output = self.llm.create_completion(
            prompt=f"{self.system_prompt}\n{text}",
            echo=False,
            max_tokens=None,
            stream=True,
            stop=["END"],
        )

        answer = ""
        for item in output:
            answer += item["choices"][0]["text"]
            print(item["choices"][0]["text"], end="")
        return json.loads(answer)


Perbaiki seperti senior programmer, perbaiki selengkap-lengkapnya agar tidak memiliki masalah tersebut!