<template>
  <div class="interpretation">
    <progress-bar :num="processNum" />
    <div class="header">
      <home-header sub-title="自然资源大模型" />
    </div>
    <div class="content-box">
      <div class="left-panel">
        <div class="content-top">
          <div class="left">
            <a-input :value="fileDetail?.name" style="width: 400px; margin-right: 10px" />
            <a-upload
              class="upload"
              action="/aisKnowledge/infra/file/upload"
              @change="handleChange"
              :showUploadList="false"
              :data="{ type: 'temp' }"
              accept=".pdf"
            >
              <img src="/images/zcjd/upload-icon.png" />上传本地文件
            </a-upload>

            <a-button class="ai-btn">AI解读</a-button>
          </div>
          <div class="right" v-if="false">
            <span @click="downloadFile"><img src="/images/zcjd/download-icon.png" />下载</span>
            <span><img src="/images/zcjd/star-icon.png" />收藏</span>
          </div>
        </div>
        <div class="content-detail">
          <div class="file-preview">
            <!-- <img :src="fileDetail?.content" alt="" v-if="fileDetail?.content" /> -->

            <!-- <div class="spin" v-if="loading"><a-spin></a-spin></div> -->
            <PDFViewer :src="fileUrl" ref="ifRef"></PDFViewer>
          </div>
        </div>
      </div>
      <div class="affix_box" :offsetTop="20">
        <div class="right-panel">
          <div class="ai-interpretation">
            <div class="check-type">
              <div class="check">
                <a-radio-group v-model:value="checkType" button-style="solid">
                  <a-radio-button value="interpretation">AI解读</a-radio-button>
                  <a-radio-button value="question">AI问答</a-radio-button>
                </a-radio-group>
              </div>
            </div>
            <div class="result">
              <div class="content" id="scrollArea" v-if="checkType == 'interpretation'">
                <a-spin class="spin" v-if="aiLoading"></a-spin>
                <template v-else>
                  <div class="desc">
                    <vue-markdown-it
                      :source="content"
                      v-if="content"
                      :options="{
                        html: true,
                        linkify: true
                      }"
                    />
                  </div>
                </template>
              </div>
              <div class="question" v-else>
                <div class="chat_box" id="chat_box">
                  <div class="item">
                    <div class="value-panel">
                      <div class="name">
                        文件内容太多，读起来太累了？可以试着让我来帮您解读。<span
                          >你可以试着这样问我:</span
                        >
                      </div>
                      <div
                        class="citem"
                        v-for="(item, index) in question"
                        :key="index"
                        @click="toggleQuestion(index)"
                      >
                        <div class="value">{{ item }}</div>
                      </div>
                    </div>
                  </div>
                  <div class="chat">
                    <div class="item" v-for="(item, index) in chatDesc" :key="index">
                      <div class="user-panel">
                        <div class="name">{{ item.name }}</div>
                        <img src="/images/zczk/user.png" />
                      </div>
                      <div class="ai-panel">
                        <img src="/images/zczk/icon-ai-title.png" />
                        <div class="desc" v-if="item.content" id="scrollArea-1">
                          <vue-markdown-it
                            :source="item.content"
                            :options="{
                              html: true,
                              linkify: true
                            }"
                          />
                        </div>
                        <div class="desc animation" v-else>正在思考中<span class="dots"></span></div>
                      </div>
                    </div>
                  </div>
                </div>

                <div class="input-panel">
                  <a-textarea
                    v-model:value="keyword"
                    placeholder="请输入"
                    @keydown.enter="keydownEnter"
                  >
                  </a-textarea>
                  <div class="send" @click="send">
                    发送<img src="/images/zczk/icon-white-send.png" />
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup>

/**
 * @description 解读详情
 */
import { ref, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import HomeHeader from '@/views/home/components/HomeHeader.vue';
import PDFViewer from '@/components/pdf/PDFViewerSearch.vue';
import ProgressBar from '@/components/ProgressBar.vue';
import api from '@/utils/policy-api';
import { getNumAll } from '@/utils/common';
import { message } from 'ant-design-vue';
import { fetchEventSource } from '@microsoft/fetch-event-source';
import { VueMarkdownIt } from '@f3ve/vue-markdown-it';
const route = useRoute();
const chatDesc = ref([]);
const keyword = ref('');
const ctr = new AbortController();
const fileDetail = ref(null);
const fileUrl = ref('');
const aiLoading = ref(false);
const queryText = ref('分别给出该文章的全文综述和要点总结');
const content = ref('');
const loading = ref(false);
const ifRef = ref(null);
const docs = ref([]);
const question = [
  '帮我总结一下核心内容？',
  '有没有类似的政策文件？',
  '文件中提到了哪些信息化内容？'
];
const checkType = ref('interpretation');
onMounted(async () => {
  const id = route.query.id;
  const url = route.query.url;
  //政策跳转 请求文件
  if (id) {
    getFileByID(id);
  }
  //政策解读 请求文件
  if (url) {
    fileUrl.value = url;
    var name = url.substring(url.lastIndexOf('/') + 1);
    var file = await fetchPdfFileStream(fileUrl.value, name);
    if (file) {
      setTimeout(() => {
        fileDetail.value = file;
        query();
      }, 100);
    }
  }
});
const getFileByID = (id) => {
  loading.value = true;
  var url = '/policy/query/' + id;
  api.get(url, {}, this, false).then(async (res) => {
    if (res && res.code == 200) {
      if (res.data.item) {
        var fileName = res.data.file_name;
        fileName = res.data.file_fullname;
        fileUrl.value = '/knowledge/file/' + fileName;
        loading.value = false;
        var file = await fetchPdfFileStream(fileUrl.value, fileName);
        if (file) {
          setTimeout(() => {
            fileDetail.value = file;

            query();
          }, 100);
        }
      }
    }
  });
};
import axios from 'axios';
//在线地址转文件
const fetchPdfFileStream = (pdfUrl, name) => {
  return new Promise((resolve, reject) => {
    var type = 'application/pdf';
    if (name.indexOf('pdf') > -1) {
      type = 'application/pdf';
    } else {
      type = 'application/docx';
    }
    axios
      .get(pdfUrl, { responseType: 'blob' })
      .then((response) => {
        const blob = new Blob([response.data], { type: type });
        const file = new File([blob], name, { type: type });
        resolve(file);
        // 接下来可以使用URL.createObjectURL(blob)创建一个可以用于<iframe>的URL
      })
      .catch((error) => {
        console.error('Error loading PDF:', error)
        reject(new Error('网络请求失败,请检查网络连接')); // 处理网络错误
      });
  });
};
const send = () => {
  if (!keyword.value) {
    message.info('请输入！');
    return;
  }
  queryText.value = keyword.value;
  keyword.value = '';
  var item = { name: queryText.value, content: '' };
  chatDesc.value.push(item);
  query();
  scrollToBottom('chat_box')
};
const toggleQuestion = (index) => {
  keyword.value = question[index];
};
const keydownEnter = () => {
  send();
};
const processNum = ref(0)
//文件上传
const handleChange = (info) => {
  loading.value = true;
  fileDetail.value = null;
  const status = info.file.status;
  processNum.value = 1
  if (status === 'done') {
    processNum.value = 100;
    fileDetail.value = info.file.originFileObj;
    fileUrl.value = 'https://ai.zrzyt.zj.gov.cn/aisKnowledge' + info.file.response.data;
    chatDesc.value = [];
    loading.value = false;
    content.value = '';
    checkType.value = 'interpretation';
    uploadFile();
  } else if (status === 'error') {
    message.error(`${info.file.name} file upload failed.`);
  }
};
const downloadFile = () => {
  let a = document.createElement('a');
  var name = fileDetail.value.name;
  var type = fileUrl.value.indexOf('temp') > -1 ? 'temp' : '1';
  a.href = '/knowledge/policy/download/' + name + '/' + type;
  a.click();
};
const uploadFile = () => {
  queryText.value = '分别给出该文章的全文综述和要点总结';
  query();
};
const scrollToBottom = async (idDom) => {
  // 滚动到底部
  if (!idDom) return;
  await nextTick(() => {
    const scrollEle = document.getElementById(idDom);

    if (scrollEle != null) {
      scrollEle.scrollTo({
        top: scrollEle.scrollHeight - scrollEle.clientHeight + 50,
        behavior: 'smooth'
      });
    }
  });
};
const goLocation = (content) => {
  nextTick(() => {
    ifRef.value.goSourceLocation(content, 2);
  });
};
const openDocByIndex = (ind) => {
  var flag = false;
  docs.value.forEach((t) => {
    if (t.index == ind) {
      flag = true;
      goLocation(t.content);
    }
  });
  if (!flag) {
    message.info('未找到出处！');
  }
};
window.openDocByIndex = openDocByIndex;
const handleDocs = (data) => {
  if (data) {
    docs.value = data.map((v, i) => {
      if (v.indexOf('.pdf') > 0) {
        return {
          index: v.substring(v.indexOf('[[') + 2, v.indexOf(']]')),
          doc: v.substring(v.indexOf('] [') + 3, v.indexOf('.pdf]') + 4),
          link: v.substring(v.indexOf('.pdf]') + 6, v.indexOf('.pdf)') + 4),
          content: v.substring(v.indexOf('.pdf]') + 6),
          showContent: false,
          type: 'pdf'
        };
      } else if (v.indexOf('.txt') > 0) {
        return {
          index: i++,
          doc: v.substring(v.indexOf('] [') + 3, v.indexOf('.txt]') + 4),
          link: v.substring(v.indexOf('.txt]') + 6, v.indexOf('.txt)') + 4),
          content: v.substring(v.indexOf('.txt)') + 6),
          showContent: false,
          type: 'txt'
        };
      }
    });
  }
};
const timers = ref([])  //缓存定时器
const timerIndex = ref(0)
const query = async () => {
  var params = new FormData();
  aiLoading.value = true;
  params.append('files', fileDetail.value);
  params.append('stream', true);
  params.append('query', queryText.value);
  timers.value = []
  timerIndex.value = 0
  await fetchEventSource(window.AppGlobalConfig.aiServer + '/chat/complete_file_chat', {
    method: 'POST',
    openWhenHidden: true,
    body: params,
    signal: ctr.signal,
    async onmessage(msg) {
      if (msg) {
        try {
          aiLoading.value = false;
          const rData = JSON.parse(msg.data);
          if (rData) {
            var con = rData.choices[0].delta.content;
            if (rData.status == 3) {
              timers.value.forEach((timer) => {
                clearTimeout(timer);
              })
              let nums = getNumAll(con);
              nums.forEach(num => {
                con = con.replace(
                      `[[${num}]]`,
                      `<span onclick="window.openDocByIndex(${num})" class="poi" style="    cursor: pointer; display: inline-block; width: 20px; height: 20px; font-size: 14px; line-height: 20px; text-align: center; margin: 0 5px; border-radius: 4px;background: #fff;color:#435C80;border: 1px solid #BACAE3">${num}</span>`
                  )
              })
              if (checkType.value == 'interpretation') {
                content.value = con;
                scrollToBottom('scrollArea');
              } else {
                chatDesc.value[chatDesc.value.length - 1].content = con + '\n\n #### 以上是我思考的内容！\n\n';
                scrollToBottom('chat_box');
              }
              if (rData.docs) {
                handleDocs(rData.docs);
              }
            } else if (rData.status == 2) {
              let timer = null;
              if (checkType.value == 'interpretation') {
                timer = setTimeout(() => {
                  content.value += con;
                  scrollToBottom('scrollArea');
                  clearTimeout(timer)
                }, timerIndex.value * 15)
              } else {
                timer = setTimeout(() => {
                  chatDesc.value[chatDesc.value.length - 1].content += con;
                  scrollToBottom('chat_box');
                  clearTimeout(timer)
                }, timerIndex.value * 15)
              }
              timers.value.push(timer)
              timerIndex.value++;
            }
          }
        } catch (e) {
          console.log('===' + e.message);
        }
      }
    },
    onclose() {
      aiLoading.value = false;
    },
    onerror(err) {
      aiLoading.value = false;
      throw err;
    },
    onopen() {}
  });
};
</script>
<style scoped lang="scss">
.interpretation {
  width: 100%;
  height: 100%;
  position: relative;
  z-index: 1;
  background: #f0f4f7;
  .content-box {
    width: calc(100% - 300px);
    height: calc(100% - 75px);
    margin: auto;
    margin-top: 15px;
    overflow-y: auto;
    box-shadow: 0px 1px 8px 0px #e4e4e4;
    display: flex;
    .left-panel {
      border-radius: 6px;
      padding: 10px 0px 0px 0px;
      background-color: #fff;
      width: calc(100% - 600px);
    }
    .affix_box {
      position: fixed;
      right: 150px;
      top: 75px;
    }
    .right-panel {
      width: 580px;
      height: calc(100vh - 86px) !important;
      border-radius: 6px;
      background-color: #fff;
      margin-left: 20px;
      .ai-interpretation {
        width: 100%;
        height: 100%;
        .check-type {
          width: 100%;
          display: flex;
          align-items: center;
          height: 50px;
          .check {
            height: 50px;
            line-height: 50px;
            padding-left: 10px;
          }
          justify-content: space-between;
        }
        .icon {
          width: 30px;
          cursor: pointer;
          height: 30px;
          margin-right: 12px;
          background: #e0efff;
          display: flex;
          justify-content: center;
          align-items: center;
          border-radius: 5px 5px 5px 5px;
          img {
            width: 17px;
            height: 17px;
          }
        }
        .result {
          width: 100%;
          height: calc(100% - 50px);

          padding: 0px 0px 20px 0px;
          .content {
            padding: 0px 27px 0px 23px;
            height: 100%;
            background: transparent;
            box-shadow: none;
            overflow-y: scroll;
            .title {
              font-family: PingFang SC;
              font-weight: bold;
              font-size: 16px;
              margin-bottom: 23px;
              color: #000;
            }
            .desc {
              font-family: PingFang SC;
              font-weight: normal;
              font-size: 14px;
              //color: #85909e;
              line-height: 28px;
              margin-bottom: 36px;
            }
            .spin {
              height: 100%;
              display: flex;
              align-items: center;
              justify-content: center;
            }
          }

          .question {
            height: 100%;
            padding: 0px 0px 6px 0px;
            position: relative;
            display: flex;
            flex-direction: column;
            .item {
              display: flex;
              width: 100%;
              background: #fff;
              padding: 4px 20px 15px 20px;
              img {
                width: 40px;
                height: 29px;
                margin-right: 13px;
              }
              .value-panel {
                flex: 1;
                .name {
                  font-family: PingFang SC, PingFang SC;
                  font-weight: 400;
                  font-size: 14px;
                  color: #2c2c2c;
                  line-height: 21px;
                  span {
                    color: #5a5b5e;
                  }
                }
                .citem {
                  margin-top: 0px;
                  display: flex;
                  cursor: pointer;
                  align-items: center;
                  padding: 16px 0px 0px 0px;
                  img {
                    width: 18px;
                    height: 18px;
                    margin-right: 9px;
                  }
                  .value {
                    flex: 1;
                    font-family: PingFang SC, PingFang SC;
                    font-weight: 400;
                    font-size: 14px;
                    color: #ef7217;
                    line-height: 21px;
                  }
                }
              }
            }
            .scale-panel {
              display: flex;
              justify-content: flex-end;
              font-family: PingFang SC, PingFang SC;
              font-weight: 400;
              margin-top: 7px;
              margin-bottom: 27px;
              cursor: pointer;
              width: calc(100% - 30px);
              font-size: 13px;
              color: #778490;
              span {
                font-family: PingFang SC, PingFang SC;
                font-weight: 500;
                font-size: 13px;
                color: #3c7bff;
              }
            }
            .chat_box {
              flex: 1;
              height: 0px;
              overflow-y: auto;
            }
            .chat {
              font-family: PingFang SC;
              font-weight: 500;
              margin: 10px 0px;
              line-height: 28px;
              font-size: 16px;
              color: #333333;
              .item {
                display: flex;
                flex-direction: column;
                padding: 0px;
                background: transparent;
                width: unset;
                .user-panel {
                  display: flex;
                  margin: 20px 0px;
                  justify-content: flex-end;
                  img {
                    width: 36px;
                    margin-left: 7px;
                    height: 36px;
                  }
                  .name {
                    max-width: calc(100% - 43px);
                    background: #3c7bff;
                    border-radius: 5px 5px 5px 5px;
                    padding: 7px 24px 7px 11px;
                    font-family: PingFang SC, PingFang SC;
                    font-weight: 500;
                    font-size: 14px;
                    color: #ffffff;
                    line-height: 21px;
                  }
                }
                .ai-panel {
                  display: flex;
                  img {
                    width: 32px;
                    margin-left: 13px;
                    height: 32px;
                  }
                  .desc {
                    max-width: calc(100% - 95px);
                    background: #f5f8fc;
                    border-radius: 6px 6px 6px 6px;
                    padding: 10px 18px 10px 13px;
                    font-weight: 500;
                    overflow-y: auto;
                    font-size: 14px;
                    color: #333333;
                    line-height: 28px;
                  }
                  .animation {
                    @keyframes dot {
                      0%,
                      20% {
                        content: '';
                      }
                      40% {
                        content: '.';
                      }
                      60% {
                        content: '..';
                      }
                      80%,
                      100% {
                        content: '...';
                      }
                    }
                    .dots::after {
                      display: inline-block;
                      animation: dot 1.5s steps(1, end) infinite;
                      content: '';
                    }
                  }
                }
              }
            }
            .input-panel {
              position: relative;
              bottom: 0px;
              background: #f5f8fc;
              border-radius: 6px;
              height: 111px;
              padding: 2px;
              width: calc(100% - 54px);
              margin-left: 25px;
              textarea {
                border: none;
                padding: 16px 22px;
                height: 100%;
                background: #f5f8fc;
                font-weight: 400;
                font-size: 16px;
                color: #333333;
                &:focus-visible {
                  border: none !important;
                  outline: none;
                  box-shadow: none;
                }
                &:focus {
                  border: none !important;
                  outline: none;
                  box-shadow: none;
                }
              }
              .send {
                right: 17px;
                bottom: 14px;
                cursor: pointer;
                width: 79px;
                height: 32px;
                background: linear-gradient(134deg, #1ba3fb 0%, #0745f6 100%);
                border-radius: 16px 16px 16px 16px;
                z-index: 2;
                position: absolute;
                display: flex;
                align-items: center;
                justify-content: center;
                img {
                  width: 13px;
                  height: 13px;
                  margin-left: 6px;
                }
                font-family: PingFang SC, PingFang SC;
                font-weight: 400;
                font-size: 14px;
                color: #ffffff;
              }
            }
          }
        }
      }
    }
    .zm {
      width: 640px;
    }
  }
  .content-top {
    width: 100%;
    height: 80px;
    padding: 0 30px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    border-bottom: 1px solid #e9e9e9;
    .left {
      .upload {
        font-size: 16px;
        color: #2185f2;
        cursor: pointer;
        img {
          margin-right: 5px;
        }
      }
      .ai-btn {
        width: 120px;
        height: 40px;
        background: url('/images/zcjd/ai-btn-icon.png');
        background-repeat: no-repeat;
        background-size: 100% 100%;
        border-radius: 12px;
        padding-left: 35px;
        margin-left: 20px;
        font-size: 18px;
        font-weight: 600;
        color: #ffffff;
      }
    }
    .right {
      height: 80px;
      line-height: 80px;
      color: #666666;
      span {
        margin-left: 20px;
        cursor: pointer;
      }
      span:hover {
        box-shadow: 1px 1px 1px 1px rgba(140, 140, 140, 0.2);
      }
      img {
        margin-right: 4px;
        width: 20px;
        height: 20px;
      }
    }
  }
  .content-detail {
    width: 100%;
    min-height: calc(100% - 80px);
    display: flex;
    .file-preview {
      flex: 1;
      text-align: center;
      .spin {
        display: flex;
        align-items: center;
        height: 100%;
        justify-content: center;
      }
    }
  }
  ::-webkit-scrollbar {
    width: 3px !important;
  }
}
</style>
