https://github.com/Chen11111112/flask--AI-.git

你現在是一個專業的flask工程師,你要協助我完成一個專案,運用以下技術:

  1. Flask,app.py
  2. Jinja ,includes,macros,base.html,extands

製作專案: AI應用系統: user可以在我的系統,透過前端,與gemini AI 進行互動。

我是初學者,請你一步驟一步驟地仔細教導我。

我會給你error提示,你要告訴我發生的原因以及如何解決。

pip install flask google-generativeai python-dotenv

templates/base.html

<!DOCTYPE html>
<html lang="zh-Hant">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}AI 互動系統{% endblock %}</title>
    <link href="<https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css>" rel="stylesheet">
    <style>
        body { background-color: #f8f9fa; }
        .chat-container { max-width: 800px; margin: 30px auto; }
    </style>
</head>
<body>

    {% block navbar %}
    {% endblock %}

    <div class="container chat-container">
        {% block content %}
        {% endblock %}
    </div>

    <script src="<https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js>"></script>
    
    {% block scripts %}
    {% endblock %}
</body>
</html>

templates/index.html

{% extends "base.html" %}

{% block title %}首頁 - Gemini AI{% endblock %}

{% block content %}
    <div class="card shadow">
        <div class="card-header bg-primary text-white">
            <h4>與 Gemini 對話</h4>
        </div>
        <div class="card-body" id="chat-box" style="height: 400px; overflow-y: auto;">
            <div class="text-center text-muted mt-5">
                <p>你好!請在下方輸入訊息開始對話。</p>
            </div>
        </div>
        <div class="card-footer">
            <form id="chat-form" class="d-flex gap-2">
                <input type="text" id="user-input" class="form-control" placeholder="輸入你的問題..." required>
                <button type="submit" class="btn btn-primary">發送</button>
            </form>
        </div>
    </div>
{% endblock %}

.env

GEMINI_API_KEY=你的_API_Key_貼在這裡

app.py

from flask import Flask, render_template, request, jsonify
import os
import google.generativeai as genai
from dotenv import load_dotenv

# 1. 載入環境變數
load_dotenv()

# 2. 設定 Gemini API
genai.configure(api_key=os.getenv("GEMINI_API_KEY"))

app = Flask(__name__)

# 首頁路由
@app.route('/')
def index():
    return render_template('index.html')

# 3. 新增聊天接口 (POST 方法)
@app.route('/chat', methods=['POST'])
def chat():
    try:
        # 接收前端傳來的 JSON 資料
        user_message = request.json.get('message')
        
        if not user_message:
            return jsonify({'error': '沒有收到訊息'}), 400

        # 呼叫 Gemini 模型
        model = genai.GenerativeModel('gemini-3-flash-preview')
        response = model.generate_content(user_message)
        
        # 回傳 AI 的回應文字
        return jsonify({'response': response.text})

    except Exception as e:
        return jsonify({'error': str(e)}), 500

if __name__ == '__main__':
    app.run(debug=True, port=5000)

補上static資料夾 並在其中寫上script.js檔案,實作功能: 讓使用者可以實現跟AI進行互動 1. 取得Gemini API 2. 實現串接功能 3. 完成UIUX

static/style.css

/* 聊天訊息的共用樣式 */
.message {
    max-width: 75%;
    padding: 10px 15px;
    border-radius: 20px;
    margin-bottom: 10px;
    line-height: 1.5;
    position: relative;
    word-wrap: break-word;
}

/* 使用者的訊息:靠右,藍色 */
.user-message {
    background-color: #0d6efd; /* Bootstrap Primary Color */
    color: white;
    align-self: flex-end; /* Flexbox 靠右對齊 */
    border-bottom-right-radius: 5px;
    margin-left: auto; /* 強制靠右 */
}

/* AI 的訊息:靠左,灰色 */
.ai-message {
    background-color: #e9ecef;
    color: #333;
    align-self: flex-start; /* Flexbox 靠左對齊 */
    border-bottom-left-radius: 5px;
    margin-right: auto;
}

/* 聊天框框設定為 Flex 佈局,方便排版 */
#chat-box {
    display: flex;
    flex-direction: column;
}

static/script.js

document.addEventListener('DOMContentLoaded', function() {
    const chatForm = document.getElementById('chat-form');
    const userInput = document.getElementById('user-input');
    const chatBox = document.getElementById('chat-box');

    // 監聽表單送出事件
    chatForm.addEventListener('submit', async function(e) {
        e.preventDefault(); // 1. 阻止表單預設的跳頁行為

        const message = userInput.value.trim();
        if (!message) return;

        // 2. 顯示使用者的訊息在畫面上
        appendMessage(message, 'user-message');
        userInput.value = ''; // 清空輸入框
        
        // 顯示「思考中...」的提示 (UIUX 優化)
        const loadingId = showLoading();

        try {
            // 3. 發送請求給後端 (Flask)
            const response = await fetch('/chat', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({ message: message })
            });

            const data = await response.json();

            // 移除讀取提示
            removeLoading(loadingId);

            if (response.ok) {
                // 4. 顯示 AI 回傳的訊息
                appendMessage(data.response, 'ai-message');
            } else {
                appendMessage('錯誤: ' + data.error, 'ai-message text-danger');
            }

        } catch (error) {
            removeLoading(loadingId);
            appendMessage('發生連線錯誤,請稍後再試。', 'ai-message text-danger');
            console.error('Error:', error);
        }
    });

    // 輔助函式:將訊息加入聊天視窗
    function appendMessage(text, className) {
        const messageDiv = document.createElement('div');
        messageDiv.className = `message ${className}`;
        // 為了安全,這裡使用 textContent,若要支援 Markdown 需用其他套件
        messageDiv.textContent = text; 
        chatBox.appendChild(messageDiv);
        
        // 自動捲動到底部
        chatBox.scrollTop = chatBox.scrollHeight;
    }

    // UIUX: 顯示思考中
    function showLoading() {
        const id = 'loading-' + Date.now();
        const loadingDiv = document.createElement('div');
        loadingDiv.id = id;
        loadingDiv.className = 'message ai-message text-muted fst-italic';
        loadingDiv.textContent = 'Gemini 正在思考...';
        chatBox.appendChild(loadingDiv);
        chatBox.scrollTop = chatBox.scrollHeight;
        return id;
    }

    function removeLoading(id) {
        const element = document.getElementById(id);
        if (element) element.remove();
    }
});
  1. **在 <head> 裡面,原本 <style> 的下方加入:**HTML

    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">

  2. **在 </body> 之前,{% block scripts %} 的區塊內加入:**HTML

    {% block scripts %} <script src="{{ url_for('static', filename='script.js') }}"></script> {% endblock %}