mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Add DreamDict API client for dictionary and translation lookups
Standalone HTTP client for the DreamDict service supporting word lookup, random word generation, and cross-language translation (en/fr/pt-PT). Used by hangman, lookup, and WOTD plugins. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
186
internal/dreamclient/client.go
Normal file
186
internal/dreamclient/client.go
Normal file
@@ -0,0 +1,186 @@
|
||||
package dreamclient
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Client is an HTTP client for the DreamDict dictionary service.
|
||||
type Client struct {
|
||||
baseURL string
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
// New creates a new DreamDict client.
|
||||
func New(baseURL string) *Client {
|
||||
return &Client{
|
||||
baseURL: baseURL,
|
||||
httpClient: &http.Client{Timeout: 3 * time.Second},
|
||||
}
|
||||
}
|
||||
|
||||
// Definition is a single definition entry from DreamDict.
|
||||
type Definition struct {
|
||||
POS string `json:"pos"`
|
||||
Gloss string `json:"gloss"`
|
||||
Source string `json:"source"`
|
||||
Priority int `json:"priority"`
|
||||
}
|
||||
|
||||
// HealthResponse is the response from /health.
|
||||
type HealthResponse struct {
|
||||
Status string `json:"status"`
|
||||
DBPath string `json:"db_path"`
|
||||
WordCounts map[string]int `json:"word_counts"`
|
||||
DefCounts map[string]int `json:"def_counts"`
|
||||
ImportedAt string `json:"imported_at"`
|
||||
SchemaVersion string `json:"schema_version"`
|
||||
}
|
||||
|
||||
// IsValidWord checks if a word exists in a language's word list.
|
||||
func (c *Client) IsValidWord(word, lang string) (bool, error) {
|
||||
u := c.baseURL + "/valid?" + url.Values{"word": {word}, "lang": {lang}}.Encode()
|
||||
resp, err := c.httpClient.Get(u)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("dreamdict: valid: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return false, fmt.Errorf("dreamdict: valid: status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var result struct {
|
||||
Valid bool `json:"valid"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return false, fmt.Errorf("dreamdict: valid: decode: %w", err)
|
||||
}
|
||||
return result.Valid, nil
|
||||
}
|
||||
|
||||
// RandomWord returns a random word for a language with optional filters.
|
||||
// pos can be empty. min/max of 0 means no filter.
|
||||
func (c *Client) RandomWord(lang, pos string, min, max int) (string, error) {
|
||||
params := url.Values{"lang": {lang}}
|
||||
if pos != "" {
|
||||
params.Set("pos", pos)
|
||||
}
|
||||
if min > 0 {
|
||||
params.Set("min", strconv.Itoa(min))
|
||||
}
|
||||
if max > 0 {
|
||||
params.Set("max", strconv.Itoa(max))
|
||||
}
|
||||
|
||||
u := c.baseURL + "/random?" + params.Encode()
|
||||
resp, err := c.httpClient.Get(u)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("dreamdict: random: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
return "", fmt.Errorf("dreamdict: random: no match")
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("dreamdict: random: status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var result struct {
|
||||
Word string `json:"word"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return "", fmt.Errorf("dreamdict: random: decode: %w", err)
|
||||
}
|
||||
return result.Word, nil
|
||||
}
|
||||
|
||||
// Define returns all definitions for a word in a language.
|
||||
func (c *Client) Define(word, lang string) ([]Definition, error) {
|
||||
u := c.baseURL + "/define?" + url.Values{"word": {word}, "lang": {lang}}.Encode()
|
||||
resp, err := c.httpClient.Get(u)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dreamdict: define: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("dreamdict: define: status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var result struct {
|
||||
Definitions []Definition `json:"definitions"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return nil, fmt.Errorf("dreamdict: define: decode: %w", err)
|
||||
}
|
||||
return result.Definitions, nil
|
||||
}
|
||||
|
||||
// Synonyms returns synonyms for a word in a language.
|
||||
func (c *Client) Synonyms(word, lang string) ([]string, error) {
|
||||
u := c.baseURL + "/synonyms?" + url.Values{"word": {word}, "lang": {lang}}.Encode()
|
||||
resp, err := c.httpClient.Get(u)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dreamdict: synonyms: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("dreamdict: synonyms: status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var result struct {
|
||||
Synonyms []string `json:"synonyms"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return nil, fmt.Errorf("dreamdict: synonyms: decode: %w", err)
|
||||
}
|
||||
return result.Synonyms, nil
|
||||
}
|
||||
|
||||
// Translate returns translations of a word from one language to another.
|
||||
func (c *Client) Translate(word, from, to string) ([]string, error) {
|
||||
u := c.baseURL + "/translate?" + url.Values{"word": {word}, "from": {from}, "to": {to}}.Encode()
|
||||
resp, err := c.httpClient.Get(u)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dreamdict: translate: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("dreamdict: translate: status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var result struct {
|
||||
Translations []string `json:"translations"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return nil, fmt.Errorf("dreamdict: translate: decode: %w", err)
|
||||
}
|
||||
return result.Translations, nil
|
||||
}
|
||||
|
||||
// Health checks if the DreamDict service is reachable and returns stats.
|
||||
func (c *Client) Health() (*HealthResponse, error) {
|
||||
resp, err := c.httpClient.Get(c.baseURL + "/health")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("dreamdict: health: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("dreamdict: health: status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var result HealthResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return nil, fmt.Errorf("dreamdict: health: decode: %w", err)
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user