Running python script in Laravel
Asked Answered
P

3

23

So, I am trying to run a python script in my Laravel 5.3.

This function is inside my Controller. This simply passes data to my python script

public function imageSearch(Request $request) {
    $queryImage = 'c:\\\xampp\\\htdocs\\\identificare_api\\\public\\\gallery\\\herbs\\\query.png'; //queryImage
    $trainImage = 'c:\\\xampp\\\htdocs\\\identificare_api\\\public\\\gallery\\\herbs\\\2nd.png'; //trainImage
    $trainImage1 = 'c:\\\xampp\\\htdocs\\\identificare_api\\\public\\\gallery\\\herbs\\\3rd.png';
    $trainImage2 = 'c:\\\xampp\\\htdocs\\\identificare_api\\\public\\\gallery\\\herbs\\\4th.jpg';
    $trainImage3 = 'c:\\\xampp\\\htdocs\\\identificare_api\\\public\\\gallery\\\herbs\\\1st.jpg';

    $data = array
        (
            array(0, $queryImage),
            array(1, $trainImage),
            array(3, $trainImage1),
            array(5, $trainImage2),
            array(7, $trainImage3),
        );

    $count= count($data);
    $a = 1;
    $string = "";

    foreach( $data as $d){
        $string .= $d[0] . '-' . $d[1];

        if($a < $count){
            $string .= ","; 
        }
        $a++;

    }

    $result = shell_exec("C:\Python27\python c:\xampp\htdocs\identificare_api\app\http\controllers\ORB\orb.py " . escapeshellarg($string));

    echo $result;
}

My python script is an ORB algorithm where it returns the smallest distance and its id after comparing the train images to the query image. So, this is my python script:

import cv2
import sys
import json
from matplotlib import pyplot as plt

arrayString = sys.argv[1].split(",")

final = []

for i in range(len(arrayString)):
    final.append(arrayString[i].split("-"))

img1 = cv2.imread(final[0][1], 0)

for i in range(1, len(arrayString)):

    img2 = cv2.imread(final[i][1], 0)

    # Initiate STAR detector
    orb = cv2.ORB_create()

    # find the keypoints and descriptors with SIFT
    kp1, des1 = orb.detectAndCompute(img1,None)
    kp2, des2 = orb.detectAndCompute(img2,None)

    # create BFMatcher object
    bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

    # Match descriptors.
    matches = bf.match(des1,des2)

    # Sort them in the order of their distance.
    matches = sorted(matches, key = lambda x:x.distance)

    # Draw first 10 matches.
    img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10], None, flags=2)

    if i == 1:
       distance = matches[0].distance
    else:
       if distance > matches[0].distance:
           distance = matches[0].distance
           smallestID = final[i][0]

print str(smallestID) + "-" + json.dumps(distance)

I already tried running both file without using Laravel and it is working well. But when I tried to integrate the php code to my Laravel, it displays nothing. The Status code is 200 OK.

EDIT: Problem Solved. In PHP code, just change

$result = shell_exec("C:\Python27\python c:\xampp\htdocs\identificare_api\app\http\controllers\ORB\orb.py " . escapeshellarg($string));

to

$result = shell_exec("python " . app_path(). "\http\controllers\ORB\orb.py " . escapeshellarg($string));

then, you can also do like this

$queryImage = public_path() . "\gallery\herbs\query.png";
Piane answered 7/12, 2016 at 14:31 Comment(0)
B
43

Use Symfony Process. https://symfony.com/doc/current/components/process.html

Install:

composer require symfony/process

Code:

use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;

$process = new Process(['python', '/path/to/your_script.py']);
$process->run();

// executes after the command finishes
if (!$process->isSuccessful()) {
    throw new ProcessFailedException($process);
}

echo $process->getOutput();
Bois answered 7/12, 2016 at 14:42 Comment(10)
I edited my question above. I didn't able to use the Symfony Process anymore which you have suggested. Thanks anyway!Piane
This actually gave me an exception showing a subtle error why 'shell_exec' wouldn't work. I left the symfony version, just in case more errors show up in the future. Thanks.Interrelation
As per below I used symphony process to call my python script which is in a virtual environment. My script imports a library (downloaded from pip) and works well from the shell command but strangely when script called from Laravel the imported library cannot be found, ModuleNotFound exception. Did you already encounter the problem? (the lib path is already in python path)Synchro
@mg3 did you solve that issue, that is what is happening with me, "module pymysql not found"Sheugh
@caro...yes, my issue was i am using virtual environment and i created a special one for my python files and libraries.So in command line, I launch files from this environment but from Laravel, it used the normal python environment on my laptop and not the virtual one which contains appropriate libraries. The solution was from the Laravel command to activate the proper virtual environment before launching the python script. Something like : $process = new Process("c:\Users\myPC\Envs\CloudScrapper\Scripts\activate.bat && python {$path}myFile.py {$json}");Synchro
I placed the python codes in public folder and did everything as mentioned and it is working if i run project with php artisan serve but not working when i call public folder of the project.What am I missing ??Cracked
its worked fine...But how to pass arguments to pythonKuroshio
@CelinVeronicca new Process(['python', '/path/to/your_script.py', 'arg-1', 'arg2'])Bois
This did not work when i used php artisan: serve, i had to use wamp for this to workHaldane
For those confused, this is already included with Laravel, no longer needs to be installed, when trying to require it, it actually fails, because it tries to install a different version but I was able to use the included version without issue.Commorancy
D
7

The solution that worked for me was to add 2>&1 to the end.

shell_exec("python path/to/script.py 2>&1");

The issue I was having was no error and no response, I had the wrong path to the script but no way of knowing. 2>&1 will redirect the debug info to be the result.

In the shell, what does " 2>&1 " mean?

Danit answered 19/1, 2019 at 11:55 Comment(0)
M
4

Would be handy to use Symfony Process. https://symfony.com/doc/current/components/process.html

Make sure symfony is available to use in your project

composer show symfony/process

If not installed do composer require symfony/process

And then do some thing like

use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;

//$process = new Process('python /path/to/your_script.py'); //This won't be handy when going to pass argument
$process = new Process(['python','/path/to/your_script.py',$arg(optional)]);
$process->run();

// executes after the command finishes
if (!$process->isSuccessful()) {
    throw new ProcessFailedException($process);
}

echo $process->getOutput();
Medical answered 22/4, 2019 at 10:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.