|
|
@@ -0,0 +1,357 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="zh-CN">
|
|
|
+<head>
|
|
|
+ <meta charset="UTF-8">
|
|
|
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
|
|
|
+ <title>萧e生大模型</title>
|
|
|
+ <link rel="stylesheet" href="./css/bootstrap.min.css">
|
|
|
+ <link rel="stylesheet" href="./css/all.min.css">
|
|
|
+ <link rel="stylesheet" href="./css/github.min.css">
|
|
|
+ <link rel="stylesheet" href="./css/styles.css">
|
|
|
+ <link rel="stylesheet" href="./css/chat.css">
|
|
|
+</head>
|
|
|
+<body>
|
|
|
+<div class="container-fluid not-bg vh-100 d-flex flex-column">
|
|
|
+ <!-- 顶部标题栏 -->
|
|
|
+ <header class="p-2" style="min-height: 44px; text-align: center; font-size: 18px; font-weight: 700;">
|
|
|
+ <!--中医AI助手-->
|
|
|
+ </header>
|
|
|
+
|
|
|
+ <!-- 聊天主区域 -->
|
|
|
+ <main class="flex-grow-1 d-flex flex-column overflow-hidden" id="chat-container">
|
|
|
+ <div class="flex-grow-1 overflow-auto px-2 py-3" id="chat-messages"></div>
|
|
|
+
|
|
|
+ <!-- 输入区域 -->
|
|
|
+ <div class="px-3 py-2 border-top">
|
|
|
+ <div class="input-group input-group-sm">
|
|
|
+ <textarea
|
|
|
+ id="message-input"
|
|
|
+ class="form-control"
|
|
|
+ placeholder="请输入..."
|
|
|
+ rows="1"
|
|
|
+ enterkeyhint="send"
|
|
|
+ ></textarea>
|
|
|
+ <button id="send-btn" class="btn btn-primary btn-sm">
|
|
|
+ <i class="fas fa-paper-plane"></i>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </main>
|
|
|
+</div>
|
|
|
+
|
|
|
+<!-- 隐藏字段 -->
|
|
|
+<input type="hidden" id="session-id" value="{{ session_id }}">
|
|
|
+
|
|
|
+<!-- JavaScript 依赖 -->
|
|
|
+<script src="./js/bootstrap.bundle.min.js"></script>
|
|
|
+<script src="./js/marked.min.js"></script>
|
|
|
+<script src="./js/highlight.min.js"></script>
|
|
|
+<script>document.addEventListener('gesturestart', function (event) {
|
|
|
+ event.preventDefault();
|
|
|
+}, false);</script>
|
|
|
+
|
|
|
+<!-- 主应用脚本 -->
|
|
|
+<script>
|
|
|
+const u1 = `
|
|
|
+**杨红,男,38岁**
|
|
|
+<br>
|
|
|
+1. **主诉**:脘腹痞胀1年余,去年10月以来多次出血(黑便)
|
|
|
+1. **现病史**:脘腹痞胀1年余,去年10月以来多次出血(黑便),平素饮酒量多,形体丰腴。
|
|
|
+1. **既往史**:有嗜酸粒细胞增多症病史,常服用强的松。
|
|
|
+1. **中医四诊**:脘腹痞胀,右腹隐痛,大便溏薄,易出汗,舌质紫暗,苔薄白,脉沉细。
|
|
|
+1. **辅助检查**:胃镜示“慢性浅表性胃炎伴糜烂”。
|
|
|
+`
|
|
|
+const r1 = `
|
|
|
+根据您描述的情况,患者目前最可能的原因是与消化系统相关,肝脾不调,气血瘀滞导致便血。以下是具体分析:
|
|
|
+
|
|
|
+<br>
|
|
|
+
|
|
|
+### 辨证分析:
|
|
|
+1. 患者形体肥胖属湿盛体质,且平素酒,更易蕴生湿热,湿热灼伤络脉,血溢脉外则为瘀血。
|
|
|
+1. 湿邪壅滞,脾失健运,故大便溏薄。证属肝脾不调,气血瘀滞。
|
|
|
+
|
|
|
+<br>
|
|
|
+
|
|
|
+### 推荐方案:
|
|
|
+治以理气活血,健脾和胃,化瘀通络。常用药:当归、赤芍药、五灵脂、延胡索,另吞服三七粉1~2g
|
|
|
+
|
|
|
+<br>
|
|
|
+
|
|
|
+#### 中药方剂:
|
|
|
+1. **痛泻要方加减** ([国医徐景藩](#)) <a href="javascript:void(0):">转方</a>
|
|
|
+ - 组成:焦白术10g,白芍药15g,炒防风10g,煨木香6g,鸡内金10g,佛手10g,三棱10g,葛根花68,泽泻15g,牡丹皮10g,黄连2g,补骨脂6g,石斛10g,炙甘草3g,焦山楂、神曲各15g,青皮、陈皮各6g。
|
|
|
+ - 煎服方法:每日1剂,水煎服。
|
|
|
+ - **另**:三七粉1g,研末冲服,每日2次。
|
|
|
+ <span></span>
|
|
|
+
|
|
|
+2. **柴胡疏肝散(疏肝理气)** <a href="">转方</a>
|
|
|
+ - 组成:柴胡10g,陈皮12g,川芎10g,香附12g,枳壳10g,芍药12g,甘草6g
|
|
|
+ - 作用:疏肝解郁,行气止痛,缓解右腹隐痛及气滞症状。
|
|
|
+ <span></span>
|
|
|
+
|
|
|
+3. **丹参饮(活血化瘀)** <a href="">转方</a>
|
|
|
+ - 组成:丹参15g,檀香10g(后下),砂仁6g(后下),木香10g
|
|
|
+ - 作用:活血化瘀,改善舌质紫暗及血瘀状态。
|
|
|
+ <span></span>
|
|
|
+
|
|
|
+<br>
|
|
|
+
|
|
|
+#### 适宜技术:
|
|
|
+1. **针刺疗法**:<a href="javascript:void(0):">转方</a>
|
|
|
+ - 【取穴】足三里(健脾和胃)、中脘(调理脾胃)、脾俞(健脾益气)、三阴交(调和肝脾)。
|
|
|
+ - 【操作方法】直刺进针,得气后,每5min行针(平补平泻法)一次,留针 30 min 后出针。
|
|
|
+ - 【疗程说明】针刺、刮痧,可任选一种或两种均选,针刺每周干预2次,连续治疗8次为一疗程;刮痧每周干预1次,连续治疗4次为1疗程。
|
|
|
+ <span></span>
|
|
|
+
|
|
|
+2. **艾灸**:<a href="javascript:void(0):">转方</a>
|
|
|
+ 选用神阙、关元、气海,温阳散寒,增强脾阳。距皮肤2~3cm处进行熏烤,根据患者的热感情况调整合适的距离,当患者感觉温热舒适时固定不动,每穴灸10~15分钟,以局部皮肤出现潮红为度。
|
|
|
+
|
|
|
+3. **推拿**:<a href="javascript:void(0):">转方</a>
|
|
|
+ 腹部顺时针按摩,配合按压足三里、合谷穴,每日10分钟,促进气血运行。
|
|
|
+
|
|
|
+4. **足浴**:
|
|
|
+ - 银杏叶100g,槐花40g,菊花30g,丹参20g。将以上药物同入药罐中,清水浸泡30分钟,加水2000mL煎汤,煮沸20分钟后去渣取汁,将汁倒入足浴器中,先熏蒸再足浴,每晚1次。20天为一疗程。
|
|
|
+ - 当归50g,牛膝20g,干姜20g,桂枝10g,桑枝10g。将以上药物同入药罐中,清水浸泡30分钟,加水2000mL煎汤,煮沸20分钟后去渣取汁,将汁倒入足浴器中,先熏蒸再足浴,每晚1次。20天为一疗程。
|
|
|
+ <span></span>
|
|
|
+
|
|
|
+5. **茶饮**:
|
|
|
+ - **芎归茶**
|
|
|
+ <span></span>
|
|
|
+ 
|
|
|
+ <span></span>
|
|
|
+ - 【成分】:川芎5克,当归2克。
|
|
|
+ - 【用法】:将川芎、当归放入砂锅中,加适量水煎煮30分钟,去渣取汁。每日1剂,代茶饮用。
|
|
|
+ - 【功效】:活血祛瘀。
|
|
|
+ - 【禁忌】:阴虚火旺的人不宜饮用此茶。
|
|
|
+ <span></span>
|
|
|
+
|
|
|
+ - **通脉花果茶**
|
|
|
+ <span></span>
|
|
|
+ 
|
|
|
+ <span></span>
|
|
|
+ - 【原料】:山楂15g,玫瑰花10g,月季花10g,红花5g。
|
|
|
+ - 【制作】:将山楂、玫瑰花、月季花和红花用水冲净,放入保温杯中,倒入滚开的热水,盖上盖子拧紧。然后将保温杯上下颠倒几次,使水充分地浸泡药材。静置20分钟后可以饮用。此药茶可以反复冲泡至味淡。
|
|
|
+ - 【效用】:活血化瘀,理气消食。适合血瘀质兼见面部黄褐斑、情志不遂者饮用。
|
|
|
+ <span></span>
|
|
|
+
|
|
|
+<br>
|
|
|
+
|
|
|
+### 生活调护建议:
|
|
|
+- 饮食清淡,忌辛辣油腻,避免饮酒,可适量食用山药、莲子等健脾食物。
|
|
|
+- 保持规律作息,避免熬夜,适当运动以助气血流通。
|
|
|
+- 建议进一步检查肠镜及血液指标,排除其他潜在疾病。
|
|
|
+
|
|
|
+<br>
|
|
|
+
|
|
|
+### 注意事项:
|
|
|
+- 中医治疗需结合个体情况调整,以上方案需在专业医师指导下使用。
|
|
|
+- 长期服用激素需警惕副作用(如骨质疏松、免疫力下降),建议定期复查。
|
|
|
+- 若出现头晕、乏力、心悸等症状,需警惕气血两虚或出血加重,及时就医。
|
|
|
+
|
|
|
+<br>
|
|
|
+
|
|
|
+**以上建议旨在辅助调理,具体治疗需结合临床实际调整。**
|
|
|
+`
|
|
|
+</script>
|
|
|
+<script>
|
|
|
+ window.addEventListener('message', e => {
|
|
|
+ const messageInput = document.getElementById('message-input');
|
|
|
+ if (e.data && e.data.type === 'input') messageInput.value = e.data.value
|
|
|
+ }, false);
|
|
|
+ function getValue() {
|
|
|
+ const messageInput = document.getElementById('message-input');
|
|
|
+ return messageInput.value;
|
|
|
+ }
|
|
|
+</script>
|
|
|
+<script>
|
|
|
+ const searchParams = new URLSearchParams(window.location.search);
|
|
|
+ const host = `https://dev.hzliuzhi.com:62006`;
|
|
|
+ document.addEventListener('DOMContentLoaded', function () {
|
|
|
+ if (searchParams.has('hide_title')) document.querySelector('.container-fluid header').style.display = 'none';
|
|
|
+ else document.querySelector('.container-fluid header').innerHTML = document.title;
|
|
|
+ // 获取DOM元素
|
|
|
+ const chatMessages = document.getElementById('chat-messages');
|
|
|
+ const messageInput = document.getElementById('message-input');
|
|
|
+ const sendBtn = document.getElementById('send-btn');
|
|
|
+ let sessionId = document.getElementById('session-id').value;
|
|
|
+ if (sessionId.replace(/\s/g, '') === `{{session_id}}`) document.querySelector(`#session-id`).value = sessionId = searchParams.get('session_id');
|
|
|
+
|
|
|
+ let eventSource = null;
|
|
|
+
|
|
|
+ // 初始化Marked和Highlight.js
|
|
|
+ marked.setOptions({
|
|
|
+ breaks: true,
|
|
|
+ highlight: function (code, language) {
|
|
|
+ const validLanguage = hljs.getLanguage(language) ? language : 'plaintext';
|
|
|
+ return hljs.highlight(validLanguage, code).value;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 发送消息
|
|
|
+ function sendMessage() {
|
|
|
+ const message = messageInput.value.trim();
|
|
|
+ if (!message) return;
|
|
|
+
|
|
|
+ // 添加用户消息
|
|
|
+ addMessage('user', message);
|
|
|
+ messageInput.value = '';
|
|
|
+
|
|
|
+ // 添加AI思考状态
|
|
|
+ const aiMessageElement = addMessage('assistant', '', true);
|
|
|
+
|
|
|
+ // 关闭之前的连接
|
|
|
+ if (eventSource) {
|
|
|
+ eventSource.close();
|
|
|
+ eventSource = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ let aiResponse = '';
|
|
|
+ let responseElement = null;
|
|
|
+
|
|
|
+ // 使用fetch进行流式请求
|
|
|
+ fetch(`${host}/tcm_chat/chat/tcm`, {
|
|
|
+ method: 'POST',
|
|
|
+ headers: {
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
+ },
|
|
|
+ body: JSON.stringify({
|
|
|
+ session_id: sessionId,
|
|
|
+ message: message
|
|
|
+ })
|
|
|
+ })
|
|
|
+ .then(response => {
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error(`HTTP error! status: ${response.status}`);
|
|
|
+ }
|
|
|
+
|
|
|
+ const reader = response.body.getReader();
|
|
|
+ const decoder = new TextDecoder();
|
|
|
+
|
|
|
+ function readStream() {
|
|
|
+ return reader.read().then(({done, value}) => {
|
|
|
+ if (done) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const chunk = decoder.decode(value);
|
|
|
+ const lines = chunk.split('\n');
|
|
|
+
|
|
|
+ for (const line of lines) {
|
|
|
+ if (line.startsWith('think: ')) { // 思考内容
|
|
|
+ try {
|
|
|
+ const data = JSON.parse(line.slice(7));
|
|
|
+ if (data.content) {
|
|
|
+ console.log('流信号 思考内容', data.content)
|
|
|
+ // 这里没实现呢,需要你参考openai的实现@xiong
|
|
|
+ // 进入思考状态
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('解析响应数据失败:', e);
|
|
|
+ }
|
|
|
+ } else if (line.startsWith('data: ')) { // 返回内容
|
|
|
+ try {
|
|
|
+ const data = JSON.parse(line.slice(6));
|
|
|
+ if (data.error) {
|
|
|
+ // 处理错误
|
|
|
+ if (!responseElement) {
|
|
|
+ aiMessageElement.innerHTML = `<div class="alert alert-danger">${data.error}</div>`;
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data.content) {
|
|
|
+ console.log('流信号', data.content)
|
|
|
+ aiResponse += data.content;
|
|
|
+ if (!responseElement) {
|
|
|
+ // 移除思考状态
|
|
|
+ aiMessageElement.innerHTML = '';
|
|
|
+ responseElement = aiMessageElement;
|
|
|
+ }
|
|
|
+ updateMessageContent(responseElement, aiResponse);
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.error('解析响应数据失败:', e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 继续读取流
|
|
|
+ return readStream();
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ return readStream();
|
|
|
+ })
|
|
|
+ .catch(error => {
|
|
|
+ console.error('请求失败:', error);
|
|
|
+ if (!responseElement) {
|
|
|
+ aiMessageElement.innerHTML = '<div class="alert alert-danger">连接错误,请重试</div>';
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 添加消息到聊天界面
|
|
|
+ function addMessage(role, content, isThinking = false) {
|
|
|
+ const messageDiv = document.createElement('div');
|
|
|
+ messageDiv.className = `message ${role}-message mb-3`;
|
|
|
+
|
|
|
+ const avatar = document.createElement('div');
|
|
|
+ avatar.className = 'avatar';
|
|
|
+ avatar.innerHTML = role === 'user' ?
|
|
|
+ '<i class="fas fa-user"></i>' :
|
|
|
+ '<img src="./image/robot.png" alt="">';
|
|
|
+
|
|
|
+ const contentDiv = document.createElement('div');
|
|
|
+ contentDiv.className = 'content';
|
|
|
+
|
|
|
+ if (isThinking) {
|
|
|
+ contentDiv.innerHTML = `
|
|
|
+ <div class="thinking-container">
|
|
|
+ <div class="thinking-indicator">
|
|
|
+ <span></span><span></span><span></span>
|
|
|
+ </div>
|
|
|
+ <div class="thinking-text">思考中...</div>
|
|
|
+ </div>
|
|
|
+ `;
|
|
|
+ } else {
|
|
|
+ contentDiv.innerHTML = marked.parse(content);
|
|
|
+ hljs.highlightAll();
|
|
|
+ }
|
|
|
+
|
|
|
+ messageDiv.appendChild(avatar);
|
|
|
+ messageDiv.appendChild(contentDiv);
|
|
|
+ chatMessages.appendChild(messageDiv);
|
|
|
+
|
|
|
+ // 滚动到底部
|
|
|
+ // chatMessages.scrollTop = chatMessages.scrollHeight;
|
|
|
+ messageDiv.scrollIntoView({ behavior: 'smooth', block: 'end', inline: 'start' });
|
|
|
+
|
|
|
+ return contentDiv;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新消息内容
|
|
|
+ function updateMessageContent(element, content) {
|
|
|
+ element.innerHTML = marked.parse(content);
|
|
|
+ hljs.highlightAll();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 事件监听
|
|
|
+ sendBtn.addEventListener('click', sendMessage);
|
|
|
+
|
|
|
+ messageInput.addEventListener('keypress', function (e) {
|
|
|
+ if (e.key === 'Enter' && !e.shiftKey) {
|
|
|
+ e.preventDefault();
|
|
|
+ sendMessage();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 初始聚焦输入框
|
|
|
+ messageInput.focus();
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ addMessage('user', u1);
|
|
|
+ const el = addMessage('robot', '', true);
|
|
|
+ setTimeout(() => { updateMessageContent(el, r1) }, 3000);
|
|
|
+ }, 1000)
|
|
|
+ });
|
|
|
+</script>
|
|
|
+</body>
|
|
|
+</html>
|