-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add textract driver to puterai module
- Loading branch information
1 parent
b520783
commit f924d48
Showing
8 changed files
with
4,883 additions
and
2,531 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
const BaseService = require("../../services/BaseService"); | ||
|
||
class AIInterfaceService extends BaseService { | ||
async ['__on_driver.register.interfaces'] () { | ||
const svc_registry = this.services.get('registry'); | ||
const col_interfaces = svc_registry.get('interfaces'); | ||
|
||
col_interfaces.set('puter-ocr', { | ||
description: 'Optical character recognition', | ||
methods: { | ||
recognize: { | ||
description: 'Recognize text in an image or document.', | ||
parameters: { | ||
source: { | ||
type: 'file', | ||
}, | ||
}, | ||
result: { | ||
type: { | ||
$: 'stream', | ||
content_type: 'image', | ||
} | ||
}, | ||
}, | ||
} | ||
}); | ||
} | ||
} | ||
|
||
module.exports = { | ||
AIInterfaceService | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
const { TextractClient, AnalyzeDocumentCommand, InvalidS3ObjectException } = require("@aws-sdk/client-textract"); | ||
|
||
const BaseService = require("../../services/BaseService"); | ||
|
||
class AWSTextractService extends BaseService { | ||
_construct () { | ||
this.clients_ = {}; | ||
} | ||
|
||
static IMPLEMENTS = { | ||
['puter-ocr']: { | ||
async recognize ({ source, test_mode }) { | ||
const resp = await this.analyze_document(source); | ||
|
||
// Simplify the response for common interface | ||
const puter_response = { | ||
blocks: [] | ||
}; | ||
|
||
for ( const block of resp.Blocks ) { | ||
if ( block.BlockType === 'PAGE' ) continue; | ||
if ( block.BlockType === 'CELL' ) continue; | ||
if ( block.BlockType === 'TABLE' ) continue; | ||
if ( block.BlockType === 'MERGED_CELL' ) continue; | ||
if ( block.BlockType === 'LAYOUT_FIGURE' ) continue; | ||
if ( block.BlockType === 'LAYOUT_TEXT' ) continue; | ||
|
||
const puter_block = { | ||
type: `text/textract:${block.BlockType}`, | ||
confidence: block.Confidence, | ||
text: block.Text, | ||
}; | ||
puter_response.blocks.push(puter_block); | ||
} | ||
|
||
return puter_response; | ||
} | ||
}, | ||
}; | ||
|
||
_create_aws_credentials () { | ||
return { | ||
accessKeyId: this.config.aws.access_key, | ||
secretAccessKey: this.config.aws.secret_key, | ||
}; | ||
} | ||
|
||
_get_client (region) { | ||
if ( ! region ) { | ||
region = this.config.aws?.region ?? this.global_config.aws?.region | ||
?? 'us-west-2'; | ||
} | ||
if ( this.clients_[region] ) return this.clients_[region]; | ||
|
||
this.clients_[region] = new TextractClient({ | ||
credentials: this._create_aws_credentials(), | ||
region, | ||
}); | ||
|
||
return this.clients_[region]; | ||
} | ||
|
||
async analyze_document (file_facade) { | ||
const { | ||
client, document, using_s3 | ||
} = await this._get_client_and_document(file_facade); | ||
|
||
const command = new AnalyzeDocumentCommand({ | ||
Document: document, | ||
FeatureTypes: [ | ||
// 'TABLES', | ||
// 'FORMS', | ||
// 'SIGNATURES', | ||
'LAYOUT' | ||
], | ||
}); | ||
|
||
try { | ||
return await client.send(command); | ||
} catch (e) { | ||
if ( using_s3 && e instanceof InvalidS3ObjectException ) { | ||
const { client, document } = | ||
await this._get_client_and_document(file_facade, true); | ||
const command = new AnalyzeDocumentCommand({ | ||
Document: document, | ||
FeatureTypes: [ | ||
'LAYOUT', | ||
], | ||
}) | ||
return await client.send(command); | ||
} | ||
|
||
throw e; | ||
} | ||
|
||
throw new Error('expected to be unreachable'); | ||
} | ||
|
||
async _get_client_and_document (file_facade, force_buffer) { | ||
const try_s3info = await file_facade.get('s3-info'); | ||
if ( try_s3info && ! force_buffer ) { | ||
console.log('S3 INFO', try_s3info) | ||
return { | ||
using_s3: true, | ||
client: this._get_client(try_s3info.bucket_region), | ||
document: { | ||
S3Object: { | ||
Bucket: try_s3info.bucket, | ||
Name: try_s3info.key, | ||
}, | ||
}, | ||
}; | ||
} | ||
|
||
const try_buffer = await file_facade.get('buffer'); | ||
if ( try_buffer ) { | ||
const base64 = try_buffer.toString('base64'); | ||
return { | ||
client: this._get_client(), | ||
document: { | ||
Bytes: try_buffer, | ||
}, | ||
}; | ||
} | ||
|
||
const fsNode = await file_facade.get('fs-node'); | ||
if ( fsNode && ! await fsNode.exists() ) { | ||
throw APIError.create('subject_does_not_exist'); | ||
} | ||
|
||
throw new Error('No suitable input for Textract'); | ||
} | ||
} | ||
|
||
module.exports = { | ||
AWSTextractService, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
const { AdvancedBase } = require("@heyputer/puter-js-common"); | ||
|
||
class PuterAIModule extends AdvancedBase { | ||
async install (context) { | ||
const services = context.get('services'); | ||
|
||
const { AIInterfaceService } = require('./AIInterfaceService'); | ||
services.registerService('__ai-interfaces', AIInterfaceService); | ||
|
||
const { AWSTextractService } = require('./AWSTextractService'); | ||
services.registerService('aws-textract', AWSTextractService); | ||
} | ||
} | ||
|
||
module.exports = { | ||
PuterAIModule, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
```javascript | ||
await (await fetch("http://api.puter.localhost:4100/drivers/call", { | ||
"headers": { | ||
"Content-Type": "application/json", | ||
"Authorization": `Bearer ${puter.authToken}`, | ||
}, | ||
"body": JSON.stringify({ | ||
interface: 'puter-ocr', | ||
driver: 'aws-textract', | ||
method: 'recognize', | ||
args: { | ||
source: '~/Desktop/testocr.png', | ||
}, | ||
}), | ||
"method": "POST", | ||
})).json(); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters