mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-12 04:15:25 +00:00
feat/enh: create note from input
This commit is contained in:
parent
65d4b22c7c
commit
00c2b6ca40
5 changed files with 93 additions and 20 deletions
|
|
@ -135,7 +135,6 @@ async def search_notes(
|
|||
async def create_new_note(
|
||||
request: Request, form_data: NoteForm, user=Depends(get_verified_user)
|
||||
):
|
||||
|
||||
if user.role != "admin" and not has_permission(
|
||||
user.id, "features.notes", request.app.state.config.USER_PERMISSIONS
|
||||
):
|
||||
|
|
@ -187,8 +186,12 @@ async def get_note_by_id(request: Request, id: str, user=Depends(get_verified_us
|
|||
status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()
|
||||
)
|
||||
|
||||
write_access = has_access(
|
||||
user.id, type="write", access_control=note.access_control, strict=False
|
||||
write_access = (
|
||||
user.role == "admin"
|
||||
or (user.id == note.user_id)
|
||||
or has_access(
|
||||
user.id, type="write", access_control=note.access_control, strict=False
|
||||
)
|
||||
)
|
||||
|
||||
return NoteResponse(**note.model_dump(), write_access=write_access)
|
||||
|
|
|
|||
|
|
@ -1,14 +1,22 @@
|
|||
<script lang="ts">
|
||||
import DOMPurify from 'dompurify';
|
||||
import { marked } from 'marked';
|
||||
|
||||
import { toast } from 'svelte-sonner';
|
||||
|
||||
import { marked } from 'marked';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { createPicker, getAuthToken } from '$lib/utils/google-drive-picker';
|
||||
import { pickAndDownloadFile } from '$lib/utils/onedrive-file-picker';
|
||||
import dayjs from '$lib/dayjs';
|
||||
import duration from 'dayjs/plugin/duration';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
|
||||
dayjs.extend(duration);
|
||||
dayjs.extend(relativeTime);
|
||||
|
||||
import { onMount, tick, getContext, createEventDispatcher, onDestroy } from 'svelte';
|
||||
|
||||
import { createPicker, getAuthToken } from '$lib/utils/google-drive-picker';
|
||||
import { pickAndDownloadFile } from '$lib/utils/onedrive-file-picker';
|
||||
import { KokoroWorker } from '$lib/workers/KokoroWorker';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
import {
|
||||
|
|
@ -49,6 +57,9 @@
|
|||
|
||||
import { WEBUI_BASE_URL, WEBUI_API_BASE_URL, PASTED_TEXT_CHARACTER_LIMIT } from '$lib/constants';
|
||||
|
||||
import { createNoteHandler } from '../notes/utils';
|
||||
import { getSuggestionRenderer } from '../common/RichTextInput/suggestions';
|
||||
|
||||
import InputMenu from './MessageInput/InputMenu.svelte';
|
||||
import VoiceRecording from './MessageInput/VoiceRecording.svelte';
|
||||
import FilesOverlay from './MessageInput/FilesOverlay.svelte';
|
||||
|
|
@ -60,11 +71,9 @@
|
|||
import Image from '../common/Image.svelte';
|
||||
|
||||
import XMark from '../icons/XMark.svelte';
|
||||
import Headphone from '../icons/Headphone.svelte';
|
||||
import GlobeAlt from '../icons/GlobeAlt.svelte';
|
||||
import Photo from '../icons/Photo.svelte';
|
||||
import Wrench from '../icons/Wrench.svelte';
|
||||
import CommandLine from '../icons/CommandLine.svelte';
|
||||
import Sparkles from '../icons/Sparkles.svelte';
|
||||
|
||||
import InputVariablesModal from './MessageInput/InputVariablesModal.svelte';
|
||||
|
|
@ -74,12 +83,11 @@
|
|||
import Component from '../icons/Component.svelte';
|
||||
import PlusAlt from '../icons/PlusAlt.svelte';
|
||||
|
||||
import { KokoroWorker } from '$lib/workers/KokoroWorker';
|
||||
|
||||
import { getSuggestionRenderer } from '../common/RichTextInput/suggestions';
|
||||
import CommandSuggestionList from './MessageInput/CommandSuggestionList.svelte';
|
||||
import Knobs from '../icons/Knobs.svelte';
|
||||
import ValvesModal from '../workspace/common/ValvesModal.svelte';
|
||||
import PageEdit from '../icons/PageEdit.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
|
|
@ -109,6 +117,8 @@
|
|||
export let webSearchEnabled = false;
|
||||
export let codeInterpreterEnabled = false;
|
||||
|
||||
let inputContent = null;
|
||||
|
||||
let showInputVariablesModal = false;
|
||||
let inputVariablesModalCallback = (variableValues) => {};
|
||||
let inputVariables = {};
|
||||
|
|
@ -730,6 +740,23 @@
|
|||
});
|
||||
};
|
||||
|
||||
const createNote = async () => {
|
||||
if (inputContent?.md.trim() === '' && inputContent?.html.trim() === '') {
|
||||
toast.error($i18n.t('Cannot create an empty note.'));
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await createNoteHandler(
|
||||
dayjs().format('YYYY-MM-DD'),
|
||||
inputContent?.md,
|
||||
inputContent?.html
|
||||
);
|
||||
|
||||
if (res) {
|
||||
goto(`/notes/${res.id}`);
|
||||
}
|
||||
};
|
||||
|
||||
const onDragOver = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
|
|
@ -1195,8 +1222,9 @@
|
|||
<RichTextInput
|
||||
bind:this={chatInputElement}
|
||||
id="chat-input"
|
||||
onChange={(e) => {
|
||||
prompt = e.md;
|
||||
onChange={(content) => {
|
||||
prompt = content.md;
|
||||
inputContent = content;
|
||||
command = getCommand();
|
||||
}}
|
||||
json={true}
|
||||
|
|
@ -1620,13 +1648,13 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="self-end flex space-x-1 mr-1 shrink-0">
|
||||
<div class="self-end flex space-x-1 mr-1 shrink-0 gap-[0.5px]">
|
||||
{#if (!history?.currentId || history.messages[history.currentId]?.done == true) && ($_user?.role === 'admin' || ($_user?.permissions?.chat?.stt ?? true))}
|
||||
<!-- {$i18n.t('Record voice')} -->
|
||||
<Tooltip content={$i18n.t('Dictate')}>
|
||||
<button
|
||||
id="voice-input-button"
|
||||
class=" text-gray-600 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-200 transition rounded-full p-1.5 mr-0.5 self-center"
|
||||
class=" text-gray-600 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-200 transition rounded-full p-1.5 self-center"
|
||||
type="button"
|
||||
on:click={async () => {
|
||||
try {
|
||||
|
|
@ -1759,6 +1787,24 @@
|
|||
</Tooltip>
|
||||
</div>
|
||||
{:else}
|
||||
{#if ($config?.features?.enable_notes ?? false) && ($user?.role === 'admin' || ($user?.permissions?.features?.notes ?? true))}
|
||||
<div class=" flex items-center">
|
||||
<Tooltip content={$i18n.t('Create note')}>
|
||||
<button
|
||||
id="send-message-button"
|
||||
class=" text-gray-600 mr-0.5 dark:text-gray-300 hover:text-gray-700 dark:hover:text-gray-200 transition rounded-full p-1.5 self-center"
|
||||
type="button"
|
||||
disabled={prompt === '' && files.length === 0}
|
||||
on:click={() => {
|
||||
createNote();
|
||||
}}
|
||||
>
|
||||
<PageEdit className="size-5" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class=" flex items-center">
|
||||
<Tooltip content={$i18n.t('Send message')}>
|
||||
<button
|
||||
|
|
|
|||
24
src/lib/components/icons/PagePlus.svelte
Normal file
24
src/lib/components/icons/PagePlus.svelte
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
<script lang="ts">
|
||||
export let className = 'w-4 h-4';
|
||||
export let strokeWidth = '1.5';
|
||||
</script>
|
||||
|
||||
<svg
|
||||
class={className}
|
||||
aria-hidden="true"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
stroke-width={strokeWidth}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
><path d="M9 12H12M15 12H12M12 12V9M12 12V15" stroke-linecap="round" stroke-linejoin="round"
|
||||
></path><path
|
||||
d="M4 21.4V2.6C4 2.26863 4.26863 2 4.6 2H16.2515C16.4106 2 16.5632 2.06321 16.6757 2.17574L19.8243 5.32426C19.9368 5.43679 20 5.5894 20 5.74853V21.4C20 21.7314 19.7314 22 19.4 22H4.6C4.26863 22 4 21.7314 4 21.4Z"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></path><path
|
||||
d="M16 2V5.4C16 5.73137 16.2686 6 16.6 6H20"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></path></svg
|
||||
>
|
||||
|
|
@ -337,7 +337,7 @@
|
|||
>
|
||||
<Plus className="size-3" strokeWidth="2.5" />
|
||||
|
||||
<div class=" hidden md:block md:ml-1 text-xs">{$i18n.t('New Note')}</div>
|
||||
<div class=" md:ml-1 text-xs">{$i18n.t('New Note')}</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ export const downloadPdf = async (note) => {
|
|||
pdf.save(`${note.title}.pdf`);
|
||||
};
|
||||
|
||||
export const createNoteHandler = async (title: string, content?: string) => {
|
||||
export const createNoteHandler = async (title: string, md?: string, html?: string) => {
|
||||
// $i18n.t('New Note'),
|
||||
const res = await createNewNote(localStorage.token, {
|
||||
// YYYY-MM-DD
|
||||
|
|
@ -115,8 +115,8 @@ export const createNoteHandler = async (title: string, content?: string) => {
|
|||
data: {
|
||||
content: {
|
||||
json: null,
|
||||
html: content ?? '',
|
||||
md: content ?? ''
|
||||
html: html || md || '',
|
||||
md: md || ''
|
||||
}
|
||||
},
|
||||
meta: null,
|
||||
|
|
|
|||
Loading…
Reference in a new issue