App.vue 6.5 KB
Newer Older
6
UPDATE  
64104061f23fda247c679fa8 已提交
1
<template>
6
update  
64104061f23fda247c679fa8 已提交
2 3 4 5 6 7 8 9
  <div class="container ivu-p">
    <div class="dialog">
      <template v-for="(item, index) in dialogs" :key="index">
        <div class="dialog-item" :class="{ 'dialog-item-me': item.role === 'me', 'dialog-item-ai': item.role === 'ai' }">
          <div class="dialog-item-main">{{ item.text }}</div>
        </div>
      </template>
    </div>
10
    <div class="question ivu-mt">
I
InsCode 已提交
11
      <Input v-model="question" type="textarea" :autosize="{ minRows: 4, maxRows: 6 }" placeholder="输入内容..." />
6
update  
64104061f23fda247c679fa8 已提交
12 13 14 15 16 17 18
      <Row class="ivu-mt">
        <Col>
          <Button type="primary" size="large" icon="md-send" :loading="loading" @click="handleSend">发送</Button>
        </Col>
        <Col>
          <Button size="large" class="ivu-ml" icon="md-add" :disabled="loading" @click="handleNewChat">新对话</Button>
        </Col>
I
InsCode 已提交
19 20 21
        <Col>
          <Button size="large" class="ivu-ml" icon="md-settings" :disabled="loading" @click="handleOpenPrompt">设置 Prompt</Button>
        </Col>
6
update  
64104061f23fda247c679fa8 已提交
22
      </Row>
6
64104061f23fda247c679fa8 已提交
23
      <Typography class="ivu-text-center ivu-m">
6
64104061f23fda247c679fa8 已提交
24
        Powered By <img src="./assets/logo.png" class="logo"> <a href="https://inscode.net" target="_blank">InsCode.net</a>
6
64104061f23fda247c679fa8 已提交
25
      </Typography>
6
update  
64104061f23fda247c679fa8 已提交
26
    </div>
I
InsCode 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40
    <Modal v-model="showPrompt" title="设置 Prompt" footer-hide>
      <Title :level="4">Prompt:</Title>
      <Input v-model="prompt" type="textarea" :autosize="{minRows: 3,maxRows: 5}" placeholder="例如:写一个策划,主题是_____" />
      <Title class="ivu-mt" :level="4">推荐:</Title>
      <Space :wrap="true">
        <Button @click="handleSetPrompt('写一篇140字以内的朋友圈配文,语言风格要浪漫文艺的,主题是__________')">朋友圈神器</Button>
        <Button @click="handleSetPrompt('扮演一位知心姐姐进行在线聊天。__________')">知心姐姐</Button>
        <Button @click="handleSetPrompt('你现在需要扮演一个高情商、幽默的人,去参加一些聚会社交,请帮我回应接下来的问题,__________')">高情商回复</Button>
        <Button @click="handleSetPrompt('我是你的专属心理咨询师,你有什么想咨询的么?')">心理咨询师</Button>
      </Space>
      <Title class="ivu-mt" :level="4">操作:</Title>
      <Button icon="md-trash" @click="handleClearPrompt">清空 Prompt</Button>
      <Button size="large" type="primary" long class="ivu-mt" @click="handleSavePrompt">保存</Button>
    </Modal>
6
622eda98dfef6c4fdb84ccca 已提交
41
  </div>
6
UPDATE  
64104061f23fda247c679fa8 已提交
42
</template>
6
update  
64104061f23fda247c679fa8 已提交
43
<script>
6
UPDATE  
64104061f23fda247c679fa8 已提交
44 45
import { fetchEventSource } from '@microsoft/fetch-event-source';
import { apiKey, apiUrl } from './api';
46

I
InsCode 已提交
47 48
let prompt = '';

49 50 51 52 53
export default {
  data() {
    return {
      question: '',
      loading: false,
I
InsCode 已提交
54 55 56
      dialogs: [],
      prompt: '',
      showPrompt: false
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
    }
  },
  methods: {
    handleSend() {
      if (this.loading || this.question === '') return;
      this.loading = true;

      const question = this.question;
      this.question = '';

      this.dialogs.push({
        id: this.dialogs.length + 1,
        role: 'me',
        text: question
      });

      const aiDialogID = this.dialogs.length + 1;
74

75 76 77 78 79
      this.dialogs.push({
        id: aiDialogID,
        role: 'ai',
        text: 'AI 思考中...'
      });
80

6
UPDATE  
64104061f23fda247c679fa8 已提交
81
      const dialog = this.dialogs.find(item => item.id === aiDialogID);
6
update  
64104061f23fda247c679fa8 已提交
82

6
UPDATE  
64104061f23fda247c679fa8 已提交
83 84 85 86 87 88 89 90 91 92
      /**
       * 发送请求,InsCode 已经集成了 GPT 能力
       * 在 vite.config.js 中已通过环境变量写入了 apiKey(该 key 是动态写入使用者的,在 IDE 中是作者,发布到社区是运行该作品的用户)
       * 发布到社区后,将消耗运行者的额度
       * 注意:如果部署应用,任何人通过部署后的域名访问应用时,都将消耗部署者的额度
       */
      const body = {
        messages: [
          {
            role: 'user',
I
InsCode 已提交
93
            content: prompt + question
6
update  
64104061f23fda247c679fa8 已提交
94
          }
6
UPDATE  
64104061f23fda247c679fa8 已提交
95 96 97
        ],
        apikey: apiKey
      }
98

6
UPDATE  
64104061f23fda247c679fa8 已提交
99 100 101 102 103 104 105 106 107 108
      const source = fetchEventSource(apiUrl, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(body),
        onopen: (response) => {
          dialog.text = '';
        },
        onmessage: (msg) => {
6
64104061f23fda247c679fa8 已提交
109 110 111 112
          if (msg.data === '[DONE]') {
            this.loading = false;
            return;
          };
6
UPDATE  
64104061f23fda247c679fa8 已提交
113
          const data = JSON.parse(msg.data);
6
64104061f23fda247c679fa8 已提交
114 115
          const finish_reason = data.choices[0].finish_reason;
          const finish = finish_reason === 'stop' || finish_reason === 'length';
6
UPDATE  
64104061f23fda247c679fa8 已提交
116 117 118 119 120 121 122 123 124 125 126
          const content = data.choices[0].delta.content;

          if (finish) {
            this.loading = false;
          } else if (content) {
            const text = content;
            dialog.text += text;
          }
        },
        onerror: (err) => {
          console.log("error", err);
127
        }
6
UPDATE  
64104061f23fda247c679fa8 已提交
128
      });
129 130 131
    },
    handleNewChat() {
      this.dialogs = [];
I
InsCode 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
    },
    handleOpenPrompt () {
      this.showPrompt = true;
    },
    handleSetPrompt (prompt) {
      this.prompt = prompt;
    },
    handleSavePrompt () {
      if (!this.prompt) {
        this.$Message.error({
          content: '提示词内容不能为空',
          duration: 3,
          background: true
        });
      } else {
        const prompt = this.prompt;
        localStorage.setItem('setting-prompt', prompt);
        this.showPrompt = false;
        this.handleLoadPrompt();
      }
    },
    handleLoadPrompt () {
      const localPrompt = localStorage.getItem('setting-prompt');
      if (localPrompt) {
        this.prompt = localPrompt;
        prompt = localPrompt;
        this.$nextTick(() => {
          this.$Message.success({
            content: '已加载 Prompt',
            background: true
          });
        });
      }
    },
    handleClearPrompt () {
      localStorage.removeItem('setting-prompt');
      this.prompt = '';
      prompt = '';
      this.$nextTick(() => {
        this.$Message.success({
          content: '已清空 Prompt',
          background: true
        });
      });
6
update  
64104061f23fda247c679fa8 已提交
176
    }
I
InsCode 已提交
177 178 179
  },
  mounted () {
    this.handleLoadPrompt();
6
update  
64104061f23fda247c679fa8 已提交
180
  }
181
}
6
622eda98dfef6c4fdb84ccca 已提交
182
</script>
6
update  
64104061f23fda247c679fa8 已提交
183
<style>
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
.container {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.dialog {
  flex: 1;
  overflow: auto;
}

.dialog-item {
  display: flex;
}

.dialog-item-main {
  max-width: 80%;
  padding: 8px;
  word-wrap: break-word;
  margin-top: 16px;
  border-radius: 4px;
}

.dialog-item-me {
  justify-content: flex-end;
}

.dialog-item-me .dialog-item-main {
  background-color: antiquewhite;
}

.dialog-item-ai .dialog-item-main {
  background-color: #eee;
}
6
64104061f23fda247c679fa8 已提交
218 219 220 221 222 223 224
.logo{
  width: 16px;
  height: 16px;
  vertical-align: middle;
  position: relative;
  top: -1px;
}
6
update  
64104061f23fda247c679fa8 已提交
225
</style>