浏览代码

enh: delete_message, continue_response, regenerate_response, rate_response user permissions

Co-Authored-By: G30 <50341825+silentoplayz@users.noreply.github.com>
Timothy Jaeryang Baek 1 月之前
父节点
当前提交
803b2e35be

+ 21 - 0
backend/open_webui/config.py

@@ -1208,6 +1208,23 @@ USER_PERMISSIONS_CHAT_DELETE = (
     os.environ.get("USER_PERMISSIONS_CHAT_DELETE", "True").lower() == "true"
     os.environ.get("USER_PERMISSIONS_CHAT_DELETE", "True").lower() == "true"
 )
 )
 
 
+USER_PERMISSIONS_CHAT_DELETE_MESSAGE = (
+    os.environ.get("USER_PERMISSIONS_CHAT_DELETE_MESSAGE", "True").lower() == "true"
+)
+
+USER_PERMISSIONS_CHAT_CONTINUE_RESPONSE = (
+    os.environ.get("USER_PERMISSIONS_CHAT_CONTINUE_RESPONSE", "True").lower() == "true"
+)
+
+USER_PERMISSIONS_CHAT_REGENERATE_RESPONSE = (
+    os.environ.get("USER_PERMISSIONS_CHAT_REGENERATE_RESPONSE", "True").lower()
+    == "true"
+)
+
+USER_PERMISSIONS_CHAT_RATE_RESPONSE = (
+    os.environ.get("USER_PERMISSIONS_CHAT_RATE_RESPONSE", "True").lower() == "true"
+)
+
 USER_PERMISSIONS_CHAT_EDIT = (
 USER_PERMISSIONS_CHAT_EDIT = (
     os.environ.get("USER_PERMISSIONS_CHAT_EDIT", "True").lower() == "true"
     os.environ.get("USER_PERMISSIONS_CHAT_EDIT", "True").lower() == "true"
 )
 )
@@ -1290,6 +1307,10 @@ DEFAULT_USER_PERMISSIONS = {
         "params": USER_PERMISSIONS_CHAT_PARAMS,
         "params": USER_PERMISSIONS_CHAT_PARAMS,
         "file_upload": USER_PERMISSIONS_CHAT_FILE_UPLOAD,
         "file_upload": USER_PERMISSIONS_CHAT_FILE_UPLOAD,
         "delete": USER_PERMISSIONS_CHAT_DELETE,
         "delete": USER_PERMISSIONS_CHAT_DELETE,
+        "delete_message": USER_PERMISSIONS_CHAT_DELETE_MESSAGE,
+        "continue_response": USER_PERMISSIONS_CHAT_CONTINUE_RESPONSE,
+        "regenerate_response": USER_PERMISSIONS_CHAT_REGENERATE_RESPONSE,
+        "rate_response": USER_PERMISSIONS_CHAT_RATE_RESPONSE,
         "edit": USER_PERMISSIONS_CHAT_EDIT,
         "edit": USER_PERMISSIONS_CHAT_EDIT,
         "share": USER_PERMISSIONS_CHAT_SHARE,
         "share": USER_PERMISSIONS_CHAT_SHARE,
         "export": USER_PERMISSIONS_CHAT_EXPORT,
         "export": USER_PERMISSIONS_CHAT_EXPORT,

+ 4 - 0
backend/open_webui/routers/users.py

@@ -146,6 +146,10 @@ class ChatPermissions(BaseModel):
     params: bool = True
     params: bool = True
     file_upload: bool = True
     file_upload: bool = True
     delete: bool = True
     delete: bool = True
+    delete_message: bool = True
+    continue_response: bool = True
+    regenerate_response: bool = True
+    rate_response: bool = True
     edit: bool = True
     edit: bool = True
     share: bool = True
     share: bool = True
     export: bool = True
     export: bool = True

+ 4 - 0
src/lib/components/admin/Users/Groups.svelte

@@ -71,6 +71,10 @@
 			params: true,
 			params: true,
 			file_upload: true,
 			file_upload: true,
 			delete: true,
 			delete: true,
+			delete_message: true,
+			continue_response: true,
+			regenerate_response: true,
+			rate_response: true,
 			edit: true,
 			edit: true,
 			share: true,
 			share: true,
 			export: true,
 			export: true,

+ 4 - 0
src/lib/components/admin/Users/Groups/EditGroupModal.svelte

@@ -53,6 +53,10 @@
 			params: true,
 			params: true,
 			file_upload: true,
 			file_upload: true,
 			delete: true,
 			delete: true,
+			delete_message: true,
+			continue_response: true,
+			regenerate_response: true,
+			rate_response: true,
 			edit: true,
 			edit: true,
 			share: true,
 			share: true,
 			export: true,
 			export: true,

+ 38 - 2
src/lib/components/admin/Users/Groups/Permissions.svelte

@@ -26,6 +26,10 @@
 			params: true,
 			params: true,
 			file_upload: true,
 			file_upload: true,
 			delete: true,
 			delete: true,
+			delete_message: true,
+			continue_response: true,
+			regenerate_response: true,
+			rate_response: true,
 			edit: true,
 			edit: true,
 			share: true,
 			share: true,
 			export: true,
 			export: true,
@@ -292,6 +296,14 @@
 			</div>
 			</div>
 		{/if}
 		{/if}
 
 
+		<div class="  flex w-full justify-between my-2 pr-2">
+			<div class=" self-center text-xs font-medium">
+				{$i18n.t('Allow Chat Edit')}
+			</div>
+
+			<Switch bind:state={permissions.chat.edit} />
+		</div>
+
 		<div class="  flex w-full justify-between my-2 pr-2">
 		<div class="  flex w-full justify-between my-2 pr-2">
 			<div class=" self-center text-xs font-medium">
 			<div class=" self-center text-xs font-medium">
 				{$i18n.t('Allow Chat Delete')}
 				{$i18n.t('Allow Chat Delete')}
@@ -302,10 +314,34 @@
 
 
 		<div class="  flex w-full justify-between my-2 pr-2">
 		<div class="  flex w-full justify-between my-2 pr-2">
 			<div class=" self-center text-xs font-medium">
 			<div class=" self-center text-xs font-medium">
-				{$i18n.t('Allow Chat Edit')}
+				{$i18n.t('Allow Delete Messages')}
 			</div>
 			</div>
 
 
-			<Switch bind:state={permissions.chat.edit} />
+			<Switch bind:state={permissions.chat.delete_message} />
+		</div>
+
+		<div class="  flex w-full justify-between my-2 pr-2">
+			<div class=" self-center text-xs font-medium">
+				{$i18n.t('Allow Continue Response')}
+			</div>
+
+			<Switch bind:state={permissions.chat.continue_response} />
+		</div>
+
+		<div class="  flex w-full justify-between my-2 pr-2">
+			<div class=" self-center text-xs font-medium">
+				{$i18n.t('Allow Response Regeneration')}
+			</div>
+
+			<Switch bind:state={permissions.chat.regenerate_response} />
+		</div>
+
+		<div class="  flex w-full justify-between my-2 pr-2">
+			<div class=" self-center text-xs font-medium">
+				{$i18n.t('Allow Response Rating')}
+			</div>
+
+			<Switch bind:state={permissions.chat.rating_response} />
 		</div>
 		</div>
 
 
 		<div class="  flex w-full justify-between my-2 pr-2">
 		<div class="  flex w-full justify-between my-2 pr-2">

+ 117 - 113
src/lib/components/chat/Messages/ResponseMessage.svelte

@@ -1227,7 +1227,7 @@
 								{/if}
 								{/if}
 
 
 								{#if !readOnly}
 								{#if !readOnly}
-									{#if !$temporaryChatEnabled && ($config?.features.enable_message_rating ?? true)}
+									{#if !$temporaryChatEnabled && ($config?.features.enable_message_rating ?? true) && ($user?.role === 'admin' || ($user?.permissions?.chat?.rate_response ?? true))}
 										<Tooltip content={$i18n.t('Good Response')} placement="bottom">
 										<Tooltip content={$i18n.t('Good Response')} placement="bottom">
 											<button
 											<button
 												aria-label={$i18n.t('Good Response')}
 												aria-label={$i18n.t('Good Response')}
@@ -1305,7 +1305,7 @@
 										</Tooltip>
 										</Tooltip>
 									{/if}
 									{/if}
 
 
-									{#if isLastMessage}
+									{#if isLastMessage && ($user?.role === 'admin' || ($user?.permissions?.chat?.continue_response ?? true))}
 										<Tooltip content={$i18n.t('Continue Response')} placement="bottom">
 										<Tooltip content={$i18n.t('Continue Response')} placement="bottom">
 											<button
 											<button
 												aria-label={$i18n.t('Continue Response')}
 												aria-label={$i18n.t('Continue Response')}
@@ -1342,52 +1342,96 @@
 										</Tooltip>
 										</Tooltip>
 									{/if}
 									{/if}
 
 
-									{#if $settings?.regenerateMenu ?? true}
-										<button
-											type="button"
-											class="hidden regenerate-response-button"
-											on:click={() => {
-												showRateComment = false;
-												regenerateResponse(message);
-
-												(model?.actions ?? []).forEach((action) => {
-													dispatch('action', {
-														id: action.id,
-														event: {
-															id: 'regenerate-response',
-															data: {
-																messageId: message.id
+									{#if $user?.role === 'admin' || ($user?.permissions?.chat?.regenerate_response ?? false)}
+										{#if $settings?.regenerateMenu ?? true}
+											<button
+												type="button"
+												class="hidden regenerate-response-button"
+												on:click={() => {
+													showRateComment = false;
+													regenerateResponse(message);
+
+													(model?.actions ?? []).forEach((action) => {
+														dispatch('action', {
+															id: action.id,
+															event: {
+																id: 'regenerate-response',
+																data: {
+																	messageId: message.id
+																}
 															}
 															}
-														}
+														});
 													});
 													});
-												});
-											}}
-										/>
-
-										<RegenerateMenu
-											onRegenerate={(prompt = null) => {
-												showRateComment = false;
-												regenerateResponse(message, prompt);
-
-												(model?.actions ?? []).forEach((action) => {
-													dispatch('action', {
-														id: action.id,
-														event: {
-															id: 'regenerate-response',
-															data: {
-																messageId: message.id
+												}}
+											/>
+
+											<RegenerateMenu
+												onRegenerate={(prompt = null) => {
+													showRateComment = false;
+													regenerateResponse(message, prompt);
+
+													(model?.actions ?? []).forEach((action) => {
+														dispatch('action', {
+															id: action.id,
+															event: {
+																id: 'regenerate-response',
+																data: {
+																	messageId: message.id
+																}
 															}
 															}
-														}
+														});
 													});
 													});
-												});
-											}}
-										>
+												}}
+											>
+												<Tooltip content={$i18n.t('Regenerate')} placement="bottom">
+													<div
+														aria-label={$i18n.t('Regenerate')}
+														class="{isLastMessage
+															? 'visible'
+															: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition"
+													>
+														<svg
+															xmlns="http://www.w3.org/2000/svg"
+															fill="none"
+															viewBox="0 0 24 24"
+															stroke-width="2.3"
+															aria-hidden="true"
+															stroke="currentColor"
+															class="w-4 h-4"
+														>
+															<path
+																stroke-linecap="round"
+																stroke-linejoin="round"
+																d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99"
+															/>
+														</svg>
+													</div>
+												</Tooltip>
+											</RegenerateMenu>
+										{:else}
 											<Tooltip content={$i18n.t('Regenerate')} placement="bottom">
 											<Tooltip content={$i18n.t('Regenerate')} placement="bottom">
-												<div
+												<button
+													type="button"
 													aria-label={$i18n.t('Regenerate')}
 													aria-label={$i18n.t('Regenerate')}
 													class="{isLastMessage
 													class="{isLastMessage
 														? 'visible'
 														? 'visible'
-														: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition"
+														: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition regenerate-response-button"
+													on:click={() => {
+														showRateComment = false;
+														regenerateResponse(message);
+
+														(model?.actions ?? []).forEach((action) => {
+															dispatch('action', {
+																id: action.id,
+																event: {
+																	id: 'regenerate-response',
+																	data: {
+																		messageId: message.id
+																	}
+																}
+															});
+														});
+													}}
 												>
 												>
 													<svg
 													<svg
 														xmlns="http://www.w3.org/2000/svg"
 														xmlns="http://www.w3.org/2000/svg"
@@ -1404,83 +1448,43 @@
 															d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99"
 															d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99"
 														/>
 														/>
 													</svg>
 													</svg>
-												</div>
+												</button>
 											</Tooltip>
 											</Tooltip>
-										</RegenerateMenu>
-									{:else}
-										<Tooltip content={$i18n.t('Regenerate')} placement="bottom">
-											<button
-												type="button"
-												aria-label={$i18n.t('Regenerate')}
-												class="{isLastMessage
-													? 'visible'
-													: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition regenerate-response-button"
-												on:click={() => {
-													showRateComment = false;
-													regenerateResponse(message);
-
-													(model?.actions ?? []).forEach((action) => {
-														dispatch('action', {
-															id: action.id,
-															event: {
-																id: 'regenerate-response',
-																data: {
-																	messageId: message.id
-																}
-															}
-														});
-													});
-												}}
-											>
-												<svg
-													xmlns="http://www.w3.org/2000/svg"
-													fill="none"
-													viewBox="0 0 24 24"
-													stroke-width="2.3"
-													aria-hidden="true"
-													stroke="currentColor"
-													class="w-4 h-4"
-												>
-													<path
-														stroke-linecap="round"
-														stroke-linejoin="round"
-														d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99"
-													/>
-												</svg>
-											</button>
-										</Tooltip>
+										{/if}
 									{/if}
 									{/if}
 
 
-									{#if siblings.length > 1}
-										<Tooltip content={$i18n.t('Delete')} placement="bottom">
-											<button
-												type="button"
-												aria-label={$i18n.t('Delete')}
-												id="delete-response-button"
-												class="{isLastMessage || ($settings?.highContrastMode ?? false)
-													? 'visible'
-													: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition"
-												on:click={() => {
-													showDeleteConfirm = true;
-												}}
-											>
-												<svg
-													xmlns="http://www.w3.org/2000/svg"
-													fill="none"
-													viewBox="0 0 24 24"
-													stroke-width="2"
-													stroke="currentColor"
-													aria-hidden="true"
-													class="w-4 h-4"
+									{#if $user?.role === 'admin' || ($user?.permissions?.chat?.delete_message ?? false)}
+										{#if siblings.length > 1}
+											<Tooltip content={$i18n.t('Delete')} placement="bottom">
+												<button
+													type="button"
+													aria-label={$i18n.t('Delete')}
+													id="delete-response-button"
+													class="{isLastMessage || ($settings?.highContrastMode ?? false)
+														? 'visible'
+														: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition"
+													on:click={() => {
+														showDeleteConfirm = true;
+													}}
 												>
 												>
-													<path
-														stroke-linecap="round"
-														stroke-linejoin="round"
-														d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
-													/>
-												</svg>
-											</button>
-										</Tooltip>
+													<svg
+														xmlns="http://www.w3.org/2000/svg"
+														fill="none"
+														viewBox="0 0 24 24"
+														stroke-width="2"
+														stroke="currentColor"
+														aria-hidden="true"
+														class="w-4 h-4"
+													>
+														<path
+															stroke-linecap="round"
+															stroke-linejoin="round"
+															d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
+														/>
+													</svg>
+												</button>
+											</Tooltip>
+										{/if}
 									{/if}
 									{/if}
 
 
 									{#if isLastMessage}
 									{#if isLastMessage}

+ 27 - 25
src/lib/components/chat/Messages/UserMessage.svelte

@@ -495,32 +495,34 @@
 						</Tooltip>
 						</Tooltip>
 					{/if}
 					{/if}
 
 
-					{#if !readOnly && (!isFirstMessage || siblings.length > 1)}
-						<Tooltip content={$i18n.t('Delete')} placement="bottom">
-							<button
-								class="{($settings?.highContrastMode ?? false)
-									? ''
-									: 'invisible group-hover:visible'} p-1 rounded-sm dark:hover:text-white hover:text-black transition"
-								on:click={() => {
-									showDeleteConfirm = true;
-								}}
-							>
-								<svg
-									xmlns="http://www.w3.org/2000/svg"
-									fill="none"
-									viewBox="0 0 24 24"
-									stroke-width="2"
-									stroke="currentColor"
-									class="w-4 h-4"
+					{#if $_user?.role === 'admin' || ($_user?.permissions?.chat?.delete_message ?? false)}
+						{#if !readOnly && (!isFirstMessage || siblings.length > 1)}
+							<Tooltip content={$i18n.t('Delete')} placement="bottom">
+								<button
+									class="{($settings?.highContrastMode ?? false)
+										? ''
+										: 'invisible group-hover:visible'} p-1 rounded-sm dark:hover:text-white hover:text-black transition"
+									on:click={() => {
+										showDeleteConfirm = true;
+									}}
 								>
 								>
-									<path
-										stroke-linecap="round"
-										stroke-linejoin="round"
-										d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
-									/>
-								</svg>
-							</button>
-						</Tooltip>
+									<svg
+										xmlns="http://www.w3.org/2000/svg"
+										fill="none"
+										viewBox="0 0 24 24"
+										stroke-width="2"
+										stroke="currentColor"
+										class="w-4 h-4"
+									>
+										<path
+											stroke-linecap="round"
+											stroke-linejoin="round"
+											d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
+										/>
+									</svg>
+								</button>
+							</Tooltip>
+						{/if}
 					{/if}
 					{/if}
 
 
 					{#if $settings?.chatBubble ?? true}
 					{#if $settings?.chatBubble ?? true}