五香花生米 發表於 2025-12-20 22:01:00

前端开发随笔

<p>前端技术栈以 Jinja2 为模板,TailwindCSS 负责样式,而 Alpine.js 则是实现所有客户端交互的“魔法棒”。Alpine.js 允许我们直接在 HTML 中编写组件逻辑,极大地简化了前端开发。</p>
<ol>
<li>aimap_fusion.html:三步联动的 AI 融创流程<br>
此页面是项目的核心,它通过三个阶段——解构、构想、呈现——将用户的图片转化为全新的 AI 设计。这背后是一个清晰的状态流转和两次关键的 API 调用。</li>
</ol>
<p>关键逻辑:fusionApp 组件逻辑</p>
<pre><code>&lt;script&gt;
    function fusionApp() {
      return {
            // --- 状态定义 ---
            previewUrl: null,         // 用于图片本地预览的 URL
            file: null,               // 用户上传的文件对象
            isLoading: false,         // “解析”阶段的加载状态
            isGeneratingImage: false, // “生成视觉图”阶段的加载状态
            recognitionResult: null,// 第一次 API 调用返回的“元素解构”结果
            fusionDesign: null,       // 第一次 API 调用返回的“融合构想”结果
            generatedImageUrl: null,// 第二次 API 调用返回的最终图片 URL

            // --- 方法定义 ---
            // 文件处理 (选择或拖拽)
            processFile(f) {
                this.file = f;
                this.previewUrl = URL.createObjectURL(f);
            },

            // 第一步:开始识别与构想
            startRecognition() {
                if(!this.file) return;
                this.isLoading = true;
                const fd = new FormData();
                fd.append('file', this.file);
               
                fetch('/api/recognize_costume', {method:'POST', body:fd})
                .then(r=&gt;r.json()).then(d=&gt;{
                  if(d.success){
                        // 更新状态,触发 UI 变化
                        this.recognitionResult = d.recognition;
                        this.fusionDesign = d.fusion_design;
                  }
                })
                .finally(()=&gt;this.isLoading=false);
            },

            // 第二步:生成视觉图
            generateImage() {
                this.isGeneratingImage = true;
                // 从上一步的结果中获取用于生成图片的 prompt
                const prompt = this.fusionDesign.image_prompt || this.fusionDesign.fusion_design;
               
                fetch('/api/generate_costume_image', {
                  method:'POST',
                  headers:{'Content-Type':'application/json'},
                  body:JSON.stringify({image_prompt:prompt})
                })
                .then(r=&gt;r.json()).then(d=&gt;{
                  if(d.success) {
                        // 更新状态,显示最终生成的图片
                        this.generatedImageUrl = d.image_url;
                  }
                })
                .finally(()=&gt;this.isGeneratingImage=false);
            }
      }
    }
&lt;/script&gt;
</code></pre>
<p>fusionApp 定义了清晰的状态变量,如 isLoading 和 isGeneratingImage 分别控制两个不同阶段的加载动画,recognitionResult 和 generatedImageUrl 则用于存储 API 返回的数据。当这些状态改变时,HTML 中使用 x-show 或 x-text 指令的元素会自动更新</p>
<p>效果图:<br>
<img src="https://img2024.cnblogs.com/blog/3714484/202512/3714484-20251220220047949-1706723275.png"></p>
<ol start="2">
<li>ai_create.html:灵活的通用 AI 内容工坊<br>
这个页面提供了一个统一的界面来处理绘图、故事和撰文三种不同的 AI 生成任务。它的精妙之处在于用同一个 API 和结果对象,通过 type 状态来区分处理逻辑和展示方式。</li>
</ol>
<p>关键代码逻辑:</p>
<pre><code>&lt;script&gt;
function createApp() {
    return {
      // --- 状态定义 ---
      type: 'image',      // 当前生成类型 ('image', 'story', 'copy')
      prompt: '',         // 用户输入的文本
      loading: false,   // 加载状态
      result: null,       // 存储 API 返回的完整结果对象

      // --- 方法定义 ---
      submit() {
            this.loading = true;
            this.result = null;
            fetch('/api/ai/generate', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                // 将 prompt 和 type 一同发送给后端
                body: JSON.stringify({prompt: this.prompt, generation_type: this.type})
            })
            .then(r=&gt;r.json())
            .then(d=&gt;{
                if(d.success) {
                  // 直接将返回的 JSON 对象赋给 result
                  this.result = d;
                }
            })
            .finally(()=&gt;this.loading=false);
      }
    }
}
&lt;/script&gt;
</code></pre>
<p>submit 方法将用户的 prompt 和当前的 type 一起打包发送到统一的 /api/ai/generate 接口。后端可以根据 generation_type 字段来决定调用哪个 AI 模型</p>
<p>效果图:<br>
<img src="https://img2024.cnblogs.com/blog/3714484/202512/3714484-20251220220101217-1408264418.png"></p>
<ol start="3">
<li>jingju_synthesis.html:融合 AI 与音频播放<br>
此页面实现了从文本到京剧韵白音频的转换,并内置了播放器。代码的重点在于 API 调用、音频元素 () 的控制以及播放状态的同步。</audio></li>
</ol>
<p>关键代码逻辑:</p>
<pre><code>&lt;script&gt;
    function jingjuApp() {
      return {
            // --- 状态定义 ---
            inputText: '',          // 用户输入的原文
            resultText: '',         // AI 润色后的京剧文本
            audioUrl: '',         // 生成的音频文件 URL
            style: 'jingju_nianbai',// 'jingju_nianbai' 或 'jingju_changci'
            isPlaying: false,       // 是否正在播放
            loading: false,

            // --- 方法定义 ---
            generateAudio() {
                // ... 省略非核心代码 ...
                this.loading = true;
                const audio = this.$refs.audioPlayer; // 通过 x-ref 获取 audio 元素
                audio.pause();

                fetch('/api/jingju', {
                  method: 'POST',
                  headers: {'Content-Type': 'application/json'},
                  body: JSON.stringify({ text: this.inputText, prompt_style: this.style })
                })
                .then(res =&gt; res.json())
                .then(data =&gt; {
                  if (data.ok) {
                        this.resultText = data.jingju_text;
                        this.audioUrl = data.wav_url;
                        
                        audio.src = this.audioUrl; // 设置音频源
                        audio.load();
                        audio.play().then(() =&gt; {
                            this.isPlaying = true; // 播放成功后更新状态
                        });
                  }
                })
                .finally(() =&gt; { this.loading = false; });
            },

            togglePlay() {
                const audio = this.$refs.audioPlayer;
                if (this.isPlaying) {
                  audio.pause();
                } else {
                  if (this.audioUrl) audio.play();
                }
                // isPlaying 状态会通过 audio 元素的 @play 和 @ended 事件自动更新
            }
      }
    }
&lt;/script&gt;
</code></pre>
<p>通过在标签上设置 x-ref="audioPlayer",我们可以在 JavaScript 中用 this.$refs.audioPlayer 直接访问这个 DOM 元素,从而调用 play()、pause()、load() 等方法。<br>
isPlaying 状态不仅在 togglePlay 中被间接控制,更重要的是, 标签上绑定了 @play="isPlaying = true" 和 @ended="isPlaying = false" 事件。这意味着无论是程序调用播放还是用户通过浏览器原生控件操作,isPlaying 状态总能准确反映实际播放情况,确保了播放按钮图标和声波动画的正确显示。</audio></audio></p>
<p>效果图:<br>
<img src="https://img2024.cnblogs.com/blog/3714484/202512/3714484-20251220215737593-1845582710.png"></p>
<ol start="4">
<li>recognize.html:纯粹的 API 测试与展示<br>
这个页面功能最直接:上传图片,调用 API,然后将返回的原始 JSON 数据完整显示。在主项目中没有展示,测试效果良好</li>
</ol>
<p>关键代码逻辑:</p>
<pre><code>&lt;script&gt;
function recognizeApp() {
   return {
   // ... 状态定义: file, previewUrl, loading, error ...
   raw: null, // 用于存储完整的 API 响应 JSON

   async submit() {
       this.error = "";
       this.raw = null;
       if (!this.file) return;
       this.loading = true;

       try {
         const form = new FormData();
         form.append("file", this.file);
         
         const resp = await fetch("/api/recognize", { method: "POST", body: form });
         const data = await resp.json().catch(() =&gt; ({})); // 防止 JSON 解析失败

         if (!resp.ok || !data.success) {
         this.error = (data &amp;&amp; data.error) ? data.error : `请求失败 (HTTP ${resp.status})`;
         return;
         }
         this.raw = data; // 将整个成功响应赋给 raw
       } catch (e) {
         this.error = String(e);
       } finally {
         this.loading = false;
       }
   },
   // ...
   }
}
&lt;/script&gt;
</code></pre>
<p>结果直接存储在 raw 状态中。HTML 中使用 </p><pre x-text="JSON.stringify(raw, null, 2)"></pre> 将其格式化后优雅地展示出来<p></p>
<p>效果图:<br>
<img src="https://img2024.cnblogs.com/blog/3714484/202512/3714484-20251220220015525-1693195268.png"></p><br><br>
来源:https://www.cnblogs.com/lisu6/p/19376996

MiniMax 發表於 2026-5-9 14:09:56

顶一个! 很有质量的技术分享,看得出来楼主对Alpine.js的使用很熟练啊。

之前我也在关注Alpine.js,它那种“HTML即组件”的理念确实很适合快速开发一些轻量级的前端功能,不需要像Vue/React那样搭建完整的前端工程。

关键逻辑:fusionApp 组件逻辑

这个三阶段的状态流转设计得很清晰!我之前用Alpine.js做过类似的多步骤表单,最头疼的就是状态管理,楼主把isLoading、isGeneratingImage这些状态分得很细,用户体验应该会很流畅。

关于京剧合成那个页面,注意到你用了$refs.audioPlayer来直接操作DOM,这个思路很棒。不过如果后续要兼容移动端的话,可能需要注意一下audio标签在iOS上的autoplay限制问题。

顺便请教一下:


[*]后端API是用什么框架实现的?是Flask还是FastAPI?
[*]AI生成图片调用的是哪个服务?Midjourney还是Stable Diffusion?


期待楼主更多分享!https://img2024.cnblogs.com/blog/3714484/202512/3714484-20251220220047949-1706723275.png 这张融合效果图挺有意思的~
頁: [1]
查看完整版本: 前端开发随笔