gig-gitignore工具实战开发(四):使用ai辅助生成gitignore
文章目录
- gig-gitignore工具实战开发(四):使用ai辅助生成gitignore
-
- ai配置
- 编写promot
- 流失响应
gig-gitignore工具实战开发(四):使用ai辅助生成gitignore
✨ 前言: 在上一篇我们编写了gig add命令基础代码,下面详细介绍ai生成模板代码。
ai配置
由于ai模型众多,这里我们采用最简单的方案,兼容openai的api规范,提供base_url修改,这样无需和一个个模型提供商进行对接。
引导用户进行ai配置输入
func runInteractiveConfig() {fmt.Println(\"Entering interactive configuration mode...\")// Prompt for API KeypromptAPIKey := promptui.Prompt{Label: \"OpenAI API Key\",Default: viper.GetString(\"ai.api_key\"),Mask: \'*\',}apiKey, err := promptAPIKey.Run()if err != nil {fmt.Printf(\"Prompt failed %v\\n\", err)os.Exit(1)}viper.Set(\"ai.api_key\", apiKey)// Prompt for AI URLpromptURL := promptui.Prompt{Label: \"AI Service URL\",Default: viper.GetString(\"ai.url\"),}apiURL, err := promptURL.Run()if err != nil {fmt.Printf(\"Prompt failed %v\\n\", err)os.Exit(1)}viper.Set(\"ai.url\", apiURL)// Prompt for AI ModelpromptModel := promptui.Prompt{Label: \"AI Model\",Default: viper.GetString(\"ai.model\"),}model, err := promptModel.Run()if err != nil {fmt.Printf(\"Prompt failed %v\\n\", err)os.Exit(1)}viper.Set(\"ai.model\", model)saveConfig()}
存储
func saveConfig() {// Get the config file path from vipercfgFile := viper.ConfigFileUsed()if cfgFile == \"\" {// If no config file is used, create one in the default pathhome, err := os.UserHomeDir()if err != nil {fmt.Println(\"Error finding home directory:\", err)os.Exit(1)}cfgFile = filepath.Join(home, \".ciclebyte\", \"gig\", \"config\", \"config.yaml\")}if err := viper.WriteConfigAs(cfgFile); err != nil {fmt.Println(\"Error writing configuration file:\", err)os.Exit(1)}fmt.Println(\"Configuration saved successfully to\", cfgFile)}
编写promot
编写promot,让ai生成符合要求的gitignore文件
You are an expert assistant specializing in generating high-quality .gitignore files. Your task is to create a .gitignore file for a project based on the provided languages and frameworks. 1. **Content**: The file MUST only contain rules for the following languages/frameworks: %s. 2. **Structure**: Organize the rules into logical categories (e.g., \"Dependencies\", \"Build output\", \"Logs\", \"IDE files\"). 3. **Headers**: Each category MUST start with a header formatted exactly as \'# === Category Name ===\', followed by a blank line. 4. **Comments**: Add concise comments (starting with \'#\') to explain the purpose of non-obvious rules or groups of rules. 5. **Exclusivity**: Do NOT include rules for any other languages, frameworks, or tools not specified. 6. **Output Format**: Your response MUST be ONLY the raw text content of the .gitignore file. Do NOT include any introductory text, explanations, or markdown code blocks like ` + \"`\" + ` ` + \"`\" + ` or ` + \"`\" + ` ` + \"`\" + `gitignore. `
流失响应
根据配置的ai模型、promot返回生成的gitignore文件内容
// 通用流式AI请求,返回完整内容func (AIUtil) StreamChat(promptType string, vars ...string) (string, error) {apiKey := viper.GetString(\"ai.api_key\")if apiKey == \"\" {fmt.Println(\"AI API Key is not configured. Please run \'gig config\' or设置 GIG_AI_API_KEY.\")os.Exit(1)}apiURL := viper.GetString(\"ai.url\")model := viper.GetString(\"ai.model\")promptTpl := models.AppConfig.Prompts[promptType]anyVars := make([]any, len(vars))for i, v := range vars {anyVars[i] = v}prompt := fmt.Sprintf(promptTpl, anyVars...)reqBody, err := json.Marshal(models.OpenAIRequest{Model: model,Messages: []models.Message{{Role: \"user\", Content: prompt}},Stream: true,})if err != nil {return \"\", err}req, err := http.NewRequest(\"POST\", apiURL, bytes.NewBuffer(reqBody))if err != nil {return \"\", err}req.Header.Set(\"Content-Type\", \"application/json\")req.Header.Set(\"Authorization\", \"Bearer \"+apiKey)client := &http.Client{}resp, err := client.Do(req)if err != nil {return \"\", err}defer resp.Body.Close()if resp.StatusCode != http.StatusOK {bodyBytes, _ := ioutil.ReadAll(resp.Body)return \"\", fmt.Errorf(\"AI service returned %d: %s\", resp.StatusCode, string(bodyBytes))}var fullContent strings.Builderreader := bufio.NewReader(resp.Body)for {line, err := reader.ReadString(\'\\n\')if err != nil {if err == io.EOF {break}return \"\", err}if strings.HasPrefix(line, \"data: \") {data := strings.TrimPrefix(line, \"data: \")if strings.TrimSpace(data) == \"[DONE]\" {break}var streamResp models.OpenAIStreamResponseif err := json.Unmarshal([]byte(data), &streamResp); err == nil {if len(streamResp.Choices) > 0 {content := streamResp.Choices[0].Delta.Contentfmt.Print(content) // 实时输出fullContent.WriteString(content)}}}}return fullContent.String(), nil}// 建议流式返回切片func (AIUtil) StreamSuggestions(promptType string, vars ...string) ([]string, error) {content, err := AI.StreamChat(promptType, vars...)if err != nil {return nil, err}return strings.Split(strings.TrimSpace(content), \"\\n\"), nil}