Analyze images in ZIP for business info
- Scan extracted ZIP for image files (jpg, png, gif, webp) - Skip small files (<10KB, likely icons) and _files folder assets - Send up to 3 images to Claude for business info extraction - Merge extracted name, address, phone, hours, brandColor - Only fills in fields not already found from HTML Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
cf34636879
commit
f9bfbc8960
1 changed files with 113 additions and 0 deletions
|
|
@ -505,6 +505,119 @@
|
||||||
</cftry>
|
</cftry>
|
||||||
|
|
||||||
<cfset arrayAppend(response.steps, "Extracted " & arrayLen(toastItems) & " unique items from " & arrayLen(toastCategories) & " categories")>
|
<cfset arrayAppend(response.steps, "Extracted " & arrayLen(toastItems) & " unique items from " & arrayLen(toastCategories) & " categories")>
|
||||||
|
|
||||||
|
<!--- Scan for images in ZIP and analyze them for business info --->
|
||||||
|
<cftry>
|
||||||
|
<cfdirectory action="list" directory="#extractDir#" name="zipImages" recurse="true" type="file">
|
||||||
|
<cfset imageExtensions = "jpg,jpeg,png,gif,webp">
|
||||||
|
<cfset zipImageFiles = []>
|
||||||
|
<cfloop query="zipImages">
|
||||||
|
<cfset imgExt = lCase(listLast(zipImages.name, "."))>
|
||||||
|
<cfif listFindNoCase(imageExtensions, imgExt)>
|
||||||
|
<!--- Skip small files (likely icons) and _files folder assets --->
|
||||||
|
<cfif zipImages.size GT 10000 AND NOT findNoCase("_files", zipImages.directory)>
|
||||||
|
<cfset arrayAppend(zipImageFiles, "#zipImages.directory#/#zipImages.name#")>
|
||||||
|
</cfif>
|
||||||
|
</cfif>
|
||||||
|
</cfloop>
|
||||||
|
|
||||||
|
<cfif arrayLen(zipImageFiles) GT 0>
|
||||||
|
<cfset arrayAppend(response.steps, "Found " & arrayLen(zipImageFiles) & " images in ZIP to analyze for business info")>
|
||||||
|
|
||||||
|
<!--- Analyze up to 3 images for business info --->
|
||||||
|
<cfset imgLimit = min(arrayLen(zipImageFiles), 3)>
|
||||||
|
<cfloop from="1" to="#imgLimit#" index="imgIdx">
|
||||||
|
<cfset imgPath = zipImageFiles[imgIdx]>
|
||||||
|
<cftry>
|
||||||
|
<cfset imgContent = fileReadBinary(imgPath)>
|
||||||
|
<cfset imgExt = lCase(listLast(imgPath, "."))>
|
||||||
|
<cfset mediaType = "image/jpeg">
|
||||||
|
<cfif imgExt EQ "png"><cfset mediaType = "image/png">
|
||||||
|
<cfelseif imgExt EQ "gif"><cfset mediaType = "image/gif">
|
||||||
|
<cfelseif imgExt EQ "webp"><cfset mediaType = "image/webp">
|
||||||
|
</cfif>
|
||||||
|
|
||||||
|
<cfset base64Img = toBase64(imgContent)>
|
||||||
|
<cfset arrayAppend(response.steps, "Analyzing image: " & listLast(imgPath, "/\"))>
|
||||||
|
|
||||||
|
<!--- Build Claude request for business info extraction --->
|
||||||
|
<cfset imgMsgContent = []>
|
||||||
|
<cfset arrayAppend(imgMsgContent, {
|
||||||
|
"type": "image",
|
||||||
|
"source": {
|
||||||
|
"type": "base64",
|
||||||
|
"media_type": mediaType,
|
||||||
|
"data": base64Img
|
||||||
|
}
|
||||||
|
})>
|
||||||
|
<cfset arrayAppend(imgMsgContent, {
|
||||||
|
"type": "text",
|
||||||
|
"text": "Extract business information from this image. Return JSON with: name, addressLine1, city, state, zip, phone, hours, brandColor (6-digit hex without #). Only include fields you can see. Return ONLY valid JSON, no markdown."
|
||||||
|
})>
|
||||||
|
|
||||||
|
<cfset imgRequest = {
|
||||||
|
"model": "claude-sonnet-4-20250514",
|
||||||
|
"max_tokens": 1024,
|
||||||
|
"temperature": 0,
|
||||||
|
"messages": [{
|
||||||
|
"role": "user",
|
||||||
|
"content": imgMsgContent
|
||||||
|
}]
|
||||||
|
}>
|
||||||
|
|
||||||
|
<cfhttp url="https://api.anthropic.com/v1/messages" method="POST" timeout="60" result="imgHttpResult">
|
||||||
|
<cfhttpparam type="header" name="Content-Type" value="application/json">
|
||||||
|
<cfhttpparam type="header" name="x-api-key" value="#CLAUDE_API_KEY#">
|
||||||
|
<cfhttpparam type="header" name="anthropic-version" value="2023-06-01">
|
||||||
|
<cfhttpparam type="body" value="#serializeJSON(imgRequest)#">
|
||||||
|
</cfhttp>
|
||||||
|
|
||||||
|
<cfif findNoCase("200", imgHttpResult.statusCode)>
|
||||||
|
<cfset imgResponse = deserializeJSON(imgHttpResult.fileContent)>
|
||||||
|
<cfif structKeyExists(imgResponse, "content") AND arrayLen(imgResponse.content)>
|
||||||
|
<cfset imgText = imgResponse.content[1].text>
|
||||||
|
<!--- Clean up JSON --->
|
||||||
|
<cfset imgText = trim(imgText)>
|
||||||
|
<cfif left(imgText, 7) EQ "```json">
|
||||||
|
<cfset imgText = mid(imgText, 8, len(imgText) - 7)>
|
||||||
|
</cfif>
|
||||||
|
<cfif left(imgText, 3) EQ "```">
|
||||||
|
<cfset imgText = mid(imgText, 4, len(imgText) - 3)>
|
||||||
|
</cfif>
|
||||||
|
<cfif right(imgText, 3) EQ "```">
|
||||||
|
<cfset imgText = left(imgText, len(imgText) - 3)>
|
||||||
|
</cfif>
|
||||||
|
<cfset imgText = trim(imgText)>
|
||||||
|
|
||||||
|
<cftry>
|
||||||
|
<cfset imgBizData = deserializeJSON(imgText)>
|
||||||
|
<!--- Merge into toastBusiness (only fill in missing fields) --->
|
||||||
|
<cfset bizFieldsToCheck = "name,addressLine1,city,state,zip,phone,hours,brandColor">
|
||||||
|
<cfloop list="#bizFieldsToCheck#" index="bizField">
|
||||||
|
<cfif structKeyExists(imgBizData, bizField) AND isSimpleValue(imgBizData[bizField]) AND len(trim(imgBizData[bizField]))>
|
||||||
|
<cfif NOT structKeyExists(toastBusiness, bizField) OR NOT len(toastBusiness[bizField])>
|
||||||
|
<cfset toastBusiness[bizField] = trim(imgBizData[bizField])>
|
||||||
|
<cfset arrayAppend(response.steps, "Found " & bizField & " from image: " & left(toastBusiness[bizField], 50))>
|
||||||
|
</cfif>
|
||||||
|
</cfif>
|
||||||
|
</cfloop>
|
||||||
|
<cfcatch>
|
||||||
|
<cfset arrayAppend(response.steps, "Could not parse image analysis JSON")>
|
||||||
|
</cfcatch>
|
||||||
|
</cftry>
|
||||||
|
</cfif>
|
||||||
|
</cfif>
|
||||||
|
<cfcatch>
|
||||||
|
<cfset arrayAppend(response.steps, "Error analyzing image: " & cfcatch.message)>
|
||||||
|
</cfcatch>
|
||||||
|
</cftry>
|
||||||
|
</cfloop>
|
||||||
|
</cfif>
|
||||||
|
<cfcatch>
|
||||||
|
<cfset arrayAppend(response.steps, "Could not scan ZIP for images: " & cfcatch.message)>
|
||||||
|
</cfcatch>
|
||||||
|
</cftry>
|
||||||
|
|
||||||
<!--- Summary of business info found --->
|
<!--- Summary of business info found --->
|
||||||
<cfset bizKeys = structKeyList(toastBusiness)>
|
<cfset bizKeys = structKeyList(toastBusiness)>
|
||||||
<cfset arrayAppend(response.steps, "Business info keys: " & (len(bizKeys) ? bizKeys : "(none)"))>
|
<cfset arrayAppend(response.steps, "Business info keys: " & (len(bizKeys) ? bizKeys : "(none)"))>
|
||||||
|
|
|
||||||
Reference in a new issue