软件工程第一次个人作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/202601SofwareEngineering
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/202601SofwareEngineering/homework/15712
这个作业的目标 1.能够独立或者组队完成小型软件项目,从需求构思,到编码实现、测试、部署上线。本次作业的 AI 图像生成网页、GitHub 个人主页,就是小型工程实践。2.学会用 Markdown 撰写规范项目文档、技术随笔、开发报告,清晰记录开发过程、踩坑记录、成果说明。3.熟练使用 Git/GitHub 管理代码与项目文档,理解版本控制在团队开发中的价值。4.开发过程中定位接口报错、前后端联调异常,分析 API 调用失败原因,排查 bug。
学号 102401202

一、huggingface-API的调用

1.实验目标:调用 XLabs-AI/flux-RealismLora 模型,通过 Hugging Face Inference API 生成贴近真实世界的图片,并结合前端接口实现用户输入 prompt 后交互生成图片。

2.实验环境

操作系统:Windows11

Python 环境:Anaconda base 环境,Python3.10

依赖库:huggingface‑hub、flask、pillow、python‑dotenv

推理后端:fal‑ai

模型地址:https://huggingface.co/XLabs‑AI/flux‑RealismLora

3.操作步骤记录

步骤 1 HuggingFace 账号注册与 API‑Token 获取

  1. 打开 Hugging Face 官网完成邮箱注册,完成邮箱验证后登录账号。

  2. 点击右上角头像进入 Settings 设置页面,找到 Access Tokens 选项。

  3. 创建新 Token,命名为flux,权限write权限,生成并复制密钥 HF_TOKEN,密钥仅展示一次。

  4. 将密钥保存到项目根目录.env配置文件中,不直接写在代码内,避免密钥泄露。

步骤 2 本地项目环境搭建

1.创建项目文件夹"E:\Codeproject\PythonProject",项目文件结构如下:

E:\Codeproject\PythonProject\      ←你执行 python app.py 的当前目录
├─ app.py
├─ .env
├─ templates/               
│   └─ index.html           ✅html必须放在templates内部,不能在外层
└─ static/
    └─ output/

2.在终端执行依赖安装命令

pip install huggingface-hub flask pillow python-dotenv

3.编写.env配置文件,写入HuggingFace访问令牌

HF_TOKEN=粘贴自己前面得到的token密钥

步骤 3 后端代码编写(app.py)

核心逻辑:使用Flux模型提供的InferenceClient接口,指定provider="fal‑ai"调用 XLabs‑AI/flux‑RealismLora ;编写后端接口接收前端传入提示词,调用 API 获取 PIL 图像对象,自动创建图片保存目录,保存图片并向前端返回图片访问地址;内置 HTML 前端,规避本地 templates 文件夹缺失报错。

import os
from dotenv import load_dotenv
from huggingface_hub import InferenceClient
from flask import Flask, request, jsonify
from PIL import Image
import time

# 读取环境变量
load_dotenv()
HF_TOKEN = os.getenv("HF_TOKEN")

app = Flask(__name__)

# 初始化推理客户端,设置超时时间,解决境外网络SSL断开问题
client = InferenceClient(
    provider="fal-ai",
    api_key=HF_TOKEN,
    timeout=120
)

def generate_real_image(prompt: str) -> str:
    """调用Flux‑RealismLora生成写实图片,返回图片相对访问路径"""
    print(f"开始调用API,传入提示词:{prompt}")
    output_dir = os.path.join("static", "output")
    # 自动创建输出文件夹,防止文件夹不存在报错
    os.makedirs(output_dir, exist_ok=True)

    # HuggingFace API核心调用
    image = client.text_to_image(
        prompt,
        model="XLabs-AI/flux-RealismLora",
        num_inference_steps=28,
        guidance_scale=3.5
    )
    print("✅API调用成功,获取到PIL图像对象")

    timestamp = int(time.time())
    save_name = f"gen_{timestamp}.png"
    save_path = os.path.join(output_dir, save_name)
    image.save(save_path)
    return f"/static/output/{save_name}"

# 首页路由,内置HTML前端页面,无需templates文件夹
@app.route("/")
def index():
    html_text = """
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Flux RealismLora 写实图像生成</title>
    <style>
        body{max-width:900px;margin:30px auto;padding:0 20px;font-family:Microsoft Yahei;}
        textarea{width:100%;height:120px;font-size:16px;padding:10px;box-sizing:border-box;}
        button{padding:12px 30px;font-size:17px;margin:15px 0;cursor:pointer;}
        #result-img{max-width:100%;border:2px solid #ccc;margin-top:20px;}
        .loading{color:#2266bb;font-size:18px;}
    </style>
</head>
<body>
    <h2>Flux‑RealismLora 真实世界图像生成器</h2>
    <div>
        <h4>输入提示词(Prompt):</h4>
        <textarea id="prompt_input" placeholder="输入英文提示词,描述真实世界场景"></textarea>
    </div>
    <button onclick="submitGenerate()">点击生成图片</button>
    <div id="status"></div>
    <div>
        <img id="result-img" style="display:none;">
    </div>
<script>
async function submitGenerate(){
    const prompt = document.getElementById("prompt_input").value;
    const statusDom = document.getElementById("status");
    const imgDom = document.getElementById("result-img");
    imgDom.style.display="none";
    statusDom.innerHTML = "<p class='loading'>正在请求HuggingFace API,生成图片,请等待…</p>";
    const resp = await fetch("/generate",{
        method:"POST",
        headers:{"Content-Type":"application/json"},
        body:JSON.stringify({prompt:prompt})
    });
    const res = await resp.json();
    if(res.code===200){
        statusDom.innerHTML="<p style='color:green'>✅API调用成功,图片生成完成</p>";
        imgDom.src = res.image_url;
        imgDom.style.display="block";
    }else{
        statusDom.innerHTML=`<p style='color:red'>❌错误:${res.msg}</p>`;
    }
}
</script>
</body>
</html>
    """
    return html_text

# 后端生成接口,供前端AJAX调用
@app.route("/generate", methods=["POST"])
def api_generate():
    try:
        data = request.get_json()
        user_prompt = data.get("prompt", "")
        if not user_prompt.strip():
            return jsonify({"code": 400, "msg": "提示词不能为空"}),400
        img_url = generate_real_image(user_prompt)
        return jsonify({
            "code":200,
            "msg":"生成成功",
            "image_url": img_url
        })
    except Exception as e:
        print(f"❌调用异常:{str(e)}")
        return jsonify({"code":500,"msg":f"生成失败:{str(e)}"}),500

if __name__ == "__main__":
    app.run(debug=True, host="127.0.0.1", port=5000)

      

步骤 4 运行程序与交互测试

  1. 在项目目录终端运行:python app.py,启动 Flask 服务,访问地址: http://127.0.0.1:5000

1

  1. 在网页输入框填写英文写实提示词,点击按钮向后端发起请求;后端调用 Hugging Face 云端 API 推理,返回图片,前端页面渲染展示生成图像。

第一轮测试提示词:A girl standing on street

问题描述:只描述主体对象,缺少摄影属性,生成画面 AI 绘画感重,光影虚假,细节纹理不足,距离真实照片差距大。

1

第二轮迭代提示词:photograph of a young girl standing on city street, natural daylight

改进:加入photograph、自然光描述,画面开始具备照片质感;缺陷:缺少相机参数、分辨率、景深细节,画面清晰度不足。

1

第三轮最终使用提示词:photorealistic photo, young woman walking on urban street in golden hour, soft natural sunset light, shot on Sony A7M4, 8k RAW photograph, shallow depth of field, highly detailed skin, realistic textures, real‑world scene

设计思路:

  1. 基础标签:photorealistic photo指定输出写实照片风格;

  2. 场景光线:golden hour、soft natural sunset light定义黄昏黄金时刻柔和自然光;

  3. 摄影硬件参数:shot on Sony A7M4、8k RAW photograph模拟专业单反拍摄原图;

  4. 画质细节:shallow depth of field、highly detailed skin、realistic textures控制景深、皮肤、物体真实纹理;

  5. 规避插画、动漫、手绘类词汇,保证模型输出现实世界实拍效果。

1

4.实验过程遇到的问题及解决方法

jinja2.exceptions.TemplateNotFound: index.html

原因:Flask 默认读取templates文件夹下模板,文件夹缺失或者文件放置位置错误。解决:本次实验采用直接在代码返回 HTML 字符串的方式,绕开模板文件路径问题。

[Errno 2] No such file or directory: 'static\\output\\xxx.png'

原因:程序保存图片的输出目录不存在,Flask 不会自动创建文件夹。解决:使用

os.makedirs(output_dir, exist_ok=True)

代码自动创建存储目录。

[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocol

原因:fal‑ai 为境外推理服务,国内网络不稳定造成 SSL 连接中途断开。解决:切换手机热点网络,在InferenceClient设置timeout=120延长请求超时时间,减少中断概率。

(Request ID: Root=1-6aa25dbc-622873cb4b21ac8367ea7fe3;a1549f6e-b421-46ef-95ab-710bca768928)

403 Forbidden: This authentication method does not have sufficient permissions to call Inference Providers on behalf of user wohenruzngong.
Cannot access content at: https://router.huggingface.co/fal-ai/fal-ai/flux-lora.
Make sure your token has the correct permissions.

原因:API权限设置错误,需选择write权限!

5.API 调用体验与实验心得

1.Hugging Face 提供的InferenceClient对推理接口做了封装,不需要手动编写 HTTP 请求报文,仅传入 API 密钥、推理服务商、模型名称与提示词,就可以直接获取 PIL 图像对象,降低大模型 API 调用开发门槛。

2.API 密钥安全十分关键,不能硬编码写死在源代码,使用.env环境变量保存访问令牌,能够避免密钥泄露,防止他人盗用推理额度。

3.使用第三方推理提供商 fal‑ai,需要账号完成授权绑定;Flux 大模型推理消耗算力高,单张图片生成耗时几十秒,需要设置合理超时时间,不能频繁重复提交请求。

4.提示词直接决定图像输出质量,写实 LoRA 不能仅写主体描述,需要补充摄影、光线、相机、纹理相关关键词,不断迭代调试提示词,才能得到贴近现实世界的照片效果。

5.通过 Flask 封装后端 API 接口,配合简单 HTML 前端,快速完成浏览器交互式 AI 绘图应用,实现前后端交互;开发过程要考虑文件夹自动创建、网络异常捕获等工程细节,提升程序健壮性。

6.免费云端推理存在额度限制,本次作业采用通过多个邮箱创建多个账号解决,正式项目需要关注计费情况,同时境外推理服务会受网络条件影响,网络问题会直接造成 API 调用失败。

二、Github个人主页搭建

参考资料:https://blog.csdn.net/qd1813100174/article/details/128604858

最终完成主页:https://hongyalin.github.io/

截图如下:

1

三、在博客园发一篇随笔

随笔链接:https://www.cnblogs.com/yalinhong/p/22880475

截图如下:
1

四、使用Markdown编辑器编辑记录

1

posted @ 2026-09-10 16:21  广陵鸭梨  阅读(16)  评论(0)    收藏  举报