├── go.mod ├── internal ├── .DS_Store ├── ai │ ├── .DS_Store │ ├── azureai │ │ ├── .DS_Store │ │ └── azureai.go │ └── openai │ │ └── openai.go ├── markdown │ └── markdown.go └── scanner │ └── scanner.go ├── config.json ├── scanner.go ├── config ├── ascii.go └── config.go ├── README.md └── main.go /go.mod: -------------------------------------------------------------------------------- 1 | module source-code-review 2 | 3 | go 1.23.2 4 | -------------------------------------------------------------------------------- /internal/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecFathy/Flash/HEAD/internal/.DS_Store -------------------------------------------------------------------------------- /internal/ai/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecFathy/Flash/HEAD/internal/ai/.DS_Store -------------------------------------------------------------------------------- /internal/ai/azureai/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SecFathy/Flash/HEAD/internal/ai/azureai/.DS_Store -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "azure_openai": { 3 | "endpoint": "", 4 | "api_key": "", 5 | "deployment_name": "", 6 | "api_version": "" 7 | }, 8 | "openai": { 9 | "api_key": "your-openai-api-key" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /internal/markdown/markdown.go: -------------------------------------------------------------------------------- 1 | package markdown 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | ) 7 | 8 | func SaveMarkdown(fileName string, content string) error { 9 | filePath := fmt.Sprintf("%s.md", fileName) 10 | return os.WriteFile(filePath, []byte(content), 0644) 11 | } 12 | -------------------------------------------------------------------------------- /scanner.go: -------------------------------------------------------------------------------- 1 | package scanner 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | ) 7 | 8 | func ScanFile(filePath string) (string, error) { 9 | content, err := os.ReadFile(filePath) 10 | if err != nil { 11 | return "", err 12 | } 13 | 14 | return string(content), nil 15 | } 16 | 17 | func ScanDirectory(dirPath string) ([]string, error) { 18 | var files []string 19 | 20 | err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error { 21 | if !info.IsDir() && filepath.Ext(path) == ".go" { 22 | files = append(files, path) 23 | } 24 | return nil 25 | }) 26 | 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | return files, nil 32 | } 33 | -------------------------------------------------------------------------------- /internal/scanner/scanner.go: -------------------------------------------------------------------------------- 1 | package scanner 2 | 3 | import ( 4 | "os" 5 | "path/filepath" 6 | ) 7 | 8 | func ScanFile(filePath string) (string, error) { 9 | content, err := os.ReadFile(filePath) 10 | if err != nil { 11 | return "", err 12 | } 13 | 14 | return string(content), nil 15 | } 16 | 17 | func ScanDirectory(dirPath string) ([]string, error) { 18 | var files []string 19 | 20 | err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error { 21 | if !info.IsDir() && filepath.Ext(path) == ".go" { 22 | files = append(files, path) 23 | } 24 | return nil 25 | }) 26 | 27 | if err != nil { 28 | return nil, err 29 | } 30 | 31 | return files, nil 32 | } 33 | -------------------------------------------------------------------------------- /config/ascii.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "fmt" 4 | 5 | const ( 6 | Yellow = "\033[33m" // Yellow color for normal information 7 | Red = "\033[31m" // Red color for warnings and errors 8 | Reset = "\033[0m" // Reset the color 9 | ) 10 | 11 | func Info(message string) { 12 | fmt.Printf("%s[INF] %s%s\n", Yellow, message, Reset) 13 | } 14 | func Warn(message string) { 15 | fmt.Printf("%s[WRN] %s%s\n", Red, message, Reset) 16 | } 17 | func ShowASCII() { 18 | asciiArt := ` 19 | _____ __ _____ _____ _____ 20 | | __| | | _ | __| | | 21 | | __| |__| |__ | | 22 | |__| |_____|__|__|_____|__|__| v1.0.1 23 | 24 | By Mohammed Fathy @Secfathy` 25 | fmt.Println(asciiArt) 26 | fmt.Println("") 27 | } 28 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | // Config structure to hold all credentials 10 | type Config struct { 11 | AzureOpenAI struct { 12 | Endpoint string `json:"endpoint"` 13 | APIKey string `json:"api_key"` 14 | DeploymentName string `json:"deployment_name"` 15 | APIVersion string `json:"api_version"` 16 | } `json:"azure_openai"` 17 | OpenAI struct { 18 | APIKey string `json:"api_key"` 19 | } `json:"openai"` 20 | } 21 | 22 | // LoadConfig loads the configuration from a JSON file 23 | func LoadConfig(configFilePath string) (*Config, error) { 24 | file, err := os.Open(configFilePath) 25 | if err != nil { 26 | return nil, fmt.Errorf("error opening config file: %v", err) 27 | } 28 | defer file.Close() 29 | 30 | var config Config 31 | decoder := json.NewDecoder(file) 32 | err = decoder.Decode(&config) 33 | if err != nil { 34 | return nil, fmt.Errorf("error decoding config file: %v", err) 35 | } 36 | 37 | return &config, nil 38 | } 39 | -------------------------------------------------------------------------------- /internal/ai/openai/openai.go: -------------------------------------------------------------------------------- 1 | package openai 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "net/http" 9 | "time" 10 | ) 11 | 12 | type Client struct { 13 | APIKey string 14 | HTTPClient *http.Client 15 | } 16 | 17 | type Message struct { 18 | Role string `json:"role"` 19 | Content string `json:"content"` 20 | } 21 | 22 | type ChatRequest struct { 23 | Model string `json:"model"` 24 | Messages []Message `json:"messages"` 25 | MaxTokens int `json:"max_tokens"` 26 | Temperature float64 `json:"temperature"` 27 | } 28 | 29 | type ChatResponse struct { 30 | Choices []struct { 31 | Message struct { 32 | Content string `json:"content"` 33 | } `json:"message"` 34 | } `json:"choices"` 35 | } 36 | 37 | // NewClient initializes a new OpenAI ChatGPT client. 38 | func NewClient(apiKey string) (*Client, error) { 39 | if apiKey == "" { 40 | return nil, fmt.Errorf("API key must be provided") 41 | } 42 | 43 | httpClient := &http.Client{ 44 | Timeout: 30 * time.Second, 45 | } 46 | 47 | return &Client{ 48 | APIKey: apiKey, 49 | HTTPClient: httpClient, 50 | }, nil 51 | } 52 | 53 | // Chat sends a request to the OpenAI API. 54 | func (c *Client) Chat(messages []Message, model string, maxTokens int, temperature float64) (string, error) { 55 | url := "https://api.openai.com/v1/chat/completions" 56 | 57 | requestBody := ChatRequest{ 58 | Model: model, 59 | Messages: messages, 60 | MaxTokens: maxTokens, 61 | Temperature: temperature, 62 | } 63 | 64 | jsonBody, err := json.Marshal(requestBody) 65 | if err != nil { 66 | return "", fmt.Errorf("error marshaling request: %v", err) 67 | } 68 | 69 | req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody)) 70 | if err != nil { 71 | return "", fmt.Errorf("error creating request: %v", err) 72 | } 73 | 74 | req.Header.Set("Content-Type", "application/json") 75 | req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.APIKey)) 76 | 77 | resp, err := c.HTTPClient.Do(req) 78 | if err != nil { 79 | return "", fmt.Errorf("error sending request: %v", err) 80 | } 81 | defer resp.Body.Close() 82 | 83 | body, err := io.ReadAll(resp.Body) 84 | if err != nil { 85 | return "", fmt.Errorf("error reading response: %v", err) 86 | } 87 | 88 | if resp.StatusCode != http.StatusOK { 89 | return "", fmt.Errorf("unexpected status code: %d, body: %s", resp.StatusCode, string(body)) 90 | } 91 | 92 | var chatResponse ChatResponse 93 | if err := json.Unmarshal(body, &chatResponse); err != nil { 94 | return "", fmt.Errorf("error unmarshaling response: %v", err) 95 | } 96 | 97 | if len(chatResponse.Choices) == 0 { 98 | return "", fmt.Errorf("no choices in response") 99 | } 100 | 101 | return chatResponse.Choices[0].Message.Content, nil 102 | } 103 | -------------------------------------------------------------------------------- /internal/ai/azureai/azureai.go: -------------------------------------------------------------------------------- 1 | package azureai 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "io" 8 | "net/http" 9 | "time" 10 | ) 11 | 12 | type Client struct { 13 | Endpoint string 14 | APIKey string 15 | DeploymentName string 16 | APIVersion string 17 | HTTPClient *http.Client 18 | } 19 | 20 | type Message struct { 21 | Role string `json:"role"` 22 | Content string `json:"content"` 23 | } 24 | 25 | type ChatRequest struct { 26 | Messages []Message `json:"messages"` 27 | MaxTokens int `json:"max_tokens"` 28 | Temperature float64 `json:"temperature"` 29 | } 30 | 31 | type ChatResponse struct { 32 | Choices []struct { 33 | Message struct { 34 | Content string `json:"content"` 35 | } `json:"message"` 36 | } `json:"choices"` 37 | } 38 | 39 | // NewClient initializes a new Azure AI client. 40 | func NewClient(endpoint, apiKey, deploymentName, apiVersion string) (*Client, error) { 41 | if endpoint == "" || apiKey == "" || deploymentName == "" || apiVersion == "" { 42 | return nil, fmt.Errorf("all parameters must be provided") 43 | } 44 | 45 | httpClient := &http.Client{ 46 | Timeout: 30 * time.Second, 47 | } 48 | 49 | return &Client{ 50 | Endpoint: endpoint, 51 | APIKey: apiKey, 52 | DeploymentName: deploymentName, 53 | APIVersion: apiVersion, 54 | HTTPClient: httpClient, 55 | }, nil 56 | } 57 | 58 | // Chat sends a request to Azure OpenAI. 59 | func (c *Client) Chat(messages []Message, maxTokens int, temperature float64) (string, error) { 60 | url := fmt.Sprintf("%s/openai/deployments/%s/chat/completions?api-version=%s", c.Endpoint, c.DeploymentName, c.APIVersion) 61 | 62 | requestBody := ChatRequest{ 63 | Messages: messages, 64 | MaxTokens: maxTokens, 65 | Temperature: temperature, 66 | } 67 | 68 | jsonBody, err := json.Marshal(requestBody) 69 | if err != nil { 70 | return "", fmt.Errorf("error marshaling request: %v", err) 71 | } 72 | 73 | req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody)) 74 | if err != nil { 75 | return "", fmt.Errorf("error creating request: %v", err) 76 | } 77 | 78 | req.Header.Set("Content-Type", "application/json") 79 | req.Header.Set("api-key", c.APIKey) 80 | 81 | resp, err := c.HTTPClient.Do(req) 82 | if err != nil { 83 | return "", fmt.Errorf("error sending request: %v", err) 84 | } 85 | defer resp.Body.Close() 86 | 87 | body, err := io.ReadAll(resp.Body) 88 | if err != nil { 89 | return "", fmt.Errorf("error reading response: %v", err) 90 | } 91 | 92 | if resp.StatusCode != http.StatusOK { 93 | return "", fmt.Errorf("unexpected status code: %d, body: %s", resp.StatusCode, string(body)) 94 | } 95 | 96 | var chatResponse ChatResponse 97 | if err := json.Unmarshal(body, &chatResponse); err != nil { 98 | return "", fmt.Errorf("error unmarshaling response: %v", err) 99 | } 100 | 101 | if len(chatResponse.Choices) == 0 { 102 | return "", fmt.Errorf("no choices in response") 103 | } 104 | 105 | return chatResponse.Choices[0].Message.Content, nil 106 | } 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |