我不在乎你做什么项目,但我建议你做一些具体的事情,而不是瞄准太大胆的目标 —— Elad Gil(Investor of Silicon Valley)
Requirements Background
markitdown - github stars: 33k .
今天,看到有人将微软开源的markitdown Python库包装了一个桌面应用,使用的是Electron 技术栈,但是没开源。我就想自己试一试。
由于自己一直在学Rust,也在使用Tauri,但我自身是一名前端工程师,一直想打通各种语言的界限,特别是Node.js和Ptyhon。由于官网上只有集成Node.js的教程,就想试一试在Tauri.app 如何集成Python。
当然,为了提高效率,必须使用AI协助,下面是整个过程。
START - AI ASSISTANT
LLM: Claude 3.5 Sonnet
AI APP: Claude Desktop App
1. how to get started?
- 1
- 2
- 3
- 4
- 5
I am using tauri(2.x) to develop one tool application, now I want to execute python codes inner the app.
please providing one available solution and detailed implement steps.
if there are anything unclear, please point it out.
COPY
**Response**
Integrating Python Execution in Tauri 2.x
Prerequisites
- Tauri 2.x project set up
- Python installed on development machine
- pip package manager
- Rust toolchain
Implementation Steps
1. Project Structure
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
your-app/
├── src/
│ ├── main.rs
│ └── python/
│ ├── main.py
│ └── requirements.txt
├── src-tauri/
│ ├── Cargo.toml
│ └── tauri.conf.json
└── package.json
COPY
2. Python Script Setup
Create src/python/main.py
:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
import sys
import json
def main():
# Get input from stdin
input_data = sys.stdin.readline()
# Parse the JSON input
try:
data = json.loads(input_data)
# Example: Process the data
result = {
"status": "success",
"result": f"Processed: {data['command']}"
}
except Exception as e:
result = {
"status": "error",
"error": str(e)
}
# Send result back
print(json.dumps(result))
if __name__ == "__main__":
main()
COPY
3. Rust Implementation
Update src-tauri/Cargo.toml
:
- 1
- 2
- 3
- 4
- 5
[dependencies]
tauri = { version = "2.0.0-alpha" }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1.0", features = ["full"] }
COPY
Update src/main.rs
:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
use std::process::{Command, Stdio};
use std::io::Write;
use tauri::{command, State};
use serde::{Deserialize, Serialize};
struct PythonCommand {
command: String,
}
struct PythonResponse {
status: String,
result: Option<String>,
error: Option<String>,
}
async fn execute_python(command: PythonCommand) -> Result<PythonResponse, String> {
let python_executable = if cfg!(debug_assertions) {
"python" // Use system Python in debug
} else {
"./resources/python/python" // Use bundled Python in release
};
let mut child = Command::new(python_executable)
.arg("./resources/python/main.py")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.map_err(|e| e.to_string())?;
// Write command to Python process
let stdin = child.stdin.as_mut().unwrap();
stdin.write_all(serde_json::to_string(&command).unwrap().as_bytes())
.map_err(|e| e.to_string())?;
stdin.write_all(b"\n").map_err(|e| e.to_string())?;
// Read response
let output = child.wait_with_output().map_err(|e| e.to_string())?;
let response: PythonResponse = serde_json::from_slice(&output.stdout)
.map_err(|e| e.to_string())?;
Ok(response)
}
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![execute_python])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
COPY
4. Frontend Integration
Example usage in your frontend code:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
import { invoke } from '@tauri-apps/api';
async function runPythonCode() {
try {
const response = await invoke('execute_python', {
command: {
command: 'your_command_here'
}
});
console.log('Python response:', response);
} catch (error) {
console.error('Error executing Python:', error);
}
}
COPY
5. Production Build Setup
Install PyInstaller:
- 1
pip install pyinstaller
COPYCreate a build script
build-python.sh
:- 1
- 2
- 3
- 4
cd src/python pyinstaller --onefile main.py cp dist/main ./../../src-tauri/resources/python/
COPYUpdate
tauri.conf.json
:- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
{ "build": { "beforeBuildCommand": "bash build-python.sh", "resources": [ "resources/python/*" ] } }
COPY
Important Notes
Development vs Production:
- In development, the code uses the system Python
- In production, it uses the bundled Python executable created by PyInstaller
Security Considerations:
- Validate all input from the frontend before passing to Python
- Consider implementing proper error handling and timeout mechanisms
- Be cautious with file system operations in Python code
Cross-Platform Considerations:
- PyInstaller needs to create executables for each target platform
- Path separators should be handled properly for cross-platform compatibility
- Python executable name differs on Windows (
python.exe
)
Performance:
- Each Python execution creates a new process
- For better performance with frequent calls, consider implementing a Python process pool
Package Management:
- All Python packages are installed in a virtual environment
- The virtual environment is recreated during development setup
- Production builds include all required packages in the PyInstaller bundle
Cross-Platform Considerations:
- Setup scripts are provided for both Windows (.bat) and Unix (.sh) systems
- Path handling is normalized using Node.js path module
- PyInstaller creates platform-specific executables
Development Workflow:
- Run
npm run setup:python
to initialize/update the Python environment - During development, the app uses the virtual environment
- Production builds create a self-contained Python executable
- Run
Adding New Python Libraries:
- Add the library to
requirements.txt
- Create a wrapper in
scripts/
directory - Update
main.py
to handle new commands - Add the library to
hiddenimports
inmain.spec
- Run
npm run setup:python
to update the environment
- Add the library to
Security Notes:
- The virtual environment isolates Python dependencies
- Package versions should be pinned in
requirements.txt
- Input validation should be implemented for all Python commands
I'll help you integrate Python execution within your Tauri 2.x application. I'll provide a solution using pyinstaller to bundle Python with your app and communicate between Rust and Python.
A few points to clarify:
- Are you planning to run the Python code in development mode only, or do you need it in the production build as well? This affects how we should bundle Python with your application.
- What kind of Python operations do you need to perform? This could impact whether we need additional security measures or performance optimizations.
- Which platforms (Windows/Mac/Linux) do you need to support? This affects the build process and path handling.
Let me know if you need clarification on any part of the implementation or have specific requirements I should address.
2. To clarify some key points based on AI's responses, as follows:
- 1
- 2
- 3
- 4
go on. I will clarify something:
* I want to run the Python code in development and production mode.
* I want to wrap some helpful Python libraries then execute them, such as the open source library of markitdown by microsoft. Of course, I want to install any Python libraries inner the application.
* I want to support all platforms(Windows/Mac/Linux)
COPY
**Response**
Thank you for the clarification. Let me provide a more specific solution with Python package management and multi-platform support.
Integrating Python Execution in Tauri 2.x
Prerequisites
- Tauri 2.x project set up
- Python installed on development machine (3.8+ recommended)
- pip package manager
- Rust toolchain
- virtualenv (
pip install virtualenv
)
Implementation Steps
1. Enhanced Project Structure
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
your-app/
├── src/
│ ├── main.rs
│ └── python/
│ ├── main.py
│ ├── requirements.txt
│ ├── venv/ # Virtual environment
│ └── scripts/
│ ├── __init__.py
│ └── markdown_helper.py # Example wrapper for markitdown
├── src-tauri/
│ ├── Cargo.toml
│ ├── tauri.conf.json
│ └── scripts/
│ ├── setup_python.sh # Unix setup script
│ └── setup_python.bat # Windows setup script
└── package.json
COPY
2. Python Virtual Environment Setup
Create src-tauri/scripts/setup_python.sh
:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
PYTHON_DIR="$PROJECT_ROOT/src/python"
# Create virtual environment if it doesn't exist
if [ ! -d "$PYTHON_DIR/venv" ]; then
python -m virtualenv "$PYTHON_DIR/venv"
fi
# Activate virtual environment and install packages
source "$PYTHON_DIR/venv/bin/activate"
pip install -r "$PYTHON_DIR/requirements.txt"
# Create dist directory if it doesn't exist
mkdir -p "$PROJECT_ROOT/src-tauri/resources/python"
COPY
Create src-tauri/scripts/setup_python.bat
:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
@echo off
setlocal
set SCRIPT_DIR=%~dp0
set PROJECT_ROOT=%SCRIPT_DIR%\..\..
set PYTHON_DIR=%PROJECT_ROOT%\src\python
:: Create virtual environment if it doesn't exist
if not exist "%PYTHON_DIR%\venv" (
python -m virtualenv "%PYTHON_DIR%\venv"
)
:: Activate virtual environment and install packages
call "%PYTHON_DIR%\venv\Scripts\activate.bat"
pip install -r "%PYTHON_DIR%\requirements.txt"
:: Create dist directory if it doesn't exist
mkdir "%PROJECT_ROOT%\src-tauri\resources\python" 2>nul
COPY
3. Python Package Management
Update src/python/requirements.txt
:
- 1
- 2
- 3
markitdown
pyinstaller
# Add other required packages here
COPY
Create src/python/scripts/markdown_helper.py
:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
from markitdown import markitdown
import json
class MarkdownHelper:
def process_markdown(text):
try:
result = markitdown.to_html(text)
return {
"status": "success",
"result": result
}
except Exception as e:
return {
"status": "error",
"error": str(e)
}
COPY
Update src/python/main.py
:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
import sys
import json
from scripts.markdown_helper import MarkdownHelper
def main():
input_data = sys.stdin.readline()
try:
data = json.loads(input_data)
command = data.get('command')
if command == 'process_markdown':
result = MarkdownHelper.process_markdown(data.get('text', ''))
else:
result = {
"status": "error",
"error": f"Unknown command: {command}"
}
except Exception as e:
result = {
"status": "error",
"error": str(e)
}
print(json.dumps(result))
if __name__ == "__main__":
main()
COPY
4. Cross-Platform Build Setup
Update package.json
:
- 1
- 2
- 3
- 4
- 5
- 6
{
"scripts": {
"setup:python": "node scripts/setup-python.js",
"build": "npm run setup:python && tauri build"
}
}
COPY
Create scripts/setup-python.js
:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
const { execSync } = require('child_process');
const path = require('path');
const os = require('os');
const isWindows = os.platform() === 'win32';
const setupScript = isWindows ? 'setup_python.bat' : 'setup_python.sh';
const scriptPath = path.join(__dirname, '../src-tauri/scripts', setupScript);
try {
execSync(isWindows ? scriptPath : `bash ${scriptPath}`, {
stdio: 'inherit'
});
} catch (error) {
console.error('Failed to setup Python environment:', error);
process.exit(1);
}
COPY
5. Updated Frontend Integration
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
import { invoke } from '@tauri-apps/api';
interface MarkdownResponse {
status: string;
result?: string;
error?: string;
}
async function processMarkdown(text: string): Promise<MarkdownResponse> {
try {
const response = await invoke('execute_python', {
command: {
command: 'process_markdown',
text: text
}
});
return response as MarkdownResponse;
} catch (error) {
console.error('Error processing markdown:', error);
throw error;
}
}
// Usage example
const markdown = "# Hello World\nThis is a test";
const result = await processMarkdown(markdown);
if (result.status === 'success') {
console.log('HTML:', result.result);
} else {
console.error('Error:', result.error);
}
COPY
6. Production Build Process
Update
tauri.conf.json
:- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
{ "build": { "beforeBuildCommand": "npm run setup:python", "resources": [ "resources/python/*" ], "windows": { "webviewInstallMode": { "silent": true } } } }
COPYCreate a PyInstaller spec file
src/python/main.spec
: ```python block_cipher = None
a = Analysis( ['main.py'], pathex=[], binaries=[], datas=[('scripts', 'scripts')], # Include scripts directory hiddenimports=['markitdown'], # Add required packages hookspath=[], hooksconfig={}, runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False, )
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE( pyz, a.scripts, a.binaries, a.zipfiles, a.datas, [], name='main', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, upx_exclude=[], runtime_tmpdir=None, console=True, disable_windowed_traceback=False, target_arch=None, codesign_identity=None, entitlements_file=None, )
```
Important Notes
Package Management:
- All Python packages are installed in a virtual environment
- The virtual environment is recreated during development setup
- Production builds include all required packages in the PyInstaller bundle
Cross-Platform Considerations:
- Setup scripts are provided for both Windows (.bat) and Unix (.sh) systems
- Path handling is normalized using Node.js path module
- PyInstaller creates platform-specific executables
Development Workflow:
- Run
npm run setup:python
to initialize/update the Python environment - During development, the app uses the virtual environment
- Production builds create a self-contained Python executable
- Run
Adding New Python Libraries:
- Add the library to
requirements.txt
- Create a wrapper in
scripts/
directory - Update
main.py
to handle new commands - Add the library to
hiddenimports
inmain.spec
- Run
npm run setup:python
to update the environment
- Add the library to
Security Notes:
- The virtual environment isolates Python dependencies
- Package versions should be pinned in
requirements.txt
- Input validation should be implemented for all Python commands
**** END - AI ASSISTANT ****
评论区
写评论
登录
所以,就随便说点什么吧...
这里什么都没有,快来评论吧...