internal/ and libs/ were split into 9 single-package Go modules, held together by 22 replace directives across 7 go.mod files. The module boundaries bought nothing: internal/dto, internal/browser and internal/migrations were already plain packages in the root module and worked fine. Delete the 9 go.mod/go.sum pairs so those packages belong to the root github.com/jobs-scraper module. Import paths are unchanged -- github.com/jobs-scraper/internal/domain resolves identically whether it is its own module or a package inside the root module -- so no .go file is touched by this commit. Each deployable module now needs one require + one replace on the root module instead of four to six: go.work entries: 14 -> 5 replace directives: 22 -> 4 go.mod files: 14 -> 5 Dependency versions are deliberately held at their previous pins. A bare go mod tidy resolved several to latest once the per-package constraints were gone (lib/pq 1.10.9 -> 1.12.3, amqp091-go 1.10.0 -> 1.13.0, migrate 4.19.0 -> 4.19.1, go-openai 1.41.2 -> 1.42.0, genai 1.39.0 -> 1.66.0); all five are pinned back, since a structural refactor should not move dependency versions. Side effect worth noting: `go build ./...` at the repo root previously matched only 2 packages, because everything else sat behind a module boundary. It now covers all 12 shared packages, so the build and vet steps in .forgejo/workflows/ actually exercise the shared code. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| interface.go | ||
| openai.go | ||
| README.md | ||
OpenAI Service
This package provides an OpenAI-powered service for job analysis and CV generation using the official OpenAI Go SDK.
Features
- Job Analysis: Analyze job descriptions against CVs to determine fit and provide recommendations
- CV Generation: Create tailored CVs based on job descriptions
- Cover Letter Generation: Generate personalized cover letters
Setup
- Install the OpenAI Go SDK:
go get github.com/sashabaranov/go-openai
- Set your OpenAI API key as an environment variable:
export OPENAI_API_KEY="your-api-key-here"
- (Optional) Set a custom base URL:
export OPENAI_BASE_URL="https://your-custom-endpoint.com/v1"
Usage
Basic Job Analysis
package main
import (
"fmt"
"os"
"github.com/jobs-scraper/internal/domain"
"github.com/jobs-scraper/internal/openai"
)
func main() {
// Create service
apiKey := os.Getenv("OPENAI_API_KEY")
service := openai.NewOpenAIService(apiKey, "gpt-4o-mini")
// Prepare job description
jobDesc := domain.JobDescription{
JobID: 1,
Description: "Looking for a Go developer...",
Criteria: map[string]string{
"experience": "5+ years",
"languages": "Go, JavaScript",
},
}
// Analyze job
result, err := service.AnalyzeJobDescription(cv, jobDesc)
if err != nil {
panic(err)
}
fmt.Printf("Should apply: %t\n", result.ShouldApply())
fmt.Printf("Confidence: %d%%\n", result.ConfidenceScore)
}
Using Custom Base URL
You can configure a custom base URL in two ways:
Method 1: Environment Variable
export OPENAI_BASE_URL="https://api.openai-proxy.com/v1"
# Service will automatically use this URL
service := openai.NewOpenAIService(apiKey, "gpt-4o-mini")
Method 2: Direct Parameter
// Use a custom base URL directly
service := openai.NewOpenAIServiceWithBaseURL(apiKey, "gpt-4o-mini", "https://api.openai-proxy.com/v1")
// Or use Azure OpenAI
service := openai.NewOpenAIServiceWithBaseURL(apiKey, "gpt-4", "https://your-resource.openai.azure.com/")
Generate Tailored CV
tailoredCV, err := service.GenerateCV(originalCV, jobDesc)
if err != nil {
panic(err)
}
fmt.Println(tailoredCV)
Generate Cover Letter
coverLetter, err := service.GenerateCoverLetter(cv, jobDesc, "Tech Company Inc")
if err != nil {
panic(err)
}
fmt.Println(coverLetter)
Models
The service supports all OpenAI models. Common choices:
gpt-4o-mini- Cost-effective, good performance (default)gpt-4o- Higher quality, more expensivegpt-3.5-turbo- Fastest, most cost-effective
Environment Variables
OPENAI_API_KEY- Your OpenAI API key (required)OPENAI_BASE_URL- Custom base URL for OpenAI API (optional)OPENAI_MODEL- Default model to use (optional)
Response Structure
JobAnalysisResult
type JobAnalysisResult struct {
Recommendation string // "apply" or "do_not_apply"
ConfidenceScore int // 0-100
MatchingSkills []string
MissingSkills []string
ExperienceMatch string // "excellent", "good", "fair", "poor"
Summary string
ImprovementSuggestions []string
}
Error Handling
The service handles common errors:
- API authentication issues
- Rate limiting
- Invalid JSON responses
- Network timeouts
Always check for errors when calling service methods.
Testing
Run the example test:
cd internal/pkg/openai
go test -v
Make sure to set OPENAI_API_KEY environment variable before running tests that make actual API calls.