@model AiChatMessageModel
@using Dpz.Core.Service.Network.Models
@{
Layout = null;
string IsSelected(AiModel model) => Model.ModelType == model ? "selected" : "";
}
<div class="container">
<div class="header">
<button type="button" class="sidebar-toggle-mobile" id="sidebarToggle">☰</button>
<h1>🤖 AI 助手</h1>
<div class="status disconnected" id="status">未连接</div>
<button class="theme-toggle" id="themeToggle" title="切换深色/浅色">🌓</button>
</div>
<div class="model-selector">
<label for="modelSelect">AI 模型:</label>
<select id="modelSelect" class="model-select">
<optgroup label="ChatGPT">
<option value="@((int)AiModel.Gpt5)" selected="@(Model.ModelType == AiModel.Gpt5)">GPT-5</option>
<option value="@((int)AiModel.Gpt5Mini)" selected="@(Model.ModelType == AiModel.Gpt5Mini)">GPT-5-Mini</option>
<option value="@((int)AiModel.Gpt5Nano)" selected="@(Model.ModelType == AiModel.Gpt5Nano)">GPT-5-Nano</option>
<option value="@((int)AiModel.O1Mini)" selected="@(Model.ModelType == AiModel.O1Mini)">O1-Mini</option>
<option value="@((int)AiModel.Gpt41)" selected="@(Model.ModelType == AiModel.Gpt41)">GPT-4.1</option>
<option value="@((int)AiModel.Gpt41Mini)" selected="@(Model.ModelType == AiModel.Gpt41Mini)">GPT-4.1-Mini</option>
<option value="@((int)AiModel.Gpt4oMini)" selected="@(Model.ModelType == AiModel.Gpt4oMini)">GPT-4o-Mini</option>
</optgroup>
<optgroup label="Claude">
<option value="@((int)AiModel.ClaudeSonnet420250514)" selected="@(Model.ModelType == AiModel.ClaudeSonnet420250514)">Claude-Sonnet-4-20250514</option>
<option value="@((int)AiModel.Claude37SonnetLatest)" selected="@(Model.ModelType == AiModel.Claude37SonnetLatest)">Claude-3-7-Sonnet-Latest</option>
<option value="@((int)AiModel.Claude35SonnetLatest)" selected="@(Model.ModelType == AiModel.Claude35SonnetLatest)">Claude-3-5-Sonnet-Latest</option>
</optgroup>
<optgroup label="Gemini">
<option value="@((int)AiModel.Gemini25Pro)" selected="@(Model.ModelType == AiModel.Gemini25Pro)">Gemini-2.5-Pro</option>
<option value="@((int)AiModel.Gemini25Flash)" selected="@(Model.ModelType == AiModel.Gemini25Flash)">Gemini-2.5-Flash</option>
</optgroup>
<optgroup label="DeepSeek">
<option value="@((int)AiModel.DeepSeekV3)" selected="@(Model.ModelType == AiModel.DeepSeekV3)">DeepSeek-V3</option>
<option value="@((int)AiModel.DeepSeekR1)" selected="@(Model.ModelType == AiModel.DeepSeekR1)">DeepSeek-R1</option>
<option value="@((int)AiModel.DeepSeekR1DistillQwen7B)" selected="@(Model.ModelType == AiModel.DeepSeekR1DistillQwen7B)">DeepSeek-R1-Distill-Qwen-7B</option>
<option value="@((int)AiModel.DeepSeekR1DistillQwen32B)" selected="@(Model.ModelType == AiModel.DeepSeekR1DistillQwen32B)">DeepSeek-R1-Distill-Qwen-32B</option>
</optgroup>
<optgroup label="文心一言">
<option value="@((int)AiModel.Ernie35_8K)" selected="@(Model.ModelType == AiModel.Ernie35_8K)">ERNIE-3.5-8K</option>
</optgroup>
<optgroup label="通义千问">
<option value="@((int)AiModel.QwenTurbo)" selected="@(Model.ModelType == AiModel.QwenTurbo)">Qwen-Turbo</option>
<option value="@((int)AiModel.QwenPlus)" selected="@(Model.ModelType == AiModel.QwenPlus)">Qwen-Plus</option>
<option value="@((int)AiModel.QwenMax)" selected="@(Model.ModelType == AiModel.QwenMax)">Qwen-Max</option>
</optgroup>
<optgroup label="智谱AI">
<option value="@((int)AiModel.Glm3Turbo)" selected="@(Model.ModelType == AiModel.Glm3Turbo)">GLM-3-Turbo</option>
<option value="@((int)AiModel.Glm4)" selected="@(Model.ModelType == AiModel.Glm4)">GLM-4</option>
<option value="@((int)AiModel.Glm4V)" selected="@(Model.ModelType == AiModel.Glm4V)">GLM-4V</option>
</optgroup>
<optgroup label="豆包">
<option value="@((int)AiModel.DoubaoP32K)" selected="@(Model.ModelType == AiModel.DoubaoP32K)">Doubao-Pro-32K</option>
<option value="@((int)AiModel.DoubaoLite32K)" selected="@(Model.ModelType == AiModel.DoubaoLite32K)">Doubao-Lite-32K</option>
</optgroup>
</select>
</div>
<div class="chat-area" id="chatArea">
@* 历史聊天记录 *@
@if (Model.Messages.Count > 0)
{
foreach (var r in Model.Messages.OrderBy(x => x.SendTime))
{
var role = r.Sender?.Id == Model.SessionId ? "assistant" : "user";
var html = r.Message.MarkdownToHtml();
<div class="message @role">
<div class="message-content markdown-body">
@Html.Raw(html)
@if (role == "assistant")
{
<button class="btn-copy-markdown" title="复制原始内容">
<svg viewBox="0 0 24 24" width="14" height="14" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
</button>
<div class="raw-markdown" style="display:none;">@r.Message</div>
}
<div class="timestamp">@r.SendTime.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")</div>
</div>
<div class="avatar">@(role == "user" ? "👤" : "🤖")</div>
</div>
}
}
else
{
<div class="message assistant">
<div class="message-content markdown-body">👋 你好!我是 AI 助手,有什么我可以帮助你的吗?<div class="timestamp">@DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")</div></div>
<div class="avatar">🤖</div>
</div>
}
</div>
<div class="input-area">
<div class="input-group">
<textarea id="messageInput" placeholder="输入消息,Enter发送,Shift+Enter换行" disabled></textarea>
<button id="sendBtn" disabled>
<span class="btn-text">发送</span>
<span class="btn-loading" style="display: none;">
<span class="loading-dots"><span></span><span></span><span></span></span>
</span>
</button>
</div>
</div>
<div class="info">💡 提示:内容会实时流式显示,这是 AI 正在思考的过程</div>
</div>
<input id="currentSessionId" type="hidden" value="@Model.SessionId" />