-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
71 lines (63 loc) · 2.26 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import { ExifTool } from 'exiftool-vendored'
import { z } from 'zod'
import dedent from 'dedent'
// Do all this ceremony to get the package version
import { readFile } from 'node:fs/promises'
import { fileURLToPath } from 'node:url'
import { dirname, join } from 'node:path'
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
const packageJsonPath = join(__dirname, 'package.json')
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf-8'))
export const schema = z.object({
description: z.string().describe('An explanatory blurb about the MediaProvenance spec itself. This is set automatically by tools.'),
provider: z.string().describe('The app or service that ran the model.'),
model: z.string().describe('The model used to generate the image'),
input: z.record(z.any()).describe('The input parameters to the model'),
output: z.any().describe('The output of the model'),
meta: z.record(z.unknown()).describe('Extra metadata')
})
export default {
get,
set,
schema
}
export async function set (fullyQualifiedImagePath, provenanceData) {
const exiftool = new ExifTool()
try {
const description = dedent`
MediaProvenance (v${packageJson.version}): A spec for describing the origins of AI-generated images.
See https://github.com/zeke/media-provenance
`
const provenanceDataWithDescription = { description, ...provenanceData }
const validatedMetadata = schema.parse(provenanceDataWithDescription)
const json = JSON.stringify(validatedMetadata, null, 2)
await exiftool.write(fullyQualifiedImagePath, {
MakerNote: json
}, ['-overwrite_original_in_place'])
} catch (error) {
if (error instanceof z.ZodError) {
console.error('Invalid metadata:', error.errors)
} else {
console.error('Error writing EXIF data:', error)
}
throw error
} finally {
await exiftool.end()
}
}
export async function get (fullyQualifiedImagePath) {
const exiftool = new ExifTool()
try {
const exifData = await exiftool.read(fullyQualifiedImagePath)
if (exifData.MakerNote) {
return JSON.parse(exifData.MakerNote)
}
return null
} catch (error) {
console.error('Error reading EXIF data:', error)
return null
} finally {
await exiftool.end()
}
}