mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-03-05 23:57:13 +08:00
# RAGFlow Go Implementation Plan 🚀 This repository tracks the progress of porting RAGFlow to Go. We'll implement core features and provide performance comparisons between Python and Go versions. ## Implementation Checklist - [x] User Management APIs - [x] Dataset Management Operations - [x] Retrieval Test - [x] Chat Management Operations - [x] Infinity Go SDK --------- Signed-off-by: Jin Hai <haijin.chn@gmail.com> Co-authored-by: Yingfeng Zhang <yingfeng.zhang@gmail.com>
168 lines
4.1 KiB
Go
168 lines
4.1 KiB
Go
//
|
|
// Copyright 2026 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.
|
|
//
|
|
|
|
package cli
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"unicode"
|
|
)
|
|
|
|
// PrintTableSimple prints data in a simple table format
|
|
// Similar to Python's _print_table_simple
|
|
func PrintTableSimple(data []map[string]interface{}) {
|
|
if len(data) == 0 {
|
|
fmt.Println("No data to print")
|
|
return
|
|
}
|
|
|
|
// Collect all column names
|
|
columnSet := make(map[string]bool)
|
|
for _, item := range data {
|
|
for key := range item {
|
|
columnSet[key] = true
|
|
}
|
|
}
|
|
|
|
// Sort columns
|
|
columns := make([]string, 0, len(columnSet))
|
|
for col := range columnSet {
|
|
columns = append(columns, col)
|
|
}
|
|
// Simple sort - in production you might want specific column ordering
|
|
for i := 0; i < len(columns); i++ {
|
|
for j := i + 1; j < len(columns); j++ {
|
|
if columns[i] > columns[j] {
|
|
columns[i], columns[j] = columns[j], columns[i]
|
|
}
|
|
}
|
|
}
|
|
|
|
// Calculate column widths
|
|
colWidths := make(map[string]int)
|
|
for _, col := range columns {
|
|
maxWidth := getStringWidth(col)
|
|
for _, item := range data {
|
|
value := fmt.Sprintf("%v", item[col])
|
|
valueWidth := getStringWidth(value)
|
|
if valueWidth > maxWidth {
|
|
maxWidth = valueWidth
|
|
}
|
|
}
|
|
if maxWidth < 2 {
|
|
maxWidth = 2
|
|
}
|
|
colWidths[col] = maxWidth
|
|
}
|
|
|
|
// Generate separator
|
|
separatorParts := make([]string, 0, len(columns))
|
|
for _, col := range columns {
|
|
separatorParts = append(separatorParts, strings.Repeat("-", colWidths[col]+2))
|
|
}
|
|
separator := "+" + strings.Join(separatorParts, "+") + "+"
|
|
|
|
// Print header
|
|
fmt.Println(separator)
|
|
headerParts := make([]string, 0, len(columns))
|
|
for _, col := range columns {
|
|
headerParts = append(headerParts, fmt.Sprintf(" %-*s ", colWidths[col], col))
|
|
}
|
|
fmt.Println("|" + strings.Join(headerParts, "|") + "|")
|
|
fmt.Println(separator)
|
|
|
|
// Print data rows
|
|
for _, item := range data {
|
|
rowParts := make([]string, 0, len(columns))
|
|
for _, col := range columns {
|
|
value := fmt.Sprintf("%v", item[col])
|
|
valueWidth := getStringWidth(value)
|
|
// Truncate if too long
|
|
if valueWidth > colWidths[col] {
|
|
runes := []rune(value)
|
|
truncated := truncateString(runes, colWidths[col])
|
|
value = truncated
|
|
valueWidth = getStringWidth(value)
|
|
}
|
|
// Pad to column width
|
|
padding := colWidths[col] - valueWidth + len(value)
|
|
rowParts = append(rowParts, fmt.Sprintf(" %-*s ", padding, value))
|
|
}
|
|
fmt.Println("|" + strings.Join(rowParts, "|") + "|")
|
|
}
|
|
|
|
fmt.Println(separator)
|
|
}
|
|
|
|
// getStringWidth calculates the display width of a string
|
|
// Treats CJK characters as width 2
|
|
func getStringWidth(text string) int {
|
|
width := 0
|
|
for _, r := range text {
|
|
if isHalfWidth(r) {
|
|
width++
|
|
} else {
|
|
width += 2
|
|
}
|
|
}
|
|
return width
|
|
}
|
|
|
|
// isHalfWidth checks if a rune is half-width
|
|
func isHalfWidth(r rune) bool {
|
|
// ASCII printable characters and common whitespace
|
|
if r >= 0x20 && r <= 0x7E {
|
|
return true
|
|
}
|
|
if r == '\t' || r == '\n' || r == '\r' {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// truncateString truncates a string to fit within maxWidth display width
|
|
func truncateString(runes []rune, maxWidth int) string {
|
|
width := 0
|
|
for i, r := range runes {
|
|
if isHalfWidth(r) {
|
|
width++
|
|
} else {
|
|
width += 2
|
|
}
|
|
if width > maxWidth-3 {
|
|
return string(runes[:i]) + "..."
|
|
}
|
|
}
|
|
return string(runes)
|
|
}
|
|
|
|
// getMax returns the maximum of two integers
|
|
func getMax(a, b int) int {
|
|
if a > b {
|
|
return a
|
|
}
|
|
return b
|
|
}
|
|
|
|
// isWideChar checks if a character is wide (CJK, etc.)
|
|
func isWideChar(r rune) bool {
|
|
return unicode.Is(unicode.Han, r) ||
|
|
unicode.Is(unicode.Hiragana, r) ||
|
|
unicode.Is(unicode.Katakana, r) ||
|
|
unicode.Is(unicode.Hangul, r)
|
|
}
|