Models.svelte 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <script lang="ts">
  2. import { generatePrompt } from '$lib/apis/ollama';
  3. import { models } from '$lib/stores';
  4. import { splitStream } from '$lib/utils';
  5. import { tick } from 'svelte';
  6. import toast from 'svelte-french-toast';
  7. export let prompt = '';
  8. export let user = null;
  9. export let chatInputPlaceholder = '';
  10. export let messages = [];
  11. let selectedIdx = 0;
  12. let filteredModels = [];
  13. $: filteredModels = $models
  14. .filter((p) => p.name !== 'hr' && p.name.includes(prompt.split(' ')?.at(0)?.substring(1) ?? ''))
  15. .sort((a, b) => a.name.localeCompare(b.name));
  16. $: if (prompt) {
  17. selectedIdx = 0;
  18. }
  19. export const selectUp = () => {
  20. selectedIdx = Math.max(0, selectedIdx - 1);
  21. };
  22. export const selectDown = () => {
  23. selectedIdx = Math.min(selectedIdx + 1, filteredModels.length - 1);
  24. };
  25. const confirmSelect = async (model) => {
  26. // dispatch('select', model);
  27. prompt = '';
  28. user = JSON.parse(JSON.stringify(model.name));
  29. await tick();
  30. chatInputPlaceholder = `'${model.name}' is thinking...`;
  31. const chatInputElement = document.getElementById('chat-textarea');
  32. await tick();
  33. chatInputElement?.focus();
  34. await tick();
  35. const convoText = messages.reduce((a, message, i, arr) => {
  36. return `${a}### ${message.role.toUpperCase()}\n${message.content}\n\n`;
  37. }, '');
  38. const res = await generatePrompt(localStorage.token, model.name, convoText);
  39. if (res && res.ok) {
  40. const reader = res.body
  41. .pipeThrough(new TextDecoderStream())
  42. .pipeThrough(splitStream('\n'))
  43. .getReader();
  44. while (true) {
  45. const { value, done } = await reader.read();
  46. if (done) {
  47. break;
  48. }
  49. try {
  50. let lines = value.split('\n');
  51. for (const line of lines) {
  52. if (line !== '') {
  53. console.log(line);
  54. let data = JSON.parse(line);
  55. if ('detail' in data) {
  56. throw data;
  57. }
  58. if (data.done == false) {
  59. if (prompt == '' && data.response == '\n') {
  60. continue;
  61. } else {
  62. prompt += data.response;
  63. console.log(data.response);
  64. chatInputElement.scrollTop = chatInputElement.scrollHeight;
  65. await tick();
  66. }
  67. }
  68. }
  69. }
  70. } catch (error) {
  71. console.log(error);
  72. if ('detail' in error) {
  73. toast.error(error.detail);
  74. }
  75. break;
  76. }
  77. }
  78. } else {
  79. if (res !== null) {
  80. const error = await res.json();
  81. console.log(error);
  82. if ('detail' in error) {
  83. toast.error(error.detail);
  84. } else {
  85. toast.error(error.error);
  86. }
  87. } else {
  88. toast.error(`Uh-oh! There was an issue connecting to Ollama.`);
  89. }
  90. }
  91. chatInputPlaceholder = '';
  92. console.log(user);
  93. };
  94. </script>
  95. {#if filteredModels.length > 0}
  96. <div class="md:px-2 mb-3 text-left w-full">
  97. <div class="flex w-full rounded-lg border border-gray-100 dark:border-gray-700">
  98. <div class=" bg-gray-100 dark:bg-gray-700 w-10 rounded-l-lg text-center">
  99. <div class=" text-lg font-semibold mt-2">@</div>
  100. </div>
  101. <div class="max-h-60 flex flex-col w-full rounded-r-lg">
  102. <div class=" overflow-y-auto bg-white p-2 rounded-tr-lg space-y-0.5">
  103. {#each filteredModels as model, modelIdx}
  104. <button
  105. class=" px-3 py-1.5 rounded-lg w-full text-left {modelIdx === selectedIdx
  106. ? ' bg-gray-100 selected-command-option-button'
  107. : ''}"
  108. type="button"
  109. on:click={() => {
  110. confirmSelect(model);
  111. }}
  112. on:mousemove={() => {
  113. selectedIdx = modelIdx;
  114. }}
  115. on:focus={() => {}}
  116. >
  117. <div class=" font-medium text-black line-clamp-1">
  118. {model.name}
  119. </div>
  120. <!-- <div class=" text-xs text-gray-600 line-clamp-1">
  121. {doc.title}
  122. </div> -->
  123. </button>
  124. {/each}
  125. </div>
  126. </div>
  127. </div>
  128. </div>
  129. {/if}