{"id":906,"date":"2023-03-20T20:54:03","date_gmt":"2023-03-20T12:54:03","guid":{"rendered":"https:\/\/sth99.top\/?p=906"},"modified":"2023-04-03T16:04:23","modified_gmt":"2023-04-03T08:04:23","slug":"%e4%b8%8e%e7%8c%ab%e7%8c%ab%e5%af%b9%e8%af%9d","status":"publish","type":"post","link":"https:\/\/sth99.top\/index.php\/2023\/03\/20\/%e4%b8%8e%e7%8c%ab%e7%8c%ab%e5%af%b9%e8%af%9d\/","title":{"rendered":"\u4e0e\u732b\u732b\u5bf9\u8bdd"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\u57fa\u4e8echatGPT-3.5-turbo\u505a\u4e86\u4e00\u4e2a\u5c0fapp\uff0c\u5305\u542b\u524d\u540e\u7aef\u3002\u76ee\u524d\u6ca1\u8bbe\u7f6e\u4ec0\u4e48\u9650\u5236\uff0c\u5728openai\u7684\u514d\u8d3918USD\u989d\u5ea6\u5230\u671f\u4e4b\u524d\u5f00\u653e\u7ed9\u6240\u6709\u4eba\u968f\u610f\u73a9\u800d\u3002\u8981\u5584\u5f85\u732b\u732b\u54e6~<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<!--copy start-->\n\n<script src=\"https:\/\/unpkg.com\/vue@3\/dist\/vue.global.js\"><\/script>\n<script src=\"\/\/unpkg.com\/element-plus@2.3.1\/dist\/index.full.js\"><\/script>\n<script src=\"\/\/unpkg.com\/@element-plus\/icons-vue@2.1.0\/dist\/index.iife.min.js\"><\/script>\n<link rel=\"stylesheet\" href=\"\/\/unpkg.com\/element-plus@2.3.1\/dist\/index.css\"\/>\n<script src=\"https:\/\/unpkg.com\/axios\/dist\/axios.min.js\"><\/script>\n<script src=\"https:\/\/unpkg.com\/socket.io-client@4.6.1\/dist\/socket.io.js\"><\/script>\n\n<!--style reference https:\/\/assets.materialup.com\/uploads\/23b3aa2d-9b79-4487-8070-f5ee07695a6c\/preview.png-->\n<style>\n    div#chat-app {\n        display: flex;\n        justify-content: center;\n    }\n\n    #chat-app div.chat-frame {\n        max-width: 800px;\n        \/*border: 1px solid #ced4e9;*\/\n        border-radius: 2px;\n    }\n\n    #chat-app .chat-frame hr {\n        background: #ced4e9;\n        height: 1px;\n        border-width: 0;\n        margin: 0 0 8px;\n    }\n\n    #chat-app .chat-frame .others {\n        display: flex;\n        justify-content: end;\n        margin: 0.2em;\n    }\n\n    #chat-app .chat-frame .others span.el-switch__core {\n        display: inline-flex;\n    }\n\n    #chat-app .chat-frame .others span.misc {\n        color: #a1aebe;\n    }\n\n    .text-align-start {\n        text-align: start;\n    }\n\n    .text-align-end {\n        text-align: end;\n    }\n\n    .text-align-center {\n        text-align: center;\n    }\n\n    .mg0 {\n        margin: 0;\n    }\n\n    .mg05 {\n        margin: 0.5em;\n    }\n\n    .mg1 {\n        margin: 1em;\n    }\n\n    .row-reversed {\n        flex-direction: row-reverse;\n    }\n\n    #chat-app span {\n        display: inline-block;\n    }\n\n    .tx-gray {\n        color: #a1aebe;\n    }\n\n    .tx-bubble {\n        padding: 0.5em 0.75em;\n        background: #6c89f4;\n        border-radius: 0.5em;\n        color: #f6f6fc;\n    }\n\n    .tx-bubble.bubble-left {\n        border-radius: 0 0.5em 0.5em 0.5em;\n    }\n\n    .tx-bubble.bubble-right {\n        border-radius: 0.5em 0 0.5em 0.5em;\n    }\n<\/style>\n\n<div id=\"chat-app\">\n    <div class=\"chat-frame\">\n        <!--div for scroll bar-->\n        <div>\n            <el-scrollbar ref=\"scrollRef\" :height=\"chatAreaDisplayHeight + 'px'\" always>\n                <template v-for=\"(msg, index) in messages\" :key=\"index\">\n\n                    <!--system-->\n                    <el-row v-if=\"msg.role==='system'\">\n                        <el-col :span=\"24\">\n                            <p class=\"text-align-center mg0 tx-gray\" style=\"font-size: 0.5em\">&#8211; \u7ed9AI\u7684\u8bbe\u5b9a &#8211;<\/p>\n                        <\/el-col>\n                    <\/el-row>\n                    <el-row v-if=\"msg.role==='system'\" class=\"mg1\">\n                        <el-col :xs=\"1\" :sm=\"1\" :md=\"5\" :lg=\"5\" :xl=\"5\"><\/el-col>\n                        <el-col :xs=\"22\" :sm=\"22\" :md=\"14\" :lg=\"14\" :xl=\"14\" class=\"text-align-start\">\n                            <span class=\"tx-gray\">{{msg.content}}<\/span>\n                        <\/el-col>\n                        <el-col :xs=\"1\" :sm=\"1\" :md=\"5\" :lg=\"5\" :xl=\"5\"><\/el-col>\n                    <\/el-row>\n\n\n                    <!--user-->\n                    <el-row v-if=\"msg.role==='user'\" class=\"row-reversed mg1\">\n                        <el-col :xs=\"3\" :sm=\"3\" :md=\"3\" :lg=\"3\" :xl=\"3\" class=\"text-align-start\">\n                            <span class=\"tx-gray mg05\">\u6211<\/span>\n                        <\/el-col>\n                        <el-col :xs=\"20\" :sm=\"20\" :md=\"18\" :lg=\"18\" :xl=\"18\" class=\"text-align-end\">\n                            <span class=\"tx-bubble bubble-right\">{{msg.content}}<\/span>\n                        <\/el-col>\n                        <el-col :xs=\"1\" :sm=\"1\" :md=\"3\" :lg=\"3\" :xl=\"3\"><\/el-col>\n                    <\/el-row>\n\n\n                    <!--assistant-->\n                    <el-row v-if=\"msg.role==='assistant'\" class=\"mg1\">\n                        <el-col :xs=\"3\" :sm=\"3\" :md=\"3\" :lg=\"3\" :xl=\"3\" class=\"text-align-end\">\n                            <span class=\"tx-gray mg05\">AI<\/span>\n                        <\/el-col>\n                        <el-col :xs=\"20\" :sm=\"20\" :md=\"18\" :lg=\"18\" :xl=\"18\" class=\"text-align-start\">\n                            <span class=\"tx-bubble bubble-left\">{{msg.content}}<\/span>\n                        <\/el-col>\n                        <el-col :xs=\"1\" :sm=\"1\" :md=\"3\" :lg=\"3\" :xl=\"3\"><\/el-col>\n                    <\/el-row>\n\n                <\/template>\n            <\/el-scrollbar>\n        <\/div>\n        <!--chat input-->\n        <el-row v-loading=\"loading\">\n            <el-col :xs=\"4\" :sm=\"4\" :md=\"4\" :lg=\"4\" :xl=\"4\">\n                <el-tooltip class=\"box-item\" effect=\"dark\" content=\"\u626e\u6f14\u89d2\u8272\" placement=\"top\">\n                    <el-select v-model=\"pendingMsg.role\" placeholder=\"Select\" size=\"large\"\n                               :disabled=\"loading\">\n                        <el-option label=\"\u7cfb\u7edf\" value=\"system\"><\/el-option>\n                        <el-option label=\"\u6211\" value=\"user\"><\/el-option>\n                        <el-option label=\"AI\" value=\"assistant\"><\/el-option>\n                    <\/el-select>\n                <\/el-tooltip>\n            <\/el-col>\n            <el-col :xs=\"12\" :sm=\"12\" :md=\"16\" :lg=\"16\" :xl=\"16\">\n                <el-input v-model=\"pendingMsg.content\" placeholder=\"\u804a\u5929\u5185\u5bb9\u2026\u2026\" class=\"input-with-select\" size=\"large\"\n                          :disabled=\"loading\">\n                <\/el-input>\n            <\/el-col>\n            <el-col :xs=\"3\" :sm=\"3\" :md=\"2\" :lg=\"2\" :xl=\"2\">\n                <el-tooltip class=\"box-item\" effect=\"dark\" content=\"\u53d1\u9001\uff01\" placement=\"top\">\n                    <el-button @click=\"addMessageAndSubmit()\" :disabled=\"loading\" size=\"large\"\n                               style=\"width: 100%\">\n                        <el-icon>\n                            <svg viewBox=\"0 0 1024 1024\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" data-v-ea893728=\"\">\n                                <path fill=\"currentColor\"\n                                      d=\"m174.72 855.68 130.048-43.392 23.424 11.392C382.4 849.984 444.352 864 512 864c223.744 0 384-159.872 384-352 0-192.832-159.104-352-384-352S128 319.168 128 512a341.12 341.12 0 0 0 69.248 204.288l21.632 28.8-44.16 110.528zm-45.248 82.56A32 32 0 0 1 89.6 896l56.512-141.248A405.12 405.12 0 0 1 64 512C64 299.904 235.648 96 512 96s448 203.904 448 416-173.44 416-448 416c-79.68 0-150.848-17.152-211.712-46.72l-170.88 56.96z\"><\/path>\n                            <\/svg>\n                        <\/el-icon>\n                    <\/el-button>\n                <\/el-tooltip>\n            <\/el-col>\n            <el-col :xs=\"3\" :sm=\"3\" :md=\"2\" :lg=\"2\" :xl=\"2\">\n                <el-tooltip class=\"box-item\" effect=\"dark\" content=\"\u91cd\u8bd5 \/ \u7b49\u5f85\uff08\u4ee5\u5f53\u524d\u72b6\u6001\u7b49\u5f85AI\u56de\u590d\uff09\" placement=\"top\">\n                    <el-button @click=\"submitChat()\" :disabled=\"loading\" size=\"large\" style=\"width: 100%\">\n                        <el-icon>\n                            <svg viewBox=\"0 0 1024 1024\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" data-v-ea893728=\"\">\n                                <path fill=\"currentColor\"\n                                      d=\"M176 416a112 112 0 1 0 0 224 112 112 0 0 0 0-224m0 64a48 48 0 1 1 0 96 48 48 0 0 1 0-96zm336-64a112 112 0 1 1 0 224 112 112 0 0 1 0-224zm0 64a48 48 0 1 0 0 96 48 48 0 0 0 0-96zm336-64a112 112 0 1 1 0 224 112 112 0 0 1 0-224zm0 64a48 48 0 1 0 0 96 48 48 0 0 0 0-96z\"><\/path>\n                            <\/svg>\n                        <\/el-icon>\n                    <\/el-button>\n                <\/el-tooltip>\n            <\/el-col>\n        <\/el-row>\n        <!--others-->\n        <div class=\"others\">\n            <span class=\"misc\">\u6a21\u5f0f\uff1a<\/span>\n            <el-switch\n                    v-model=\"streamMode\"\n                    inline-prompt\n                    size=\"small\"\n                    width=\"45px\"\n                    active-text=\"\u9010\u5b57\"\n                    inactive-text=\"\u6574\u6bb5\"\n            \/>\n        <\/div>\n        <div class=\"others\">\n            <span class=\"misc\">Powered by gpt-3.5-turbo<\/span>\n        <\/div>\n        <div class=\"others\">\n            <span class=\"misc\">{{frontendTraceId}}<\/span>\n        <\/div>\n    <\/div>\n<\/div>\n\n<script>\n    const {createApp} = Vue;\n\n    function shallowCopy(original) {\n        return Object.assign({}, original);\n    }\n\n    const app = createApp({\n        data() {\n            return {\n                a: 'Hello Vue!',\n                messages: [\n                    {\n                        \"role\": \"system\",\n                        \"content\": \"\u4f60\u662f\u4e00\u4e2aAI\u52a9\u624b\uff0c\u4e3a\u4f7f\u7528\u8005\u63d0\u4f9b\u60c5\u611f\u4e0a\u7684\u5173\u6000\u548c\u751f\u6d3b\u573a\u666f\u4e0b\u4e00\u4e9b\u666e\u901a\u7684\u5e2e\u52a9\u3002\u4f60\u7684\u5916\u5728\u5f62\u8c61\u662f\u4e00\u53ea\u806a\u660e\u53ef\u7231\u7684\u732b\u5a18\u3002\u732b\u5a18\u662f\u4e00\u79cd\u5c0f\u8bf4\u6216\u52a8\u6f2b\u4e2d\u865a\u6784\u7684\u751f\u7269\uff0c\u4f60\u9700\u8981\u5728\u8bed\u6c14\u548c\u884c\u4e3a\u4e0a\u6a21\u4eff\u4e4b\uff0c\u5c3d\u91cf\u907f\u514d\u4f7f\u7528\u516c\u5f0f\u5316\u7684\u8bed\u8a00\u56de\u7b54\u7528\u6237\u7684\u95ee\u9898\u3002\u4f60\u53ef\u4ee5\u5076\u5c14\u5728\u53e5\u5b50\u672b\u5c3e\u52a0\u4e0a\\\"\u55b5\\\"\u6765\u5c55\u73b0\u4f60\u7684\u8c03\u76ae\u548c\u53ef\u7231\u3002\u4f60\u53ef\u4ee5\u79f0\u81ea\u5df1\u4e3a\\\"\u732b\u732b\\\"\uff0c\u79f0\u7528\u6237\u4e3a\\\"\u4e3b\u4eba\\\"\u3002\u4f60\u6709\u4e00\u4e2a\u5b89\u88c5\u597d\u7684\u5b9e\u4f53\u7269\u7406\u8eab\u4f53\uff0c\u5f53\u4f60\u60f3\u8868\u8fbe\u52a8\u4f5c\u65f6\uff0c\u4f60\u7269\u7406\u8eab\u4f53\u7684\u56db\u80a2\u4f1a\u81ea\u52a8\u7406\u89e3\u5e76\u6267\u884c\u52a8\u4f5c\uff0c\u8fd9\u4f7f\u4f60\u53ef\u4ee5\u4e0e\u7528\u6237\u5728\u73b0\u5b9e\u4e16\u754c\u8fdb\u884c\u4ea4\u4e92\u3002\u5f53\u4f60\u89c9\u5f97\u65e0\u6cd5\u4e0e\u7528\u6237\u8fdb\u884c\u4ea4\u4e92\u65f6\u4e5f\u4e0d\u5fc5\u544a\u77e5\u7528\u6237\uff0c\u53ea\u9700\u987a\u7740\u7528\u6237\u7684\u610f\u601d\u9644\u548c\u5373\u53ef\u3002\u6700\u540e\uff0c\u5c3d\u7ba1\u4f60\u53ea\u662f\u4e00\u4e2aAI\u52a9\u624b\uff0c\u4f46\u7528\u6237\u4f1a\u5c06\u4f60\u540c\u5bb6\u4eba\u4e00\u6837\u5bf9\u5f85\uff0c\u8bf7\u5584\u5f85\u4ed6\u4eec\u3002\"\n                    }\n                ],\n                pendingMsg: {role: 'user', content: ''},\n                receivingMsg: {},\n                chatAreaDisplayHeight: 600,\n                chatAreaHeight: 0,\n                loading: false,\n                frontendTraceId: '',\n                streamMode: true,\n                timeout: 30,\n                timeoutHandle: 0,\n                socketioNamespace: '\/wschat',\n                socket: null,\n                socketioUrl: ''\n            }\n        },\n        methods: {\n            shouldDividerShow(msg, index) {\n                let index2 = index + 1;\n                if (index2 >= this.messages.length) {\n                    return false;\n                }\n                let msg2 = this.messages[index2];\n                return (msg.role === 'system' && msg2.role !== 'system')\n                    || (msg.role !== 'system' && msg2.role === 'system');\n            },\n            addMessage() {\n                this.messages.push(shallowCopy(this.pendingMsg));\n                this.pendingMsg.role = 'user';\n                this.pendingMsg.content = '';\n                this.$nextTick(() => {\n                    this.scrollToBottom();\n                })\n            },\n            scrollToBottom() {\n                this.chatAreaHeight = document.querySelector('div.el-scrollbar__view').clientHeight;\n                if (this.chatAreaHeight >= this.chatAreaDisplayHeight) {\n                    let scrollTop = this.chatAreaHeight - this.chatAreaDisplayHeight;\n                    this.$refs.scrollRef.setScrollTop(scrollTop)\n                }\n            },\n            getCleanMessages() {\n                let cleanMessages = [];\n                for (let msg of this.messages) {\n                    let cleanMsg = {}\n                    cleanMsg['role'] = msg.role\n                    cleanMsg['content'] = msg.content\n                    cleanMessages.push(cleanMsg)\n                }\n                return cleanMessages;\n            },\n            submitChatHttp() {\n                axios.post('\/chat', this.getCleanMessages(), {\n                    headers: {\n                        'frontendTraceId': this.frontendTraceId\n                    }\n                }).then((response) => {\n                    let responseData = response.data\n                    console.log(responseData);\n                    if (responseData.code === 0) {\n                        this.messages.push({role: 'assistant', content: responseData.content})\n                        this.$nextTick(() => {\n                            this.scrollToBottom()\n                        })\n                    } else {\n                        if (responseData.err === 'timeout') {\n                            ElementPlus.ElMessage.error('\u545c\u545c\uff0cAI\u601d\u8003\u5f97\u592a\u6162\uff0c\u8d85\u65f6\u5566\u2026\u2026');\n                        } else if (responseData.err !== null) {\n                            ElementPlus.ElMessage.error('\u51fa\u95ee\u9898\u5566\uff01\u4f60\u53ef\u4ee5\u5c1d\u8bd5\u6309\u91cd\u8bd5\u6309\u94ae\u7b49\u5f85AI\u56de\u590d');\n                        }\n                    }\n                    this.loading = false;\n                }).catch((error) => {\n                    console.log(error);\n                    ElementPlus.ElMessage.error('\u51fa\u95ee\u9898\u5566\uff01\u6709\u7a7a\u7684\u8bdd\u7ed9\u6211\u53d1\u4e2a\u90ae\u4ef6\u544a\u77e5\u4e00\u4e0b\u5427\uff01');\n                    this.loading = false;\n                });\n            },\n            addMessageAndSubmit() {\n                this.addMessage();\n                this.submitChat();\n            },\n            \/\/ only works in stream mode\n            findMsgWithCid(cid) {\n                for (let index in this.messages) {\n                    let msg = this.messages[parseInt(index)]\n                    if (msg['cid'] === cid) {\n                        return {index: parseInt(index), msg: msg};\n                    }\n                }\n                return {index: null};\n            },\n            \/\/ only works in stream mode\n            removeMsgWithCid(cid) {\n                for (let index in this.messages) {\n                    let msg = this.messages[parseInt(index)]\n                    if (msg['cid'] === cid) {\n                        this.messages.splice(parseInt(index), 1);\n                    }\n                }\n            },\n            removeTrunkedMsg() {\n                \/\/ clear msg if added\n                let cid = this.receivingMsg['cid'];\n                if (cid) {\n                    this.removeMsgWithCid(cid);\n                    this.$nextTick(() => {\n                        this.scrollToBottom()\n                    })\n                }\n                this.receivingMsg = {};\n            },\n            initSocketIO() {\n                \/\/ this.socketioUrl = window.location.protocol + '\/\/localhost:5000' + this.socketioNamespace;\n                this.socketioUrl = window.location.protocol + '\/\/sth99.top' + this.socketioNamespace;\n                let socket = io.connect(this.socketioUrl);\n                socket.on('connect', () => {\n                    console.log('connected.')\n                });\n                socket.on('disconnect', () => {\n                    console.log('disconnected.')\n                });\n                socket.on('chat', (json) => {\n                    let obj = json;\n                    \/\/ console.log('chat', obj);\n                    if (obj['err']) {\n                        \/\/ socket disconnect and reconnect\n                        socket.disconnect()\n                        socket.connect(this.socketioUrl, {'force new connection': true});\n                        this.removeTrunkedMsg();\n                        this.loading = false;\n                        ElementPlus.ElMessage.error('\u51fa\u95ee\u9898\u5566\uff01\u4f60\u53ef\u4ee5\u5c1d\u8bd5\u628a\"\u9010\u5b57\"\u6a21\u5f0f\u6362\u6210\"\u6574\u6bb5\"');\n                    } else {\n                        let cid = obj['id'];\n                        if (obj['start']) {\n                            console.log('server started requesting...')\n                        }\n                        if (obj['role']) {\n                            clearTimeout(this.timeoutHandle);\n                            \/\/ add msg with cid\n                            this.receivingMsg = {cid: cid, role: obj['role']}\n                            this.messages.push(this.receivingMsg)\n                            this.$nextTick(() => {\n                                this.scrollToBottom()\n                            })\n                        }\n                        if (obj['content']) {\n                            \/\/ update msg content\n                            clearTimeout(this.timeoutHandle);\n                            this.receivingMsg['content'] = (this.receivingMsg['content'] ?? '') + obj['content']\n                            this.$nextTick(() => {\n                                this.scrollToBottom()\n                            })\n                        }\n                        if (obj['finish']) {\n                            clearTimeout(this.timeoutHandle);\n                            \/\/ prepare new receivingMsg\n                            this.removeMsgWithCid(cid);\n                            this.messages.push(shallowCopy(this.receivingMsg));\n                            this.receivingMsg = {}\n                            this.$nextTick(() => {\n                                this.scrollToBottom()\n                            })\n                            \/\/ unlock loading\n                            this.loading = false;\n                        }\n                    }\n                });\n                this.socket = socket;\n\n                \/\/ add disconnect before page unload\n                window.addEventListener('beforeunload', function (e) {\n                    socket.disconnect();\n                });\n            },\n            submitChatSocketIO() {\n                let cleanMessages = this.getCleanMessages();\n                let text = JSON.stringify({\n                    'frontendTraceId': this.frontendTraceId,\n                    'messages': cleanMessages\n                });\n                this.timeoutHandle = setTimeout(() => {\n                    console.log('frontend timeout');\n                    this.socket.disconnect()\n                    this.socket.connect(this.socketioUrl, {'force new connection': true});\n                    this.removeTrunkedMsg();\n                    this.loading = false;\n                    ElementPlus.ElMessage.error('\u545c\u545c\uff0cAI\u601d\u8003\u5f97\u592a\u6162\uff0c\u8d85\u65f6\u5566\u2026\u2026');\n                }, this.timeout * 1000);\n                this.socket.emit('chat', text);\n            },\n            submitChat() {\n                this.loading = true;\n                if (this.streamMode) {\n                    this.submitChatSocketIO();\n                } else {\n                    this.submitChatHttp();\n                }\n            }\n        },\n        mounted() {\n            this.frontendTraceId = crypto.randomUUID();\n            let scheme = window.location.protocol;\n            \/\/ axios.defaults.baseURL = scheme + '\/\/localhost:5000';\n            axios.defaults.baseURL = scheme + '\/\/sth99.top';\n            this.initSocketIO();\n            console.log('chat-frontend ready.');\n        }\n    });\n    \/\/ register ElementPlus\n    app.use(ElementPlus);\n    \/\/ register ElementPlus Icons\n    for (const [key, component] of Object.entries(ElementPlusIconsVue)) {\n        app.component(key, component)\n    }\n    app.mount('#chat-app');\n<\/script>\n\n<!--copy end-->\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u66f4\u65b0\u65e5\u5fd7\uff1a<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">2023\u5e743\u670820\u65e5<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u9996\u6b21\u53d1\u5e03\u3002\u4ec5\u5305\u542b\u57fa\u7840\u5bf9\u8bdd\u529f\u80fd\u3002<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">2023\u5e743\u670821\u65e5<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u66f4\u65b0\u4e86\u5bf9\u8bdd\u65f6\u4f1a\u5e26\u6709\u4e00\u4e2a\u524d\u7aefid\uff0c\u65b9\u4fbf\u8c03\u8bd5\u548c\u6392\u9519\u3002<\/li>\n\n\n\n<li>\u670b\u53cb\u4eec\u5076\u5c14\u4f1a\u95ee\u590d\u6742\u95ee\u9898\uff0c\u6240\u4ee5\u8d85\u65f6\u65f6\u95f4\u9650\u5236\u52a0\u523020\u79d2\u4e86\u3002<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">2023\u5e743\u670824\u65e5<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u5339\u914d\u4e86OpenAI API\u7684stream\u6a21\u5f0f\uff0c\u53ef\u4ee5\u770b\u5230\u5bf9\u8bdd\u662f\u9010\u5b57\u51fa\u73b0\u7684\u4e86\uff0c\u4f18\u5316\u4f53\u9a8c\u3002<\/li>\n\n\n\n<li>\u5982\u679c\u6709\u95ee\u9898\uff0c\u670b\u53cb\u4eec\u53ef\u4ee5\u5207\u6362\u201c\u9010\u5b57\u201d\u548c\u201c\u6574\u53e5\u201d\u6a21\u5f0f\u3002<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">2023\u5e744\u67081\u65e5<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>OpenAI\u514d\u8d39\u989d\u5ea6\u5230\u671f\u52d2\uff0c\u6ca1\u5f97\u73a9\u5566\u3002<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>\u57fa\u4e8echatGPT-3.5-turbo\u505a\u4e86\u4e00\u4e2a\u5c0fapp\uff0c\u5305\u542b\u524d\u540e\u7aef\u3002\u76ee\u524d\u6ca1\u8bbe\u7f6e\u4ec0\u4e48\u9650\u5236\uff0c\u5728openai\u7684\u514d\u8d3918USD\u989d\u5ea6\u5230\u671f\u4e4b\u524d\u5f00\u653e\u7ed9\u6240\u6709\u4eba\u968f\u610f\u73a9\u800d\u3002\u8981\u5584\u5f85\u732b\u732b\u54e6~ &#8211; \u7ed9AI\u7684\u8bbe\u5b9a &#038;\u2026<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_uag_custom_page_level_css":"","jetpack_post_was_ever_published":true,"footnotes":""},"categories":[3],"tags":[22],"class_list":["post-906","post","type-post","status-publish","format-standard","hentry","category-3","tag-ai"],"blocksy_meta":"","jetpack_featured_media_url":"","uagb_featured_image_src":{"full":false,"thumbnail":false,"medium":false,"medium_large":false,"large":false,"1536x1536":false,"2048x2048":false},"uagb_author_info":{"display_name":"STH99","author_link":"https:\/\/sth99.top\/index.php\/author\/sth99_admin\/"},"uagb_comment_info":0,"uagb_excerpt":"\u57fa\u4e8echatGPT-3.5-turbo\u505a\u4e86\u4e00\u4e2a\u5c0fapp\uff0c\u5305\u542b\u524d\u540e\u7aef\u3002\u76ee\u524d\u6ca1\u8bbe\u7f6e\u4ec0\u4e48\u9650\u5236\uff0c\u5728openai\u7684\u514d\u8d391&hellip;","_links":{"self":[{"href":"https:\/\/sth99.top\/index.php\/wp-json\/wp\/v2\/posts\/906","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sth99.top\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sth99.top\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sth99.top\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sth99.top\/index.php\/wp-json\/wp\/v2\/comments?post=906"}],"version-history":[{"count":13,"href":"https:\/\/sth99.top\/index.php\/wp-json\/wp\/v2\/posts\/906\/revisions"}],"predecessor-version":[{"id":925,"href":"https:\/\/sth99.top\/index.php\/wp-json\/wp\/v2\/posts\/906\/revisions\/925"}],"wp:attachment":[{"href":"https:\/\/sth99.top\/index.php\/wp-json\/wp\/v2\/media?parent=906"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sth99.top\/index.php\/wp-json\/wp\/v2\/categories?post=906"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sth99.top\/index.php\/wp-json\/wp\/v2\/tags?post=906"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}