-
Notifications
You must be signed in to change notification settings - Fork 260
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue: AWS Textract Service - 400 and CORS errors #6008
Comments
There's this version I tried also where I was using HTTP.post after using the AWS sdks import 'dart:convert';
import 'dart:typed_data';
import 'package:aws_textract_api/textract-2018-06-27.dart';
import 'package:aws_common/aws_common.dart';
import 'package:aws_signature_v4/aws_signature_v4.dart';
import 'package:crypto/crypto.dart';
import 'package:esc_pos_utils_plus/dart_hex/hex.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:http/http.dart' as http;
import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart';
/// AWS Textract service that uses the aws_signature_v4 package for authentication
class AwsTextractService {
static AwsTextractService? _instance;
final String accessKey;
final String secretKey;
final String region;
final AWSCredentials _credentials;
final AWSCredentialsProvider _credentialsProvider;
late final AWSSigV4Signer _signer;
final Uuid _uuid = const Uuid();
// Private constructor for singleton
AwsTextractService._({
required this.accessKey,
required this.secretKey,
required this.region,
}) : _credentials = AWSCredentials(accessKey, secretKey),
_credentialsProvider =
AWSCredentialsProvider(AWSCredentials(accessKey, secretKey)) {
_signer = AWSSigV4Signer(
credentialsProvider: _credentialsProvider,
);
}
/// Get the singleton instance
static AwsTextractService getInstance({
required String accessKey,
required String secretKey,
String region = 'ap-south-1',
}) {
_instance ??= AwsTextractService._(
accessKey: accessKey,
secretKey: secretKey,
region: region,
);
return _instance!;
}
String _formatDate(DateTime dateTime) {
return '${dateTime.year}${dateTime.month.toString().padLeft(2, '0')}${dateTime.day.toString().padLeft(2, '0')}';
}
String _formatAmzDate(DateTime dateTime) {
return '${_formatDate(dateTime)}T${dateTime.hour.toString().padLeft(2, '0')}${dateTime.minute.toString().padLeft(2, '0')}${dateTime.second.toString().padLeft(2, '0')}Z';
}
/// Analyze document clarity using AWS Textract
/// Returns a confidence score between 0.0 and 1.0
Future<double> analyzeDocumentClarity(Uint8List documentBytes) async {
try {
// Host and endpoint information
final host = 'textract.$region.amazonaws.com';
final endpoint = Uri.parse('https://$host');
final timestamp = DateTime.now().toUtc();
final amzDate = _formatAmzDate(timestamp);
// Prepare the request body
final requestBody = jsonEncode({
'Document': {
'Bytes': base64Encode(documentBytes),
},
});
// Create a unique request ID
final requestId = _uuid.v4();
// Prepare headers
final headers = {
'Content-Type': 'application/x-amz-json-1.1',
'X-Amz-Target': 'Textract.DetectDocumentText',
'amz-sdk-invocation-id': requestId,
'amz-sdk-request': 'attempt=1; max=3',
'Accept': '*/*',
'X-Amz-Date': amzDate,
'X-Amz-Content-Sha256': const HexEncoder()
.convert(sha256.convert(utf8.encode(requestBody)).bytes),
};
debugPrint('Headers: $headers');
// Create the AWS request
final request = AWSHttpRequest(
method: AWSHttpMethod.post,
uri: endpoint,
headers: headers,
body: Uint8List.fromList(utf8.encode(requestBody)),
);
final scope = AWSCredentialScope(
region: 'ap-south-1',
service: AWSService.textract,
);
debugPrint('Request: $request');
// Sign the request
final AWSSignedRequest signedRequest = await _signer.sign(
request,
credentialScope: scope,
// this is un-nessecarry
serviceConfiguration: const ServiceConfiguration(
signBody: true,
normalizePath: true,
omitSessionToken: true,
doubleEncodePathSegments: true,
),
);
debugPrint(
'Signed Headers: ${Map<String, String>.from(signedRequest.headers)}');
// Make the HTTP request
final response = await http.post(
endpoint,
headers: Map<String, String>.from(signedRequest.headers),
body: requestBody,
);
if (response.statusCode != 200) {
throw Exception(
'AWS Textract request failed with status ${response.statusCode}: ${response.body}',
);
}
// Parse the response
final responseJson = jsonDecode(response.body);
final textractResponse =
DetectDocumentTextResponse.fromJson(responseJson);
// Calculate and return the document clarity score
return _calculateDocumentClarityScore(textractResponse);
} catch (e) {
print('Error analyzing document: $e');
rethrow;
}
}
/// Calculate document clarity score based on Textract response
double _calculateDocumentClarityScore(DetectDocumentTextResponse response) {
final blocks = response.blocks;
if (blocks == null || blocks.isEmpty) {
return 0.0; // No text detected
}
// Calculate average confidence across all detected text blocks
double totalConfidence = 0.0;
int textBlockCount = 0;
for (final block in blocks) {
if (block.blockType == BlockType.line ||
block.blockType == BlockType.word) {
if (block.confidence != null) {
totalConfidence += block.confidence!;
textBlockCount++;
}
}
}
// If no text blocks found, document might be blank or an image
if (textBlockCount == 0) {
return 0.3; // Assign a low default score
}
// Return average confidence as a value between 0.0 and 1.0
return totalConfidence / textBlockCount / 100;
}
}
Also these are the headers that are being generated in this:
I was getting response:
I would say this is the main issue why is my signature not valid what am I doing wrong here. BTW I am 100% on my creds being right as I tried the same creds using the react sdk. |
Why does sending the request using the AWSSignedRequest.send() add a /? at the end there are no query params this results in 404 error curl 'https://textract.ap-south-1.amazonaws.com/?' This is what it's sending. If I remove the /? from the uri it results in 200. Anyway the original post request doesn't work either way. It always errors: "__type": "InvalidSignatureException", |
Description
I'll help you craft a GitHub issue for the CORS and 404 errors you're experiencing. Here's a template you can use:
Error Messages
Error analyzing document: POST https://textract.ap-south-1.amazonaws.com? failed: TypeError: Failed to fetch
DartError: Bad state: Future already completed
Expected Behavior
The AWS Textract API call should complete successfully without CORS errors.
Attempted Solutions
Would appreciate guidance on:
What I am trying to do.
Categories
Steps to Reproduce
Here's a detailed "Steps to Reproduce" section you can add to your GitHub issue:
Create a service class for AWS Textract (as shown in code example)
Set up a simple UI with:
Implement the document analysis workflow:
Select a document image and click the analyze button
Observe in the Network tab:
Check the Console tab for the complete error message about CORS policy violation
The text was updated successfully, but these errors were encountered: