Skip to content

Commit

Permalink
refactored interactions with chatGPT
Browse files Browse the repository at this point in the history
  • Loading branch information
kholmogorov27 committed Mar 11, 2023
1 parent 0806108 commit cd0ce27
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 31 deletions.
38 changes: 14 additions & 24 deletions src/chatGPT/createCompletion.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,67 +7,57 @@ const PARAMS = {
// frequency_penalty: 1.0,
}

function createCompletion(stateSetter, query, temperature, key) {
function createCompletion(stateSetter, messages, temperature, key, endCallback) {
const controller = new AbortController()

console.log(messages);

fetch(API_URL, {
signal: controller.signal,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + String(key)
},
body: JSON.stringify({ ...PARAMS, messages: [{ role: 'user', content: query }], temperature })
body: JSON.stringify({ ...PARAMS, messages, temperature })
}).then(result => {
const stream = result.body
fetchStream(stream, stateSetter)
fetchStream(result.body, stateSetter).then(content => endCallback({ content, role: 'assistant' }))
})

return controller
}

async function fetchStream(stream, stateSetter) {
function fetchStream(stream, stateSetter) {
let content = ''
const reader = stream.getReader()
let charsReceived = 0
const li = document.createElement('li')

// read() returns a promise that resolves
// when a value has been received
reader.read().then(
return reader.read().then(
function processText({ done, value }) {
// Result objects contain two properties:
// done - true if the stream has already given you all its data.
// value - some data. Always undefined when done is true.
if (done)
return li.innerText
// value for fetch streams is a Uint8Array
charsReceived += value.length
const chunk = value
li.appendChild(document.createTextNode(chunk))

const list = li.innerText.split(',')
const numList = list.map(item => parseInt(item))

stateSetter('')
return content

for (const entry of new TextDecoder('utf-8').decode(new Uint8Array(numList)).split('\n'))
for (const entry of new TextDecoder('utf-8').decode(value).split('\n'))
if (entry) {
const text = entry.slice(entry.indexOf(':') + 2)

let response
try {
response = JSON.parse(text)
} catch (error) { /* pass */ }

if (response && typeof response.choices[0].delta.content === 'string')
stateSetter(state => state + response.choices[0].delta.content)
if (response && response.choices[0].delta.content)
content += response.choices[0].delta.content
stateSetter(content)
}

return reader.read().then(processText)
}
)

return reader
}


export default createCompletion
30 changes: 23 additions & 7 deletions src/components/AIcompletion/AIcompletion.jsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,55 @@
import { useContext, useEffect } from 'react'
import { useContext, useEffect, useRef } from 'react'
import { useState } from 'react'
import { SettingsContext } from '../../contexts/Settings'
import { ReactMarkdown } from 'react-markdown/lib/react-markdown'
import createCompletion from '../../chatGPT/createCompletion'

const MESSAGES_PREFIX = {
role: 'system',
content: 'You are ChatGPT, a large language model trained by OpenAI.\nKnowledge cutoff: 2021-09\nCurrent date and time: ' + new Date().toLocaleString()
}

function AIcompletion({ query, className }) {
// settings
const settings = useContext(SettingsContext)
const enabled = settings.query.AI.enabled
const apiKey = settings.query.AI.apiKey
const temperature = settings.query.AI.temperature

const [state, setState] = useState('')
const [completion, setCompletion] = useState('')
const chatLogRef = useRef([])

useEffect(() => {
if (!enabled)
return

let controller = null

if (query)
controller = createCompletion(setState, query, temperature, apiKey)
if (query) {
const currentQuery = { content: query, role: 'user' }
const messages = [MESSAGES_PREFIX, ...chatLogRef.current, currentQuery ]

controller = createCompletion(
setCompletion,
messages,
temperature,
apiKey,
result => chatLogRef.current.push(currentQuery, result)
)
}
else
setState('')
setCompletion('')

return () => controller && controller.abort()
}, [query, temperature, apiKey, enabled])

if (!state || !enabled)
if (!completion || !enabled)
return null

return (
<div className={className}>
<div className='md-container'>
<ReactMarkdown children={state}/>
<ReactMarkdown children={completion}/>
</div>
</div>
)
Expand Down

0 comments on commit cd0ce27

Please sign in to comment.