一、环境准备与基础组件安装
在开始构建企业数字档案馆系统之前,必须先搭建好稳定的基础运行环境。本指南基于Python 3.9+、PostgreSQL 14和Tesseract OCR引擎构建,这套组合能够满足企业级文档处理、结构化存储及全文检索的需求。
1. 安装Python环境
确保系统已安装Python 3.9或更高版本。在Linux终端执行以下命令安装依赖管理工具:
```bash
sudo apt-get update
sudo apt-get install python3.9 python3.9-venv python3-pip -y
```
2. 安装PostgreSQL数据库
PostgreSQL用于存储档案元数据及支持高效的全文检索:
```bash
sudo apt-get install postgresql postgresql-contrib -y
sudo service postgresql start
```
安装完成后,需要创建数据库和用户。执行以下命令进入PostgreSQL命令行:
```bash
sudo -u postgres psql
```
在PostgreSQL命令行中执行以下SQL语句完成初始化:
```sql
CREATE DATABASE digital_archive;
CREATE USER archive_admin WITH PASSWORD 'SecurePass123!';
GRANT ALL PRIVILEGES ON DATABASE digital_archive TO archive_admin;
\q
```
3. 安装Tesseract OCR引擎
这是实现纸质档案数字化的核心组件,支持中文识别:
```bash
sudo apt-get install tesseract-ocr tesseract-ocr-chi-sim -y
```
二、项目架构与依赖配置
创建一个标准的项目目录结构,并配置Python虚拟环境。请在合适的位置执行以下操作:
```bash
mkdir digital_archive_system
cd digital_archive_system
python3.9 -m venv venv
source venv/bin/activate
mkdir -p {app/static,app/templates,uploads,logs}
touch app/__init__.py app/main.py app/models.py app/database.py
```
1. 配置依赖文件
在项目根目录创建requirements.txt,并填入以下精确的依赖版本,避免版本冲突导致系统不可用:
```text
fastapi==0.104.1
uvicorn[standard]==0.24.0
sqlalchemy==2.0.23
psycopg2-binary==2.9.9
python-multipart==0.0.6
python-dotenv==1.0.0
pytesseract==0.3.10
pillow==10.1.0
passlib[bcrypt]==1.7.4
python-jose[cryptography]==3.3.0
alembic==1.12.1
```
执行安装命令:
```bash
pip install -r requirements.txt
```
2. 数据库连接配置
编辑app/database.py,配置数据库连接池。企业级应用必须配置连接池参数以防止高并发下连接耗尽:
```python
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
企业级连接字符串,请根据实际修改密码
SQLALCHEMY_DATABASE_URL = "postgresql://archive_admin:SecurePass123!@localhost/digital_archive"
连接池配置:预Ping检查连接有效性,池大小设为5,最大溢出10
engine = create_engine(
SQLALCHEMY_DATABASE_URL,
pool_size=5,
max_overflow=10,
pool_pre_ping=True,
pool_recycle=3600
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
依赖项获取数据库会话
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
```
三、数据模型设计(企业细则核心)
企业数字档案馆的核心在于对档案的精细化管理。我们需要定义符合档案管理规范的元数据模型,包括保管期限、密级、归档部门等关键字段。

编辑app/models.py,定义完整的数据库模型:
```python
from sqlalchemy import Column, Integer, String, Text, DateTime, Enum as SQLEnum
from sqlalchemy.sql import func
from app.database import Base
import enum
定义枚举类型,确保数据规范性
class RetentionPeriod(enum.Enum):
PERMANENT = "永久"
LONG_TERM = "30年"
SHORT_TERM = "10年"
class SecurityLevel(enum.Enum):
PUBLIC = "公开"
INTERNAL = "内部"
CONFIDENTIAL = "机密"
TOP_SECRET = "绝密"
class ArchiveRecord(Base):
__tablename__ = "archive_records"
id = Column(Integer, primary_key=True, index=True)
archive_code = Column(String(50), unique=True, index=True, nullable=False, comment="档号")
title = Column(String(200), nullable=False, comment="题名")
file_path = Column(String(500), nullable=False, comment="电子文件存储路径")
department = Column(String(100), nullable=False, comment="归档部门")
企业细则核心字段
retention_period = Column(SQLEnum(RetentionPeriod), nullable=False, comment="保管期限")
security_level = Column(SQLEnum(SecurityLevel), default=SecurityLevel.INTERNAL, comment="密级")
OCR识别后的全文内容,用于检索
ocr_content = Column(Text, nullable=True, comment="全文识别内容")
created_at = Column(DateTime(timezone=True), server_default=func.now(), comment="归档日期")
updated_at = Column(DateTime(timezone=True), onupdate=func.now(), comment="修改日期")
```
执行数据库初始化,创建表结构:
```bash
在项目根目录创建初始化脚本
cat > init_db.py << 'EOF'
from app.database import engine, Base
from app.models import ArchiveRecord
def init():
Base.metadata.create_all(bind=engine)
print("数据库表创建完成")
if __name__ == "__main__":
init()
EOF
python init_db.py
```
四、核心功能开发:文件上传与OCR识别
这一部分实现档案的接收、物理存储及文本化处理。这是数字档案馆区别于普通网盘的关键功能。
编辑app/main.py,实现文件上传和OCR处理逻辑:
```python
import os
import shutil
import uuid
from datetime import datetime
from fastapi import FastAPI, UploadFile, File, Depends, HTTPException, Form
from fastapi.staticfiles import StaticFiles
from sqlalchemy.orm import Session
from PIL import Image
import pytesseract
from typing import Optional
from app.database import get_db
from app.models import ArchiveRecord, RetentionPeriod, SecurityLevel
app = FastAPI(title="Enterprise Digital Archive System")
挂载静态文件目录
os.makedirs("uploads", exist_ok=True)
app.mount("/static", StaticFiles(directory="uploads"), name="static")
配置Tesseract路径(如果是Windows需要指定绝对路径,Linux通常默认)
pytesseract.pytesseract.tesseract_cmd = r'/usr/bin/tesseract'
@app.post("/api/v1/archives/upload")
async def upload_archive(
file: UploadFile = File(...),
title: str = Form(...),
department: str = Form(...),
retention_period: str = Form(...),
security_level: str = Form("INTERNAL"),
db: Session = Depends(get_db)
):
1. 校验文件类型
if not file.content_type.startswith("image/") and not file.filename.endswith(".pdf"):
raise HTTPException(status_code=400, detail="仅支持图片或PDF格式")
2. 生成唯一文件名和存储路径
file_extension = os.path.splitext(file.filename)[1]
unique_filename = f"{uuid.uuid4().hex}{file_extension}"
file_location = f"uploads/{unique_filename}"
保存文件
with open(file_location, "wb+") as file_object:
shutil.copyfileobj(file.file, file_object)
3. 执行OCR识别(仅针对图片演示,PDF需先拆页)
ocr_text = ""
try:
if file.content_type.startswith("image/"):
image = Image.open(file_location)
指定中英文混合识别
ocr_text = pytesseract.image_to_string(image, lang='chi_sim+eng')
except Exception as e:
print(f"OCR识别失败: {e}")
4. 生成档号 (规则: 部门代码-年-流水号,此处简化处理)
archive_code = f"{department[:3].upper()}-{datetime.now().strftime('%Y%m%d')}-{unique_filename[:8]}"
5. 构建数据库记录
try:
db_record = ArchiveRecord(
archive_code=archive_code,
title=title,
file_path=file_location,
department=department,
retention_period=RetentionPeriod(retention_period),
security_level=SecurityLevel(security_level),
ocr_content=ocr_text
)
db.add(db_record)
db.commit()
db.refresh(db_record)
except Exception as e:
db.rollback()
如果数据库写入失败,删除已上传的文件
if os.path.exists(file_location):
os.remove(file_location)
raise HTTPException(status_code=500, detail=f"数据库写入失败: {str(e)}")
return {
"message": "档案归档成功",
"archive_id": db_record.id,
"archive_code": db_record.archive_code,
"ocr_preview": ocr_text[:100] + "..." if len(ocr_text) > 100 else ocr_text
}
```
五、核心功能开发:全文检索与查询
企业档案馆不仅要存,还要能快速查。我们将利用PostgreSQL的强大全文检索能力,结合元数据进行多维度查询。
继续在app/main.py中添加检索接口:
```python
from sqlalchemy import or_, and_
@app.get("/api/v1/archives/search")
def search_archives(
keyword: Optional[str] = None,
department: Optional[str] = None,
security_level: Optional[str] = None,
db: Session = Depends(get_db)
):
query = db.query(ArchiveRecord)
1. 构建过滤条件
filters = []
if department:
filters.append(ArchiveRecord.department == department)
if security_level:
filters.append(ArchiveRecord.security_level == SecurityLevel(security_level))
if filters:
query = query.filter(and_(filters))
2. 全文检索逻辑 (在OCR内容和题名中搜索)
if keyword:
search_pattern = f"%{keyword}%"
query = query.filter(
or_(
ArchiveRecord.title.like(search_pattern),
ArchiveRecord.ocr_content.like(search_pattern),
ArchiveRecord.archive_code.like(search_pattern)
)
)
results = query.all()
格式化返回结果
return [
{
"id": r.id,
"archive_code": r.archive_code,
"title": r.title,
"department": r.department,
"retention_period": r.retention_period.value,
"security_level": r.security_level.value,
"created_at": r.created_at,
"file_url": f"/static/{os.path.basename(r.file_path)}"
}
for r in results
]
```
六、系统启动与接口测试
所有代码已就绪,现在启动服务并进行实际操作测试。
1. 启动Uvicorn服务器
在项目根目录执行以下命令启动API服务:
```bash
uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
```
2. 使用curl测试上传功能
准备一张测试图片test.jpg,然后执行以下命令模拟前端上传:
```bash
curl -X POST "http://localhost:8000/api/v1/archives/upload" \
-F "file=@test.jpg" \
-F "title=2023年度财务审计报告" \
-F "department=财务部" \
-F "retention_period=PERMANENT" \
-F "security_level=CONFIDENTIAL"
```
3. 测试检索功能
上传成功后,使用关键词检索档案:
```bash
curl -X GET "http://localhost:8000/api/v1/archives/search?keyword=财务&security_level=CONFIDENTIAL"
```
4. 验证OCR效果
检查返回结果中的ocr_preview字段,确认系统已成功提取图片中的文字信息。如果返回的是乱码,请检查系统是否安装了中文字库包tesseract-ocr-chi-sim。
七、生产环境部署补充细则
为了确保系统在企业生产环境中的高可用性,还需注意以下细则:
- 文件存储迁移:当前代码将文件存储在本地
uploads目录。生产环境务必将此目录挂载到高性能NAS或通过FastAPI适配MinIO/S3兼容的对象存储,以实现扩容和备份。
- Nginx反向代理:使用Nginx作为反向代理处理静态文件请求和负载均衡,并配置
client_max_body_size以支持大文件上传(建议设置为100M或更大)。
- 异步任务队列:OCR识别是耗时操作。在生产环境中,应引入Celery或Redis Queue,将上传和OCR解耦。API收到文件后立即返回“归档中”状态,后台异步处理OCR和数据库更新,避免请求超时。
- 权限控制:当前代码未包含JWT认证逻辑。在
app/main.py中引入依赖注入get_current_user,对所有接口进行权限校验,确保只有授权员工才能访问特定密级的档案。