Skip to content

Commit

Permalink
Added support for OpenSERP API
Browse files Browse the repository at this point in the history
  • Loading branch information
shadowy-pycoder committed Nov 20, 2024
1 parent a0578d1 commit c49a391
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 11 deletions.
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ CGO_ENABLED=0 go install -ldflags "-s -w" -trimpath github.com/shadowy-pycoder/g
This will install the `goso` binary to your `$GOPATH/bin` directory.


## Search Engine Setup

This tool uses [Custom Search JSON API](https://developers.google.com/custom-search/v1/overview) from Google to obtain most relevant results from Stack Overflow. So, to make it work, you need to obtain an API key from Google and also a [Search Engine ID](https://developers.google.com/custom-search/v1/overview#search_engine_id).
### Google Search JSON API
This approach employs [Custom Search JSON API](https://developers.google.com/custom-search/v1/overview) from Google to obtain most relevant results from Stack Overflow. So, to make it work, you need to get an API key from Google and also a [Search Engine ID](https://developers.google.com/custom-search/v1/overview#search_engine_id). That gives you `100 requests per day`, which I believe is enough for most use cases.

Setup your `Search Engine ID` like this:

Expand All @@ -39,6 +41,33 @@ echo "export GOSO_API_KEY=<YOUR_API_KEY>" >> $HOME/.profile
echo "export GOSO_SE=<YOUR_SEARCH_ENGINE_ID>" >> $HOME/.profile
source $HOME/.profile
```

### OpenSerp API
`goso` also supports [OpenSERP (Search Engine Results Page)](https://github.com/karust/openserp) from [Karust](https://github.com/karust). This is a completely *FREE* alternative to the Google Search JSON API, though it works a little bit slower, but gives basically the same results.

So, to make it work, you need tu run OperSERP server locally. You can do it like this:

With Docker:
```shell
docker run -p 127.0.0.1:7000:7000 -it karust/openserp serve -a 0.0.0.0 -p 7000
```

Or as a CLI command:

```shell
openserp serve
```
You can learn more on how to install OpenSERP [here](https://github.com/karust/openserp).

Once you have it running, add variables to your environment:
```shell
echo "export GOSO_OS_HOST=127.0.0.1" >> $HOME/.profile
echo "export GOSO_OS_PORT=7000" >> $HOME/.profile
source $HOME/.profile
```
These variables will have priority over the `GOSO_API_KEY` and `GOSO_SE`.


## Usage

```shell
Expand Down
33 changes: 23 additions & 10 deletions cmd/goso/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,21 +104,34 @@ func root(args []string) error {
return fmt.Errorf("-a should be within [min=1, max=10]")
}
conf.AnswerNum = *aNum
apiKey, set := os.LookupEnv("GOSO_API_KEY")
if !set {
return fmt.Errorf("api key is not set")
}
conf.ApiKey = apiKey
se, set := os.LookupEnv("GOSO_SE")
if !set {
return fmt.Errorf("search engine is not set")
var fetchFunc func(*goso.Config, map[int]*goso.Result) error
osHost, hostSet := os.LookupEnv("GOSO_OS_HOST")
osPort, portSet := os.LookupEnv("GOSO_OS_PORT")
if hostSet && portSet {
conf.OpenSerpHost = osHost
conf.OpenSerpPort, err = strconv.Atoi(osPort)
if err != nil {
return fmt.Errorf("failed parsing `GOSO_OS_PORT`")
}
fetchFunc = goso.FetchOpenSerp
} else {
apiKey, set := os.LookupEnv("GOSO_API_KEY")
if !set {
return fmt.Errorf("`GOSO_API_KEY` is not set")
}
conf.ApiKey = apiKey
se, set := os.LookupEnv("GOSO_SE")
if !set {
return fmt.Errorf("`GOSO_SE` is not set")
}
conf.SearchEngine = se
fetchFunc = goso.FetchGoogle
}
conf.SearchEngine = se
conf.Query = strings.Join(flags.Args(), " ")
if conf.Query == "" {
return fmt.Errorf("query is empty")
}
answers, err := goso.GetAnswers(conf, goso.FetchGoogle, goso.FetchStackOverflow)
answers, err := goso.GetAnswers(conf, fetchFunc, goso.FetchStackOverflow)
if err != nil {
return err
}
Expand Down
42 changes: 42 additions & 0 deletions goso.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,14 @@ type StackOverflowResult struct {
QuotaRemaining int `json:"quota_remaining"`
}

type OpenSerpResult struct {
Rank int `json:"rank"`
URL string `json:"url"`
Title string `json:"title"`
Description string `json:"description"`
Ad bool `json:"ad"`
}

type Config struct {
ApiKey string
SearchEngine string
Expand All @@ -244,6 +252,8 @@ type Config struct {
Lexer string
QuestionNum int
AnswerNum int
OpenSerpHost string
OpenSerpPort int
Client *http.Client
}
type Answer struct {
Expand Down Expand Up @@ -365,6 +375,38 @@ func FetchGoogle(conf *Config, results map[int]*Result) error {
return nil
}

func FetchOpenSerp(conf *Config, results map[int]*Result) error {
url := fmt.Sprintf("http://%s:%d/google/search?lang=EN&limit=%d&text=%s&site=stackoverflow.com",
conf.OpenSerpHost, conf.OpenSerpPort, conf.QuestionNum, netUrl.QueryEscape(conf.Query))
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return err
}
res, err := conf.Client.Do(req)
if err != nil {
return fmt.Errorf("failed connecting to OpenSerp API: check your internet connection")
}
defer res.Body.Close()
if res.StatusCode > 299 {
return fmt.Errorf("failed connecting to OpenSerp API: %s", res.Status)
}
var osResp []OpenSerpResult
err = json.NewDecoder(res.Body).Decode(&osResp)
if err != nil {
return err
}
for _, item := range osResp {
u, _ := netUrl.Parse(item.URL)
questionId, _ := strconv.Atoi(strings.Split(u.Path, "/")[2])
results[questionId] = &Result{
Title: item.Title,
Link: item.URL,
QuestionId: questionId,
}
}
return nil
}

func FetchStackOverflow(conf *Config, results map[int]*Result) error {
questions := make([]string, len(results))
var idx int
Expand Down

0 comments on commit c49a391

Please sign in to comment.