From cc7e94ffb6e1e518bf716006e1f8f2207d27c563 Mon Sep 17 00:00:00 2001 From: Jin Hai Date: Fri, 13 Mar 2026 19:05:30 +0800 Subject: [PATCH] Use different API route according the ENV (#13597) ### What problem does this PR solve? 1. Fix go server date precision 2. Use API_SCHEME_PROXY to control the web API route ### Type of change - [x] New Feature (non-breaking change which adds functionality) --------- Signed-off-by: Jin Hai --- build.sh | 41 ++++++++---- docker/.env | 3 + docker/docker-compose.yml | 2 + docker/entrypoint.sh | 11 +++- internal/admin/service.go | 8 +-- internal/dao/kb.go | 4 +- internal/dao/system_settings.go | 8 +-- internal/handler/auth.go | 2 +- internal/handler/user.go | 8 --- internal/service/chat.go | 4 +- internal/service/chat_session.go | 4 +- internal/service/kb.go | 4 +- internal/service/user.go | 4 +- web/vite.config.ts | 110 ++++++++++++++++++++++--------- 14 files changed, 140 insertions(+), 73 deletions(-) diff --git a/build.sh b/build.sh index 5c075120d1..13cbb26343 100755 --- a/build.sh +++ b/build.sh @@ -14,7 +14,8 @@ PROJECT_ROOT="$SCRIPT_DIR" # Build directories CPP_DIR="$PROJECT_ROOT/internal/cpp" BUILD_DIR="$CPP_DIR/cmake-build-release" -OUTPUT_BINARY="$PROJECT_ROOT/bin/server_main" +RAGFLOW_SERVER_BINARY="$PROJECT_ROOT/bin/server_main" +ADMIN_SERVER_BINARY="$PROJECT_ROOT/bin/admin_server" echo -e "${GREEN}=== RAGFlow Go Server Build Script ===${NC}" @@ -90,16 +91,22 @@ build_go() { sudo apt -y install libpcre2-dev fi - echo "Building Go binary: $OUTPUT_BINARY" - GOPROXY=${GOPROXY:-https://goproxy.cn,https://proxy.golang.org,direct} CGO_ENABLED=1 go build -o "$OUTPUT_BINARY" ./cmd/server_main.go - GOPROXY=${GOPROXY:-https://goproxy.cn,https://proxy.golang.org,direct} CGO_ENABLED=1 go build -o "$OUTPUT_BINARY" ./cmd/admin_server.go + echo "Building API server binary: $RAGFLOW_SERVER_BINARY and $ADMIN_SERVER_BINARY" + GOPROXY=${GOPROXY:-https://goproxy.cn,https://proxy.golang.org,direct} CGO_ENABLED=1 go build -o "$RAGFLOW_SERVER_BINARY" ./cmd/server_main.go + GOPROXY=${GOPROXY:-https://goproxy.cn,https://proxy.golang.org,direct} CGO_ENABLED=1 go build -o "$ADMIN_SERVER_BINARY" ./cmd/admin_server.go - if [ ! -f "$OUTPUT_BINARY" ]; then - echo -e "${RED}Error: Failed to build Go binary${NC}" + if [ ! -f "$RAGFLOW_SERVER_BINARY" ]; then + echo -e "${RED}Error: Failed to build RAGFlow server binary${NC}" exit 1 fi - - echo -e "${GREEN}✓ Go server built successfully: $OUTPUT_BINARY${NC}" + + if [ ! -f "$ADMIN_SERVER_BINARY" ]; then + echo -e "${RED}Error: Failed to build Admin server binary${NC}" + exit 1 + fi + + echo -e "${GREEN}✓ Go server_main built successfully: $RAGFLOW_SERVER_BINARY${NC}" + echo -e "${GREEN}✓ Go admin_server built successfully: $ADMIN_SERVER_BINARY${NC}" } # Clean build artifacts @@ -107,14 +114,24 @@ clean() { print_section "Cleaning build artifacts" rm -rf "$BUILD_DIR" - rm -f "$OUTPUT_BINARY" - + rm -f "$RAGFLOW_SERVER_BINARY" + rm -f "$ADMIN_SERVER_BINARY" + echo -e "${GREEN}✓ Build artifacts cleaned${NC}" } # Run the server run() { - if [ ! -f "$OUTPUT_BINARY" ]; then + if [ ! -f "$ADMIN_SERVER_BINARY" ]; then + echo -e "${RED}Error: Binary not found. Build first with --all or --go${NC}" + exit 1 + fi + + print_section "Starting ADMIN server" + cd "$PROJECT_ROOT" + ./admin_server + + if [ ! -f "$RAGFLOW_SERVER_BINARY" ]; then echo -e "${RED}Error: Binary not found. Build first with --all or --go${NC}" exit 1 fi @@ -184,7 +201,7 @@ main() { build_cpp build_go echo -e "\n${GREEN}=== Build completed successfully! ===${NC}" - echo "Binary: $OUTPUT_BINARY" + echo "Binary: $RAGFLOW_SERVER_BINARY, $ADMIN_SERVER_BINARY" ;; *) echo -e "${RED}Unknown option: $1${NC}" diff --git a/docker/.env b/docker/.env index c7e68a756a..733689ccce 100644 --- a/docker/.env +++ b/docker/.env @@ -155,6 +155,9 @@ SVR_MCP_PORT=9382 GO_HTTP_PORT=9384 GO_ADMIN_PORT=9385 +# API_PROXY_SCHEME=hybrid # go and python hybrid deploy mode +API_PROXY_SCHEME=python # use pure python server deployment + # The RAGFlow Docker image to download. v0.22+ doesn't include embedding models. RAGFLOW_IMAGE=infiniflow/ragflow:v0.24.0 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index a32c2b609e..5214ee986b 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -34,6 +34,8 @@ services: - ${SVR_HTTP_PORT}:9380 - ${ADMIN_SVR_HTTP_PORT}:9381 - ${SVR_MCP_PORT}:9382 # entry for MCP (host_port:docker_port). The docker_port must match the value you set for `mcp-port` above. + - ${GO_HTTP_PORT}:9384 + - ${GO_ADMIN_PORT}:9385 volumes: - ./ragflow-logs:/ragflow/logs - ./nginx/ragflow.conf:/etc/nginx/conf.d/ragflow.conf diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 9497d8c6a1..b26b5034b1 100755 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -230,7 +230,11 @@ if [[ "${ENABLE_WEBSERVER}" -eq 1 ]]; then echo "Starting ragflow_server..." while true; do "$PY" api/ragflow_server.py ${INIT_SUPERUSER_ARGS} & - bin/server_main & + + if [[ "${API_PROXY_SCHEME}" == "hybrid" ]]; then + echo "Starting RAGFlow server in hybrid mode..." + bin/server_main & + fi wait; sleep 1; done & @@ -249,7 +253,10 @@ if [[ "${ENABLE_ADMIN_SERVER}" -eq 1 ]]; then echo "Starting admin_server..." while true; do "$PY" admin/server/admin_server.py & - bin/admin_server & + if [[ "${API_PROXY_SCHEME}" == "hybrid" ]]; then + echo "Starting Admin server in hybrid mode..." + bin/admin_server & + fi wait; sleep 1; done & diff --git a/internal/admin/service.go b/internal/admin/service.go index 14abc87a0d..74c50fa562 100644 --- a/internal/admin/service.go +++ b/internal/admin/service.go @@ -183,7 +183,7 @@ func (s *Service) CreateUser(username, password, role string) (map[string]interf isSuperuser := role == "admin" now := time.Now().Unix() - nowDate := time.Now() + nowDate := time.Now().Truncate(time.Second) user := &model.User{ ID: userID, @@ -440,7 +440,7 @@ func (s *Service) getInitTenantLLM(userID string) ([]*model.TenantLLM, error) { llmName := llm.LLMName modelType := llm.ModelType now := time.Now().Unix() - nowDate := time.Now() + nowDate := time.Now().Truncate(time.Second) tenantLLM := &model.TenantLLM{ TenantID: userID, @@ -1559,7 +1559,7 @@ func (s *Service) InitDefaultAdmin() error { if len(users) == 0 { now := time.Now().Unix() - nowDate := time.Now() + nowDate := time.Now().Truncate(time.Second) userID := utility.GenerateToken() accessToken := utility.GenerateToken() status := "1" @@ -1635,7 +1635,7 @@ func (s *Service) InitDefaultAdmin() error { // addTenantForAdmin add tenant for admin user func (s *Service) addTenantForAdmin(userID, nickname string) error { now := time.Now().Unix() - nowDate := time.Now() + nowDate := time.Now().Truncate(time.Second) status := "1" role := "owner" tenantName := nickname + "'s Kingdom" diff --git a/internal/dao/kb.go b/internal/dao/kb.go index 6411dcd3e7..9fdc5c8405 100644 --- a/internal/dao/kb.go +++ b/internal/dao/kb.go @@ -293,7 +293,7 @@ func (dao *KnowledgebaseDAO) DuplicateName(name, tenantID string) string { // This matches the Python atomic_increase_doc_num_by_id method func (dao *KnowledgebaseDAO) AtomicIncreaseDocNumByID(kbID string) error { now := time.Now().Unix() - nowDate := time.Now() + nowDate := time.Now().Truncate(time.Second) return DB.Model(&model.Knowledgebase{}). Where("id = ?", kbID). Updates(map[string]interface{}{ @@ -307,7 +307,7 @@ func (dao *KnowledgebaseDAO) AtomicIncreaseDocNumByID(kbID string) error { // This matches the Python decrease_document_num_in_delete method func (dao *KnowledgebaseDAO) DecreaseDocumentNum(kbID string, docNum, chunkNum, tokenNum int64) error { now := time.Now().Unix() - nowDate := time.Now() + nowDate := time.Now().Truncate(time.Second) return DB.Model(&model.Knowledgebase{}). Where("id = ?", kbID). Updates(map[string]interface{}{ diff --git a/internal/dao/system_settings.go b/internal/dao/system_settings.go index 858d63ba50..514a60ea65 100644 --- a/internal/dao/system_settings.go +++ b/internal/dao/system_settings.go @@ -59,7 +59,7 @@ func (d *SystemSettingsDAO) GetByName(name string) ([]model.SystemSettings, erro // Updates the setting with the given name using the provided data func (d *SystemSettingsDAO) UpdateByName(name string, setting *model.SystemSettings) error { now := time.Now().Unix() - nowDate := time.Now() + nowDate := time.Now().Truncate(time.Second) return DB.Model(&model.SystemSettings{}). Where("name = ?", name). @@ -76,7 +76,7 @@ func (d *SystemSettingsDAO) UpdateByName(name string, setting *model.SystemSetti // Inserts a new system setting record into database func (d *SystemSettingsDAO) Create(setting *model.SystemSettings) error { now := time.Now().Unix() - nowDate := time.Now() + nowDate := time.Now().Truncate(time.Second) setting.CreateTime = &now setting.CreateDate = &nowDate @@ -161,7 +161,7 @@ func (d *SystemSettingsDAO) Transaction(fn func(tx *gorm.DB) error) error { // CreateWithTx create setting within transaction func (d *SystemSettingsDAO) CreateWithTx(tx *gorm.DB, setting *model.SystemSettings) error { now := time.Now().Unix() - nowDate := time.Now() + nowDate := time.Now().Truncate(time.Second) setting.CreateTime = &now setting.CreateDate = &nowDate @@ -174,7 +174,7 @@ func (d *SystemSettingsDAO) CreateWithTx(tx *gorm.DB, setting *model.SystemSetti // UpdateByNameWithTx update setting within transaction func (d *SystemSettingsDAO) UpdateByNameWithTx(tx *gorm.DB, name string, setting *model.SystemSettings) error { now := time.Now().Unix() - nowDate := time.Now() + nowDate := time.Now().Truncate(time.Second) return tx.Model(&model.SystemSettings{}). Where("name = ?", name). diff --git a/internal/handler/auth.go b/internal/handler/auth.go index b98a4ddd2f..3c336b2ecb 100644 --- a/internal/handler/auth.go +++ b/internal/handler/auth.go @@ -67,7 +67,7 @@ func (h *AuthHandler) AuthMiddleware() gin.HandlerFunc { if *user.IsSuperuser { c.JSON(http.StatusForbidden, gin.H{ "code": common.CodeForbidden, - "message": "Super user should access the URL", + "message": "Super user shouldn't access the URL", }) return } diff --git a/internal/handler/user.go b/internal/handler/user.go index a8507a1b7b..651115115d 100644 --- a/internal/handler/user.go +++ b/internal/handler/user.go @@ -336,14 +336,6 @@ func (h *UserHandler) Logout(c *gin.Context) { return } - if *user.IsSuperuser { - c.JSON(http.StatusForbidden, gin.H{ - "code": common.CodeForbidden, - "message": "Super user should access the URL", - }) - return - } - // Logout user code, err = h.userService.Logout(user) if err != nil { diff --git a/internal/service/chat.go b/internal/service/chat.go index c1a7915ac7..ac15bcb7da 100644 --- a/internal/service/chat.go +++ b/internal/service/chat.go @@ -434,7 +434,7 @@ func (s *ChatService) SetDialog(userID string, req *SetDialogRequest) (*SetDialo } // Get current time - now := time.Now() + now := time.Now().Truncate(time.Second) createTime := now.UnixMilli() // Set default language @@ -479,7 +479,7 @@ func (s *ChatService) SetDialog(userID string, req *SetDialogRequest) (*SetDialo } // Update existing chat - also update update_time - now := time.Now() + now := time.Now().Truncate(time.Second) updateTime := now.UnixMilli() updateData := map[string]interface{}{ "name": name, diff --git a/internal/service/chat_session.go b/internal/service/chat_session.go index e32dea3fa3..e8aa142c25 100644 --- a/internal/service/chat_session.go +++ b/internal/service/chat_session.go @@ -113,8 +113,8 @@ func (s *ChatSessionService) SetChatSession(userID string, req *SetChatSessionRe } } - now := time.Now() - createTime := now.UnixMilli() + now := time.Now().Truncate(time.Second) + createTime := time.Now().UnixMilli() // Create initial message - store as JSON object with messages array messagesObj := map[string]interface{}{ diff --git a/internal/service/kb.go b/internal/service/kb.go index 143c0e9a40..ba71bc321d 100644 --- a/internal/service/kb.go +++ b/internal/service/kb.go @@ -146,7 +146,7 @@ func (s *KnowledgebaseService) CreateKB(req *CreateKBRequest, tenantID string) ( // Create knowledge base model now := time.Now().Unix() - nowDate := time.Now() + nowDate := time.Now().Truncate(time.Second) kb := &model.Knowledgebase{ ID: kbID, Name: duplicateName, @@ -256,7 +256,7 @@ func (s *KnowledgebaseService) UpdateKB(req *UpdateKBRequest, userID string) (ma } now := time.Now().Unix() - nowDate := time.Now() + nowDate := time.Now().Truncate(time.Second) updates["update_time"] = now updates["update_date"] = nowDate diff --git a/internal/service/user.go b/internal/service/user.go index 5abcec2fe2..dbdb3db847 100644 --- a/internal/service/user.go +++ b/internal/service/user.go @@ -150,7 +150,7 @@ func (s *UserService) Register(req *RegisterRequest) (*model.User, common.ErrorC now := time.Now().Unix() user.CreateTime = &now user.UpdateTime = &now - now_date := time.Now() + now_date := time.Now().Truncate(time.Second) user.CreateDate = &now_date user.UpdateDate = &now_date user.LastLoginTime = &now_date @@ -343,7 +343,7 @@ func (s *UserService) LoginByEmail(req *EmailLoginRequest, adminLogin bool) (*mo now := time.Now().Unix() user.UpdateTime = &now - now_date := time.Now() + now_date := time.Now().Truncate(time.Second) user.UpdateDate = &now_date if err := s.userDAO.Update(user); err != nil { return nil, common.CodeServerError, fmt.Errorf("failed to update user: %w", err) diff --git a/web/vite.config.ts b/web/vite.config.ts index 4e0f5f0989..bca290b2f5 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -30,6 +30,83 @@ const inspectorBabelPlugin = (): import('vite').Plugin => ({ export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), ''); + const proxySchemes = { + python: { + '/api/v1/admin': { + target: 'http://127.0.0.1:9381/', + changeOrigin: true, + ws: true, + }, + '/api': { + target: 'http://127.0.0.1:9380/', + changeOrigin: true, + ws: true, + }, + '/v1': { + target: 'http://127.0.0.1:9380/', + changeOrigin: true, + ws: true, + }, + }, + hybrid: { + '/v1/system/config': { + target: 'http://127.0.0.1:9384/', + changeOrigin: true, + ws: true, + }, + '/v1/user/login': { + target: 'http://127.0.0.1:9384/', + changeOrigin: true, + ws: true, + }, + '/v1/user/logout': { + target: 'http://127.0.0.1:9384/', + changeOrigin: true, + ws: true, + }, + '/api/v1/admin/sandbox': { + target: 'http://127.0.0.1:9381/', + changeOrigin: true, + ws: true, + }, + '/api/v1/admin': { + target: 'http://127.0.0.1:9385/', + changeOrigin: true, + ws: true, + }, + '/api': { + target: 'http://127.0.0.1:9380/', + changeOrigin: true, + ws: true, + }, + '/v1': { + target: 'http://127.0.0.1:9380/', + changeOrigin: true, + ws: true, + }, + }, + go: { + '/api/v1/admin': { + target: 'http://127.0.0.1:9385/', + changeOrigin: true, + ws: true, + }, + '/api': { + target: 'http://127.0.0.1:9384/', + changeOrigin: true, + ws: true, + }, + '/v1': { + target: 'http://127.0.0.1:9384/', + changeOrigin: true, + ws: true, + }, + }, + }; + + const proxy = + proxySchemes[env.API_PROXY_SCHEME || 'python'] || proxySchemes.python; + return { plugins: [ inspectorBabelPlugin(), @@ -85,38 +162,7 @@ export default defineConfig(({ mode }) => { hmr: { overlay: false, }, - proxy: { - '/api/v1/admin': { - target: 'http://127.0.0.1:9381/', - changeOrigin: true, - ws: true, - }, - '/api': { - target: 'http://127.0.0.1:9380/', - changeOrigin: true, - ws: true, - }, - // '/v1/system/config': { - // target: 'http://127.0.0.1:9382/', - // changeOrigin: true, - // ws: true, - // }, - // '/v1/user/login': { - // target: 'http://127.0.0.1:9382/', - // changeOrigin: true, - // ws: true, - // }, - // '/v1/user/logout': { - // target: 'http://127.0.0.1:9382/', - // changeOrigin: true, - // ws: true, - // }, - '/v1': { - target: 'http://127.0.0.1:9380/', - changeOrigin: true, - ws: true, - }, - }, + proxy, }, assetsInclude: ['**/*.md'], base: env.VITE_BASE_URL,