Merge branch 'staging' into woo-yeah
| @@ -2692,7 +2692,7 @@ | |||
| 2692 | <option value="windowai">Window AI</option> | 2692 | <option value="windowai">Window AI</option> |
| 2693 | </optgroup> | 2693 | </optgroup> |
| 2694 | </select> | 2694 | </select> |
| 2695 | <div class="inline-drawer wide100p" data-source="openai,claude,mistralai,makersuite"> | 2695 | <div class="inline-drawer wide100p" data-source="openai,claude,mistralai,makersuite,deepseek"> |
| 2696 | <div class="inline-drawer-toggle inline-drawer-header"> | 2696 | <div class="inline-drawer-toggle inline-drawer-header"> |
| 2697 | <b data-i18n="Reverse Proxy">Reverse Proxy</b> | 2697 | <b data-i18n="Reverse Proxy">Reverse Proxy</b> |
| 2698 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> | 2698 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> |
| @@ -2755,7 +2755,7 @@ | |||
| 2755 | </div> | 2755 | </div> |
| 2756 | </div> | 2756 | </div> |
| 2757 | </div> | 2757 | </div> |
| 2758 | <div id="ReverseProxyWarningMessage" data-source="openai,claude,mistralai,makersuite"> | 2758 | <div id="ReverseProxyWarningMessage" data-source="openai,claude,mistralai,makersuite,deepseek"> |
| 2759 | <div class="reverse_proxy_warning"> | 2759 | <div class="reverse_proxy_warning"> |
| 2760 | <b> | 2760 | <b> |
| 2761 | <div data-i18n="Using a proxy that you're not running yourself is a risk to your data privacy."> | 2761 | <div data-i18n="Using a proxy that you're not running yourself is a risk to your data privacy."> |
| @@ -724,6 +724,7 @@ async function getSystemMessages() { | |||
| 724 | is_user: false, | 724 | is_user: false, |
| 725 | is_system: true, | 725 | is_system: true, |
| 726 | mes: await renderTemplateAsync('assistantNote'), | 726 | mes: await renderTemplateAsync('assistantNote'), |
| 727 | uses_system_ui: true, | ||
| 727 | extra: { | 728 | extra: { |
| 728 | isSmallSys: true, | 729 | isSmallSys: true, |
| 729 | }, | 730 | }, |
| @@ -11,6 +11,7 @@ import { | |||
| 11 | getCurrentChatId, | 11 | getCurrentChatId, |
| 12 | getRequestHeaders, | 12 | getRequestHeaders, |
| 13 | hideSwipeButtons, | 13 | hideSwipeButtons, |
| 14 | name1, | ||
| 14 | name2, | 15 | name2, |
| 15 | reloadCurrentChat, | 16 | reloadCurrentChat, |
| 16 | saveChatDebounced, | 17 | saveChatDebounced, |
| @@ -21,6 +22,7 @@ import { | |||
| 21 | chat_metadata, | 22 | chat_metadata, |
| 22 | neutralCharacterName, | 23 | neutralCharacterName, |
| 23 | updateChatMetadata, | 24 | updateChatMetadata, |
| 25 | system_message_types, | ||
| 24 | } from '../script.js'; | 26 | } from '../script.js'; |
| 25 | import { selected_group } from './group-chats.js'; | 27 | import { selected_group } from './group-chats.js'; |
| 26 | import { power_user } from './power-user.js'; | 28 | import { power_user } from './power-user.js'; |
| @@ -34,6 +36,7 @@ import { | |||
| 34 | humanFileSize, | 36 | humanFileSize, |
| 35 | saveBase64AsFile, | 37 | saveBase64AsFile, |
| 36 | extractTextFromOffice, | 38 | extractTextFromOffice, |
| 39 | download, | ||
| 37 | } from './utils.js'; | 40 | } from './utils.js'; |
| 38 | import { extension_settings, renderExtensionTemplateAsync, saveMetadataDebounced } from './extensions.js'; | 41 | import { extension_settings, renderExtensionTemplateAsync, saveMetadataDebounced } from './extensions.js'; |
| 39 | import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; | 42 | import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; |
| @@ -41,6 +44,7 @@ import { ScraperManager } from './scrapers.js'; | |||
| 41 | import { DragAndDropHandler } from './dragdrop.js'; | 44 | import { DragAndDropHandler } from './dragdrop.js'; |
| 42 | import { renderTemplateAsync } from './templates.js'; | 45 | import { renderTemplateAsync } from './templates.js'; |
| 43 | import { t } from './i18n.js'; | 46 | import { t } from './i18n.js'; |
| 47 | import { humanizedDateTime } from './RossAscends-mods.js'; | ||
| 44 | 48 | ||
| 45 | /** | 49 | /** |
| 46 | * @typedef {Object} FileAttachment | 50 | * @typedef {Object} FileAttachment |
| @@ -1437,6 +1441,19 @@ jQuery(function () { | |||
| 1437 | await viewMessageFile(messageId); | 1441 | await viewMessageFile(messageId); |
| 1438 | }); | 1442 | }); |
| 1439 | 1443 | ||
| 1444 | $(document).on('click', '.assistant_note_export', async function () { | ||
| 1445 | const chatToSave = [ | ||
| 1446 | { | ||
| 1447 | user_name: name1, | ||
| 1448 | character_name: name2, | ||
| 1449 | chat_metadata: chat_metadata, | ||
| 1450 | }, | ||
| 1451 | ...chat.filter(x => x?.extra?.type !== system_message_types.ASSISTANT_NOTE), | ||
| 1452 | ]; | ||
| 1453 | |||
| 1454 | download(JSON.stringify(chatToSave, null, 4), `Assistant - ${humanizedDateTime()}.json`, 'application/json'); | ||
| 1455 | }); | ||
| 1456 | |||
| 1440 | // Do not change. #attachFile is added by extension. | 1457 | // Do not change. #attachFile is added by extension. |
| 1441 | $(document).on('click', '#attachFile', function () { | 1458 | $(document).on('click', '#attachFile', function () { |
| 1442 | $('#file_form_input').trigger('click'); | 1459 | $('#file_form_input').trigger('click'); |
| @@ -1922,7 +1922,7 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 1922 | } | 1922 | } |
| 1923 | 1923 | ||
| 1924 | // Proxy is only supported for Claude, OpenAI, Mistral, and Google MakerSuite | 1924 | // Proxy is only supported for Claude, OpenAI, Mistral, and Google MakerSuite |
| 1925 | if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE].includes(oai_settings.chat_completion_source)) { | 1925 | if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE, chat_completion_sources.DEEPSEEK].includes(oai_settings.chat_completion_source)) { |
| 1926 | await validateReverseProxy(); | 1926 | await validateReverseProxy(); |
| 1927 | generate_data['reverse_proxy'] = oai_settings.reverse_proxy; | 1927 | generate_data['reverse_proxy'] = oai_settings.reverse_proxy; |
| 1928 | generate_data['proxy_password'] = oai_settings.proxy_password; | 1928 | generate_data['proxy_password'] = oai_settings.proxy_password; |
| @@ -3371,7 +3371,7 @@ async function getStatusOpen() { | |||
| 3371 | chat_completion_source: oai_settings.chat_completion_source, | 3371 | chat_completion_source: oai_settings.chat_completion_source, |
| 3372 | }; | 3372 | }; |
| 3373 | 3373 | ||
| 3374 | if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE].includes(oai_settings.chat_completion_source)) { | 3374 | if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI, chat_completion_sources.MISTRALAI, chat_completion_sources.MAKERSUITE, chat_completion_sources.DEEPSEEK].includes(oai_settings.chat_completion_source)) { |
| 3375 | await validateReverseProxy(); | 3375 | await validateReverseProxy(); |
| 3376 | } | 3376 | } |
| 3377 | 3377 | ||
| @@ -4750,7 +4750,7 @@ async function onConnectButtonClick(e) { | |||
| 4750 | await writeSecret(SECRET_KEYS.DEEPSEEK, api_key_deepseek); | 4750 | await writeSecret(SECRET_KEYS.DEEPSEEK, api_key_deepseek); |
| 4751 | } | 4751 | } |
| 4752 | 4752 | ||
| 4753 | if (!secret_state[SECRET_KEYS.DEEPSEEK]) { | 4753 | if (!secret_state[SECRET_KEYS.DEEPSEEK] && !oai_settings.reverse_proxy) { |
| 4754 | console.log('No secret key saved for DeepSeek'); | 4754 | console.log('No secret key saved for DeepSeek'); |
| 4755 | return; | 4755 | return; |
| 4756 | } | 4756 | } |
| @@ -1,3 +1,9 @@ | |||
| 1 | <div data-type="assistant_note"> | ||
| 1 | <div> | 2 | <div> |
| 2 | <b data-i18n="Note:">Note:</b> <span data-i18n="this chat is temporary and will be deleted as soon as you leave it.">this chat is temporary and will be deleted as soon as you leave it.</span> | 3 | <b data-i18n="Note:">Note:</b> <span data-i18n="this chat is temporary and will be deleted as soon as you leave it.">this chat is temporary and will be deleted as soon as you leave it.</span> |
| 4 | <span>Click the button to save it as a file.</span> | ||
| 5 | </div> | ||
| 6 | <div class="assistant_note_export menu_button menu_button_icon" title="Export as JSONL"> | ||
| 7 | <i class="fa-solid fa-file-export"></i> | ||
| 8 | </div> | ||
| 3 | </div> | 9 | </div> |
| @@ -5795,3 +5795,17 @@ body:not(.movingUI) .drawer-content.maximized { | |||
| 5795 | .alternate_greetings_list { | 5795 | .alternate_greetings_list { |
| 5796 | overflow-y: scroll; | 5796 | overflow-y: scroll; |
| 5797 | } | 5797 | } |
| 5798 | |||
| 5799 | .mes_text div[data-type="assistant_note"]:has(.assistant_note_export) { | ||
| 5800 | display: flex; | ||
| 5801 | flex-direction: row; | ||
| 5802 | flex-wrap: nowrap; | ||
| 5803 | justify-content: space-between; | ||
| 5804 | align-items: center; | ||
| 5805 | gap: 10px; | ||
| 5806 | padding: 0 2px; | ||
| 5807 | } | ||
| 5808 | |||
| 5809 | .mes_text div[data-type="assistant_note"]:has(.assistant_note_export)>div:not(.assistant_note_export) { | ||
| 5810 | flex: 1; | ||
| 5811 | } | ||
| @@ -646,6 +646,89 @@ async function sendCohereRequest(request, response) { | |||
| 646 | } | 646 | } |
| 647 | } | 647 | } |
| 648 | 648 | ||
| 649 | /** | ||
| 650 | * Sends a request to DeepSeek API. | ||
| 651 | * @param {express.Request} request Express request | ||
| 652 | * @param {express.Response} response Express response | ||
| 653 | */ | ||
| 654 | async function sendDeepSeekRequest(request, response) { | ||
| 655 | const apiUrl = new URL(request.body.reverse_proxy || API_DEEPSEEK).toString(); | ||
| 656 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK); | ||
| 657 | |||
| 658 | if (!apiKey && !request.body.reverse_proxy) { | ||
| 659 | console.log('DeepSeek API key is missing.'); | ||
| 660 | return response.status(400).send({ error: true }); | ||
| 661 | } | ||
| 662 | |||
| 663 | const controller = new AbortController(); | ||
| 664 | request.socket.removeAllListeners('close'); | ||
| 665 | request.socket.on('close', function () { | ||
| 666 | controller.abort(); | ||
| 667 | }); | ||
| 668 | |||
| 669 | try { | ||
| 670 | let bodyParams = {}; | ||
| 671 | |||
| 672 | if (request.body.logprobs > 0) { | ||
| 673 | bodyParams['top_logprobs'] = request.body.logprobs; | ||
| 674 | bodyParams['logprobs'] = true; | ||
| 675 | } | ||
| 676 | |||
| 677 | const postProcessType = String(request.body.model).endsWith('-reasoner') ? 'deepseek-reasoner' : 'deepseek'; | ||
| 678 | const processedMessages = postProcessPrompt(request.body.messages, postProcessType, getPromptNames(request)); | ||
| 679 | |||
| 680 | const requestBody = { | ||
| 681 | 'messages': processedMessages, | ||
| 682 | 'model': request.body.model, | ||
| 683 | 'temperature': request.body.temperature, | ||
| 684 | 'max_tokens': request.body.max_tokens, | ||
| 685 | 'stream': request.body.stream, | ||
| 686 | 'presence_penalty': request.body.presence_penalty, | ||
| 687 | 'frequency_penalty': request.body.frequency_penalty, | ||
| 688 | 'top_p': request.body.top_p, | ||
| 689 | 'stop': request.body.stop, | ||
| 690 | 'seed': request.body.seed, | ||
| 691 | ...bodyParams, | ||
| 692 | }; | ||
| 693 | |||
| 694 | const config = { | ||
| 695 | method: 'POST', | ||
| 696 | headers: { | ||
| 697 | 'Content-Type': 'application/json', | ||
| 698 | 'Authorization': 'Bearer ' + apiKey, | ||
| 699 | }, | ||
| 700 | body: JSON.stringify(requestBody), | ||
| 701 | signal: controller.signal, | ||
| 702 | }; | ||
| 703 | |||
| 704 | console.log('DeepSeek request:', requestBody); | ||
| 705 | |||
| 706 | const generateResponse = await fetch(apiUrl + '/chat/completions', config); | ||
| 707 | |||
| 708 | if (request.body.stream) { | ||
| 709 | forwardFetchResponse(generateResponse, response); | ||
| 710 | } else { | ||
| 711 | if (!generateResponse.ok) { | ||
| 712 | const errorText = await generateResponse.text(); | ||
| 713 | console.log(`DeepSeek API returned error: ${generateResponse.status} ${generateResponse.statusText} ${errorText}`); | ||
| 714 | const errorJson = tryParse(errorText) ?? { error: true }; | ||
| 715 | return response.status(500).send(errorJson); | ||
| 716 | } | ||
| 717 | const generateResponseJson = await generateResponse.json(); | ||
| 718 | console.log('DeepSeek response:', generateResponseJson); | ||
| 719 | return response.send(generateResponseJson); | ||
| 720 | } | ||
| 721 | } catch (error) { | ||
| 722 | console.log('Error communicating with DeepSeek API: ', error); | ||
| 723 | if (!response.headersSent) { | ||
| 724 | response.send({ error: true }); | ||
| 725 | } else { | ||
| 726 | response.end(); | ||
| 727 | } | ||
| 728 | } | ||
| 729 | } | ||
| 730 | |||
| 731 | |||
| 649 | export const router = express.Router(); | 732 | export const router = express.Router(); |
| 650 | 733 | ||
| 651 | router.post('/status', jsonParser, async function (request, response_getstatus_openai) { | 734 | router.post('/status', jsonParser, async function (request, response_getstatus_openai) { |
| @@ -690,8 +773,8 @@ router.post('/status', jsonParser, async function (request, response_getstatus_o | |||
| 690 | api_key_openai = readSecret(request.user.directories, SECRET_KEYS.NANOGPT); | 773 | api_key_openai = readSecret(request.user.directories, SECRET_KEYS.NANOGPT); |
| 691 | headers = {}; | 774 | headers = {}; |
| 692 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.DEEPSEEK) { | 775 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.DEEPSEEK) { |
| 693 | api_url = API_DEEPSEEK.replace('/beta', ''); | 776 | api_url = new URL(request.body.reverse_proxy || API_DEEPSEEK.replace('/beta', '')); |
| 694 | api_key_openai = readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK); | 777 | api_key_openai = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK); |
| 695 | headers = {}; | 778 | headers = {}; |
| 696 | } else { | 779 | } else { |
| 697 | console.log('This chat completion source is not supported yet.'); | 780 | console.log('This chat completion source is not supported yet.'); |
| @@ -851,6 +934,7 @@ router.post('/generate', jsonParser, function (request, response) { | |||
| 851 | case CHAT_COMPLETION_SOURCES.MAKERSUITE: return sendMakerSuiteRequest(request, response); | 934 | case CHAT_COMPLETION_SOURCES.MAKERSUITE: return sendMakerSuiteRequest(request, response); |
| 852 | case CHAT_COMPLETION_SOURCES.MISTRALAI: return sendMistralAIRequest(request, response); | 935 | case CHAT_COMPLETION_SOURCES.MISTRALAI: return sendMistralAIRequest(request, response); |
| 853 | case CHAT_COMPLETION_SOURCES.COHERE: return sendCohereRequest(request, response); | 936 | case CHAT_COMPLETION_SOURCES.COHERE: return sendCohereRequest(request, response); |
| 937 | case CHAT_COMPLETION_SOURCES.DEEPSEEK: return sendDeepSeekRequest(request, response); | ||
| 854 | } | 938 | } |
| 855 | 939 | ||
| 856 | let apiUrl; | 940 | let apiUrl; |
| @@ -964,19 +1048,6 @@ router.post('/generate', jsonParser, function (request, response) { | |||
| 964 | apiKey = readSecret(request.user.directories, SECRET_KEYS.BLOCKENTROPY); | 1048 | apiKey = readSecret(request.user.directories, SECRET_KEYS.BLOCKENTROPY); |
| 965 | headers = {}; | 1049 | headers = {}; |
| 966 | bodyParams = {}; | 1050 | bodyParams = {}; |
| 967 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.DEEPSEEK) { | ||
| 968 | apiUrl = API_DEEPSEEK; | ||
| 969 | apiKey = readSecret(request.user.directories, SECRET_KEYS.DEEPSEEK); | ||
| 970 | headers = {}; | ||
| 971 | bodyParams = {}; | ||
| 972 | |||
| 973 | if (request.body.logprobs > 0) { | ||
| 974 | bodyParams['top_logprobs'] = request.body.logprobs; | ||
| 975 | bodyParams['logprobs'] = true; | ||
| 976 | } | ||
| 977 | |||
| 978 | const postProcessType = String(request.body.model).endsWith('-reasoner') ? 'deepseek-reasoner' : 'deepseek'; | ||
| 979 | request.body.messages = postProcessPrompt(request.body.messages, postProcessType, getPromptNames(request)); | ||
| 980 | } else { | 1051 | } else { |
| 981 | console.log('This chat completion source is not supported yet.'); | 1052 | console.log('This chat completion source is not supported yet.'); |
| 982 | return response.status(400).send({ error: true }); | 1053 | return response.status(400).send({ error: true }); |
| @@ -1114,4 +1185,3 @@ router.post('/generate', jsonParser, function (request, response) { | |||
| 1114 | } | 1185 | } |
| 1115 | } | 1186 | } |
| 1116 | }); | 1187 | }); |
| 1117 | |||