XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/gpt4free

Update main.go

3b626c82
H Lohaus <hlohaus@users.noreply.github.com>
提交于

代码差异

1 个文件 +64 -99
Modified g4f-go/main.go +64 -99
@@ -4,20 +4,15 @@ import (
4 4 "context"
5 5 "fmt"
6 6 "os"
7 "os/exec"
8 7 "os/signal"
8 "syscall"
9 9 "path/filepath"
10 10 "strings"
11 "syscall"
12 11 "time"
13 12 )
14 13
15 // Constants usually defined at build time or in a separate file
16 const (
17 Version = "1.0.0"
18 PythonVer = "3.10"
19 )
20
14 // main handles the `g4f-go <command>` interface. Anything unknown is forwarded
15 // to the embedded g4f CLI (so `g4f-go client "hello"` just works).
21 16 func printHelp() {
22 17 fmt.Printf(`g4f-go %s - gpt4free with embedded Python %s
23 18
@@ -36,148 +31,118 @@ Environment:
36 31 }
37 32
38 33 func main() {
39 // We use a helper function so we can use "return" for exit codes
40 os.Exit(run())
34 os.Exit(runMain())
41 35 }
42 36
43 func run() int {
37 func runMain() int {
44 38 binDir := installDir()
45 // os.Args[0] is the program name, we want the actual arguments
46 args := normalizeArgs(os.Args[1:])
47
39 args := normalizeArgs(os.Args)
48 40 if len(args) == 0 {
49 41 printHelp()
50 42 return 0
51 43 }
52 44
53 // 1. Handle non-python commands first
54 switch args[0] {
55 case "help", "--help", "-h":
56 printHelp()
57 return 0
58 case "--version", "-v":
59 fmt.Printf("g4f-go %s (embedded CPython %s)\n", Version, PythonVer)
60 return 0
61 }
62
63 // 2. Prepare Python Runtime
64 45 py, err := ensureRuntime()
65 46 if err != nil {
66 fmt.Fprintln(os.Stderr, "g4f-go runtime error:", err)
67 return 1
68 }
69
70 if os.Getenv("G4F_PYTHON_ONLY") == "1" {
71 fmt.Println(py)
72 return 0
47 fmt.Fprintln(os.Stderr, "g4f-go:", err)
48 os.Exit(1)
73 49 }
74 50
75 51 ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
76 52 defer stop()
77 53
78 // 3. Handle management commands
79 54 switch args[0] {
55 case "help", "--help", "-h":
56 printHelp()
57 return 0
58 case "--version", "-v":
59 fmt.Printf("g4f-go %s (embedded CPython %s)\n", Version, PythonVer)
60 return 0
80 61 case "status":
81 return handleStatus(ctx, binDir, py)
62 exe := pythonExecutable(binDir)
63 stamp := filepath.Join(binDir, ".g4f-runtime", ".installed")
64 fmt.Printf("binary dir: %s\n", binDir)
65 fmt.Printf("python: %s\n", exe)
66 if _, err := os.Stat(exe); err == nil {
67 fmt.Println("runtime: extracted")
68 } else {
69 fmt.Println("runtime: not extracted (will extract on first run)")
70 }
71 if _, err := os.Stat(stamp); err == nil {
72 fmt.Println("g4f: installed")
73 } else {
74 fmt.Println("g4f: not installed (will install on first run)")
75 }
76 code, err := runPython(ctx, py, []string{"--version"})
77 if err != nil {
78 fmt.Fprintln(os.Stderr, "g4f-go:", err)
79 return 1
80 }
81 return code
82 82 case "install", "uninstall":
83 83 if len(args) < 2 {
84 fmt.Fprintln(os.Stderr, "usage: g4f-go install <package>")
84 fmt.Fprintln(os.Stderr, "usage: g4f-go install g4f")
85 85 return 2
86 86 }
87 code, err := runPython(ctx, py, append([]string{"-m", "pip"}, args...))
87 code, err := runPython(ctx, py, []string{
88 "-m", "pip", args...
89 })
88 90 if err != nil {
89 91 fmt.Fprintln(os.Stderr, "g4f-go:", err)
92 return 1
90 93 }
91 94 return code
92 95 case "bootstrap":
96 // Refresh the embedded package installation (e.g. after updating g4f-go).
93 97 code, err := runPython(ctx, py, []string{"-m", "pip", "install", "--no-input", "g4f[slim]"}, pipEnv(binDir)...)
94 98 if err != nil {
95 99 fmt.Fprintln(os.Stderr, "g4f-go:", err)
100 return 1
96 101 }
97 102 return code
98 103 }
99 104
100 // 4. Auto-install G4F if missing before running commands
105 if os.Getenv("G4F_PYTHON_ONLY") == "1" {
106 fmt.Println(py)
107 return 0
108 }
109
101 110 exe := pythonExecutable(binDir)
102 if err := installG4F(binDir, exe, time.Now()); err != nil {
111 start := time.Now()
112 if err := installG4F(binDir, exe, start); err != nil {
103 113 fmt.Fprintln(os.Stderr, "g4f-go:", err)
104 114 return 1
105 115 }
106 116
107 // 5. Default: forward everything to the g4f module
117 // Default: forward everything to the g4f module.
108 118 code, err := runPython(ctx, py, append([]string{"-m", "g4f"}, args...))
109 119 if err != nil {
110 fmt.Fprintln(os.Stderr, "g4f-go execution error:", err)
120 fmt.Fprintln(os.Stderr, "g4f-go:", err)
111 121 return 1
112 122 }
113 123 return code
114 124 }
115 125
116 // --- Helper Functions (Stubs/Implementations) ---
117
126 // normalizeArgs cleans leading `g4f-go` repeats (typos like `g4f-go g4f-go ...`).
118 127 func normalizeArgs(args []string) []string {
119 if len(args) > 0 && args[0] == "g4f-go" {
120 return normalizeArgs(args[1:])
128 for len(args) > 0 && args[0] == "g4f-go" {
129 args = args[1:]
121 130 }
131 // A leading binary-name echo (e.g. argv[0]) is stripped by callers.
122 132 return args
123 133 }
124 134
125 func installDir() string {
126 configDir, _ := os.UserConfigDir()
127 return filepath.Join(configDir, "g4f-go")
128 }
129
130 func pythonExecutable(binDir string) string {
131 // Adjust for Windows if necessary
132 return filepath.Join(binDir, "python")
133 }
134
135 func ensureRuntime() (string, error) {
136 dir := installDir()
137 pyPath := pythonExecutable(dir)
138 // Logic to extract embedded python would go here
139 if _, err := os.Stat(dir); os.IsNotExist(err) {
140 os.MkdirAll(dir, 0755)
135 // hasSubcommand reports whether args start with a known g4f-go subcommand.
136 func hasSubcommand(args []string) bool {
137 if len(args) == 0 {
138 return true
141 139 }
142 return pyPath, nil
143 }
144
145 func runPython(ctx context.Context, pyPath string, args []string, env ...string) (int, error) {
146 cmd := exec.CommandContext(ctx, pyPath, args...)
147 cmd.Stdout = os.Stdout
148 cmd.Stderr = os.Stderr
149 cmd.Stdin = os.Stdin
150 cmd.Env = append(os.Environ(), env...)
151
152 err := cmd.Run()
153 if err != nil {
154 if exitError, ok := err.(*exec.ExitError); ok {
155 return exitError.ExitCode(), nil
156 }
157 return 1, err
140 switch args[0] {
141 case "help", "--help", "-h", "--version", "-v", "status", "install", "bootstrap":
142 return true
158 143 }
159 return 0, nil
160 }
161
162 func installG4F(binDir, pyExe string, start time.Time) error {
163 stamp := filepath.Join(binDir, ".g4f_installed")
164 if _, err := os.Stat(stamp); err == nil {
165 return nil // Already installed
144 if strings.HasPrefix(args[0], "-") {
145 return true
166 146 }
167 // Logic to install g4f via pip
168 os.WriteFile(stamp, []byte(start.String()), 0644)
169 return nil
170 }
171
172 func pipEnv(binDir string) []string {
173 return []string{fmt.Sprintf("PYTHONPATH=%s", binDir)}
174 }
175
176 func handleStatus(ctx context.Context, binDir, py string) int {
177 exe := pythonExecutable(binDir)
178 fmt.Printf("binary dir: %s\n", binDir)
179 fmt.Printf("python: %s\n", exe)
180
181 code, _ := runPython(ctx, py, []string{"--version"})
182 return code
147 return false
183 148 }