I'm trying to run a python script inside a Nodejs project. Everything works pretty well passing a local video URL in my python script, but I need to retrieve the video URL from my MongoDB and pass it to the python script. Is there a way I can do this? I have made some research and couldn't find a way to solve this issue.
app.get('/test', callName);
function callName(req, res) {
PythonShell.run('ai_part/test.py', null, function (err) {
if (err) throw err;
console.log('finished');
});
}
Python code:
#Loading the video input
cap = cv2.VideoCapture('test.wmv')
_, img = cap.read()
height, width, _ = img.shape
copy = img.copy()
I don't know if it is clear enough, but I need to pass a video URL acquired from my mongo database into the python function 'VideoCapture(url)'. Thanks in advance!
Like the documentation tells you,
function callName(req, res) {
let options = {
mode: 'text',
args: [res]
};
PythonShell.run('ai_part/test.py', options, function (err) {
if (err) throw err;
console.log('finished');
});
}
Related
The problem
I am creating an Electron-React frontend for my Python script.
Electron and Python communicate via Node.js child_process module, using the function spawn to call my Python script.
The script does the following task:
Gets path to a folder, which contains 15 pdf files.
Loads 1 pdf file at a time.
Skims through it to find the first word of the 5th page.
Saves the result in a list.
Continues until all pdf files have been read.
As you can see, this takes some time to process this script.
What I want to do: Once the process is called from Electron, I want the progress bar to appear, indicating how many pdf files are processed out of the 15 given. For example: 1/15 done, 2/15 done, and etc.
I tried googling the answer but after a week I'm at my wits end. I would very much appreciate any help I could get.
Disclaimer: I know of other good packages like Python Eel which does the job (sort of, in a hackish way). But I really want it to work with CLI.
The setup
I used Electron React Boilerplate for my purposes.
For simplicity I used a dummy function for python:
assets/python/main.py
import sys
import time
# Track the progress
progress = 0
def doStuff():
# Access the global variable
global progress
# Simulate time taken to do stuff. Set at 30 seconds per iteration.
for i in range(15):
progress += 1
time.sleep(30)
# The result
return "It is done!"
# Print is used to get the result for stdout.
print(doStuff())
src/main/main.ts
import { spawn } from 'child_process';
import path from 'path';
import { app, BrowserWindow, ipcMain, webContents } from 'electron';
...
let mainWindow: BrowserWindow | null = null;
...
app
.whenReady()
.then(() => {
ipcMain.handle('readPdfs', async (event, arg) => {
// Spawn a python instance
const python = spawn('python', [
path.join(__dirname, '..', '..', 'assets', 'python', 'main.py')
]);
// Get the result and pass it on to the frontend
python.stdout.on('data', (data) => {
const result = data.toString('utf8');
mainWindow.webContents.send('output', result);
});
});
...
src/main/preload.ts
import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron';
...
let mainWindow: BrowserWindow | null = null;
...
contextBridge.exposeInMainWorld('electron', {
...
// Just sending a command forward and getting a response.
readPdfs: async () => ipcRenderer.invoke('readPdfs'),
readPdfsOutput: (callback: any) => ipcRenderer.on('output', callback),
});
src/renderer/App.tsx
const Hello = () => {
const [text, setText] = useState('');
const handleReadPdfs = async (): Promise<void> => {
await window.electron.readPdfs();
await window.electron.output((event: any, response: string) => {
setText(response);
});
};
The question
What I have set up works. I manage to get the "It is done!" message all right. The problem is I want to get the value progress from main.py every time it increments, while the process is busy reading the pdfs.
Is there a way to get that value from the python script using child_process without interrupting a time consuming process?
Some Python libraries output the result of their functions to STDOUT - and in a Python UDF in Snowflake I need to capture that value to a String to return it.
For example the output of help() or numpy.show_config().
You can capture stdout using contextlib.redirect_stdout.
For example, to capture the output of help(numpy):
create or replace function help_numpy()
returns string
language python
runtime_version = '3.8'
packages = ('numpy')
handler = 'x'
as $$
import io
from contextlib import redirect_stdout
from pydoc import help
import numpy
def x():
f = io.StringIO()
with redirect_stdout(f):
help(numpy)
return f.getvalue()
$$;
select help_numpy();
Or to capture the output of numpy.show_config() you just need to replace the functions called inside the redirect_stdout() block:
with redirect_stdout(f):
numpy.show_config()
Note that to use help() we also had to from pydoc import help. Otherwise you'll get the error NameError: name 'help' is not defined in function HELP with handler.
That's a great idea for all UDF languages. Open source JavaScript is often filled with with alert, window.alert, console.log etc. To capture the alert and console out functions in JavaScript:
create or replace function STDOUT()
returns array
language javascript
as
$$
//----- Start of standard out intercepts. Add to top of UDF
console.logs = [];
window = {};
console.log = function(){ console.logs.push({"type":"log", "timestamp":new Date().toISOString(), "out":Array.from(arguments)}) };
console.warn = function(){ console.logs.push({"type":"warn", "timestamp":new Date().toISOString(), "out":Array.from(arguments)}) };
console.error = function(){ console.logs.push({"type":"error", "timestamp":new Date().toISOString(), "out":Array.from(arguments)}) };
console.debug = function(){ console.logs.push({"type":"debug", "timestamp":new Date().toISOString(), "out":Array.from(arguments)}) };
alert = function(){ console.logs.push({"type":"alert", "timestamp":new Date().toISOString(), "out":Array.from(arguments)}) };
window.alert = function(){ console.logs.push({"type":"alert", "timestamp":new Date().toISOString(), "out":Array.from(arguments)}) };
//----- End of standard out intercepts
console.log("My log.");
console.warn("My warning");
console.error("My error");
alert("My alert");
window.alert("My window alert");
return console.logs;
$$;
select STDOUT();
Ok I'm fairly new to swift and am trying to create an app with a button that uses python. I have seem code looking like
//
// ContentView.swift
// Shared
//
// Created by Ulto4 on 10/17/21.
//
import SwiftUI
import PythonKit
struct ContentView: View {
#State private var showDetails = false
#State var result : String = " "
var body: some View {
HStack{
Text("Hello, world!")
.padding()
Button(action : {
self.coolPerson()
}, label: {
Text("Respones")
})
Text("\(result)")
}
}
func coolPerson(){
let sys = Python.import("sys")
sys.path.append("/Users/ulto4/Documents/vsc")
let example = Python.import("ahhhhh")
let response = example.hi()
result = response.description
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.preferredColorScheme(.dark)
}
}
The code in the python file is
def hello():
return "cool"
However, when I click the button I get this error
2021-10-17 17:53:16.943097-0700 GAAIN[27059:2277939] PythonKit/PythonLibrary.swift:46: Fatal error: Python library not found. Set the PYTHON_LIBRARY environment variable with the path to a Python library.
(lldb)
I also clicked the .xcodeproj and deleted the Apple Sandbox. But it still doesn't work. Since I'm fairly new I don't know how to do this. Any help would be appreciated.
EDIT: As per the comments, IOS doesn't support PythonKIT
Set Up
I am having an odd problem.
I have a website and I am hoping to run a python script when someone presses a button.
So, I have followed this tutorial: https://www.npmjs.com/package/python-shell
Question:
My console prints this: ReferenceError: require is not defined
on this line: var PythonShell = require('python-shell');
This is the first line in my .js function. I added this line after the npm install step.
How do I overcome this error?
Potentially Helpful Notes
My script looks like this:
angular.module('MYApp')
.controller('MyTypeController', function ($scope, $http, $stateParams, $state) {
$scope.runPythonRoutine = function () {
console.log("Error 1");
var PythonShell = require('python-shell');
var myshell = new PythonShell.run('hello.py', function (err, results) {
console.log("Error 2");
// script finished
});
};
...
My package.json contains:
...
"node-uuid": "1.4.7",
"python-shell": "^0.5.0",
...
require() does not exist in the browser/client-side JavaScript. You need require.js to use require() in the browser. You must also add this to package.json:
"require.js": "version"
and specify require.js in the <script> tag of the html code at the bottom, like so:
<script src="/location/of/require.js/"></script>
The Setup:
I have an NGINX web server. On a web page I am running the javascript to refresh the file tmp_image.jpg every half a second:
var img = new Image();
img.onload = function() {
var canvas = document.getElementById("x");
var context = canvas.getContext("2d");
context.drawImage(img, 0, 0);
setTimeout(timedRefresh, 500);
};
function timedRefresh() {
// just change src attribute, will always trigger the onload callback
try {
img.src = 'tmp_image.jpg?d=' + Date.now();
}catch(e){
console.log(e);
}
}
setTimeout(timedRefresh, 100);
With the HTML:
<canvas id="x" width="700px" height="500px"></canvas>
On another process using a raspberry pi camera I am running a script to write a image to a file tmp_image.jpg with the library picamera:
for frame in cam.camera.capture_continuous(raw, format="rgb", use_video_port=True):
img = frame.array
cv2.imwrite("tmp_image.jpg", img)
The problem:
I am receiving the error:
GET http://192.168.1.234/images/tmp_img.jpg?d=1513855080653 net::ERR_CONTENT_LENGTH_MISMATCH
Which then leads the refresh to crash (even though I have put it in a try catch)
I believe this is because NGINX is trying to read the file while it is being written to. So what should I do? And is this awfully inefficient?