Files
ai_job_chat_agent/internal/client/job_client.go
2026-01-12 15:45:22 +08:00

177 lines
4.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package client
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"net/url"
"qd-sc/internal/config"
"qd-sc/internal/model"
"strconv"
)
// JobClient 岗位API客户端
type JobClient struct {
baseURL string
httpClient *http.Client
logLevel string
locationMap map[string]string // 区域代码到名称的映射
}
// NewJobClient 创建岗位API客户端
func NewJobClient(cfg *config.Config) *JobClient {
// 构建区域代码到名称的映射(反转配置中的映射)
locationMap := make(map[string]string)
for name, code := range cfg.City.AreaCodes {
locationMap[code] = name
}
return &JobClient{
baseURL: cfg.JobAPI.BaseURL,
httpClient: NewHTTPClient(HTTPClientConfig{Timeout: cfg.JobAPI.Timeout, MaxIdleConns: 100, MaxIdleConnsPerHost: 50, MaxConnsPerHost: 0}),
logLevel: cfg.Logging.Level,
locationMap: locationMap,
}
}
// QueryJobs 查询岗位
func (c *JobClient) QueryJobs(req *model.JobQueryRequest) (*model.JobAPIResponse, error) {
// 构建请求URL
params := url.Values{}
params.Set("current", strconv.Itoa(req.Current))
params.Set("pageSize", strconv.Itoa(req.PageSize))
if req.JobTitle != "" {
params.Set("jobTitle", req.JobTitle)
}
if req.Latitude != "" {
params.Set("latitude", req.Latitude)
}
if req.Longitude != "" {
params.Set("longitude", req.Longitude)
}
if req.Radius != "" {
params.Set("radius", req.Radius)
}
if req.Order != "" {
params.Set("order", req.Order)
}
if req.MinSalary != "" {
params.Set("minSalary", req.MinSalary)
}
if req.MaxSalary != "" {
params.Set("maxSalary", req.MaxSalary)
}
if req.Experience != "" {
params.Set("experience", req.Experience)
}
if req.Education != "" {
params.Set("education", req.Education)
}
if req.CompanyNature != "" {
params.Set("companyNature", req.CompanyNature)
}
if req.JobLocationAreaCode != "" {
params.Set("jobLocationAreaCode", req.JobLocationAreaCode)
}
reqURL := fmt.Sprintf("%s?%s", c.baseURL, params.Encode())
httpReq, err := http.NewRequest("GET", reqURL, nil)
if err != nil {
return nil, fmt.Errorf("创建HTTP请求失败: %w", err)
}
httpReq.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(httpReq)
if err != nil {
return nil, fmt.Errorf("HTTP请求失败: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("API返回错误状态码 %d: %s", resp.StatusCode, string(body))
}
// 读取响应体用于日志和解析
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应失败: %w", err)
}
// 打印原始响应仅在debug级别时显示完整响应否则显示摘要
if c.logLevel == "debug" {
log.Printf("岗位API原始响应: %s", string(body))
} else {
// 非debug模式下显示响应摘要
if len(body) > 200 {
log.Printf("岗位API响应摘要: %s... (共%d字节)", string(body[:200]), len(body))
} else {
log.Printf("岗位API响应: %s", string(body))
}
}
var result model.JobAPIResponse
if err := json.Unmarshal(body, &result); err != nil {
return nil, fmt.Errorf("解析响应失败: %w, 原始响应: %s", err, string(body))
}
log.Printf("岗位API解析结果: Code=%d, Msg=%s, Rows数量=%d", result.Code, result.Msg, len(result.Rows))
return &result, nil
}
// FormatJobResponse 格式化岗位响应
func (c *JobClient) FormatJobResponse(apiResp *model.JobAPIResponse) *model.JobResponse {
formattedJobs := make([]model.FormattedJob, 0, len(apiResp.Rows))
for _, job := range apiResp.Rows {
// 格式化薪资
salary := "薪资面议"
if job.MinSalary > 0 || job.MaxSalary > 0 {
salary = fmt.Sprintf("%d-%d元/月", job.MinSalary, job.MaxSalary)
}
// 转换学历代码
education := model.EducationMap[job.Education]
if education == "" {
education = "学历不限"
}
// 转换经验代码
experience := model.ExperienceMap[job.Experience]
if experience == "" {
experience = "经验不限"
}
// 转换区域代码
location := c.locationMap[strconv.Itoa(job.JobLocationAreaCode)]
if location == "" {
location = "未知地区"
}
formattedJobs = append(formattedJobs, model.FormattedJob{
JobTitle: job.JobTitle,
CompanyName: job.CompanyName,
Salary: salary,
Location: location,
Education: education,
Experience: experience,
AppJobURL: job.AppJobURL,
})
}
// 如果有data字段在最后一条job中添加
if len(formattedJobs) > 0 && apiResp.Data != nil {
formattedJobs[len(formattedJobs)-1].Data = apiResp.Data
}
return &model.JobResponse{
JobListings: formattedJobs,
Data: apiResp.Data,
}
}