Skip to content

Commit

Permalink
AI 功能上线
Browse files Browse the repository at this point in the history
  • Loading branch information
flycash committed Dec 1, 2024
1 parent 9040d2c commit eb6addb
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 60 deletions.
3 changes: 3 additions & 0 deletions .run/webook.run.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
<working_directory value="$PROJECT_DIR$" />
<go_parameters value="--tags=mock" />
<parameters value="--config=config/local.yaml" />
<envs>
<env name="EGO_DEBUG" value="false" />
</envs>
<kind value="PACKAGE" />
<package value="github.com/ecodeclub/webook" />
<directory value="$PROJECT_DIR$" />
Expand Down
4 changes: 2 additions & 2 deletions internal/ai/internal/domain/jd.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ const (
)

type JDEvaluation struct {
Score int `json:"score"`
Analysis string `json:"analysis"`
Score float64 `json:"score"`
Analysis string `json:"analysis"`
}

type JD struct {
Expand Down
21 changes: 12 additions & 9 deletions internal/ai/internal/integration/llm_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -643,21 +643,24 @@ func (s *LLMServiceSuite) TestHandler_AnalysisJD() {
return domain.LLMResponse{
Tokens: 1000,
Amount: 100,
Answer: `{"score": 7, "analysis": "tech"}`,
Answer: `score: 6
这是技术前景`,
}, nil
}
if request.Biz == "analysis_jd_biz" {
return domain.LLMResponse{
Tokens: 100,
Amount: 200,
Answer: `{"score": 8, "analysis": "biz"}`,
Answer: `score: 7
这是业务前景`,
}, nil
}
if request.Biz == "analysis_jd_position" {
return domain.LLMResponse{
Tokens: 100,
Amount: 100,
Answer: `{"score": 5, "analysis": "position"}`,
Answer: `score: 8
这是公司地位`,
}, nil
}
return domain.LLMResponse{}, errors.New("unknown biz")
Expand All @@ -675,16 +678,16 @@ func (s *LLMServiceSuite) TestHandler_AnalysisJD() {
assert.Equal(t, web.JDResponse{
Amount: 400,
TechScore: &web.JDEvaluation{
Score: 7,
Analysis: "tech",
Score: 6,
Analysis: "这是技术前景",
},
BizScore: &web.JDEvaluation{
Score: 8,
Analysis: "biz",
Score: 7,
Analysis: "这是业务前景",
},
PosScore: &web.JDEvaluation{
Score: 5,
Analysis: "position",
Score: 8,
Analysis: "这是公司地位",
},
}, resp)

Expand Down
20 changes: 15 additions & 5 deletions internal/ai/internal/service/jd_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package service

import (
"context"
"encoding/json"
"errors"
"strconv"
"strings"
"sync/atomic"

"github.com/ecodeclub/webook/internal/ai/internal/domain"
Expand Down Expand Up @@ -83,10 +85,18 @@ func (j *jdSvc) analysisJd(ctx context.Context, uid int64, biz string, jd string
if err != nil {
return 0, nil, err
}
var jdEva domain.JDEvaluation
err = json.Unmarshal([]byte(resp.Answer), &jdEva)
answer := strings.SplitN(resp.Answer, "\n", 2)
if len(answer) != 2 {
return 0, nil, errors.New("不符合预期的大模型响应")
}
score := answer[0]
scoreNum, err := strconv.ParseFloat(strings.TrimSpace(strings.TrimPrefix(score, "score:")), 64)
if err != nil {
return 0, nil, err
return 0, nil, errors.New("分数返回的数据不对")
}
return resp.Amount, &jdEva, nil

return resp.Amount, &domain.JDEvaluation{
Score: scoreNum,
Analysis: strings.TrimSpace(strings.TrimPrefix(answer[1], "analysis:")),
}, nil
}
4 changes: 2 additions & 2 deletions internal/ai/internal/web/vo.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ type JDResponse struct {
}

type JDEvaluation struct {
Score int `json:"score"`
Analysis string `json:"analysis"`
Score float64 `json:"score"`
Analysis string `json:"analysis"`
}

type Config struct {
Expand Down
13 changes: 7 additions & 6 deletions internal/resume/internal/domain/analysis.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package domain

const (
BizResumeSkillKeyPoints = "biz_resume_skill_keypoints"
BizSkillsRewrite = "biz_skills_rewrite"
BizResumeProjectKeyPoints = "biz_resume_project_keypoints"
BizResumeProjectRewrite = "biz_resume_project_rewrite"
BizResumeJobsKeyPoints = "biz_resume_jobs_keypoints"
BizResumeJobsRewrite = "biz_resume_jobs_rewrite"
BizResumeSkillKeyPoints = "biz_resume_skill_keypoints"
BizSkillsRewrite = "biz_resume_skill_rewrite"
// BizResumeProjectEvaluation 评价项目经历
BizResumeProjectEvaluation = "biz_resume_project_evaluation"
BizResumeProjectRewrite = "biz_resume_project_rewrite"
//BizResumeJobsKeyPoints = "biz_resume_job_keypoints"
BizResumeJobsRewrite = "biz_resume_job_rewrite"
)

type ResumeAnalysis struct {
Expand Down
22 changes: 8 additions & 14 deletions internal/resume/internal/integration/analysis_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,29 +47,23 @@ func (a *AnalysisTestSuite) SetupSuite() {
Amount: 200,
Answer: fmt.Sprintf("%s:%s", req.Input[0], req.Input[1]),
}, nil
case domain.BizResumeProjectKeyPoints:
case domain.BizResumeProjectEvaluation:
return ai.LLMResponse{
Tokens: 150,
Amount: 150,
Answer: fmt.Sprintf("project的keypoints %s", req.Input[0]),
Answer: fmt.Sprintf("project的评估 %s", req.Input[0]),
}, nil
case domain.BizResumeProjectRewrite:
return ai.LLMResponse{
Tokens: 220,
Amount: 220,
Answer: fmt.Sprintf("%s:%s", req.Input[0], req.Input[1]),
}, nil
case domain.BizResumeJobsKeyPoints:
return ai.LLMResponse{
Tokens: 300,
Amount: 300,
Answer: fmt.Sprintf("jobs的keypoints %s", req.Input[0]),
Answer: fmt.Sprintf("project的重写 %s", req.Input[0]),
}, nil
case domain.BizResumeJobsRewrite:
return ai.LLMResponse{
Tokens: 400,
Amount: 400,
Answer: fmt.Sprintf("%s:%s", req.Input[0], req.Input[1]),
Answer: fmt.Sprintf("工作经历重写%s", req.Input[0]),
}, nil
default:
return ai.LLMResponse{}, errors.New("mock Err")
Expand Down Expand Up @@ -107,10 +101,10 @@ func (a *AnalysisTestSuite) TestAnalysis() {
wantCode: 200,
wantResp: test.Result[web.AnalysisResp]{
Data: web.AnalysisResp{
Amount: 1370,
RewriteSkills: "resume:skill的keypoints resume",
RewriteJobs: "resume:jobs的keypoints resume",
RewriteProject: "resume:project的keypoints resume",
Amount: 1070,
RewriteSkills: ":skill的keypoints resume",
RewriteJobs: "工作经历重写resume",
RewriteProject: "project的重写 resume\n## 综合评价\nproject的评估 project的重写 resume",
},
},
},
Expand Down
52 changes: 34 additions & 18 deletions internal/resume/internal/service/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,13 @@ func (r *analysisService) Analysis(ctx context.Context, uid int64, resume string
var rewriteSKills, rewriteProject, rewriteJobs string
// 重写技能
eg.Go(func() error {
keyPointsAmount, keyPoints, err := r.getKeyPoints(ctx, uid, domain.BizResumeSkillKeyPoints, fmt.Sprintf("%s_skills_get_keypoints", tid), resume)
keyPointsAmount, keyPoints, err := r.skillKeypoint(ctx, uid, fmt.Sprintf("%s_skills_get_keypoints", tid), resume)
if err != nil {
return err
}
atomic.AddInt64(&amount, keyPointsAmount)
rewriteSkillsAmount, ans, err := r.rewriteSkills(ctx, uid, fmt.Sprintf("%s_skills_rewrite", tid), keyPoints, resume)
// 暂时不需要传入原始简历,不然会严重超时,并且上下文太长,搞崩系统
rewriteSkillsAmount, ans, err := r.rewriteSkills(ctx, uid, fmt.Sprintf("%s_skills_rewrite", tid), keyPoints, "")
if err != nil {
return err
}
Expand All @@ -50,27 +51,30 @@ func (r *analysisService) Analysis(ctx context.Context, uid int64, resume string
})
// 重写项目
eg.Go(func() error {
keyPointsAmount, keyPoints, err := r.getKeyPoints(ctx, uid, domain.BizResumeProjectKeyPoints, fmt.Sprintf("%s_project_get_keypoints", tid), resume)
rewriteProjectAmount, ans, err := r.rewriteProject(ctx, uid, fmt.Sprintf("%s_project_rewrite", tid), resume)
if err != nil {
return err
}
atomic.AddInt64(&amount, keyPointsAmount)
rewriteProjectAmount, ans, err := r.rewriteProject(ctx, uid, fmt.Sprintf("%s_project_rewrite", tid), keyPoints, resume)
atomic.AddInt64(&amount, rewriteProjectAmount)
evaluationAmt, evaluation, err := r.evaluatePrj(ctx, uid,
domain.BizResumeProjectEvaluation,
fmt.Sprintf("%s_project_get_evaludation", tid), ans)
if err != nil {
return err
}
atomic.AddInt64(&amount, rewriteProjectAmount)
rewriteProject = ans
atomic.AddInt64(&amount, evaluationAmt)
rewriteProject = fmt.Sprintf("%s\n## 综合评价\n%s", ans, evaluation)
return nil
})
// 重写工作经历
eg.Go(func() error {
keyPointsAmount, keyPoints, err := r.getKeyPoints(ctx, uid, domain.BizResumeJobsKeyPoints, fmt.Sprintf("%s_jobs_get_keypoints", tid), resume)
if err != nil {
return err
}
atomic.AddInt64(&amount, keyPointsAmount)
rewriteJobsAmount, ans, err := r.rewriteJobs(ctx, uid, fmt.Sprintf("%s_jobs_rewrite", tid), keyPoints, resume)
// 暂时还不需要提取关键字
//keyPointsAmount, keyPoints, err := r.evaluatePrj(ctx, uid, domain.BizResumeJobsKeyPoints, fmt.Sprintf("%s_jobs_get_keypoints", tid), resume)
//if err != nil {
// return err
//}
//atomic.AddInt64(&amount, keyPointsAmount)
rewriteJobsAmount, ans, err := r.rewriteJobs(ctx, uid, fmt.Sprintf("%s_jobs_rewrite", tid), "", resume)
if err != nil {
return err
}
Expand All @@ -92,14 +96,27 @@ func (r *analysisService) Analysis(ctx context.Context, uid int64, resume string

}

// 提取关键字
func (r *analysisService) getKeyPoints(ctx context.Context, uid int64, biz, tid, resume string) (int64, string, error) {
// 首先提取关键字
func (r *analysisService) evaluatePrj(ctx context.Context, uid int64, biz, tid, rewritePrj string) (int64, string, error) {
aiReq := ai.LLMRequest{
Uid: uid,
Tid: tid,
Biz: biz,
// 标题,标准答案,输入
Input: []string{rewritePrj},
}
resp, err := r.aiSvc.Invoke(ctx, aiReq)
if err != nil {
return 0, "", err
}
return resp.Amount, resp.Answer, nil
}

// 提取关键字
func (r *analysisService) skillKeypoint(ctx context.Context, uid int64, tid, resume string) (int64, string, error) {
aiReq := ai.LLMRequest{
Uid: uid,
Tid: tid,
Biz: domain.BizResumeSkillKeyPoints,
Input: []string{resume},
}
resp, err := r.aiSvc.Invoke(ctx, aiReq)
Expand Down Expand Up @@ -131,15 +148,14 @@ func (r *analysisService) rewriteSkills(ctx context.Context, uid int64, tid, key
}

// 重写项目
func (r *analysisService) rewriteProject(ctx context.Context, uid int64, tid, keyPoints, resume string) (int64, string, error) {
func (r *analysisService) rewriteProject(ctx context.Context, uid int64, tid, resume string) (int64, string, error) {
aiReq := ai.LLMRequest{
Uid: uid,
Tid: tid,
Biz: domain.BizResumeProjectRewrite,
// 标题,标准答案,输入
Input: []string{
resume,
keyPoints,
},
}
resp, err := r.aiSvc.Invoke(ctx, aiReq)
Expand Down
7 changes: 6 additions & 1 deletion ioc/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"net/http"
"strings"

"github.com/ecodeclub/webook/internal/ai"

"github.com/ecodeclub/webook/internal/cases"

baguwen "github.com/ecodeclub/webook/internal/question"
Expand All @@ -43,7 +45,9 @@ func InitAdminServer(prj *project.AdminHandler,
queSet *baguwen.AdminQuestionSetHandler,
caseHdl *cases.AdminCaseHandler,
caseSetHdl *cases.AdminCaseSetHandler,
mark *marketing.AdminHandler) AdminServer {
mark *marketing.AdminHandler,
aiHdl *ai.AdminHandler,
) AdminServer {
res := egin.Load("admin").Build()
res.Use(cors.New(cors.Config{
ExposeHeaders: []string{"X-Refresh-Token", "X-Access-Token"},
Expand Down Expand Up @@ -73,6 +77,7 @@ func InitAdminServer(prj *project.AdminHandler,
que.PrivateRoutes(res.Engine)
caseHdl.PrivateRoutes(res.Engine)
caseSetHdl.PrivateRoutes(res.Engine)
aiHdl.RegisterRoutes(res.Engine)
return res
}

Expand Down
2 changes: 1 addition & 1 deletion ioc/wire.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func InitApp() (*App, error) {
wire.FieldsOf(new(*bff.Module), "Hdl"),
resume.InitModule,
wire.FieldsOf(new(*resume.Module), "PrjHdl", "AnalysisHandler"),
wire.FieldsOf(new(*ai.Module), "Hdl"),
wire.FieldsOf(new(*ai.Module), "Hdl", "AdminHandler"),

initLocalActiveLimiterBuilder,
initCronJobs,
Expand Down
5 changes: 3 additions & 2 deletions ioc/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit eb6addb

Please sign in to comment.