From 4e8995eaed02e7e18c51d957ccb58c9fb03db636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E9=9B=A8?= Date: Sat, 6 Dec 2025 10:40:30 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat:=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6,?= =?UTF-8?q?=E7=94=9F=E6=88=90=E8=AE=B0=E5=BD=95=EF=BC=8C=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/__init__.py | 0 db/sql_db.py | 44 +++++++++++++++++++++++++++++++ main.py | 19 ++++++++++++-- requirements.txt | 5 +++- service/file_service.py | 58 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 db/__init__.py create mode 100644 db/sql_db.py create mode 100644 service/file_service.py diff --git a/db/__init__.py b/db/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/db/sql_db.py b/db/sql_db.py new file mode 100644 index 0000000..e6389fb --- /dev/null +++ b/db/sql_db.py @@ -0,0 +1,44 @@ +from sqlalchemy import Column, DateTime, Integer, BigInteger, String, create_engine, Boolean, Text +from sqlalchemy.orm import declarative_base, sessionmaker + +# 申明基类对象 +Base = declarative_base() +from decouple import config + +DB_PATH = config('DB_PATH', default='E://pyptoject//yj_resume//main.sqlite3') + + +class DBTASK(Base): + __tablename__ = 'db_task' + id = Column(String(100), primary_key=True) + create_time = Column(DateTime, nullable=False, ) + # 0 代表待执行,1 成功,2 失败 + status = Column(Integer, nullable=False, default=0) + success_num = Column(Integer, nullable=False, default=0) + total_num = Column(Integer, nullable=False, default=0) + fail_num = Column(Integer, nullable=False, default=0) + message = Column(Text, nullable=True) + + +class DBRESUME(Base): + __tablename__ = 'db_resume' + id = Column(String(100), primary_key=True) + # 每个任务对应一个文件夹ID + task_id = Column(String(100), nullable=False) + # 0 代表待执行,1 成功,2 失败 + status = Column(Integer, nullable=False, default=0) + file_name = Column(String(100), nullable=True) + # 可以用json表示提取的数据 + data_info = Column(Text, nullable=True) + # 错误信息等 + message = Column(Text, nullable=True) + + +class SqliteSqlalchemy(object): + def __init__(self): + # 创建sqlite连接引擎 + engine = create_engine(f'sqlite:///{DB_PATH}', echo=True) + # 创建表 + Base.metadata.create_all(engine, checkfirst=True) + # 创建sqlite的session连接对象 + self.session = sessionmaker(bind=engine)() diff --git a/main.py b/main.py index 6457a44..aadde7b 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,9 @@ from fastapi import FastAPI -import uvicorn +import uvicorn +from fastapi import FastAPI, File, UploadFile, HTTPException +from typing import List +from service.file_service import check_and_create_directory, upload_and_save_file + app = FastAPI() @@ -8,7 +12,18 @@ def read_root(): return {"Hello": "World"} +# 上传文件并解析,解析是异步错误 +@app.post("/upload_files_and_parse") +async def create_upload_files(files: List[UploadFile] = File(...)): + dir_id = check_and_create_directory(files) + if not dir_id: + return {"result": False, "code": 500, "message": "create directory failed"} + flag, message = await upload_and_save_file(dir_id, files) + if flag: + #触发异步任务,解析文件 TODO + pass + return {"result": flag, "message": message} if __name__ == '__main__': - uvicorn.run(app, host="127.0.0.1", port=3006) \ No newline at end of file + uvicorn.run(app, host="127.0.0.1", port=3006) diff --git a/requirements.txt b/requirements.txt index e9e78db..2972243 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,7 @@ python-docx fastapi uvicorn -docxtpl \ No newline at end of file +docxtpl +SQLAlchemy +python-decouple +python-multipart \ No newline at end of file diff --git a/service/file_service.py b/service/file_service.py new file mode 100644 index 0000000..5f83d65 --- /dev/null +++ b/service/file_service.py @@ -0,0 +1,58 @@ +from db.sql_db import DBTASK, DBRESUME, SqliteSqlalchemy +import uuid +from datetime import datetime +from decouple import config +import pathlib +from fastapi import File, UploadFile +from typing import List +import os + +BASE_PATH = config('BASE_PATH', default='E://pyptoject//yj_resume//') + + +def check_and_create_directory(files): + # 先创建一个task + if not files or len(files) == 0: + return None + id = str(uuid.uuid4()) + task = DBTASK(id=id, create_time=datetime.now(), status=0, success_num=0, total_num=len(files), + fail_num=0) + + session = SqliteSqlalchemy().session + try: + session.add(task) + session.commit() + except Exception as e: + print(f"Failed to save conversation info (id,user_id,cvs_id,question) error {e}") + session.rollback() + return None + finally: + session.close() + return id + + +async def upload_and_save_file(dir_id, files: List[UploadFile]) -> (bool, str): + pathxx = pathlib.Path(BASE_PATH).joinpath(dir_id) + pathxx.mkdir(parents=True, exist_ok=True) + data = [] + i = 0 + for file in files: + name, fix = os.path.splitext(file.filename) + if fix not in ['.doc', '.docx']: + continue + i = i + 1 + with open(pathxx.joinpath(str(i) + fix), 'wb') as f: + file_content = await file.read() + f.write(file_content) + data.append(DBRESUME(id=str(uuid.uuid4()), task_id=dir_id, status=0, file_name=str(i) + fix)) + session = SqliteSqlalchemy().session + try: + session.bulk_save_objects(data) + session.commit() + except Exception as e: + print(f"Failed to save conversation info (id,user_id,cvs_id,question) error {e}") + session.rollback() + return False, f"Failed to save conversation info (id,user_id,cvs_id,question) error {e}" + finally: + session.close() + return True, "success" From f32aa61c0fd21274059209ef94455b2ef0feb8e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E9=9B=A8?= Date: Sat, 6 Dec 2025 10:44:06 +0800 Subject: [PATCH 2/4] =?UTF-8?q?feat:=E4=BF=AE=E6=94=B9=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- service/file_service.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/service/file_service.py b/service/file_service.py index 5f83d65..6ac79cd 100644 --- a/service/file_service.py +++ b/service/file_service.py @@ -23,7 +23,7 @@ def check_and_create_directory(files): session.add(task) session.commit() except Exception as e: - print(f"Failed to save conversation info (id,user_id,cvs_id,question) error {e}") + print(f"Failed to save DBTASK info error {e}") session.rollback() return None finally: @@ -50,9 +50,9 @@ async def upload_and_save_file(dir_id, files: List[UploadFile]) -> (bool, str): session.bulk_save_objects(data) session.commit() except Exception as e: - print(f"Failed to save conversation info (id,user_id,cvs_id,question) error {e}") + print(f"Failed to save DBRESUME error {e}") session.rollback() - return False, f"Failed to save conversation info (id,user_id,cvs_id,question) error {e}" + return False, f"Failed to save DBRESUME error {e}" finally: session.close() return True, "success" From 8f3551306356501329553f0cb9e17cb8de11bf3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E9=9B=A8?= Date: Sat, 6 Dec 2025 10:58:46 +0800 Subject: [PATCH 3/4] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=88=B0excel=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/sql_db.py | 6 ++++-- requirements.txt | 4 +++- service/excel_service.py | 20 ++++++++++++++++++++ service/file_service.py | 1 + 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 service/excel_service.py diff --git a/db/sql_db.py b/db/sql_db.py index e6389fb..c95daf9 100644 --- a/db/sql_db.py +++ b/db/sql_db.py @@ -1,10 +1,8 @@ from sqlalchemy import Column, DateTime, Integer, BigInteger, String, create_engine, Boolean, Text from sqlalchemy.orm import declarative_base, sessionmaker - # 申明基类对象 Base = declarative_base() from decouple import config - DB_PATH = config('DB_PATH', default='E://pyptoject//yj_resume//main.sqlite3') @@ -42,3 +40,7 @@ class SqliteSqlalchemy(object): Base.metadata.create_all(engine, checkfirst=True) # 创建sqlite的session连接对象 self.session = sessionmaker(bind=engine)() + + + + diff --git a/requirements.txt b/requirements.txt index 2972243..a99a96a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,6 @@ uvicorn docxtpl SQLAlchemy python-decouple -python-multipart \ No newline at end of file +python-multipart +pandas +openpyxl diff --git a/service/excel_service.py b/service/excel_service.py new file mode 100644 index 0000000..db171cb --- /dev/null +++ b/service/excel_service.py @@ -0,0 +1,20 @@ +from db.sql_db import DBTASK, DBRESUME, SqliteSqlalchemy +import json +import pandas as pd +import pathlib +from decouple import config + +BASE_PATH = config('BASE_PATH', default='E://pyptoject//yj_resume//') + +#导出数据到excel +def export_to_excel(task_id): + # 获取所有成功的信息 + list_data = SqliteSqlalchemy().session.query(DBRESUME).filter_by(task_id=task_id, status=1).all() + pd_data = [] + for data in list_data: + pd_data.append(json.loads(data.data_info)) + data_frame = pd.DataFrame(pd_data) + # 导出到excel + pathxx = pathlib.Path(BASE_PATH).joinpath(task_id) + pathxx = pathxx.joinpath(f"{task_id}.xlsx") + data_frame.to_excel(pathxx, encoding='utf-8', index=False) diff --git a/service/file_service.py b/service/file_service.py index 6ac79cd..38bdc94 100644 --- a/service/file_service.py +++ b/service/file_service.py @@ -56,3 +56,4 @@ async def upload_and_save_file(dir_id, files: List[UploadFile]) -> (bool, str): finally: session.close() return True, "success" + From 9fd3376557772c4dbf65c74a406eb4c8281a7901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E9=9B=A8?= Date: Sat, 6 Dec 2025 11:14:45 +0800 Subject: [PATCH 4/4] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E5=88=B0excel=E5=8A=9F=E8=83=BD=5Fapi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.py | 9 ++++++++- service/excel_service.py | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index aadde7b..365622a 100644 --- a/main.py +++ b/main.py @@ -3,6 +3,7 @@ import uvicorn from fastapi import FastAPI, File, UploadFile, HTTPException from typing import List from service.file_service import check_and_create_directory, upload_and_save_file +from service import excel_service app = FastAPI() @@ -20,10 +21,16 @@ async def create_upload_files(files: List[UploadFile] = File(...)): return {"result": False, "code": 500, "message": "create directory failed"} flag, message = await upload_and_save_file(dir_id, files) if flag: - #触发异步任务,解析文件 TODO + # 触发异步任务,解析文件 TODO pass return {"result": flag, "message": message} +@app.get("/export_task_data_to_excel") +def export_task_data_to_excel(task_id: str): + message = excel_service.export_task_data_to_excel(task_id) + return {"message": message} + + if __name__ == '__main__': uvicorn.run(app, host="127.0.0.1", port=3006) diff --git a/service/excel_service.py b/service/excel_service.py index db171cb..3920057 100644 --- a/service/excel_service.py +++ b/service/excel_service.py @@ -6,7 +6,8 @@ from decouple import config BASE_PATH = config('BASE_PATH', default='E://pyptoject//yj_resume//') -#导出数据到excel + +# 导出数据到excel def export_to_excel(task_id): # 获取所有成功的信息 list_data = SqliteSqlalchemy().session.query(DBRESUME).filter_by(task_id=task_id, status=1).all() @@ -17,4 +18,13 @@ def export_to_excel(task_id): # 导出到excel pathxx = pathlib.Path(BASE_PATH).joinpath(task_id) pathxx = pathxx.joinpath(f"{task_id}.xlsx") - data_frame.to_excel(pathxx, encoding='utf-8', index=False) + data_frame.to_excel(pathxx, index=False) + + +def export_task_data_to_excel(task_id): + session = SqliteSqlalchemy().session + task = session.query(DBTASK).filter_by(id=task_id).first() + if not task or task.status == 0 or task.status == 2: + return "任务未完成或者失败" + export_to_excel(task_id) + return "导出成功"