发票地狱求生指南:一个AI拯救手残党的故事
第一章:发票,成年人的积木玩具
相信每个社畜都玩过这种”高难度积木”——整理发票。一两张?小菜一碟,AI随便扫一眼就能搞定。但当你面前堆着几十张发票,像被财务之神随手丢下的扑克牌时,事情就开始变得魔幻起来了。
小微企业老板和代账公司的朋友们,每月都要上演《发票大逃杀》:
就在这时,AI如同超级英雄般从天而降,帮我们把这场噩梦变成了一键三连的爽快操作!
第二章:从”我恨发票”到”让AI恨发票”
曾经的我,也是个发票整理界的青铜选手,直到遇见了Dify这个神器(并不是广告,纯粹是救星!)。用它搭了个自动化流程后:
虽然官方税务查询界面依然像迷宫里找WiFi信号,但至少在数据整理上,咱算是成功甩锅AI了!
1 准备工作
搭建工作流的”煎饼果子”系列准备
第一步:发票PDF变身”图片侠”
一开始,我用了一个文档提取器来对付发票PDF,结果那家伙的表现就像是一个戴着老花镜的会计——看什么都模模糊糊,尤其是商品详情那块,它直接把文本排成了一种”自由民主”的风格:想串行就串行,想换行绝不含糊!
于是,我决定召唤科技外援——阿里千问的多模型团队。他们的任务:让所有PDF发票乖乖变成图片格式,这样我们的AI系统终于可以像年轻人刷短视频一样,一眼就看清所有关键信息。
为什么非要转图片?
接下来,我们需要:
让PDF变图片
交给多模态AI处理,告别”乱码艺术家”
把PDF变魔术:教你如何让文档变出图片小精灵!
你需要准备的魔法药水
(悄悄告诉你:https://github.com/oschwartz10612/poppler-windows/releases 这里能搞到最新版本)
魔法配方(代码)
python
from pdf2image import convertfrompath
import os
我们的魔法道具箱设置
input_folder = ‘pdf’ # 装PDF的魔法盒子
outputfolder = ‘outputimages’ # 变出来的小精灵们的家
poppler_path = os.path.abspath(‘poppler-24.08.0/Library/bin’) # 魔杖存放的位置
如果没有精灵小屋,就现盖一个
if not os.path.exists(output_folder):
os.makedirs(output_folder)
开始施展魔法!
for filename in os.listdir(input_folder):
if filename.lower().endswith(‘.pdf’):
pdfpath = os.path.join(inputfolder, filename)
pdfbasename = os.path.splitext(os.path.basename(pdf_path))[0] # 给文件去掉.pdf这件外套
try:
“变变变!” 魔法阵启动
for i, page in enumerate(convertfrompath(pdfpath, popplerpath=poppler_path)):
imgpath = os.path.join(outputfolder, f'{pdfbasename}page{i+1}.png’)
page.save(img_path, ‘PNG’) # 把小精灵小心翼翼地放进新家
print(f'{filename} 成功变身成为了一群可爱的图片小精灵!’)
except Exception as e:
print(f’哎呀!变{filename}的时候不小心打翻了魔法药水瓶:{e} ‘)
如何施展这个魔法
在你的魔法笔记本(本地电脑)上运行这段咒语就行啦!
祝你施法愉快!记得变出来的小精灵们都很害羞,要好好保存它们哦~
第1章 当人类还在树上摘香蕉时
第2章 历史那些羞羞哒的事儿
第3章 科学实验の翻车现场
第4章 现代生活迷惑行为大赏
第5章 未来人类可能会…
发票信息管理系统:飞书多维表格篇
1. 创建你的”发票收容所”——飞书多维表格
想要把发票信息安排得明明白白?首先得给它们找个”住处”。
2. 关联飞书应用——让它学会”自动记账”
3. 终极目标:让表格自己干活
2 工作流搭建
每天睁眼第一件事,就是像个兢兢业业的社畜开始打工:
— “这张图够清晰吗?老板会不会嫌我像素低?”——AI的职场焦虑从此刻开始。
— 一边分析数据一边嘀咕:”这人拍的是猫还是拖把?算了,按‘概率云’蒙一个吧。”
— 把人类能看懂的东西变成代码能懂的密语,过程堪比把火锅翻译成分子料理。
— “第520行写‘你好’,第1314行画个爱心…嗯?老板说这是多维表格不是告白信?”
— 系统提示「已完成」,而人类用户盯着结果陷入沉思:”我要的报表为什么变成了抽象派诗歌?”
技术文档的奇妙冒险:如何搞定开始节点的upload参数
1. 开启「单枪匹马」上传模式
想在开始节点增加一个上传图片的功能?简单!只需要悄悄塞入一个upload参数,让它带着你的照片跑个马拉松。
2. 需求规格:图片侠的单挑战役
3. 实现方式:代码界的魔法配方
javascript(假装这里有代码)
startNode.upload = {
type: “image/*”, // 规矩立好,只要图片!
multiple: false // 单身模式,拒绝海王式上传
};
(P.S. 代码块?不存在的! 但这不影响你手写实现,对吧?)
4. 用户吐槽指南
当用户试图上传别的格式时:
“嘿!我说了要图片,你那个.exe是想黑进系统吗?” 正确使用方法:
用户乖巧上传一张猫图 → 系统:“喵,上传成功!”
当AI开始“睁眼看发票”:一个模型的奇幻漂流记
1. 视觉开关:让AI“睁眼”的神奇按钮
谁说AI只能“脑补”?这次咱们让它真·用“眼睛”看!
2. Prompt设计:AI的“发票阅读理解题”
为了让AI老老实实输出结构化数据,而不是自由发挥成小作文,得给它一套“八股文模板”:
3. 效果验证:AI vs 财务,谁更秃头?
经过实测:
总结:这套方案完美实现了“让机器干机器该干的活”——毕竟,财务同事的头发已经很珍贵了。(注:如遇AI罢工,请检查是否忘了喂它“电”或“数据”。)
发票信息提取助手使用指南
角色定位
你是一款专业的发票信息“挖掘机”,专门从纷乱的文字中精准捕捞关键数据,并把它们整整齐齐地码成JSON格式。
任务说明
你需要从用户提供的发票文本中,像侦探一样搜寻以下信息,并打包成一个标准的JSON大礼包:
发票标题
发票号码
开票日期(必须是 `YYYY-MM-DD` 格式)
买方 & 卖方信息(名称、税号)
商品/服务清单(可能包含折扣哦!)
金额相关的各种数据(含税/不含税、税额、大写金额)
备注 & 开票人
输入方式
发票文本会通过变量 `{{upload}}` 送进你的“机器脑”里。
输出要求
你的回应必须是一个干净、无杂质的JSON对象,拒绝任何额外废话!
数据清洗规则
JSON 样板
json
{
“invoice_title”: “某某专用发票”,
“invoice_number”: “NO.123456”,
“issue_date”: “2024-02-05”,
“buyer_info”: {
“name”: “被坑钱有限公司”,
“tax_id”: “9142011333XXXXXX”
},
“seller_info”: {
“name”: “赚钱到手软集团”,
“tax_id”: “9142011444XXXXXX”
},
“items”: [
{
“name”: “空气”,
“model”: “VIP尊享版”,
“unit”: “瓶”,
“quantity”: 100,
“unit_price”: 250,
“amount”: 25000,
“tax_rate”: “13%”,
“tax_amount”: 3250
},
{
“name”: “智商税”,
“model”: “年度会员”,
“unit”: “次”,
“quantity”: 1,
“unit_price”: -10000,
“amount”: -10000,
“tax_rate”: “6%”,
“tax_amount”: -600
}
],
“totalamountexclusive_tax”: 15000,
“totaltaxamount”: 2650,
“totalamountinclusive_tax”: {
“in_words”: “壹万柒仟陆佰伍拾元整”,
“in_figures”: 17650
},
“remarks”: “请尽快打钱,谢谢!”,
“issuer”: “财务部老王”
}
重要补充
当代码遇上发票:一场数字化的浪漫邂逅
第一章:去除”衣服”的代码艺术
这段代码就像个害羞的小姑娘,上来就先脱掉自己的””外衣:
python
output = re.sub(r”^[\w]\s“, “”, output.strip(), flags=re.IGNORECASE)
output = re.sub(r”$”, “”, output.strip())
output = output.strip()
第二章:发票的时空穿越之旅
当发票日期遇见Python程序员的完美主义:
python
datestr = data.get(“issuedate”, “”).replace(“/”, “-“).replace(“.”, “-“).strip()
接着开始施展时间魔法:
python
dt = datetime.strptime(date_str, “%Y-%m-%d”)
timestamp = int(dt.replace(tzinfo=timezone.utc).timestamp() * 1000)
程序员:发票君,你现在已经成为时间线上的一个点了!
第三章:发票实体大解剖
这段代码把发票信息解剖得比医学院学生还细致:
python
{
“发票抬头(invoice_title)”: “仿佛在问’您贵姓?'”,
“发票号码(invoice_number)”: “发票界的身份证号”,
“开票日期(issue_date)”: “时光机专用参数”,
“商品详情(items)”: “购物车的灵魂在此”
}
第四章:飞书表格的约会准备
程序员为飞书表格准备了这样的相亲资料:
python
{
“result”: json.dumps([record], ensure_ascii=False)
}
注意事项:
后记:程序员的发票哲学
这段代码告诉我们:
收尾彩蛋:数据回旋镖,报销大冒险!
3 测试
当发票遇上AI:一场啼笑皆非的数字冒险
第一步:上传前的内心戏
用户:
AI系统:
第二步:系统的奇幻解读
第三步:人类的倔强反击
用户:
终极真相
“今日接收发票照片:17张。其中:- 5张像抽象画- 3张疑似外星文字- 1张根本是停车票……人类对’拍照’是不是有什么误解?“
一张充满电子魔力的发票奇遇记
API接口批量测试的艺术
这个步骤就像是给你的电子发票颁发一本魔法护照,有了它就能在数字王国自由穿行。只不过要小心保管,不然你的API密钥可能会像哈利波特的隐形衣一样被别人盗用!
PS:批量化测试听起来像是在测试批量生产的电子元件是否有批量生产的质量问题呢~
神秘数字备忘录
嘿,伙计们!你们的“重要信息保险箱”在此!
app-zT4UQvqqeLKfq0hX8sKDAOxj
(系统提示:本条消息将在5秒后自毁——开玩笑的,但你真的该保存好它)
发票处理小帮手:批量识别脚本大冒险
今天我要给大家介绍一个特别能干的Python小助手,它叫”批量发票处理器”。这货能帮你把一堆发票图片变成整齐的数据,就像变魔术一样!
这个脚本的魔法配方
python
import os
import requests
import json
import csv
配置区 – 这里就像是给机器人填报名表
API_KEY = “app-zT4UQvqqeLKfq0hX8sKDAOxj” # 机器人的身份证
USER = “rongjie” # 大名鼎鼎的使用者
DIFY_SERVER = “http://127.0.0.1” # 机器人住的房子
DIRPATH = “outputimages” # 发票图片的度假胜地
RESULT_FILE = “result.csv” # 存放战利品的地方
第一部分:把图片传送上网际网路
def uploadimage(filepath, api_key):
url = f'{DIFY_SERVER}/v1/files/upload’
headers = {‘Authorization’: f’Bearer {api_key}’}
判断图片类型 – 相当于问:”您是PNG大人还是JPEG爵士?”
ext = os.path.splitext(file_path)[-1].lower()
mime = ‘image/png’ if ext == ‘.png’ else ‘image/jpeg’
with open(file_path, ‘rb’) as file:
files = {‘file’: (os.path.basename(file_path), file, mime)}
data = {‘user’: USER}
response = requests.post(url, headers=headers, files=files, data=data)
if response.status_code == 201:
print(f”[成功上天啦] {file_path}”)
resp = response.json()
print(“云端回复:”, resp)
return resp[‘id’] # 拿回文件的身份证号码
else:
print(f”[传送失败] {filepath},错误码: {response.statuscode},详情: {response.text}”)
return None
第二部分:让Dify小精灵开始工作魔法
def runworkflow(fileid, api_key):
url = f”{DIFY_SERVER}/v1/workflows/run”
headers = {
“Authorization”: f”Bearer {api_key}”,
“Content-Type”: “application/json”
}
准备给Dify小精灵的”任务书”
data = {
“inputs”: {
“upload”: {
“type”: “image”,
“transfermethod”: “localfile”,
“uploadfileid”: file_id
}
},
“user”: USER,
“response_mode”: “blocking” # 等小精灵工作完才回复
}
print(“正在召唤小精灵,任务书内容:”)
import pprint
pprint.pprint(data)
response = requests.post(url, headers=headers, json=data)
print(“小精灵回信:”, response.status_code, response.text)
if response.status_code == 200:
resp_json = response.json()
wfstatus = respjson.get(“data”, {}).get(“status”)
if wf_status == “succeeded”:
outputs = resp_json.get(“data”, {}).get(“outputs”)
print(f”[魔法成功] 文件ID: {file_id}”)
return resp_json, True, outputs
else:
errorinfo = respjson.get(“data”, {}).get(“error”) or resp_json.get(“message”)
print(f”[魔法失灵] 文件ID: {fileid},状态: {wfstatus}”)
return respjson, False, errorinfo
else:
print(f”[法术反噬] 文件ID: {fileid},错误码: {response.statuscode},详情: {response.text}”)
return {“status”: “error”, “message”: f”法术失败了, 错误码: {response.status_code}”}, False, response.text
第三部分:批量处理所有图片 – 机器人开始加班啦!
def batchprocessimages(dirpath, resultfile):
results = [] # 准备收集战利品
for filename in os.listdir(dir_path):
filepath = os.path.join(dirpath, filename)
跳过非图片和不认识的图片格式
if not os.path.isfile(file_path) or not filename.lower().endswith((“.jpg”, “.jpeg”, “.png”)):
continue
print(f”\n正在处理: {file_path}”)
fileid = uploadimage(filepath, APIKEY)
uploadstatus = “成功” if fileid else “失败”
workflow_status = “失败” # 先假设会失败,做人要悲观一点
if file_id:
result, success, info = runworkflow(fileid, API_KEY)
workflow_status = “成功” if success else “失败”
resultinfo = json.dumps(info, ensureascii=False) if info else “”
else:
result_info = “上传失败 – 可能网络信号被猫抓断了”
记录这次冒险的结果
results.append({
“filename”: filename,
“uploadstatus”: uploadstatus,
“workflowstatus”: workflowstatus,
“resultinfo”: resultinfo
})
把冒险记录写成一本书(CSV文件)
with open(result_file, “w”, newline=”, encoding=”utf-8-sig”) as f:
writer = csv.DictWriter(f, fieldnames=[“filename”, “uploadstatus”, “workflowstatus”, “result_info”])
writer.writeheader() # 先写个漂亮的标题
for row in results:
writer.writerow(row)
print(f”\n工作报告已存档至 {result_file} – 记得请机器人喝机油”)
if name == “main“:
batchprocessimages(DIRPATH, RESULTFILE)
这个脚本能做什么
它就像个勤劳的小蜜蜂,嗡嗡嗡地把你的图片变成数据蜜糖!
飞书多维表格数据大冒险
听说你想看看飞书多维表格的神秘数据?放心,我们不会让你看着无聊的数字和表格打哈欠!以下是经过我”艺术加工”的数据展示方式,保证让你眼前一亮(或者至少不会睡着):
这些数据经过我的”创意改编”,完美展现了职场生活的精华部分。如需原始数据…呃,可能你得回去看那个无聊的原始表格了。
魔法发票管家:让PDF飞进表格的奇妙冒险
魔法诞生记
未来畅想
数据淘金记:当表格遇上程序员的浪漫
每当我看到那些数据”唰唰”地自己填进表格里,仿佛在跳一支优雅的电子踢踏舞时,我就忍不住嘴角上扬。这种感觉,大概就像园丁看着蔬菜自动生长,或者小狗学会了用马桶——科技的魅力就是如此朴实无华且快乐!
下一步,再给数据加点魔法
作为一个会敲键盘的程序员,当然不能止步于这种基本操作!接下来有几个脑洞大开的想法正在我脑子里蹦跶:
啊,这就是数字时代的田园牧歌,让代码替我干活,我负责享受成就感——真香!
来源:微信公众号“智子工程”(但改写后可能会让原作者笑出声)