From 83f44a324abb45993e16b55b27ff3e33ebccd7db Mon Sep 17 00:00:00 2001 From: josc146 Date: Sat, 30 Sep 2023 15:29:28 +0800 Subject: [PATCH] improve claude api prompt (#516) --- src/services/apis/claude-api.mjs | 133 +++++++++++++++---------------- 1 file changed, 63 insertions(+), 70 deletions(-) diff --git a/src/services/apis/claude-api.mjs b/src/services/apis/claude-api.mjs index b60811d..7c87988 100644 --- a/src/services/apis/claude-api.mjs +++ b/src/services/apis/claude-api.mjs @@ -1,6 +1,5 @@ import { getUserConfig } from '../../config/index.mjs' -import { getChatSystemPromptBase, pushRecord, setAbortController } from './shared.mjs' -import { getConversationPairs } from '../../utils/get-conversation-pairs.mjs' +import { pushRecord, setAbortController } from './shared.mjs' import { fetchSSE } from '../../utils/fetch-sse.mjs' import { isEmpty } from 'lodash-es' @@ -13,75 +12,69 @@ export async function generateAnswersWithClaudeApi(port, question, session) { const { controller, messageListener, disconnectListener } = setAbortController(port) const config = await getUserConfig() - const prompt = getConversationPairs( - session.conversationRecords.slice(-config.maxConversationContextLength), - false, - ) - prompt.unshift({ role: 'Assistant', content: await getChatSystemPromptBase() }) - prompt.push({ role: 'Human', content: question }) + let prompt = '' + for (const record of session.conversationRecords.slice(-config.maxConversationContextLength)) { + prompt += '\n\nHuman: ' + record.question + '\n\nAssistant: ' + record.answer + } + prompt += `\n\nHuman: ${question}\n\nAssistant:` let answer = '' - await fetchSSE( - `https://api.anthropic.com/v1/complete`, - { - method: 'POST', - signal: controller.signal, - headers: { - 'Content-Type': 'application/json', - 'accept': 'application/json', - 'anthropic-version': '2023-06-01', - 'x-api-key': config.claudeApiKey, - }, - body: JSON.stringify({ - model: "claude-2", - prompt: "\n\nHuman: " + question + "\n\nAssistant:", - stream: true, - max_tokens_to_sample: config.maxResponseTokenLength, - temperature: config.temperature, - }), - onMessage(message) { - console.debug('sse message', message); - - let data; - try { - data = JSON.parse(message); - } catch (error) { - console.debug('json error', error); - return; - } - - // The Claude v2 API may send metadata fields, handle them here - if (data.conversationId) session.conversationId = data.conversationId; - if (data.parentMessageId) session.parentMessageId = data.parentMessageId; - - // In Claude's case, the "completion" key holds the text - if (data.completion) { - answer += data.completion; - port.postMessage({ answer: answer, done: false, session: null }); - } - - // Check if the message indicates that Claude is done - if (data.stop_reason === 'stop_sequence') { - pushRecord(session, question, answer); - console.debug('conversation history', { content: session.conversationRecords }); - port.postMessage({ answer: null, done: true, session: session }); - } - }, - async onStart() {}, - async onEnd() { - port.postMessage({ done: true }) - port.onMessage.removeListener(messageListener) - port.onDisconnect.removeListener(disconnectListener) - }, - async onError(resp) { - port.onMessage.removeListener(messageListener) - port.onDisconnect.removeListener(disconnectListener) - if (resp instanceof Error) throw resp - const error = await resp.json().catch(() => ({})) - throw new Error( - !isEmpty(error) ? JSON.stringify(error) : `${resp.status} ${resp.statusText}`, - ) - }, + await fetchSSE(`https://api.anthropic.com/v1/complete`, { + method: 'POST', + signal: controller.signal, + headers: { + 'Content-Type': 'application/json', + accept: 'application/json', + 'anthropic-version': '2023-06-01', + 'x-api-key': config.claudeApiKey, }, - ) + body: JSON.stringify({ + model: 'claude-2', + prompt: prompt, + stream: true, + max_tokens_to_sample: config.maxResponseTokenLength, + temperature: config.temperature, + }), + onMessage(message) { + console.debug('sse message', message) + + let data + try { + data = JSON.parse(message) + } catch (error) { + console.debug('json error', error) + return + } + + // The Claude v2 API may send metadata fields, handle them here + if (data.conversationId) session.conversationId = data.conversationId + if (data.parentMessageId) session.parentMessageId = data.parentMessageId + + // In Claude's case, the "completion" key holds the text + if (data.completion) { + answer += data.completion + port.postMessage({ answer: answer, done: false, session: null }) + } + + // Check if the message indicates that Claude is done + if (data.stop_reason === 'stop_sequence') { + pushRecord(session, question, answer) + console.debug('conversation history', { content: session.conversationRecords }) + port.postMessage({ answer: null, done: true, session: session }) + } + }, + async onStart() {}, + async onEnd() { + port.postMessage({ done: true }) + port.onMessage.removeListener(messageListener) + port.onDisconnect.removeListener(disconnectListener) + }, + async onError(resp) { + port.onMessage.removeListener(messageListener) + port.onDisconnect.removeListener(disconnectListener) + if (resp instanceof Error) throw resp + const error = await resp.json().catch(() => ({})) + throw new Error(!isEmpty(error) ? JSON.stringify(error) : `${resp.status} ${resp.statusText}`) + }, + }) }