【PDF提取表格】如何提取发票内容文字并导出到Excel表格,并将发票用发票号改名,基于pdf电子发票的应用实现
应用场景
该应用主要用于企业财务部门或个人处理大量电子发票,实现以下功能:
- 自动从 PDF 电子发票中提取关键信息(如发票号码、日期、金额、销售方等)
- 将提取的信息整理并导出到 Excel 表格,方便进行财务统计和报销
- 使用发票号码自动重命名发票文件,便于文件管理和检索
界面设计
界面采用直观的标签页设计,主要包含以下部分:
- 文件选择区域:提供两种方式选择发票文件
- 单个或多个文件选择
- 整个文件夹选择
- 文件列表显示:显示已选择的发票文件
- 导出设置:设置输出 Excel 文件的路径
- 处理进度显示:包括进度条和状态文本
- 日志区域:实时显示处理过程中的信息和错误
详细代码步骤
import os
import re
import pandas as pd
import pdfplumber
from datetime import datetime
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import threading
import loggingclass InvoiceProcessor:def __init__(self):self.invoice_data = []self.logger = self.setup_logger()def setup_logger(self):"""设置日志记录"""logger = logging.getLogger('InvoiceProcessor')logger.setLevel(logging.INFO)formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')# 输出到文件file_handler = logging.FileHandler('invoice_processor.log')file_handler.setFormatter(formatter)logger.addHandler(file_handler)# 输出到控制台stream_handler = logging.StreamHandler()stream_handler.setFormatter(formatter)logger.addHandler(stream_handler)return loggerdef extract_invoice_info(self, pdf_path):"""从PDF中提取发票信息"""try:with pdfplumber.open(pdf_path) as pdf:text = ""for page in pdf.pages:text += page.extract_text() or ""# 使用正则表达式提取发票信息invoice_number = re.search(r'发票号码[::]?\s*(\d+)', text)invoice_date = re.search(r'开票日期[::]?\s*(\d{4}年\d{1,2}月\d{1,2}日)', text)total_amount = re.search(r'金额[::]?\s*¥?\s*(\d+\.\d{2})', text)# 提取纳税人识别号taxpayer_id = re.search(r'纳税人识别号[::]?\s*([0-9A-Z]+)', text)# 提取购买方名称buyer_name = re.search(r'购买方名称[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9]+)', text)# 提取销售方名称seller_name = re.search(r'销售方名称[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9]+)', text)# 提取服务名称(项目名称)service_name = re.search(r'服务名称[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9]+)', text)if not service_name:service_name = re.search(r'货物或应税劳务、服务名称\s*([\u4e00-\u9fa5a-zA-Z0-9]+)', text)# 提取价税合计total_tax_amount = re.search(r'价税合计[::]?\s*[人民币]*\s*¥?\s*(\d+\.\d{2})', text)if not total_tax_amount:total_tax_amount = total_amount# 提取密文区cipher_text = re.search(r'密文区[::]?\s*([\dA-Z]+)', text)# 提取备注remark = re.search(r'备注[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9\s]+)', text)# 提取校验码check_code = re.search(r'校验码[::]?\s*(\d+)', text)# 提取税率tax_rate = re.search(r'税率[::]?\s*(\d+\.\d+%)', text)# 提取税额tax_amount = re.search(r'税额[::]?\s*¥?\s*(\d+\.\d{2})', text)# 提取机器编号machine_code = re.search(r'机器编号[::]?\s*(\d+)', text)# 提取收款人cashier = re.search(r'收款人[::]?\s*([\u4e00-\u9fa5]+)', text)# 提取复核人reviewer = re.search(r'复核[::]?\s*([\u4e00-\u9fa5]+)', text)# 提取开票人drawer = re.search(r'开票人[::]?\s*([\u4e00-\u9fa5]+)', text)# 提取发票类型invoice_type = re.search(r'([增值税专用|增值税普通|机动车销售统一|通用机打|电子|卷式|定额])发票', text)# 提取地址、电话address_phone = re.search(r'地址、电话[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9\s]+)', text)# 提取开户行及账号bank_info = re.search(r'开户行及账号[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9\s]+)', text)# 提取机器编号machine_number = re.search(r'机器编号[::]?\s*([0-9]+)', text)# 提取发票代码invoice_code = re.search(r'发票代码[::]?\s*([0-9]+)', text)# 提取密码区password_area = re.search(r'密码区[::]?\s*([\dA-Za-z]+)', text)# 提取二维码信息qr_code = re.search(r'二维码[::]?\s*([\dA-Za-z]+)', text)# 提取商品或服务明细details_pattern = r'商品或服务名称\s*规格型号\s*单位\s*数量\s*单价\s*金额\s*税率\s*税额\s*([\s\S]*?)合计'details_match = re.search(details_pattern, text)details = details_match.group(1).strip() if details_match else ""# 提取合计金额(大写)total_amount_in_words = re.search(r'合计金额[::]?\s*([\u4e00-\u9fa5零壹贰叁肆伍陆柒捌玖拾佰仟万亿元角分整]+)', text)# 提取合计税额total_tax = re.search(r'合计税额[::]?\s*¥?\s*(\d+\.\d{2})', text)# 提取价税合计(大写)total_amount_in_words_full = re.search(r'价税合计\s*\(大写\)\s*([\u4e00-\u9fa5零壹贰叁肆伍陆柒捌玖拾佰仟万亿元角分整]+)', text)# 提取价税合计(小写)total_amount_in_figures = re.search(r'价税合计\s*\(小写\)\s*¥?\s*(\d+\.\d{2})', text)# 提取收款人、复核人、开票人signature_info = re.search(r'收款人[::]?\s*([\u4e00-\u9fa5]+)\s*复核[::]?\s*([\u4e00-\u9fa5]+)\s*开票人[::]?\s*([\u4e00-\u9fa5]+)', text)# 提取销售方纳税人识别号seller_tax_id = re.search(r'销售方[::]?\s*纳税人识别号[::]?\s*([0-9A-Z]+)', text)# 提取销售方地址、电话seller_address_phone = re.search(r'销售方[::]?\s*地址、电话[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9\s]+)', text)# 提取销售方开户行及账号seller_bank_info = re.search(r'销售方[::]?\s*开户行及账号[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9\s]+)', text)# 提取购买方纳税人识别号buyer_tax_id = re.search(r'购买方[::]?\s*纳税人识别号[::]?\s*([0-9A-Z]+)', text)# 提取购买方地址、电话buyer_address_phone = re.search(r'购买方[::]?\s*地址、电话[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9\s]+)', text)# 提取购买方开户行及账号buyer_bank_info = re.search(r'购买方[::]?\s*开户行及账号[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9\s]+)', text)# 提取机器编号、发票代码、发票号码组合信息machine_invoice_info = re.search(r'机器编号[::]?\s*([0-9]+)\s*发票代码[::]?\s*([0-9]+)\s*发票号码[::]?\s*([0-9]+)', text)# 提取日期(不同格式)date_patterns = [r'日期[::]?\s*(\d{4}年\d{1,2}月\d{1,2}日)',r'日期[::]?\s*(\d{4}/\d{1,2}/\d{1,2})',r'日期[::]?\s*(\d{4}-\d{1,2}-\d{1,2})',r'日期[::]?\s*(\d{4}\.\d{1,2}\.\d{1,2})']invoice_date = Nonefor pattern in date_patterns:date_match = re.search(pattern, text)if date_match:invoice_date = date_match.group(1)break# 提取金额(不同格式)amount_patterns = [r'金额[::]?\s*¥?\s*(\d+\.\d{2})',r'金额[::]?\s*¥?\s*(\d+\,\d+\.\d{2})',r'价税合计[::]?\s*[人民币]*\s*¥?\s*(\d+\.\d{2})',r'合计[::]?\s*¥?\s*(\d+\.\d{2})']total_amount = Nonefor pattern in amount_patterns:amount_match = re.search(pattern, text)if amount_match:total_amount = amount_match.group(1)break# 提取发票号码(不同格式)invoice_number = Nonefor pattern in [r'发票号码[::]?\s*(\d+)',r'发票号码[::]?\s*([A-Z]\d+)',r'发票号[::]?\s*(\d+)',r'发票号[::]?\s*([A-Z]\d+)']:number_match = re.search(pattern, text)if number_match:invoice_number = number_match.group(1)break# 提取其他可能的信息# 提取二维码区域信息qr_area = re.search(r'二维码[::]?\s*([\d\w\s]+)', text)# 提取机器编号(多种可能位置)machine_code = Nonefor pattern in [r'机器编号[::]?\s*(\d+)',r'机打代码[::]?\s*(\d+)',r'机打号码[::]?\s*(\d+)']:machine_match = re.search(pattern, text)if machine_match:machine_code = machine_match.group(1)break# 提取校验码check_code = re.search(r'校验码[::]?\s*([\dA-Z]+)', text)# 提取购买方信息(公司名称)buyer_info = re.search(r'购买方[::]?\s*名称[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9\(\)\(\)]+)', text)# 提取销售方信息(公司名称)seller_info = re.search(r'销售方[::]?\s*名称[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9\(\)\(\)]+)', text)# 提取项目内容items_pattern = r'项目[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9\s]+)'items_match = re.search(items_pattern, text)items = items_match.group(1).strip() if items_match else ""# 提取服务内容service_pattern = r'服务内容[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9\s]+)'service_match = re.search(service_pattern, text)service = service_match.group(1).strip() if service_match else ""# 提取金额明细amount_details_pattern = r'金额明细[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9\s\(\)\(\)\d\.\,]+)'amount_details_match = re.search(amount_details_pattern, text)amount_details = amount_details_match.group(1).strip() if amount_details_match else ""# 提取备注信息remark_pattern = r'备注[::]?\s*([\u4e00-\u9fa5a-zA-Z0-9\s\(\)\(\)\d\.\,]+)'remark_match = re.search(remark_pattern, text)remark = remark_match.group(1).strip() if remark_match else ""# 提取收款人、复核人、开票人signature_pattern = r'收款人[::]?\s*([\u4e00-\u9fa5]+)\s*复核[::]?\s*([\u4e00-\u9fa5]+)\s*开票人[::]?\s*([\u4e00-\u9fa5]+)'signature_match = re.search(signature_pattern, text)cashier = signature_match.group(1) if signature_match else ""reviewer = signature_match.group(2) if signature_match else ""drawer = signature_match.group(3) if signature_match else ""# 提取发票类型invoice_type_pattern = r'([增值税专用|增值税普通|机动车销售统一|通用机打|电子|卷式|定额])发票'invoice_type_match = re.search(invoice_type_pattern, text)invoice_type = invoice_type_match.group(1) if invoice_type_match else ""# 提取日期并格式化date_str = invoice_date.group(1) if invoice_date else ""try:if '年' in date_str and '月' in date_str and '日' in date_str:date_obj = datetime.strptime(date_str, '%Y年%m月%d日')elif '/' in date_str:date_obj = datetime.strptime(date_str, '%Y/%m/%d')elif '-' in date_str:date_obj = datetime.strptime(date_str, '%Y-%m-%d')elif '.' in date_str:date_obj = datetime.strptime(date_str, '%Y.%m.%d')else:date_obj = Noneformatted_date = date_obj.strftime('%Y-%m-%d') if date_obj else ""except:formatted_date = date_str# 提取金额并转换为浮点数amount_str = total_amount.group(1) if total_amount else "0.00"amount_str = amount_str.replace(',', '') # 移除千位分隔符try:amount = float(amount_str)except:amount = 0.00# 提取发票号码number = invoice_number.group(1) if invoice_number else ""# 提取纳税人识别号tax_id = taxpayer_id.group(1) if taxpayer_id else ""# 提取购买方名称buyer = buyer_name.group(1) if buyer_name else ""# 提取销售方名称seller = seller_name.group(1) if seller_name else ""# 提取服务名称service = service_name.group(1) if service_name else ""# 创建发票信息字典invoice_info = {'文件路径': pdf_path,'发票号码': number,'发票日期': formatted_date,'金额': amount,'纳税人识别号': tax_id,'购买方名称': buyer,'销售方名称': seller,'服务名称': service,'发票类型': invoice_type,'收款人': cashier,'复核人': reviewer,'开票人': drawer,'备注': remark,'提取状态': '成功'}# 添加其他可能提取的信息additional_info = {'机器编号': machine_code.group(1) if machine_code else "",'发票代码': invoice_code.group(1) if invoice_code else "",'校验码': check_code.group(1) if check_code else "",'价税合计': total_tax_amount.group(1) if total_tax_amount else "",'税额': tax_amount.group(1) if tax_amount else "",'税率': tax_rate.group(1) if tax_rate else "",'密文区': cipher_text.group(1) if cipher_text else "",'销售方纳税人识别号': seller_tax_id.group(1) if seller_tax_id else "",'购买方纳税人识别号': buyer_tax_id.group(1) if buyer_tax_id else "",'销售方地址电话': seller_address_phone.group(1) if seller_address_phone else "",'购买方地址电话': buyer_address_phone.group(1) if buyer_address_phone else "",'销售方开户行账号': seller_bank_info.group(1) if seller_bank_info else "",'购买方开户行账号': buyer_bank_info.group(1) if buyer_bank_info else "",'金额大写': total_amount_in_words.group(1) if total_amount_in_words else "",'价税合计大写': total_amount_in_words_full.group(1) if total_amount_in_words_full else "",'商品服务明细': details,'二维码信息': qr_code.group(1) if qr_code else ""}# 合并主要信息和附加信息invoice_info.update(additional_info)return invoice_infoexcept Exception as e:self.logger.error(f"提取文件 {pdf_path} 时出错: {str(e)}")return {'文件路径': pdf_path,'发票号码': '','发票日期': '','金额': 0.0,'提取状态': f'失败: {str(e)}'}def process_invoices(self, pdf_paths):"""处理多个发票文件"""self.invoice_data = []total_files = len(pdf_paths)for i, pdf_path in enumerate(pdf_paths):try:progress = (i + 1) / total_files * 100yield progress, f"正在处理: {os.path.basename(pdf_path)}"invoice_info = self.extract_invoice_info(pdf_path)self.invoice_data.append(invoice_info)# 如果成功提取到发票号码,重命名文件if invoice_info['发票号码']:dirname = os.path.dirname(pdf_path)base_name = f"{invoice_info['发票号码']}.pdf"new_path = os.path.join(dirname, base_name)# 处理文件已存在的情况counter = 1while os.path.exists(new_path):base_name = f"{invoice_info['发票号码']}_{counter}.pdf"new_path = os.path.join(dirname, base_name)counter += 1os.rename(pdf_path, new_path)invoice_info['新文件路径'] = new_pathself.logger.info(f"文件已重命名: {pdf_path} -> {new_path}")else:invoice_info['新文件路径'] = pdf_pathself.logger.warning(f"未能提取到发票号码,文件未重命名: {pdf_path}")except Exception as e:self.logger.error(f"处理文件 {pdf_path} 时出错: {str(e)}")yield progress, f"处理文件 {os.path.basename(pdf_path)} 时出错: {str(e)}"self.logger.info(f"处理完成,共处理 {total_files} 个文件")yield 100, "处理完成"def export_to_excel(self, output_path):"""将提取的发票信息导出到Excel"""if not self.invoice_data:self.logger.warning("没有数据可导出")return Falsetry:df = pd.DataFrame(self.invoice_data)# 确保目录存在output_dir = os.path.dirname(output_path)if not os.path.exists(output_dir):os.makedirs(output_dir)# 导出到Excelwith pd.ExcelWriter(output_path, engine='openpyxl') as writer:df.to_excel(writer, sheet_name='发票信息', index=False)# 获取工作簿和工作表对象以进行格式设置workbook = writer.bookworksheet = writer.sheets['发票信息']# 设置列宽for i, col in enumerate(df.columns):column_width = max(len(str(x)) for x in df[col])column_width = max(column_width, len(col)) + 2column_width = min(column_width, 50) # 最大宽度限制worksheet.column_dimensions[chr(65 + i)].width = column_width# 创建表头样式header_format = workbook.add_format({'bold': True,'text_wrap': True,'valign': 'top','fg_color': '#D7E4BC','border': 1})# 应用表头样式for col_num, value in enumerate(df.columns.values):worksheet.cell(row=0, column=col_num).value = valueworksheet.cell(row=0, column=col_num).set_format(header_format)self.logger.info(f"数据已成功导出到 {output_path}")return Trueexcept Exception as e:self.logger.error(f"导出到Excel时出错: {str(e)}")return Falseclass InvoiceApp:def __init__(self, root):self.root = rootself.root.title("发票处理工具")self.root.geometry("800x600")self.root.minsize(600, 400)# 设置中文字体self.root.option_add("*Font", "SimHei 10")self.processor = InvoiceProcessor()self.selected_files = []self.output_path = ""self.create_widgets()def create_widgets(self):"""创建界面组件"""# 创建主框架main_frame = ttk.Frame(self.root, padding="20")main_frame.pack(fill=tk.BOTH, expand=True)# 文件选择区域file_frame = ttk.LabelFrame(main_frame, text="文件选择", padding="10")file_frame.pack(fill=tk.X, pady=(0, 10))# 文件选择按钮ttk.Button(file_frame, text="选择发票文件", command=self.select_files).pack(side=tk.LEFT, padx=(0, 10))ttk.Button(file_frame, text="选择文件夹", command=self.select_directory).pack(side=tk.LEFT)# 文件列表self.file_listbox = tk.Listbox(file_frame, height=5, width=70)self.file_listbox.pack(fill=tk.X, pady=(10, 0))# 导出设置区域export_frame = ttk.LabelFrame(main_frame, text="导出设置", padding="10")export_frame.pack(fill=tk.X, pady=(0, 10))# 输出文件路径ttk.Label(export_frame, text="输出Excel文件:").pack(side=tk.LEFT, padx=(0, 10))self.output_var = tk.StringVar(value="发票信息汇总.xlsx")output_entry = ttk.Entry(export_frame, textvariable=self.output_var, width=50)output_entry.pack(side=tk.LEFT, padx=(0, 10))ttk.Button(export_frame, text="浏览...", command=self.select_output_path).pack(side=tk.LEFT)# 处理按钮self.process_button = ttk.Button(main_frame, text="开始处理", command=self.process_invoices)self.process_button.pack(pady=(10, 20))# 进度条self.progress_var = tk.DoubleVar()self.progress_bar = ttk.Progressbar(main_frame, variable=self.progress_var, length=100)self.progress_bar.pack(fill=tk.X, pady=(0, 10))# 状态标签self.status_var = tk.StringVar(value="就绪")ttk.Label(main_frame, textvariable=self.status_var).pack(anchor=tk.W)# 日志区域log_frame = ttk.LabelFrame(main_frame, text="处理日志", padding="10")log_frame.pack(fill=tk.BOTH, expand=True, pady=(10, 0))self.log_text = tk.Text(log_frame, height=10, wrap=tk.WORD)self.log_text.pack(fill=tk.BOTH, expand=True)# 添加日志处理程序self.add_log_handler()def add_log_handler(self):"""添加日志处理程序将日志输出到界面"""class TextHandler(logging.Handler):def __init__(self, text_widget):logging.Handler.__init__(self)self.text_widget = text_widgetdef emit(self, record):msg = self.format(record)def append():self.text_widget.configure(state='normal')self.text_widget.insert(tk.END, msg + '\n')self.text_widget.configure(state='disabled')self.text_widget.yview(tk.END)self.text_widget.after(0, append)handler = TextHandler(self.log_text)handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))self.processor.logger.addHandler(handler)def select_files(self):"""选择多个文件"""file_paths = filedialog.askopenfilenames(title="选择发票PDF文件",filetypes=[("PDF文件", "*.pdf"), ("所有文件", "*.*")])if file_paths:self.selected_files = list(file_paths)self.update_file_listbox()def select_directory(self):"""选择文件夹"""directory = filedialog.askdirectory(title="选择包含发票PDF的文件夹")if directory:pdf_files = [os.path.join(directory, f) for f in os.listdir(directory) if f.lower().endswith('.pdf')]if pdf_files:self.selected_files = pdf_filesself.update_file_listbox()else:messagebox.showinfo("提示", "所选文件夹中未找到PDF文件")def update_file_listbox(self):"""更新文件列表显示"""self.file_listbox.delete(0, tk.END)for file_path in self.selected_files:self.file_listbox.insert(tk.END, os.path.basename(file_path))file_count = len(self.selected_files)self.status_var.set(f"已选择 {file_count} 个文件")def select_output_path(self):"""选择输出文件路径"""file_path = filedialog.asksaveasfilename(title="保存Excel文件",defaultextension=".xlsx",filetypes=[("Excel文件", "*.xlsx"), ("所有文件", "*.*")])if file_path:self.output_var.set(file_path)def process_invoices(self):"""处理发票文件"""if not self.selected_files:messagebox.showwarning("警告", "请先选择发票文件")returnoutput_path = self.output_var.get()if not output_path:messagebox.showwarning("警告", "请设置输出Excel文件路径")return# 禁用处理按钮防止重复点击self.process_button.config(state=tk.DISABLED)# 启动处理线程threading.Thread(target=self._process_invoices_thread, daemon=True).start()def _process_invoices_thread(self):"""在单独线程中处理发票,避免阻塞UI"""output_path = self.output_var.get()try:# 处理发票for progress, status in self.processor.process_invoices(self.selected_files):self.progress_var.set(progress)self.status_var.set(status)self.root.update_idletasks()# 导出到Excelif self.processor.export_to_excel(output_path):self.status_var.set(f"处理完成,数据已导出到 {output_path}")messagebox.showinfo("成功", f"处理完成,数据已导出到 {output_path}")else:self.status_var.set("导出Excel失败")messagebox.showerror("错误", "导出Excel失败,请查看日志")except Exception as e:self.status_var.set(f"处理过程中出错: {str(e)}")messagebox.showerror("错误", f"处理过程中出错: {str(e)}")finally:# 重新启用处理按钮self.process_button.config(state=tk.NORMAL)if __name__ == "__main__":root = tk.Tk()app = InvoiceApp(root)root.mainloop()
- 环境准备:安装必要的库,如 pdfplumber、pandas、tkinter 等
- 发票内容提取:
- 使用 pdfplumber 打开并读取 PDF 文件
- 使用正则表达式从文本中提取关键信息(发票号码、日期、金额等)
- 处理不同格式的发票,提高提取准确性
- 文件重命名:
- 使用提取的发票号码作为新文件名
- 处理文件已存在的情况,避免冲突
- Excel 导出:
- 使用 pandas 将提取的数据整理成 DataFrame
- 导出到 Excel 文件,并设置适当的格式
- 图形界面开发:
- 使用 tkinter 创建用户友好的界面
- 实现文件选择、进度显示和日志记录功能
- 使用多线程处理避免界面卡顿
总结优化
- 优点:
- 自动化处理,减少人工输入错误
- 界面友好,操作简单
- 详细的日志记录,方便排查问题
- 支持多种发票格式和内容提取
- 优化方向:
- 提高复杂发票的识别准确率,可以考虑使用 OCR 技术
- 添加数据验证和纠错功能
- 支持更多格式的发票文件(如图片格式)
- 增加数据统计和分析功能
- 实现批量处理和定时任务功能
- 添加用户权限管理和数据安全保护
使用这个应用程序,你可以轻松地处理大量电子发票,提高工作效率和准确性。
相关文章:

【PDF提取表格】如何提取发票内容文字并导出到Excel表格,并将发票用发票号改名,基于pdf电子发票的应用实现
应用场景 该应用主要用于企业财务部门或个人处理大量电子发票,实现以下功能: 自动从 PDF 电子发票中提取关键信息(如发票号码、日期、金额、销售方等)将提取的信息整理并导出到 Excel 表格,方便进行财务统计和报销使…...

Hugging Face 最新开源 SmolVLA 小模型入门教程(一)
系列文章目录 目录 系列文章目录 前言 一、引言 二、认识 SmolVLA! 三、如何使用SmolVLA? 3.1 安装 3.2 微调预训练模型 3.3 从头开始训练 四、方法 五、主要架构 5.1 视觉语言模型(VLM) 5.2 动作专家:流匹…...

封闭内网安装配置VSCode Anconda3 并配置 PyQt5开发
封闭内网安装配置VSCode Anconda3 并配置 PyQt5开发 零一 vscode1.1 下载 vscode1.2 下载插件1.3 安装 二 anaconda 32.1 下载2.2 新建虚拟环境1 新建快捷方式,启动base2 新建虚拟环境 3 配置Qt designer3.1 designer.exe和uic.exe3.2 设置插件,3.4 ui文件转为py文件 4使用4.1 …...

大话软工笔记—组合要素2之逻辑
1. 逻辑的概念 逻辑,指的是思维的规律和规则,是对思维过程的抽象。 结合逻辑的一般定义以及信息系统的设计方法,对逻辑的概念进行抽提、定义为三个核心内涵,即:规律、顺序、规则。 (1)规律&a…...
浅谈边缘计算
(꒪ꇴ꒪ ),Hello我是祐言QAQ我的博客主页:C/C语言,数据结构,Linux基础,ARM开发板,网络编程等领域UP🌍快上🚘,一起学习,让我们成为一个强大的攻城狮࿰…...
宝塔专属清理区域,宝塔清理MySQL日志(高效释放空间)
1. 删除超过 365 天的积分变更记录 宝塔面板 → 数据库 → 选择数据库 → 点击 管理 进入 phpMyAdmin 后: 选择在用的数据库名 看到顶部的 SQL 点击 输入命令 然后点击执行 DELETE FROM pre_common_credit_log WHERE dateline < UNIX_TIMESTAMP(DATE_SUB(NO…...

7.Demo Js执行同步任务,微任务,宏任务的顺序(3)
一个包含 同步任务、微任务(Promise)、宏任务(setTimeout) 的例子,JS 是怎么调度这些任务的。 🎯 例子代码(建议复制到浏览器控制台运行) console.log(‘同步任务 1’); setTimeo…...

边缘计算网关赋能沸石转轮运行故障智能诊断的配置实例
一、项目背景 在环保行业,随着国家对大气污染治理要求的不断提高,VOCs废气处理成为了众多企业的重要任务。沸石转轮作为一种高效的VOCs治理设备,被广泛应用于石油化工、汽车制造、印刷包装等主流行业。这些行业生产规模大、废气排放量多&…...
机器学习之深入理解机器学习常见算法:原理、公式与应用
机器学习之深入理解机器学习常见算法:原理、公式与应用 机器学习是一门让计算机自动从数据中学习规律的技术体系。常见的机器学习算法可以分为监督学习、无监督学习和深度学习三大类。本文将系统介绍每类中具有代表性的算法,并深入剖析其核心原理与数学基础。 一、监督学习(…...
Python实例题: Python 的简单电影信息
目录 Python实例题 题目 代码实现 实现原理 网页请求: 内容解析: 数据存储: 反爬策略: 关键代码解析 1. 网页请求处理 2. 电影列表解析 3. 电影详情解析 4. 爬虫主逻辑 使用说明 安装依赖: 修改配置&a…...
MyBatis 的动态 SQL
1. 动态 SQL 的定义 动态 SQL 是 MyBatis 的核心特性之一,它允许开发者根据运行时条件动态生成 SQL 语句。通过特殊的 XML 标签或注解语法,实现 SQL 的灵活拼接,避免在 Java 代码中手动拼接 SQL 字符串的复杂性和安全风险。 2. 核心作用 条…...
Redis中的setIfAbsent方法和execute
Redis中的setIfAbsent方法 Redis中的setIfAbsent方法是一种原子操作,它的作用是只有在指定的键不存在时才会设置值。这个方法在并发环境下非常有用,因为它可以避免多个客户端同时尝试设置相同键而导致的冲突。 代码示例 在Java中使用setIfAbsent方法通…...
高考数学易错考点02 | 临阵磨枪
文章目录 前言解析几何立体几何排列组合概率导数及应用前言 本篇内容下载于网络,网络上的都是以 WORD 版本呈现,缺字缺图很不完整,没法使用,我只是做了补充和完善。有空准备进行第二次完善,添加问题解释的链接。 ##平面向量 40.向量 0 ⃗ \vec{0} 0 与数 0 0 0 有区别…...
国产高性能pSRAM选型指南:CSS6404LS-LI 64Mb QSPI伪静态存储器
一、芯片基础特性 核心参数 容量 :64Mb(8M 8bit)电压 :单电源供电 2.7-3.6V (兼容3.3V系统)接口 :Quad-SPI(QPI/SPI)同步模式封装 : SOP-8L (150mil) &#…...
Go 中 `json.NewEncoder/Decoder` 与 `json.Marshal/Unmarshal` 的区别与实践
Go 中 json.NewEncoder/Decoder 与 json.Marshal/Unmarshal 的区别与实践(HTTP 示例) 在 Go 中处理 JSON 有两种主要方式:使用 json.Marshal/Unmarshal 和使用 json.NewEncoder/Decoder。它们都能完成 JSON 的序列化与反序列化,但…...

UE5 2D角色PaperZD插件动画状态机学习笔记
UE5 2D角色PaperZD插件动画状态机学习笔记 0.安装PaperZD插件 这是插件下载安装地址 https://www.fab.com/zh-cn/listings/6664e3b5-e376-47aa-a0dd-f7bbbd5b93c0 1.右键创建PaperZD 动画序列 2.添加动画序列 3,右键创建PaperZD AnimBP (动画蓝图&am…...

Ubuntu 16.04 密码找回
同事整理的供参考: 进入GRUB菜单 重启系统,在启动过程中长按Shift键(或Esc键)进入GRUB引导菜单。 若未显示GRUB菜单,可尝试在启动时连续按多次Shift/Esc键。 在GRUB菜单中选择默认的Ubuntu启动项(第一…...

【论文阅读】DanceGRPO: Unleashing GRPO on Visual Generation
DanceGRPO: Unleashing GRPO on Visual Generation 原文摘要 研究背景与问题 生成模型的突破:扩散模型和整流流等生成模型在视觉内容生成领域取得了显著进展。核心挑战:如何让模型的输出更好地符合人类偏好仍是一个关键问题。现有方法的局限性࿱…...

CentOS在vmware局域网内搭建DHCP服务器【踩坑记录】
1. 重新设置环境 配置dhcp服务踩了不少坑,这里重头搭建记录一下: 1.1 centos 网卡还原 如果之前搭了乱七八糟的环境,导致NAT模式也没法上网,这里重新还原 我们需要在NAT模式下联网,下载DHCP服务 先把centos的网卡还…...

AI炼丹日志-28 - Audiblez 将你的电子书epub转换为音频mp3 做有声书
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 大模型与Java双线更新中! 目前《大语言模型实战》已连载至第22篇,探索 MCP 自动操作 FigmaCursor 实…...
图像处理篇---face_recognition库实现人脸检测
以下是使用face_recognition库实现人脸检测的详细步骤、实例代码及解释: 一、环境准备 1. 安装依赖库 pip install face_recognition opencv-python # 核心库 pip install matplotlib # 用于显示图像(可选)2. 依赖说明 face_recognitio…...

74. 搜索二维矩阵 (力扣)
给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。…...

8088单板机C语言sprintf()格式化串口输出---Prj04
#include "tiny_stdarg.h" // 使用自定义可变参数实现#define ADR_273 0x0200 #define ADR_244 0x0400 #define LED_PORT 0x800 #define PC16550_THR 0x1f0 #define PC16550_LSR 0x1f5 / //基本的IO操作函数 / char str[]"Hello World! 20250531 Ve…...

板凳-------Mysql cookbook学习 (九)
第4章:表管理 4.0 引言 MySQL :: 员工样例数据库 :: 3 安装 https://dev.mysql.com/doc/employee/en/employees-installation.html Employees 数据库与几种不同的 存储引擎,默认情况下启用 InnoDB 引擎。编…...
深入解析 Flask 命令行工具与 flask run命令的使用
Flask 是一个轻量级的 Python Web 应用框架,其内置的命令行工具(CLI)基于 Click 库,提供了方便的命令行接口,用于管理和运行 Flask 应用程序。本文将详细介绍 Flask 命令行工具的功能,以及如何使用 flask r…...
第6篇:中间件 SQL 重写与语义分析引擎实现原理
6.1 章节导读 SQL 是数据库中间件的“输入语言”。 在一个真正强大的中间件系统中,SQL 语句的执行通常不再是“原封不动”地传递给数据库,而是需要先经过: 语义分析:解析 SQL 的结构和含义。 SQL 重写:根据中间件逻辑…...

基于SpringBoot的“嗨玩旅游”网站设计与实现(源码+定制+开发)嗨玩旅游平台开发:景点展示与个性化推荐系统(SpringBoot)
博主介绍: ✌我是阿龙,一名专注于Java技术领域的程序员,全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师,我在计算机毕业设计开发方面积累了丰富的经验。同时,我也是掘金、华为云、阿里云、InfoQ等平台…...

python版若依框架开发:python版若依部署
python版若依框架开发 从0起步,扬帆起航。 python版若依部署文章目录 python版若依框架开发1.源码2.概述3.部署1.源码 https://gitee.com/insistence2022/RuoYi-Vue-FastAPI 请诸君移步上述链接,即可对python版若依项目进行初步了解。 2.概述 若依框架本身基于java,可以快…...
React进阶:状态管理选择题
React进阶:状态管理选择题 引言 随着React应用复杂度增加,选择合适的状态管理方案成为我们面临的关键决策。 状态管理本质上是解决"谁来存储数据"以及"如何更新和分发这些数据"的问题。在React生态中,随着应用规模扩大…...

h5的aliplayer-min.js 加密视频会走到debugger
h5的aliplayer-min.js 如果 https://g.alicdn.com/apsara-media-box/imp-web-player/2.19.0/aliplayer-min.js走加密视频的话会有debugger 更换aliplayer-min.js版本解决了 https://g.alicdn.com/apsara-media-box/imp-web-player/2.25.1/aliplayer-min.js 对应css:…...