如何实现HTML表单调用同目录Python脚本并展示GPT响应?
问题解决与代码修改方案
核心问题分析
当前代码的关键冲突在于:Node.js通过命令行参数传递用户输入,但Python脚本却按照CGI表单的方式读取参数,两者的参数传递机制不匹配,导致Python无法获取到用户输入。此外还有几个次要问题:Python每次运行都重复安装openai包、Node.js错误时未向客户端返回响应、缺少必要的错误处理逻辑。
各文件修改后的代码(带注释)
1. Python脚本 algo.py
import sys import json import openai from openai import OpenAI # 移除重复安装openai的代码,建议提前手动执行:pip install openai # 避免每次运行脚本都重新安装,浪费资源 # 配置OpenAI API密钥 client = OpenAI( api_key='你的API密钥', # 替换为实际密钥 ) def AI_PC_Buddy(prompt): messages = [{'role': 'user', 'content': prompt}] response = client.chat.completions.create( model='gpt-3.5-turbo', messages=messages ) return response.choices[0].message.content.strip() if __name__ == "__main__": # 从命令行参数获取用户输入(Node.js传递的参数) # sys.argv[0]是脚本名,sys.argv[1]是第一个参数 if len(sys.argv) < 2: # 没有输入时返回错误信息 print(json.dumps({'response': '错误:未收到用户输入'})) sys.exit(1) prompt = sys.argv[1] try: response = AI_PC_Buddy(prompt) # 返回JSON格式的响应,和前端预期一致 print(json.dumps({'response': response})) except Exception as e: # 捕获OpenAI调用或其他异常,返回错误信息 print(json.dumps({'response': f'服务出错:{str(e)}'}))
2. Node.js服务器 server.js
const express = require('express'); const { execFile } = require('child_process'); // 改用execFile更安全,避免命令注入 const app = express(); const port = 8005; // 解析JSON请求体,前端发送的是JSON格式 app.use(express.json()); // 处理静态文件(如果需要直接访问HTML文件) app.use(express.static('.')); // 假设HTML文件和server.js在同一目录 // 处理执行脚本的POST请求 app.post('/execute_script', (req, res) => { const userInput = req.body.prompt; // 校验输入是否为空 if (!userInput.trim()) { return res.status(400).json({'response': '请输入有效内容'}); } // 用execFile执行Python脚本,参数数组传递输入,避免命令注入和特殊字符问题 execFile('python3', ['algo.py', userInput], (error, stdout, stderr) => { if (error) { console.error('执行Python脚本失败:', error.message); return res.status(500).json({'response': '服务器执行脚本出错'}); } if (stderr) { console.error('Python脚本内部错误:', stderr); return res.status(500).json({'response': '脚本处理出错'}); } try { // 解析Python输出的JSON字符串 const result = JSON.parse(stdout); res.json(result); } catch (parseError) { console.error('解析Python响应失败:', parseError.message); res.status(500).json({'response': '响应解析出错'}); } }); }); // 启动服务器 app.listen(port, () => { console.log(`服务器运行在 http://localhost:${port}`); });
3. HTML文件(补充必要元素)
<!-- 确保添加展示结果的div --> <div id="responseContainer" style="margin-top: 20px; padding: 10px; border: 1px solid #eee;"></div> <!-- SEARCH FORM --> <form id="searchform" onsubmit="submitForm(event)"> <div class="search"> <span class="search-icon material-symbols-outlined">search</span> <input id="searchinput" class="search-input" type="search" placeholder="What did you want to build? "> <button type="submit">Generate</button> </div> </form> <script> function submitForm(event) { event.preventDefault(); const userInput = document.getElementById("searchinput").value.trim(); const responseContainer = document.getElementById("responseContainer"); // 清空之前的结果并显示加载状态 responseContainer.innerHTML = "<p>正在生成响应...</p>"; if (!userInput) { responseContainer.innerHTML = "<p>请输入有效内容</p>"; return; } fetch('/execute_script', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ prompt: userInput }), }) .then(response => { if (!response.ok) { throw new Error('服务器响应异常'); } return response.json(); }) .then(data => { // 展示结果,转义HTML特殊字符避免XSS const safeContent = document.createElement('p'); safeContent.textContent = data.response; responseContainer.innerHTML = ''; responseContainer.appendChild(safeContent); // 清空输入框 document.getElementById("searchinput").value = ''; }) .catch(error => { console.error('请求出错:', error); responseContainer.innerHTML = "<p>请求失败,请稍后重试</p>"; }); } </script>
修改思路说明
参数传递机制统一:
- 放弃Python的CGI方式,改用命令行参数接收Node.js传递的用户输入,两者机制匹配,解决核心的参数传递失败问题。
- 使用
execFile替代exec,通过参数数组传递输入,避免字符串拼接导致的命令注入风险,同时兼容包含空格、引号的用户输入。
优化性能与稳定性:
- 移除Python中每次运行都安装openai的代码,改为提前手动安装,避免重复安装的资源浪费。
- 增加输入校验(前端+后端),避免空请求触发无效的API调用。
- 完善错误处理:前端显示加载状态、错误提示;后端捕获执行错误、解析错误,并向客户端返回对应的错误响应,而不是静默失败。
安全性与用户体验:
- 前端用
textContent替代innerHTML直接拼接,避免XSS攻击。 - 添加加载状态提示,清空输入框等细节,提升用户体验。
- 前端用
内容的提问来源于stack exchange,提问作者Hector Damian Reyes
相关产品推荐
相关产品推荐

