数据库课程设计实践:构建DeOldify图像处理任务管理系统

发布时间:2026/7/4 1:23:00

数据库课程设计实践:构建DeOldify图像处理任务管理系统 数据库课程设计实践构建DeOldify图像处理任务管理系统每次数据库课程设计是不是都感觉在做“学生信息管理系统”或者“图书管理系统”这些经典题目虽然能练手但总觉得离现在火热的技术有点远。这次我们来点不一样的——用数据库技术亲手搭建一个能调用AI模型、处理真实任务的图像上色管理系统。想象一下用户上传一张黑白老照片系统自动调用DeOldify模型为它上色然后返回一张色彩生动的图片。这背后需要一个可靠的系统来管理用户、排队任务、记录状态。这不正是数据库大显身手的地方吗这个项目将带你从零开始设计数据库表、编写后端API并最终与星图GPU平台上的DeOldify服务对接完成一个完整的、有实际应用价值的系统。它不仅能帮你巩固数据库知识还能让你亲手体验如何将AI能力集成到自己的应用中。1. 项目概述与核心价值这个项目本质上是一个“任务调度与状态管理”系统。它的核心业务流程非常清晰用户提交任务系统记录并排队调用AI服务处理更新状态并返回结果。整个过程数据库扮演着“大脑”和“记事本”的角色确保每个环节的信息都不丢失、不错乱。对于学习者而言这个项目的价值是多方面的。首先它跳出了传统管理系统的框架引入了“异步任务”和“外部服务集成”这两个在现代Web开发中极其常见的概念。其次你将面对真实的技术选型问题比如图片怎么存、任务状态怎么设计、如何保证API的健壮性。最后当你看到自己写的代码成功调起AI模型将一张黑白照片变得色彩斑斓时那种成就感是无可比拟的。这不仅仅是一次课程作业更是一个可以写进简历的、能体现你综合工程能力的实战项目。2. 系统架构与核心流程在动手写代码之前我们先在脑子里把整个系统跑一遍。一个简化的系统架构可以分为三层表现层、应用层和数据层。表现层就是用户直接交互的界面可能是一个简单的网页表单让用户上传图片并点击“开始上色”。应用层是我们后端服务的核心它接收前端的请求与数据库和AI服务打交道。数据层就是我们的MySQL数据库负责持久化存储所有信息。而DeOldify模型则作为一个独立的AI服务部署在星图GPU平台上等待我们的调用。整个核心流程就像一条流水线用户通过前端页面上传一张黑白图片。后端API接收到图片立即在数据库中创建一条新的“任务”记录状态标记为“等待中”并把图片保存到服务器的某个目录或对象存储将路径记入数据库。后端有一个任务调度器可以是一个独立的进程或线程定时扫描数据库中状态为“等待中”的任务。调度器取出一个任务调用星图平台上的DeOldify服务API将图片路径或二进制数据发送过去。调用成功后将数据库中该任务的状态更新为“处理中”。DeOldify服务处理完成后可能是异步回调也可能是我们轮询结果后端获取到处理后的彩色图片。后端将彩色图片保存更新数据库中的任务状态为“已完成”并记录彩色图片的存储路径和完成时间。用户在前端可以通过任务ID查询状态当状态变为“已完成”时前端就能展示或提供下载链接了。这个流程里数据库在每一步都至关重要它记录了任务的“生命轨迹”。3. 数据库设计与实现数据库设计是整个系统的基石设计得好后续开发会非常顺畅。我们主要需要三张核心表。3.1 核心表结构设计用户表 (users)这张表管理系统的使用者。虽然我们这个demo可能不需要复杂的用户体系但设计上保留它以体现完整性。CREATE TABLE users ( id int(11) NOT NULL AUTO_INCREMENT, username varchar(50) NOT NULL COMMENT 用户名用于登录, email varchar(100) DEFAULT NULL COMMENT 邮箱, created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, PRIMARY KEY (id), UNIQUE KEY username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;任务表 (tasks)这是系统的核心表记录了每一个上色任务的完整信息。字段设计需要仔细考虑。CREATE TABLE tasks ( id int(11) NOT NULL AUTO_INCREMENT, user_id int(11) DEFAULT NULL COMMENT 提交任务的用户ID关联users.id, task_name varchar(255) DEFAULT 未命名任务 COMMENT 任务名称用户可自定义, original_image_path varchar(500) NOT NULL COMMENT 原始黑白图片的服务器存储路径, processed_image_path varchar(500) DEFAULT NULL COMMENT 处理后的彩色图片存储路径, status enum(pending, processing, completed, failed) NOT NULL DEFAULT pending COMMENT 任务状态等待中、处理中、已完成、失败, submit_time timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 任务提交时间, start_time timestamp NULL DEFAULT NULL COMMENT 任务开始处理时间, completion_time timestamp NULL DEFAULT NULL COMMENT 任务完成时间, error_message text COMMENT 如果任务失败记录错误信息, PRIMARY KEY (id), KEY idx_user_id (user_id), KEY idx_status (status), KEY idx_submit_time (submit_time), CONSTRAINT fk_tasks_user FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE SET NULL ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT图像上色任务表;字段设计思路status使用枚举类型明确限定几种状态比用数字代码更直观。original_image_path和processed_image_path存储的是图片在服务器上的相对或绝对路径。在实际生产环境中更推荐将图片存入对象存储如阿里云OSS这里存储的就是文件的URL。索引的创建user_id用于查询某个用户的所有任务status和submit_time是任务调度器最常用来查询的字段加上索引能极大提升扫描效率。时间戳字段清晰地记录了任务的生命周期便于后期统计和分析。可选任务参数表 (task_parameters)如果未来DeOldify服务支持调整参数如上色强度、艺术风格我们可以用这张表来扩展实现更灵活的任务管理。这里采用与任务表一对一的关联。CREATE TABLE task_parameters ( task_id int(11) NOT NULL COMMENT 关联的任务ID, render_factor int(11) DEFAULT 35 COMMENT 渲染因子影响上色效果强度, artistic tinyint(1) DEFAULT 0 COMMENT 是否使用艺术模式, created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (task_id), CONSTRAINT fk_params_task FOREIGN KEY (task_id) REFERENCES tasks (id) ON DELETE CASCADE ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT任务参数表;3.2 数据关系与操作用户和任务之间是一对多的关系一个用户可以提交多个任务。任务和任务参数之间是一对一的关系。主要的数据库操作集中在任务表上插入 (Create)用户提交任务时插入一条状态为pending的新记录。查询 (Read)前端查询任务列表或单个任务详情任务调度器查询状态为pending的任务。更新 (Update)任务状态流转pending-processing-completed/failed时更新对应字段特别是status,start_time,completion_time。删除 (Delete)通常我们不物理删除任务而是通过状态过滤。必要时可提供管理功能。4. 后端服务开发实战数据库设计好后我们开始用PythonFlask框架为例搭建后端服务。项目结构可以这样组织deoldify-management-system/ ├── app.py # 应用主入口 ├── config.py # 配置文件 ├── models.py # 数据库模型使用SQLAlchemy ├── routes.py # API路由 ├── services/ # 业务逻辑层 │ ├── task_service.py # 任务管理服务 │ └── deoldify_client.py # DeOldify服务调用客户端 ├── utils/ # 工具函数 │ └── file_handler.py # 文件上传保存工具 └── requirements.txt # 项目依赖4.1 核心API接口实现我们首先实现两个最关键的API提交任务和查询任务状态。1. 提交任务接口 (POST /api/tasks)这个接口接收用户上传的图片保存文件并在数据库中创建任务记录。# routes.py from flask import request, jsonify from services.task_service import TaskService from utils.file_handler import save_uploaded_image import uuid app.route(/api/tasks, methods[POST]) def create_task(): # 1. 接收表单数据和文件 if image not in request.files: return jsonify({error: No image file provided}), 400 file request.files[image] task_name request.form.get(task_name, 未命名任务) if file.filename : return jsonify({error: No selected file}), 400 # 2. 保存上传的图片到本地目录 original_filename file.filename # 生成唯一文件名防止冲突 saved_filename f{uuid.uuid4().hex}_{original_filename} original_image_path save_uploaded_image(file, saved_filename) # 3. 调用服务层创建数据库记录 try: # 假设当前用户ID为1演示用真实场景从会话获取 new_task TaskService.create_task( user_id1, task_nametask_name, original_image_pathoriginal_image_path ) return jsonify({ message: Task created successfully, task_id: new_task.id, status: new_task.status }), 201 except Exception as e: # 如果数据库操作失败可以考虑删除已保存的图片 # os.remove(original_image_path) return jsonify({error: str(e)}), 5002. 查询任务状态接口 (GET /api/tasks/int:task_id)这个接口让前端能轮询或直接查看任务的处理结果。# routes.py app.route(/api/tasks/int:task_id, methods[GET]) def get_task_status(task_id): task TaskService.get_task_by_id(task_id) if not task: return jsonify({error: Task not found}), 404 response_data { task_id: task.id, task_name: task.task_name, status: task.status, submit_time: task.submit_time.isoformat() if task.submit_time else None, completion_time: task.completion_time.isoformat() if task.completion_time else None, } # 如果任务已完成返回处理后的图片访问地址 if task.status completed and task.processed_image_path: # 这里拼接一个完整的HTTP访问URL而不是服务器路径 response_data[processed_image_url] f/static/processed/{os.path.basename(task.processed_image_path)} return jsonify(response_data), 2004.2 任务调度与DeOldify服务集成任务创建后处于“等待中”我们需要一个“工人”来消费这些任务。这里实现一个简单的调度器可以是一个独立的脚本通过定时任务如cron或后台线程运行。任务调度器核心逻辑 (services/task_service.py)# services/task_service.py (部分代码) import requests from models import db, Task from config import Config from .deoldify_client import DeOldifyClient import time class TaskService: # ... 其他方法 ... staticmethod def process_pending_tasks(): 获取并处理一个等待中的任务 # 使用数据库事务和行锁防止多个调度器处理同一个任务 # 这里简化处理实际应考虑更严谨的并发控制 task Task.query.filter_by(statuspending).order_by(Task.submit_time.asc()).first() if not task: print(No pending tasks found.) return print(fProcessing task {task.id}...) task.status processing task.start_time db.func.now() db.session.commit() try: # 调用DeOldify客户端处理图片 deoldify_client DeOldifyClient(api_urlConfig.DEOLDIFY_API_URL) processed_image_path deoldify_client.colorize_image(task.original_image_path) # 更新任务为完成状态 task.status completed task.processed_image_path processed_image_path task.completion_time db.func.now() db.session.commit() print(fTask {task.id} completed successfully.) except Exception as e: # 处理失败 task.status failed task.error_message str(e) db.session.commit() print(fTask {task.id} failed: {e})DeOldify服务客户端 (services/deoldify_client.py)这部分代码负责与星图GPU平台上部署的DeOldify服务进行通信。你需要根据平台提供的具体API文档进行调整。# services/deoldify_client.py import requests import os import time class DeOldifyClient: def __init__(self, api_url, api_keyNone): self.api_url api_url # 例如http://your-deoldify-service-address/predict self.api_key api_key self.headers {Content-Type: application/json} if api_key: self.headers[Authorization] fBearer {api_key} def colorize_image(self, image_path): 调用DeOldify API为图片上色 # 方式1如果API支持文件上传 with open(image_path, rb) as img_file: files {image: img_file} response requests.post(self.api_url, filesfiles, headersself.headers) # 方式2如果API需要base64编码或图片URL # 需要根据实际API要求调整 if response.status_code ! 200: raise Exception(fDeOldify API error: {response.status_code}, {response.text}) result response.json() # 假设API返回处理后的图片base64数据或URL # 这里需要将返回的图片数据保存到本地并返回保存路径 processed_data result.get(processed_image) # ... 保存图片的逻辑 ... saved_path self._save_processed_image(processed_data, image_path) return saved_path def _save_processed_image(self, image_data, original_path): 保存处理后的图片生成新文件名 import base64 from PIL import Image import io # 示例处理base64数据 image_bytes base64.b64decode(image_data) image Image.open(io.BytesIO(image_bytes)) # 生成新文件名例如在原文件名上加‘_colored’ original_name os.path.basename(original_path) name_without_ext, ext os.path.splitext(original_name) new_filename f{name_without_ext}_colored{ext} save_path os.path.join(Config.PROCESSED_IMAGE_FOLDER, new_filename) image.save(save_path) return save_path5. 前端界面与系统演示后端逻辑完成后一个简单的前端界面能让整个系统“活”起来。我们可以用最基础的HTMLJavaScript来实现。核心功能页面 (index.html)!DOCTYPE html html head title老照片上色系统/title style .container { max-width: 800px; margin: auto; padding: 20px; } .upload-area { border: 2px dashed #ccc; padding: 40px; text-align: center; margin-bottom: 20px; } .task-list { margin-top: 30px; } .task-item { border: 1px solid #eee; padding: 10px; margin-bottom: 10px; } .status-pending { color: orange; } .status-processing { color: blue; } .status-completed { color: green; } .status-failed { color: red; } /style /head body div classcontainer h1老照片上色系统/h1 div classupload-area input typefile idimageInput acceptimage/* input typetext idtaskName placeholder给任务起个名字可选 button onclicksubmitTask()开始上色/button /div div idcurrentTaskInfo styledisplay:none; h3当前任务状态/h3 p任务ID: span idcurrentTaskId/span/p p状态: span idcurrentTaskStatus classstatus-pending/span/p img idprocessedImage stylemax-width:100%; display:none; margin-top:15px; /div div classtask-list h3历史任务/h3 div idtaskListContainer/div /div /div script let currentTaskId null; let pollInterval null; async function submitTask() { const fileInput document.getElementById(imageInput); const taskNameInput document.getElementById(taskName); if (!fileInput.files[0]) { alert(请选择一张图片); return; } const formData new FormData(); formData.append(image, fileInput.files[0]); formData.append(task_name, taskNameInput.value || 未命名任务); try { const response await fetch(/api/tasks, { method: POST, body: formData }); const result await response.json(); if (response.ok) { currentTaskId result.task_id; document.getElementById(currentTaskId).textContent currentTaskId; document.getElementById(currentTaskStatus).textContent result.status; document.getElementById(currentTaskInfo).style.display block; startPollingTaskStatus(); } else { alert(提交失败: result.error); } } catch (error) { alert(网络错误: error); } } function startPollingTaskStatus() { if (pollInterval) clearInterval(pollInterval); pollInterval setInterval(async () { const response await fetch(/api/tasks/${currentTaskId}); const task await response.json(); const statusElem document.getElementById(currentTaskStatus); statusElem.textContent task.status; statusElem.className status-${task.status}; if (task.status completed) { clearInterval(pollInterval); const imgElem document.getElementById(processedImage); imgElem.src task.processed_image_url; imgElem.style.display block; loadTaskList(); // 刷新历史任务列表 } else if (task.status failed) { clearInterval(pollInterval); alert(任务处理失败); } }, 2000); // 每2秒轮询一次 } async function loadTaskList() { const response await fetch(/api/tasks?limit10); const tasks await response.json(); const container document.getElementById(taskListContainer); container.innerHTML tasks.map(task div classtask-item strong${task.task_name}/strong (ID: ${task.task_id})br 状态: span classstatus-${task.status}${task.status}/spanbr 提交时间: ${new Date(task.submit_time).toLocaleString()} /div ).join(); } // 页面加载时获取历史任务 window.onload loadTaskList; /script /body /html这个前端页面实现了文件上传、任务状态实时轮询、历史任务展示等核心功能。用户上传图片后页面会显示当前任务ID和状态并自动刷新直到任务完成并展示彩色图片。6. 项目总结与扩展思考走完整个开发流程你会发现这个项目把数据库课程里的许多知识点都串了起来ER设计、SQL语句、索引优化、事务概念并且在真实的业务逻辑中得到了应用。更重要的是你接触到了API设计、异步任务处理、外部服务集成这些在现代应用开发中必不可少的技能。实际部署运行时你可能会遇到一些挑战比如图片上传的并发处理、任务调度器的稳定性、DeOldify服务调用超时或失败的重试机制等。这些都是很好的扩展方向。例如你可以引入消息队列如Redis或RabbitMQ来解耦任务提交和处理让系统更健壮或者为任务添加优先级甚至开发一个管理员后台来监控所有任务的执行情况。这个项目就像一个技术骨架你可以根据自己的兴趣往里填充更多“肌肉”。比如尝试用Docker容器化部署整个应用或者用Vue/React重构一个更美观的前端。通过这样一个从设计到实现的完整项目你收获的将不仅仅是一个数据库课程设计的分数更是一套解决实际问题的工程思维和动手能力。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。

相关新闻