#running a python script in vercel production through nextjs

1 messages · Page 1 of 1 (latest)

vernal heart
#
const scriptPath = path.resolve('./src/process_pdf.py');
const { stderr } = await execFilePromise(scriptPath, ['qp', pdfUrl, outputDir]);

the python file starts with #!usr/bin/env python3 but in vercel production environment, it says that python3 was not found. however if i make my install command which python3 && npm install, it says that python3 was found.

frank wagonBOT
#

Hi @vernal heart. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

It seems like you're trying to run a Python script from a Next.js application deployed on Vercel. However, you're encountering an issue where the Python3 command is not found in the Vercel production environment.

Based on the knowledge sources provided, it appears that Vercel only supports one runtime for an API, either Python or NodeJS. This might be the reason why you're encountering the issue.

One of the users in the Github issue (https://github.com/vercel/next.js/issues/61750) suggested switching from using exec to spawn from the child_process module. This approach provides a promise-based solution to asynchronously execute your Python script and handle both success and error cases. Here's the suggested code:

export const pythonExec = async () => {
  const { spawn } = require('child_process');
  console.log("I am called");
  return new Promise((resolve, reject) => {
    const pyprog = spawn('python', ["/path/to/the/code/sample-script.py"]);
    
    pyprog.stdout.on('data', function(data) {
      console.log(data.toString());
      resolve(data.toString());
    });

    pyprog.stderr.on('data', (data) => {
      console.log(data.toString());
      reject(data.toString());
    });
  });
};

Remember to replace "/path/to/the/code/sample-script.py" with the absolute path to your Python script.

Also, to ensure your Python script is included in your Next.js build, consider using the copy-webpack-plugin in your next.config.js file. This plugin will help you copy your Python code into the build directory, making deployment smoother and more reliable.

#

However, please note that these solutions are based on the information available in the knowledge sources and might not fully solve your issue. You might need to further investigate the compatibility of running Python scripts in a Node.js environment on Vercel.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@vernal heart kapa.ai is still learning and improving, please let us know how it did by reacting below

vernal heart
#

@frank wagon rewrite the following using your given solution

    const scriptPath = path.resolve('./src/process_pdf.py');

    try {
        const { stderr } = await execFilePromise(scriptPath, ['qp', pdfUrl, outputDir]);

        if (stderr) {
            console.error(stderr);
            return new NextResponse(JSON.stringify({ error: 'Error processing PDF' }), { status: 500 });
        }

        ...
frank wagonBOT
#

Let me check the knowledge base for you. One moment! :books:

#

Sure, based on the solution provided in the knowledge sources, you can rewrite your code as follows:

import { spawn } from 'child_process';
import path from 'path';

export default async function processPdf(req, res) {
  const scriptPath = path.resolve('./src/process_pdf.py');
  const pdfUrl = req.body.pdfUrl;
  const outputDir = req.body.outputDir;

  try {
    const pyprog = spawn('python', [scriptPath, 'qp', pdfUrl, outputDir]);

    pyprog.stdout.on('data', function(data) {
      console.log(data.toString());
      // handle your success case here
    });

    pyprog.stderr.on('data', (data) => {
      console.error(data.toString());
      res.status(500).json({ error: 'Error processing PDF' });
    });

  } catch (error) {
    console.error(error);
    res.status(500).json({ error: 'Error processing PDF' });
  }
}

This code uses the spawn function from the child_process module to execute the Python script. The stdout.on('data') and stderr.on('data') events are used to handle the success and error cases respectively.

Please note that this code assumes that you're using this function as a Next.js API route handler, where req is the request object and res is the response object. Also, replace 'python' with 'python3' if your environment specifically requires Python 3.

Remember to include your Python script in your Next.js build using the copy-webpack-plugin in your next.config.js file as suggested in the Github issue (https://github.com/vercel/next.js/issues/61750).

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@vernal heart kapa.ai is still learning and improving, please let us know how it did by reacting below

vernal heart
#

@frank wagon ```
Uncaught Exception: Error: spawn python3 ENOENT
at ChildProcess._handle.onexit (node:internal/child_process:286:19)
at onErrorNT (node:internal/child_process:484:16)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
errno: -2,
code: 'ENOENT',
syscall: 'spawn python3',
path: 'python3',
spawnargs: [
'/var/task/src/process_pdf.py',
'qp',
'https://pastpapers.papacambridge.com/directories/CAIE/CAIE-pastpapers/upload/0610_m23_qp_22.pdf',
'/var/task/tmp/tnou3l'
]
}
Node.js process exited with exit status: 129. The logs above can help with debugging the issue.

frank wagonBOT
#

Let me check the knowledge base for you. One moment! :books:

#

The error message Error: spawn python3 ENOENT indicates that the system can't find the python3 command. This error is common when the environment where the script is running does not have Python installed, or the Python installation is not included in the system's PATH.

In the context of a Next.js application deployed on Vercel, it's important to note that Vercel's serverless functions support only one runtime. As mentioned in the Github issue (https://github.com/vercel/next.js/issues/61750), Vercel only supports one runtime for an API, either Python or NodeJS. This means you can't run Python scripts directly from a Node.js serverless function.

If you need to run Python code as part of your Next.js application, you might need to consider other options such as:

  • Running the Python code as a separate service (e.g., a separate AWS Lambda function with Python runtime) and calling this service from your Next.js application.
  • Using a WebAssembly-based Python runtime like Pyodide, although this might have limitations and performance implications.
  • Rewriting the Python logic in JavaScript/TypeScript if feasible.

Remember to always test your application locally in an environment as close as possible to your production environment to catch these kinds of issues early in the development process.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@vernal heart kapa.ai is still learning and improving, please let us know how it did by reacting below

vernal heart
#

@frank wagon can this be rewritten in ts?

import fitz, os, sys
from requests import get

def process_ms():
    answers = []
    pdf = fitz.open(stream=get(input_pdf_path).content, filetype="pdf")

    for page_num in range(len(pdf)):
        page = pdf.load_page(page_num)
        blocks = page.get_text("dict")["blocks"]

        for b in blocks:
            if b['type'] == 0:  # Text block
                for line in b["lines"]:
                    for span in line["spans"]:
                        text = span['text'].strip()
                        if text in ['A', 'B', 'C', 'D'] and 110 < span['origin'][0] < 130:
                            answers.append(text)

    pdf.close()
    print(answers, process_gt('Component ' + sys.argv[3]))

def process_gt(paper_code):
    pdf = fitz.open(stream=get(input_pdf_path.replace('_ms_', '_gt_')[:-7] + '.pdf').content, filetype="pdf")
    tabs = pdf.load_page(0).find_tables()
    for tab in tabs:
        data = tab.extract()
        for row in data:
            for cell in row:
                if cell is not None and paper_code in cell:
                    pdf.close()
                    return [int(c) for c in row if c != '' and paper_code not in c and c != row[1]] # array of integers representing minimum marks for each grade
frank wagonBOT
#

Let me check the knowledge base for you. One moment! :books:

#

The Python script you provided seems to be processing PDF files, extracting text from them, and performing some operations based on the extracted text. While it's possible to perform similar operations in TypeScript, the exact libraries and methods used in Python might not have direct equivalents in TypeScript.

Here's a rough equivalent of your Python script in TypeScript using the pdf-parse library for PDF processing. Please note that this is a simplified version and might not cover all the functionalities of your Python script:

import * as fs from 'fs';
import * as pdf from 'pdf-parse';

async function processPdf() {
  let dataBuffer = fs.readFileSync('path_to_pdf_file.pdf');

  pdf(dataBuffer).then(function(data) {
    // number of pages
    console.log(data.numpages);
    // number of rendered pages
    console.log(data.numrender);
    // PDF info
    console.log(data.info);
    // PDF metadata
    console.log(data.metadata); 
    // PDF.js version
    // check <https://mozilla.github.io/pdf.js/getting_started/>
    console.log(data.version);
    // PDF text
    console.log(data.text);        
  });
}

processPdf();

This TypeScript code reads a PDF file and extracts various information from it, including the text. However, it doesn't perform the same operations as your Python script. The pdf-parse library used in this TypeScript code might not support all the features provided by the fitz library used in your Python script, such as getting text blocks or finding tables.

If you need more advanced PDF processing features in TypeScript, you might need to look for other libraries or consider using a service that provides a PDF processing API.

#

Please note that this TypeScript code is based on the information available in the knowledge sources and might not fully meet your requirements. You might need to further investigate the available libraries and tools for PDF processing in TypeScript.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@vernal heart kapa.ai is still learning and improving, please let us know how it did by reacting below

vernal heart
#

@frank wagon if i want to use flask as my backend instead of nextjs, and my app is located in src/app, where do i need to place the python file? currently its in src/api/index.py, and in my next config i reroute /api/:path* to /api/, is this correct? do i need to configure anything else for vercel?

frank wagonBOT
#

Let me check the knowledge base for you. One moment! :books:

#

If you want to use Flask as your backend with Next.js, you can indeed place your Python file in the src/api directory. This is because Next.js treats files in the src/api directory as API routes.

In your next.config.js, you have correctly set up a rewrite rule to map any request to /api/:path* to the Flask API. This means any request to /api/ followed by any path will be handled by your Flask application.

Here's an example of how your next.config.js might look:

module.exports = {
  async rewrites() {
    return [
      {
        source: '/api/:path*',
        destination: '<http://localhost:5328/api/:path*',> // Proxy to Backend
      },
    ]
  },
}

In this configuration, any request to /api/:path* will be redirected to your Flask server running on localhost:5328.

In a local development environment, the Flask server should be running on 127.0.0.1:5328. In a production environment, the Flask server should be hosted as Python serverless functions (https://vercel.com/docs/concepts/functions/serverless-functions/runtimes/python) on Vercel.

Please note that you need to ensure that your Flask application is correctly set up to handle the incoming requests. For example, your Flask application might look like this:

from flask import Flask
app = Flask(__name__)

@app.route('/api/hello', methods=['GET'])
def hello_world():
    return "Hello! This is Flask"

In this Flask application, a GET request to /api/hello will return the string "Hello! This is Flask".

Remember to include the necessary Python dependencies in your requirements.txt file and ensure that your Vercel project is correctly configured to use the Python runtime.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@vernal heart kapa.ai is still learning and improving, please let us know how it did by reacting below

vernal heart
#

@frank wagon vercel doesnt recognize that theres python functions

frank wagonBOT
#

Let me check the knowledge base for you. One moment! :books:

#

If Vercel doesn't recognize your Python functions, it could be due to a few reasons:

  1. File Location: Python functions should be placed in the /api directory at the root of your project. For example, a Python function could be located at /api/hello.py.

  2. Function Structure: Your Python function should be structured correctly. For instance, it should define a handler that inherits from the BaseHTTPRequestHandler class. Here's an example:

    from http.server import BaseHTTPRequestHandler
    
    class handler(BaseHTTPRequestHandler):
        def do_GET(self):
            self.send_response(200)
            self.send_header('Content-type','text/plain')
            self.end_headers()
            self.wfile.write('Hello, world!'.encode('utf-8'))
            return
    
  3. Python Runtime: Ensure that your Vercel project is correctly configured to use the Python runtime. The Python runtime is available in Beta (https://vercel.com/docs/release-phases#beta) on all plans (https://vercel.com/docs/accounts/plans). You can specify the Python version in your Pipfile:

    [requires]
    python_version = "3.12"
    
  4. Python Dependencies: If your Python functions have dependencies, they should be defined in a requirements.txt or a Pipfile with a corresponding Pipfile.lock. For example:

    Flask==3.0.3
    

If you've checked all these points and Vercel still doesn't recognize your Python functions, it might be a good idea to reach out to Vercel support or check their documentation (https://vercel.com/docs) for more information.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@vernal heart kapa.ai is still learning and improving, please let us know how it did by reacting below

vernal heart
#

@frank wagon so i need to have my structure like this? ./src/app/.... (my nextjs files) ./api/index.py for flask

frank wagonBOT
#

Let me check the knowledge base for you. One moment! :books:

#

Yes, that's correct. In a Next.js project, your application code (including app) can be stored inside the src directory. This separates application code from project configuration files which mostly live in the root of a project. So, your Next.js files would be in the src/app directory.

For your Flask application, you should place your Python files in the api directory at the root of your project. This is because Vercel treats files in the api directory as serverless functions. So, your Flask application entry point would be in api/index.py.

Here's how your project structure would look:

.
├── src
│   └── app
│       └── ... (your Next.js files)
└── api
    └── index.py (your Flask application)

Remember to set up your next.config.js to correctly route API requests to your Flask application, and ensure your Flask application is correctly set up to handle these requests.

Sources:


Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@vernal heart kapa.ai is still learning and improving, please let us know how it did by reacting below

vernal heart
#

@frank wagon anything else i need to update? like my next config or vercel config

frank wagonBOT
#

Let me check the knowledge base for you. One moment! :books:

#

Based on the information provided in the knowledge sources, here are a few things you might need to consider:

  1. Next.js Configuration (next.config.js): If you want to proxy API requests from Next.js to your Flask application, you might need to set up rewrites in your next.config.js. Here's an example:

    module.exports = {
      async rewrites() {
        return [
          {
            source: '/api/:path*',
            destination: '/api/:path*', // Proxy to Flask
          },
        ]
      },
    }
    

    This configuration will redirect any request to /api/:path* to your Flask server.

  2. Vercel Configuration (vercel.json): If you have specific configuration needs for your Vercel deployment, you might need to update your vercel.json file. For example, you might need to specify environment variables or configure routes. However, based on the information provided, it's not clear if you need to make any specific changes to your vercel.json.

  3. Python Dependencies: If your Flask application has any dependencies, make sure they are specified in a requirements.txt file or a Pipfile in the root of your project. Vercel will automatically install these dependencies when deploying your Python functions.

Remember to test your application locally and ensure that your Flask application is correctly handling the proxied requests from Next.js. Also, ensure that your Vercel project is correctly configured to use the Python runtime.

#

Please note that these suggestions are based on the information available in the knowledge sources and might not cover all the configuration needs for your specific project. You might need to refer to the Next.js (https://nextjs.org/docs) and Vercel (https://vercel.com/docs) documentation for more detailed information.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: