stock-ai-agent/frontend/index.html
2026-02-03 21:16:36 +08:00

174 lines
8.3 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>龙哥的 AI 金融智能体</title>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<!-- Marked.js for Markdown rendering -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<!-- Styles -->
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<div id="app">
<!-- Main Container -->
<div class="container">
<!-- Header -->
<header class="header">
<div class="logo">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
<path d="M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z" fill="currentColor"/>
</svg>
<span>AI金融智能体</span>
</div>
<div class="header-right">
<!-- Model Selector -->
<div class="model-selector" v-if="currentModel">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="3"/>
<path d="M12 1v6m0 6v6M5.64 5.64l4.24 4.24m4.24 4.24l4.24 4.24M1 12h6m6 0h6M5.64 18.36l4.24-4.24m4.24-4.24l4.24-4.24"/>
</svg>
<select v-model="selectedModel" @change="switchModel" class="model-select">
<option v-for="model in availableModels" :key="model.provider" :value="model.provider">
{{ model.name }}
</option>
</select>
</div>
<div class="status">
<div class="status-dot"></div>
<span>在线</span>
</div>
</div>
</header>
<!-- Chat Area -->
<div class="chat-container" ref="chatContainer">
<!-- Welcome Screen -->
<div v-if="messages.length === 0" class="welcome">
<div class="welcome-icon">
<svg width="80" height="80" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
</svg>
</div>
<h1>开始对话</h1>
<p>输入股票代码或名称,获取实时分析</p>
</div>
<!-- Messages -->
<div v-else class="messages">
<div v-for="(msg, index) in messages" :key="index"
:class="['message', msg.role]">
<div class="message-content">
<div v-if="msg.role === 'user'" class="text">{{ msg.content }}</div>
<div v-else>
<div class="text markdown" v-html="renderMarkdown(msg.content)"></div>
<!-- Action Buttons for AI Messages -->
<div class="message-actions">
<button class="action-btn" @click.stop="copyMessage(msg.content)" title="复制内容">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
</svg>
<span>复制</span>
</button>
<button class="action-btn" @click.stop="generateShareImage(msg.content, index)" title="生成分享图">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/>
<circle cx="8.5" cy="8.5" r="1.5"/>
<polyline points="21 15 16 10 5 21"/>
</svg>
<span>分享图</span>
</button>
</div>
<!-- Chart Display -->
<div v-if="msg.metadata && msg.metadata.type === 'chart'" class="chart-box">
<div :id="'chart-' + index" class="chart"></div>
</div>
</div>
</div>
</div>
<!-- Loading -->
<div v-if="loading" class="message assistant">
<div class="message-content">
<div class="typing">
<span></span>
<span></span>
<span></span>
</div>
</div>
</div>
</div>
</div>
<!-- Input Area -->
<div class="input-container">
<div class="input-wrapper">
<textarea
v-model="userInput"
@keydown.enter.exact.prevent="sendMessage"
placeholder="输入消息..."
rows="1"
:disabled="loading"
ref="textarea"
></textarea>
<button
class="send-btn"
@click="sendMessage"
:disabled="loading || !userInput.trim()"
>
<svg v-if="!loading" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="22" y1="2" x2="11" y2="13"/>
<polygon points="22 2 15 22 11 13 2 9 22 2"/>
</svg>
<div v-else class="spinner"></div>
</button>
</div>
<!-- Author Info -->
<div class="author-info">
<span class="author-label">联系龙哥</span>
<span class="author-divider">|</span>
<span class="author-contact" @click="copyWechat" title="点击复制微信号">微信aaronlzhou</span>
</div>
</div>
</div>
<!-- Image Modal -->
<div v-if="showImageModal" class="image-modal" @click="closeImageModal">
<div class="image-modal-content" @click.stop>
<button class="modal-close-btn" @click="closeImageModal" title="关闭">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>
<img :src="modalImageUrl" alt="分享图" class="modal-image">
<p class="modal-hint">长按图片可保存到相册</p>
</div>
</div>
</div>
<!-- Vue 3 -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<!-- Lightweight Charts -->
<script src="https://unpkg.com/lightweight-charts/dist/lightweight-charts.standalone.production.js"></script>
<!-- html2canvas for generating share images -->
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
<!-- App Script -->
<script src="/static/js/app.js"></script>
</body>
</html>