chores: 经测试,docker环境中,聊天窗口动态调节字体仍无法正常工作,特将其移除

This commit is contained in:
zstar 2025-06-07 22:35:06 +08:00
parent d42708d618
commit ecaed85f84
14 changed files with 135 additions and 214 deletions

1
.python-version Normal file
View File

@ -0,0 +1 @@
3.10

View File

@ -11,9 +11,10 @@ COPY rag ./rag
COPY graphrag ./graphrag
COPY agentic_reasoning ./agentic_reasoning
# 复制 Python 依赖定义文件
COPY pyproject.toml ./pyproject.toml
COPY uv.lock ./uv.lock
# 安装额外依赖
RUN uv pip install --no-cache-dir mysql-connector-python==9.2.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
RUN uv pip install --no-cache-dir redis==6.2.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
# RUN uv pip install --no-cache-dir pymysql==1.1.1 -i https://pypi.tuna.tsinghua.edu.cn/simple
# 复制前端源代码目录
COPY web ./web

View File

@ -1,13 +1,13 @@
docker 镜像相关命令:
前台镜像构建相关:
docker build -t zstar1003/ragflowplus:v0.4.0 .
docker tag zstar1003/ragflowplus:v0.4.0 zstar1003/ragflowplus:v0.4.0
docker push zstar1003/ragflowplus:v0.4.0
docker build -t zstar1003/ragflowplus:v0.4.1 .
docker tag zstar1003/ragflowplus:v0.4.1 zstar1003/ragflowplus:v0.4.1
docker push zstar1003/ragflowplus:v0.4.1
后台镜像构建相关:
cd management
docker-compose build
docker tag zstar1003/ragflowplus-management-web:v0.4.0 zstar1003/ragflowplus-management-web:v0.4.0
docker tag zstar1003/ragflowplus-management-server:v0.4.0 zstar1003/ragflowplus-management-server:v0.4.0
docker push zstar1003/ragflowplus-management-web:v0.4.0
docker push zstar1003/ragflowplus-management-server:v0.4.0
docker tag zstar1003/ragflowplus-management-web:v0.4.1 zstar1003/ragflowplus-management-web:v0.4.1
docker tag zstar1003/ragflowplus-management-server:v0.4.1 zstar1003/ragflowplus-management-server:v0.4.1
docker push zstar1003/ragflowplus-management-web:v0.4.1
docker push zstar1003/ragflowplus-management-server:v0.4.1

View File

@ -51,7 +51,7 @@ MYSQL_PORT=5455
# The hostname where the MinIO service is exposed
MINIO_HOST=minio
# minio上传文件时的ip地址如需公网访问可修改为公网ip地址
MINIO_VISIT_HOST=localhost
MINIO_VISIT_HOST=host.docker.internal
# The port used to expose the MinIO console interface to the host machine,
# allowing EXTERNAL access to the web-based console running inside the Docker container.
MINIO_CONSOLE_PORT=9001
@ -76,9 +76,9 @@ REDIS_PASSWORD=infini_rag_flow
SVR_HTTP_PORT=9380
# RAGFLOW_IMAGE原始为infiniflow/ragflow:v0.18.0-slim
RAGFLOW_IMAGE=zstar1003/ragflowplus:v0.4.0
RAGFLOWPLUS_MANAGEMENT_WEB_IMAGE=zstar1003/ragflowplus-management-web:v0.4.0
RAGFLOWPLUS_MANAGEMENT_SERVER_IMAGE=zstar1003/ragflowplus-management-server:v0.4.0
RAGFLOW_IMAGE=zstar1003/ragflowplus:v0.4.1
RAGFLOWPLUS_MANAGEMENT_WEB_IMAGE=zstar1003/ragflowplus-management-web:v0.4.1
RAGFLOWPLUS_MANAGEMENT_SERVER_IMAGE=zstar1003/ragflowplus-management-server:v0.4.1
# The local time zone.
TIMEZONE='Asia/Shanghai'

View File

@ -1,49 +0,0 @@
import requests
from openai import OpenAI
# 测试 embedding 模型 (vllm-bge)
def test_embedding(model, text):
"""测试嵌入模型"""
client = OpenAI(base_url="http://localhost:8000/v1", api_key="1")
response = client.embeddings.create(
model=model, # 使用支持嵌入的模型
input=text # 需要嵌入的文本
)
# 打印嵌入响应内容
# print(f"Embedding response: {response}")
result = response.data[0].embedding
if response and response.data:
print(len(result))
else:
print("Failed to get embedding.")
# 测试文本生成模型 (vllm-deepseek)
def test_chat(model, prompt):
"""测试文本生成模型"""
client = OpenAI(base_url="http://localhost:8001/v1", api_key="1")
response = client.completions.create(
model=model,
prompt=prompt
)
# 打印生成的文本
print(f"Chat response: {response.choices[0].text}")
def main():
# 测试文本生成模型 deepseek-r1
prompt = "你好,今天的天气怎么样?"
print("Testing vllm-deepseek model for chat...")
test_chat("deepseek-r1", prompt)
# 测试嵌入模型 bge-m3
embedding_text = "我喜欢编程尤其是做AI模型。"
print("\nTesting vllm-bge model for embedding...")
test_embedding("bge-m3", embedding_text)
if __name__ == "__main__":
main()

View File

@ -1,52 +0,0 @@
#
# Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Create a dataset
echo -e "\n-- Create a dataset"
curl --request POST \
--url http://localhost:9380/api/v1/datasets \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ragflow-IzZmY1MGVhYTBhMjExZWZiYTdjMDI0Mm' \
--data '{
"name": "test"
}'
# Update the dataset
echo -e "\n-- Update the dataset"
curl --request PUT \
--url http://localhost:9380/api/v1/datasets/2e898768a0bc11efb46a0242ac120006 \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ragflow-IzZmY1MGVhYTBhMjExZWZiYTdjMDI0Mm' \
--data '
{
"name": "updated_dataset"
}'
# List datasets
echo -e "\n-- List datasets"
curl --request GET \
--url http://127.0.0.1:9380/api/v1/datasets \
--header 'Authorization: Bearer ragflow-IzZmY1MGVhYTBhMjExZWZiYTdjMDI0Mm'
# Delete datasets
echo -e "\n-- Delete datasets"
curl --request DELETE \
--url http://localhost:9380/api/v1/datasets \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ragflow-IzZmY1MGVhYTBhMjExZWZiYTdjMDI0Mm' \
--data '{
"ids": ["301298b8a0bc11efa0440242ac120006"]
}'

View File

@ -1,53 +0,0 @@
#
# Copyright 2024 The InfiniFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""
The example is about CRUD operations (Create, Read, Update, Delete) on a dataset.
"""
from ragflow_sdk import RAGFlow
import sys
HOST_ADDRESS = "http://127.0.0.1"
API_KEY = "ragflow-IzZmY1MGVhYTBhMjExZWZiYTdjMDI0Mm"
try:
# create a ragflow instance
ragflow_instance = RAGFlow(api_key=API_KEY, base_url=HOST_ADDRESS)
# crate a dataset instance
dataset_instance = ragflow_instance.create_dataset(name="dataset_instance")
# update the dataset instance
updated_message = {"name": "updated_dataset"}
updated_dataset = dataset_instance.update(updated_message)
# get the dataset (list datasets)
dataset_list = ragflow_instance.list_datasets(id=dataset_instance.id)
dataset_instance_2 = dataset_list[0]
print(dataset_instance)
print(dataset_instance_2)
# delete the dataset (delete datasets)
to_be_deleted_datasets = [dataset_instance.id]
ragflow_instance.delete_datasets(ids=to_be_deleted_datasets)
print("test done")
sys.exit(0)
except Exception as e:
print(str(e))
sys.exit(-1)

View File

@ -1,7 +1,7 @@
services:
management-frontend:
container_name: ragflowplus-management-frontend
image: zstar1003/ragflowplus-management-web:v0.4.0
image: zstar1003/ragflowplus-management-web:v0.4.1
build:
context: .
dockerfile: Dockerfile
@ -17,7 +17,7 @@ services:
management-backend:
container_name: ragflowplus-management-backend
image: zstar1003/ragflowplus-management-server:v0.4.0
image: zstar1003/ragflowplus-management-server:v0.4.1
build:
context: .
dockerfile: Dockerfile

View File

@ -111,4 +111,6 @@ mini-racer>=0.12.4,<0.13.0
pyodbc>=5.2.0,<6.0.0
flasgger>=0.9.7.1,<0.10.0
xxhash>=3.5.0,<4.0.0
trio>=0.29.0
trio>=0.29.0
mysql-connector-python==9.2.0
redis==6.2.0

View File

@ -0,0 +1,53 @@
import { useEffect, useState } from 'react';
/**
* (SSR)HooklocalStorage中的状态
* 访localStoragehydration errors
*
* @param key - localStorage中存储值的键名
* @param defaultValue - localStorage中没有值或在服务器端渲染时使用的默认值
* @returns `useState` `[state, setState]`
*/
export function useSafeLocalStorageState<T>(key: string, defaultValue: T) {
// 1. 初始状态始终使用传入的默认值。
// 这确保了在服务器端和客户端的首次渲染中,组件的状态是一致的。
const [state, setState] = useState<T>(defaultValue);
// 2. 使用useEffect确保以下代码只在客户端浏览器环境执行。
// useEffect在服务器端渲染期间不会运行。
useEffect(() => {
try {
const storedValue = localStorage.getItem(key);
// 只有当localStorage中确实存在值时才更新状态。
if (storedValue !== null) {
setState(JSON.parse(storedValue) as T);
}
} catch (error) {
console.error(`Error reading localStorage key "${key}":`, error);
// 如果读取或解析JSON失败状态将保持为defaultValue不会导致应用崩溃。
}
}, [key]); // 依赖项是key通常不会改变所以这个effect只在组件挂载后运行一次。
/**
* setState的函数React状态和localStorage
* @param newValue -
*/
const setAndStoreState = (newValue: T | ((prevState: T) => T)) => {
setState((prevState) => {
// 支持函数式更新,如 `setState(prev => prev + 1)`
const valueToStore =
newValue instanceof Function ? newValue(prevState) : newValue;
try {
// 将新状态序列化并存储到localStorage。
localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(`Error setting localStorage key "${key}":`, error);
}
return valueToStore;
});
};
// 返回与useState兼容的数组/元组。
return [state, setAndStoreState] as const;
}

View File

@ -3,11 +3,22 @@
background: #fff;
border-radius: 12px;
color: #333;
.messageContainer {
overflow-y: auto;
padding-right: 24px;
font-size: var(--chat-font-size, 18px);
// 【核心修改】: 使用更强硬的规则确保字体大小生效
// 1. 使用 & 和 * 将规则应用到容器自身和所有子元素上。
// 2. 使用 !important 来获得最高优先级,覆盖任何其他规则。
&,
* {
font-size: var(--chat-font-size, 18px) !important;
}
// ↓↓↓ 下面的 h1, p, table 等规则是为了保持原有的相对大小和样式,
// 我们需要调整它们让它们基于父元素的字体大小来计算而不是一个固定的px值。
// 使用 em 单位1em 等于当前元素的字体大小。
h1,
h2,
h3,
@ -19,7 +30,10 @@
border-bottom: 2px solid #eaeaea;
padding-bottom: 0.25em;
margin: 0.25em 0.25em;
// 示例:让标题比基本字体大一点
font-size: 1.2em !important;
}
section {
margin-top: 1em;
margin-bottom: 1em;
@ -27,11 +41,16 @@
margin-left: 0;
}
}
p {
margin-top: 1em;
margin-bottom: 1em;
margin-left: 1em;
// 确保 p 标签也继承我们设置的字体大小
font-size: 1em !important;
line-height: 1.6; // 增加行高以提高可读性
}
ul,
ol {
margin: 1em 0;
@ -40,11 +59,14 @@
margin-bottom: 0.25em;
}
}
table {
width: 80%;
border-collapse: collapse;
margin-left: 1em;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
// 表格内的字体也应该继承
font-size: 1em !important;
}
thead {

View File

@ -23,9 +23,11 @@ import styles from './index.less';
interface IProps {
controller: AbortController;
fontSize: number;
}
const ChatContainer = ({ controller }: IProps) => {
// 确认这里的默认值为 20
const ChatContainer = ({ controller, fontSize = 20 }: IProps) => {
const { conversationId } = useGetChatSearchParams();
const { data: conversation } = useFetchNextConversation();
@ -54,7 +56,12 @@ const ChatContainer = ({ controller }: IProps) => {
return (
<>
<Flex flex={1} className={styles.chatContainer} vertical>
<Flex flex={1} vertical className={styles.messageContainer}>
<Flex
flex={1}
vertical
className={styles.messageContainer}
style={{ fontSize: `${fontSize}px` }}
>
<div>
<Spin spinning={loading}>
{derivedMessages?.map((message, i) => {

View File

@ -5,6 +5,7 @@ import RenameModal from '@/components/rename-modal';
import SvgIcon from '@/components/svg-icon';
import { useTheme } from '@/components/theme-provider';
import { SharedFrom } from '@/constants/chat';
import { useSafeLocalStorageState } from '@/hooks/chat-font-hooks';
import {
useClickConversationCard,
useClickDialogCard,
@ -14,12 +15,7 @@ import {
import { useTranslate } from '@/hooks/common-hooks';
import { useSetSelectedRecord } from '@/hooks/logic-hooks';
import { IDialog } from '@/interfaces/database/chat';
import { FontStorageUtil } from '@/utils/font-storage';
import {
DeleteOutlined,
EditOutlined,
SettingOutlined,
} from '@ant-design/icons';
import { DeleteOutlined, EditOutlined } from '@ant-design/icons';
import {
Avatar,
Button,
@ -28,8 +24,8 @@ import {
Dropdown,
Flex,
MenuProps,
Modal,
Slider,
// Modal,
// Slider,
Space,
Spin,
Tag,
@ -38,7 +34,7 @@ import {
import { MenuItemProps } from 'antd/lib/menu/MenuItem';
import classNames from 'classnames';
import { PictureInPicture2 } from 'lucide-react';
import { useCallback, useEffect, useState } from 'react';
import { useCallback, useState } from 'react';
import ChatConfigurationModal from './chat-configuration-modal';
import ChatContainer from './chat-container';
import {
@ -50,8 +46,12 @@ import {
useSelectDerivedConversationList,
} from './hooks';
import styles from './index.less';
const { Text } = Typography;
const FONT_SIZE_STORAGE_KEY = 'chat_font_size_v2'; // 定义一个清晰的 key (v2 用于避免旧数据干扰)
const DEFAULT_FONT_SIZE = 20; // 默认字体设为 20
const Chat = () => {
const { data: dialogList, loading: dialogLoading } = useFetchNextDialogList();
const { onRemoveDialog } = useDeleteDialog();
@ -94,6 +94,12 @@ const Chat = () => {
const { showEmbedModal, hideEmbedModal, embedVisible, beta } =
useShowEmbedModal();
const [fontSize, setFontSize] = useSafeLocalStorageState(
FONT_SIZE_STORAGE_KEY,
DEFAULT_FONT_SIZE,
);
// const [fontSizeModalVisible, setFontSizeModalVisible] = useState(false);
const handleAppCardEnter = (id: string) => () => {
handleItemEnter(id);
};
@ -165,29 +171,10 @@ const Chat = () => {
addTemporaryConversation();
}, [addTemporaryConversation]);
const [fontSizeModalVisible, setFontSizeModalVisible] = useState(false);
// 初始化 state 时直接从工具库读取,这在客户端渲染时是安全的
const [fontSize, setFontSize] = useState(() => FontStorageUtil.getFontSize());
// 【核心修改 ①】: 使用 useEffect 监听 fontSize 的变化, 并将其应用为全局 CSS 变量
useEffect(() => {
// 设置 CSS 自定义属性到根元素 <html> 上
document.documentElement.style.setProperty(
'--chat-font-size',
`${fontSize}px`,
);
// 组件卸载时,清理掉这个自定义属性,避免影响其他页面
return () => {
document.documentElement.style.removeProperty('--chat-font-size');
};
}, [fontSize]); // 依赖项是 fontSize当它变化时重新设置
// 字体大小变化处理函数
const handleFontSizeChange = (value: number) => {
setFontSize(value);
FontStorageUtil.setFontSize(value);
};
// 用于自动更新 localStorage
// const handleFontSizeChange = (value: number) => {
// setFontSize(value);
// };
const buildAppItems = (dialog: IDialog) => {
const dialogId = dialog.id;
@ -325,16 +312,15 @@ const Chat = () => {
<b>{t('chat')}</b>
<Tag>{conversationList.length}</Tag>
</Space>
<div>
<SettingOutlined
{/* <SettingOutlined
style={{
marginRight: '8px',
fontSize: '20px',
cursor: 'pointer',
}}
onClick={() => setFontSizeModalVisible(true)}
/>
/> */}
<SvgIcon
name="plus-circle-fill"
width={20}
@ -391,7 +377,10 @@ const Chat = () => {
</Flex>
</Flex>
<Divider type={'vertical'} className={styles.divider}></Divider>
<ChatContainer controller={controller}></ChatContainer>
<ChatContainer
controller={controller}
fontSize={fontSize}
></ChatContainer>
{dialogEditVisible && (
<ChatConfigurationModal
visible={dialogEditVisible}
@ -422,7 +411,7 @@ const Chat = () => {
></EmbedModal>
)}
{fontSizeModalVisible && (
{/* {fontSizeModalVisible && (
<Modal
title={'设置字体大小'}
open={fontSizeModalVisible}
@ -435,13 +424,13 @@ const Chat = () => {
min={16}
max={24}
step={1}
value={fontSize} // 使用受控的 value
value={fontSize}
style={{ width: '80%' }}
onChange={handleFontSizeChange}
/>
</Flex>
</Modal>
)}
)} */}
</Flex>
);
};

View File

@ -42,7 +42,7 @@ const routes = [
layout: false,
wrappers: ['@/wrappers/auth'],
routes: [
{ path: '/', redirect: '/knowledge' },
{ path: '/', redirect: '/login' },
{
path: '/knowledge',
component: '@/pages/knowledge',