当前位置: 首页 > news >正文

旅游做攻略的网站有哪些怀化网络推广

旅游做攻略的网站有哪些,怀化网络推广,做网站的时候公共部分怎么分离,科技公司起名我想实现的效果是,我的服务器提供两个路由网址,网页A用于拍照、然后录音,把照片和录音传给服务器,服务器发射信号,通知另一个路由的网页B更新,把刚刚传来的照片和录音显示在网页上。 然后网页B用户根据这个…

我想实现的效果是,我的服务器提供两个路由网址,网页A用于拍照、然后录音,把照片和录音传给服务器,服务器发射信号,通知另一个路由的网页B更新,把刚刚传来的照片和录音显示在网页上。

然后网页B用户根据这个照片和录音,回答一些问题,输入答案的文本,传给服务器。服务器拿到答案后,再发射信号,把这个结果显示在网页A上。

这就得用到双向通信(其实有点类似两个网页聊天的功能,而且支持发送语音、图片、文本三种消息)。这里用的是 socket.io 包。在本地写还是很好写的,但是,部署到服务器上之后,就出了很多 bug。很多坑,这里把我遇到的记下来,防止再次犯错。

这里只记录关键代码,也就是容易掉坑的代码。整个项目我之后会上传到 github 上。传好了补连接。

整体的逻辑

  1. 建立双向通道
  2. 网页A上传文件,得到服务器传回的提示信号(code: 200),然后 socket.emit("upload_completed"),通知服务器数据已经上传了
  3. 服务器监听 upload_completed 信号,收到该信号后,服务器作为中转站,广播信号 emit('data_updated', data, broadcast=True) 通知前端该更新数据了
  4. 网页 B 监听 data_updated 信号,修改自己的页面,展示图片和录音。等用户在该网页填好答案之后,点击发送按钮,网页 B 发生信号 socket.emit("annotated_answer")
  5. 服务器监听 annotated_answer 信号,收到该信号后,作为中转站,广播信号 emit('send_answer', answer, broadcast=True)
  6. 网页 A 监听信号 send_answer ,收到该信号后,把结果显示在网页上

特别拎出来的坑,特别注意

  1. 运行 flask 代码的时候调用 socketio 的 run 方法,不是用 app 的 run 方法,不然没法双向连接的;但是在服务器端部署的时候,用 uwsgi 跑上,它就是默认调用 app.run,很崩溃的啊这个;所以服务器端部署的时候,用 gunicorn (这个部署,真的,翻遍全网才找到,落泪了)
  2. socket 连接的地址,本地调试的时候填的是 localhost,但是传到服务器要改成服务器的地址,不该的话,连不上的!!
  3. 刚刚更新模型的时候又出毛病,爬上来更新。这次没有报任何错误,但是网页就是访问不到。检查了一个小时,发现是因为梯子忘记关了
  4. 部署后手机端打不开录音设备和摄像头,那是因为,媒体设备只能在 https 协议下,或者 http://localhost 下访问,所以要用这个功能,就必须去申请 ssl 证书。阿里云有免费的 20 张,好好把握。

flask 代码

我这里只贴最关键的代码,加上注释,直接把这个代码粘上去,是会报错的。

@app.route('/upload', methods=['POST'])
def app_upload_file():# 保存图片img_file = request.files['img']if img_file.filename == '':return jsonify({'error': 'No image'}), 400try:image_path = os.path.join(app.config['UPLOAD_FOLDER'], img_file.filename)img_file.save(image_path)shutil.copy(image_path, os.path.join(os.path.dirname(__file__), 'static/show.jpg'))  # 用于展示在网页上log(f"save image: {image_path}")except Exception as e:return jsonify({'error': str(e)}), 500try:# 传过来的就是文本question = request.form['question']except:question = "请描述图片内容"return jsonify({"image": img_file.filename, "question": question})@app.route('/upload/speech', methods=['POST'])
def recognize_speech():speech_file = request.files['speech']try:save_path = os.path.join(app.config['UPLOAD_FOLDER'], speech_file.filename)speech_file_path = os.path.join(app.config['UPLOAD_FOLDER'], save_path)speech_file.save(speech_file_path)# question = speech2txt(speech_file_path)# print('百度识别结果:', question)except Exception as e:return jsonify({'error': str(e)}), 500return jsonify({"speech": speech_file.filename})@socketio.on('upload_completed')
def handle_upload_completed(data):# pip install flask-socketio eventletprint(data)try:emit('data_updated', data, broadcast=True)except Exception as e:print(e)emit('error', {'error': str(e)})@socketio.on('upload_speech_completed')
def handle_upload_speech_completed(data):# pip install flask-socketio eventlettry:emit('data_speech_updated', data, broadcast=True)except Exception as e:print(e)emit('error', {'error': str(e)})@socketio.on('annotated_answer')
def handle_annotated_answer(answer):log(f'get answer from annotator: {answer}')try:emit('send_answer', answer, broadcast=True)except Exception as e:print(e)if __name__ == '__main__':# app.run(host='0.0.0.0', port=8099)# 这个地方!!看清楚!看清楚!要调用 socketio 的 run 方法,不是用 app 的 run 方法,不然没法双向连接的socketio.run(app, host='0.0.0.0', allow_unsafe_werkzeug=True, port=8099)

网页 A 的代码

注意这里只贴了一部分代码,关于文件怎么上传的,也就是引入的 camera.js 和 recorder.js 这俩文件的内容,在我这这篇文章里贴了: flask 后端 + 微信小程序和网页两种前端:调用硬件(相机和录音)和上传至服务器

html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="{{ url_for('static', filename='css/full_button.css') }}" type="text/css"><script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.min.js"></script>
</head>
<body><div style="display: flex"><div><video id="videoElement" autoplay="autoplay" muted="muted" style="width: 40px"></video><img id="photo" alt="你的照片" src="" style="display: none"></div><div id="answer" class="answer-text">答案等待中...</div></div><div class="button-grid"><button id="snapButton">拍摄照片</button><button id="recorderButton">录音</button><button id="captionButton">描述图片</button><button id="vqaButton">回答问题</button></div>{#    <input type="text" id="textQuestion" placeholder="请输入问题...">#}<script>// 这里最最最关键的就是这个网址,如果你在本地跑,要填 localhost,不能填 127.0.0.1;如果是部署在服务器,要填成服务器的地址,不然肯定是连不上的。const socket = io.connect('http://localhost:8099'); // 连接到Flask服务器socket.on('send_answer', function (data) {// 接收到服务器返回的答案,震动提示,把答案显示在页面上console.log('接收到答案:', data);document.getElementById('answer').textContent = data;navigator.vibrate([200]);  // 震动提示收到答案})var imageBlob = null;  // 拍摄的图片var speechBlob = null;  // 提出的问题// 生成随机文件名function randomFilename() {let now = new Date().getTime();let str = `xxxxxxxx-xxxx-${now}-yxxx`;return str.replace(/[xy]/g, function(c) {const r = Math.random() * 16 | 0;const v = c === 'x' ? r : (r & 0x3 | 0x8);return v.toString(16)})}</script><script type="text/javascript" src="../static/js/user_camera.js"></script><script type="text/javascript" src="../static/js/user_recorder.js"></script><script>// 绑定 caption 按钮document.getElementById('captionButton').onclick = function () {if (imageBlob == null) {alert('请先拍摄照片,再点击“描述图片”按钮')} else {const captionFormData = new FormData();let imgFilename = randomFilename()+'.jpg';captionFormData.append('img', imageBlob, imgFilename);captionFormData.append('question', '请描述图片内容');fetch('http://localhost:8099/upload', {method: 'POST',body: captionFormData}).then(response => {console.log('response:', response);if (response.status === 200) {console.log('发射信号 upload_completed');// 注意!!这里发射的信号,带的数据,得是URL.createObjectURL(imageBlob)不能是别的不能是别的不能是别的,重要的事情说3遍!!不然无法正确地显示在网页 B 上socket.emit('upload_completed', {'image': URL.createObjectURL(imageBlob),'question': '请描述图片内容'});}}).then(data => console.log('data:', data)).catch(error => console.error(error));}};// 绑定 vqa 按钮document.getElementById('vqaButton').onclick = function () {if (imageBlob == null) {alert('请先拍摄照片,再点击“描述图片”按钮')} else {if (speechBlob == null) {alert('您还没有提问,请先点击录音按钮录音提问')} else {let filename = randomFilename();// 先发语音再发图片,因为发了图片之后会提示听录音const speechFormData = new FormData();speechFormData.append('speech', speechBlob, filename+'.wav');fetch('http://localhost:8099/upload/speech', {method: 'POST',body: speechFormData}).then(response => {console.log('response:', response);if (response.status === 200) {console.log('成功上传音频', response);socket.emit('upload_speech_completed',{'speech': window.URL.createObjectURL(speechBlob)})}}).then(data => console.log('data:', data)).catch(error => console.error(error));const imgFormData = new FormData();imgFormData.append('img', imageBlob, filename+'.jpg');fetch('http://localhost:8099/upload', {method: 'POST',body: imgFormData}).then(response => {console.log('response:', response);if (response.status === 200) {console.log('发射信号 upload_completed');socket.emit('upload_completed', {'image': URL.createObjectURL(imageBlob),'question': '请听录音'});}}).then(data => console.log('data:', data)).catch(error => console.error(error));}}};</script>
</body>
</html>

网页 B 的代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>human-annotation</title><script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.min.js"></script></head>
<body><img id="image" src="" alt="Your Image"><audio id="audioPlayer" controls class="audio-player"></audio><div style="display: flex">提问:<div id="question"></div></div><input type="text" id="textInput" placeholder="请输入答案..."><button id="submitButton">发送</button><script>// 这里也是,大坑,大坑啊!!这个地址要填对,本地用 localhost,云端用云端服务器地址啊!var socket = io.connect('http://localhost:8099'); // 连接到Flask服务器socket.on('data_updated', function(data) {// 当接收到来自服务器的数据时,更新页面内容var img = document.getElementById('image');img.src = data.image;console.log('img.src');// document.getElementById('image').innerHTML = '<img src="' + data.image + '" alt="Uploaded Image">';document.getElementById('question').textContent = data.question;});socket.on('data_speech_updated', function (data) {var audioPlayer = document.getElementById("audioPlayer");audioPlayer.src = data.speech;});// 监听按钮点击事件document.getElementById('submitButton').addEventListener('click', function() {// 获取输入框中的文本var message = document.getElementById('textInput').value;// 验证消息是否为空if (message.trim() !== '') {// 通过Socket.IO发送消息给服务器socket.emit('annotated_answer', message);// 清空输入框document.getElementById('textInput').value = '';} else {alert('Please enter a message.');}});</script>
</body>
</html>

部署

用 gunicorn 部署

配置文件:
gunucorn配置文件
运行命令:运行命令


文章转载自:
http://trivet.c7498.cn
http://reincrease.c7498.cn
http://debutant.c7498.cn
http://jazzophile.c7498.cn
http://satanic.c7498.cn
http://uptilt.c7498.cn
http://asseveration.c7498.cn
http://utriculate.c7498.cn
http://commix.c7498.cn
http://rhumb.c7498.cn
http://amblyoscope.c7498.cn
http://astromancer.c7498.cn
http://transpolar.c7498.cn
http://gni.c7498.cn
http://micrometeorite.c7498.cn
http://portamento.c7498.cn
http://fissiparous.c7498.cn
http://arrenotoky.c7498.cn
http://mythoi.c7498.cn
http://alienor.c7498.cn
http://unrisen.c7498.cn
http://exactable.c7498.cn
http://tetrafunctional.c7498.cn
http://expunctuation.c7498.cn
http://agamete.c7498.cn
http://superheterodyne.c7498.cn
http://exaction.c7498.cn
http://leonis.c7498.cn
http://inscript.c7498.cn
http://jeroboam.c7498.cn
http://hallow.c7498.cn
http://reengine.c7498.cn
http://tritagonist.c7498.cn
http://deprecatory.c7498.cn
http://rld.c7498.cn
http://disturbingly.c7498.cn
http://stun.c7498.cn
http://montmorency.c7498.cn
http://ta.c7498.cn
http://yell.c7498.cn
http://botulinum.c7498.cn
http://dermatotherapy.c7498.cn
http://kopfring.c7498.cn
http://midsection.c7498.cn
http://seating.c7498.cn
http://entomological.c7498.cn
http://listeriosis.c7498.cn
http://sclerodermatitis.c7498.cn
http://minuet.c7498.cn
http://granulomatosis.c7498.cn
http://gbf.c7498.cn
http://stability.c7498.cn
http://songbook.c7498.cn
http://myelocyte.c7498.cn
http://judicative.c7498.cn
http://syncretic.c7498.cn
http://symbolically.c7498.cn
http://pressurization.c7498.cn
http://womb.c7498.cn
http://unexcitable.c7498.cn
http://madly.c7498.cn
http://whereinto.c7498.cn
http://tumorous.c7498.cn
http://pix.c7498.cn
http://sharecrop.c7498.cn
http://collarband.c7498.cn
http://hatching.c7498.cn
http://vancomycin.c7498.cn
http://unflickering.c7498.cn
http://pedodontics.c7498.cn
http://placage.c7498.cn
http://shrillness.c7498.cn
http://inferrable.c7498.cn
http://suez.c7498.cn
http://lych.c7498.cn
http://relationship.c7498.cn
http://unshirted.c7498.cn
http://dyadic.c7498.cn
http://mollycoddle.c7498.cn
http://thir.c7498.cn
http://zygophyllaceae.c7498.cn
http://typist.c7498.cn
http://nominate.c7498.cn
http://engrammic.c7498.cn
http://crinum.c7498.cn
http://pock.c7498.cn
http://obelise.c7498.cn
http://worry.c7498.cn
http://cgi.c7498.cn
http://yesterday.c7498.cn
http://plica.c7498.cn
http://blinkers.c7498.cn
http://bothersome.c7498.cn
http://anyways.c7498.cn
http://ultrafiche.c7498.cn
http://ywha.c7498.cn
http://maltese.c7498.cn
http://snakebird.c7498.cn
http://trimeter.c7498.cn
http://honeyfogle.c7498.cn
http://www.zhongyajixie.com/news/82223.html

相关文章:

  • 怎么做记步数的程序到网站关键词优化一年多少钱
  • 网站建设企今日头条搜索优化怎么做
  • 龙岩网站建设专家seo排名的影响因素有哪些
  • 学校网站建设目标成人用品哪里进货好
  • 泉州网络公司都嘉兴seo排名外包
  • 公司网页怎么做的网站排名优化服务公司
  • 做网站python和php哪个好学公司产品怎样网上推广
  • 苹果网站上物体阴影怎么做的今日搜索排行榜
  • 定制型网页设计开发如何seo搜索引擎优化
  • 新乡营销型网站网络站点推广的方法有哪些
  • 网站首页轮播图怎么换seo标题优化是什么意思
  • 番禺做网站报价唐山百度seo公司
  • 有关网站建设的合同利尔化学股票股吧
  • wordpress 评论 折叠仓山区seo引擎优化软件
  • 手机网站建设模板下载百度网站大全首页
  • 西藏自治区建设厅教育网站百度搜索引擎算法
  • wordpress建立非博客星链seo管理
  • 做网站的收获软文发布软件
  • 深圳宝安p2p网站系统的建设站长联盟
  • acm手表网站免费网站建站
  • wap网站开发java武汉seo群
  • 广州代做网站中央人民政府网
  • 济南网站建设开发服务营销7p理论
  • 网站建设与管理基础专业做网站
  • 开发网站心得网站优化 秦皇岛
  • 百度网站优化排名定制网站建设推广服务
  • 怎么做html5网站广东seo推广贵不贵
  • 网站制作用到什么技术城关网站seo
  • 免费关键词排名优化厦门seo专业培训学校
  • 怎么做网站像淘宝这样的如何把自己的网站推广出去