You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AWS Rekognition预测结果无法在独立HTML页面显示求助

健身器材识别Web应用结果页无法显示预测值

开发了一款基于AWS Rekognition的健身器材识别Web应用,图片上传和预测功能正常,浏览器控制台能正确打印预测结果,但跳转至results.html页面后始终显示“No equipment predicted”。


homepage.html(图片上传页)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Gym Equipment Exercise Finder</title>
    <style>
        /* Your existing CSS here */
    </style>
</head>
<body>
    <header>
        <h1 style="font-family: Times New Roman, serif">Workout Wizard</h1>
        <nav>
            <a href="homepage.html">Home</a>
            <a href="products.html">Products</a>
            <a href="contact.html">Contact</a>
        </nav>
    </header>
    <section class="hero">
        <div class="hero-content">
            <h1>Find Your Workout!</h1>
            <p>Upload a photo of gym equipment and get exercises you can do with it.</p>
        </div>
    </section>
    <section class="upload-section">
        <div class="upload-container">
            <input type="file" id="imageInput" accept="image/*">
            <label for="imageInput">
                <img src="camera.png" alt="Upload Icon">
                <p>Drop an image here</p>
                <p>or</p>
                <p>click to browse</p>
            </label>
        </div>
        <button onclick="uploadImage()">Submit</button>
    </section>
    <footer>
        &copy; 2024 Workout Wizard. All rights reserved.
    </footer>
    <script>
        function uploadImage() {
            const imageInput = document.getElementById('imageInput');
            if (!imageInput || !imageInput.files || imageInput.files.length === 0) {
                alert("Please choose an image file.");
                return;
            }

            const selectedFile = imageInput.files[0];
            const reader = new FileReader();
            reader.onload = function (event) {
                const base64EncodedImage = event.target.result.split(',')[1];
                fetch('https://t6mn1ryxc4.execute-api.us-east-1.amazonaws.com/Gym_Equipments/predict', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({ image: base64EncodedImage }),
                })
                .then(response => response.json())
                .then(data => {
                    console.log('Lambda Response:', data);
                    localStorage.setItem('predictedEquipment', data);
                    console.log('Stored in localStorage:', localStorage.getItem('predictedEquipment'));
                    window.location.href = "results.html";
                })
                .catch(error => {
                    console.error('Error:', error);
                    alert('Error uploading image.');
                });
            };
            reader.readAsDataURL(selectedFile);
        }
    </script>
</body>
</html>

results.html(结果展示页)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Results</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            background-color: #f3f4f6;
        }
        header {
            background-color: #6200a9; 
            padding: 20px;
            display: flex;
            justify-content: space-between;
            align-items: center;
            color: white;
        }
        header img {
            height: 50px;
        }
        nav {
            display: flex;
            align-items: center;
        }
        nav a {
            color: white;
            text-decoration: none;
            margin: 0 10px;
            font-size: 18px;
        }
        nav a:hover {
            text-decoration: underline;
        }
        .result-section {
            padding: 20px;
            text-align: center;
            background-color: #fff;
            border-radius: 10px;
            margin: 20px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }
        footer {
            background-color: #6200a9;
            color: #ccc;
            padding: 20px;
            text-align: center;
        }
        footer a {
            color: #ff7f50;
            text-decoration: none;
        }
        footer a:hover {
            text-decoration: underline;
        }
    </style>
</head>
<body>
    <header>
        <h1>Workout Wizard</h1>
        <nav>
            <a href="homepage.html">Home</a>
            <a href="products.html">Products</a>
            <a href="contact.html">Contact</a>
        </nav>
    </header>
    <section class="result-section">
        <h1>Prediction Result</h1>
        <p id="result">Loading...</p>
    </section>
    <footer>
        &copy; 2024 Workout Wizard. All rights reserved. | <a href="privacy.html">Privacy Policy</a> | <a href="termsandconditions.html">Terms of Service</a>
    </footer>
    <script>
        window.onload = function() {
            // Retrieve the prediction result from localStorage
            const prediction = localStorage.getItem('predictedEquipment');
            if (prediction) {
                document.getElementById('result').innerText = prediction;
            } else {
                document.getElementById('result').innerText = 'No equipment predicted';
            }
        };
    </script>
</body>
</html>

Lambda函数代码

import json
import boto3
 
bucket_name = "gymhtml"
 
from botocore.exceptions import ClientError
import base64
from io import BytesIO
from datetime import datetime
 
s3 = boto3.client('s3')
 
def saveToS3(image_binary):
    # Get the current timestamp
    timestamp = datetime.utcnow().strftime("%Y%m%d%H%M%S%f")
    # Generate a filename with the timestamp
    filename = f'uploads/{timestamp}.jpg'
    print("filename: ", filename)
    try:
        # need to save the image as image/jpeg content type
        s3.put_object(Bucket=bucket_name, Key=filename, Body=image_binary, ContentType='image/jpeg')
        # Log success message
        print(f"Image saved to S3: s3://{bucket_name}/{filename}")
        return filename
    except ClientError as e:
        # Log the error
        print("Error:", str(e))
        return None
 
def predictImage(photo):
    rekognition = boto3.client('rekognition')
    model = "arn:aws:rekognition:us-east-1:414942631188:project/gymequipment/version/gymequipment.2024-07-31T18.03.52/1722420232922"
    min_confidence = 60
 
    #Call DetectCustomLabels
    response = rekognition.detect_custom_labels(Image={'S3Object': {'Bucket': bucket_name, 'Name': photo}},
        MinConfidence=min_confidence,
        ProjectVersionArn=model)
    print(response['CustomLabels'])
    result = json.dumps(response['CustomLabels'][0])
    #print to the log for debugging purposes
    print(response['CustomLabels'][0]["Name"])
    return response['CustomLabels'][0]["Name"]
 
def lambda_handler(event, context):
    # TODO implement
    msg = "INVALID REQUEST"
    print( event );
    #if event['httpMethod'] == 'POST':
        # Extract the base64-encoded image and filename from the request body
        #request_body = json.loads(event['body'])
    request_body = json.loads(event['body'])
    image_base64 = request_body['image'];
    # Decode the base64-encoded image
    image_binary = base64.b64decode(image_base64)
    #save image to S3
    imagefilename = saveToS3(image_binary)
    #msg = 'Hello from Lambda!'
    #msg = predictImage(imagefilename)
    msg = predictImage(imagefilename)
    return {
        'statusCode': 200,
        'headers': {
            'Content-Type': 'application/json',
            'Access-Control-Allow-Origin': '*'
        },
        'body': json.dumps(msg)
    }

问题原因及修复方案

核心问题

如果直接通过file://协议打开本地HTML文件,Chrome等浏览器的安全限制会导致localStorage无法跨页面共享——虽然上传页能存入数据,但结果页无法读取。此外,也可能存在页面跳转时localStorage未及时持久化的情况。

修复方案1:使用本地服务器运行

放弃直接打开本地文件,改用本地HTTP服务器托管页面:

  • Python:在项目目录执行 python -m http.server 8000,访问 http://localhost:8000/homepage.html
  • Node.js:安装http-server后执行 http-server -p 8000,访问上述地址

修复方案2:改用URL参数传递结果

修改上传页的JavaScript代码,通过URL参数传递预测结果,避免依赖localStorage:

// homepage.html中uploadImage函数的then部分修改为:
.then(data => {
    console.log('Lambda Response:', data);
    // 用URL参数传递结果
    window.location.href = `results.html?equipment=${encodeURIComponent(data)}`;
})

修改结果页的JavaScript代码,读取URL参数:

// results.html中的window.onload函数修改为:
window.onload = function() {
    const urlParams = new URLSearchParams(window.location.search);
    const prediction = urlParams.get('equipment');
    if (prediction) {
        document.getElementById('result').innerText = prediction;
    } else {
        document.getElementById('result').innerText = 'No equipment predicted';
    }
};

额外优化建议

Lambda函数中添加空值判断,避免CustomLabels为空时抛出索引越界错误:

def predictImage(photo):
    rekognition = boto3.client('rekognition')
    model = "arn:aws:rekognition:us-east-1:414942631188:project/gymequipment/version/gymequipment.2024-07-31T18.03.52/1722420232922"
    min_confidence = 60

    response = rekognition.detect_custom_labels(Image={'S3Object': {'Bucket': bucket_name, 'Name': photo}},
        MinConfidence=min_confidence,
        ProjectVersionArn=model)
    
    # 添加空值判断
    if not response['CustomLabels']:
        return "No equipment detected"
    
    print(response['CustomLabels'])
    print(response['CustomLabels'][0]["Name"])
    return response['CustomLabels'][0]["Name"]

内容的提问来源于stack exchange,提问作者Leong Hon Mun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 02:17:02