176 lines
5.1 KiB
Go
176 lines
5.1 KiB
Go
package handler
|
||
|
||
import (
|
||
"net/http"
|
||
"github.com/gin-gonic/gin"
|
||
"github.com/google/generative-ai-go/genai"
|
||
"google.golang.org/api/option"
|
||
"encoding/json"
|
||
"strings"
|
||
)
|
||
|
||
type RateHandler struct {
|
||
geminiAPIKey string
|
||
apiKey string
|
||
}
|
||
|
||
type RateRequest struct {
|
||
Content string `json:"content" binding:"required"`
|
||
Criteria string `json:"criteria"`
|
||
WritingRequirement string `json:"writing_requirement"`
|
||
APIKey string `json:"apikey" binding:"required"`
|
||
}
|
||
|
||
type RateResponse struct {
|
||
Rate int `json:"rate"`
|
||
Summary string `json:"summary"`
|
||
DetailedReview string `json:"detailed_review"`
|
||
Success bool `json:"success"`
|
||
}
|
||
|
||
func NewRateHandler(geminiAPIKey, apiKey string) *RateHandler {
|
||
return &RateHandler{
|
||
geminiAPIKey: geminiAPIKey,
|
||
apiKey: apiKey,
|
||
}
|
||
}
|
||
|
||
func (h *RateHandler) HandleRate(c *gin.Context) {
|
||
var req RateRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, RateResponse{
|
||
Success: false,
|
||
})
|
||
return
|
||
}
|
||
|
||
// Validate API key
|
||
if req.APIKey != h.apiKey {
|
||
c.JSON(http.StatusUnauthorized, RateResponse{
|
||
Success: false,
|
||
})
|
||
return
|
||
}
|
||
|
||
// Initialize Gemini client
|
||
ctx := c.Request.Context()
|
||
client, err := genai.NewClient(ctx, option.WithAPIKey(h.geminiAPIKey))
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, RateResponse{
|
||
Success: false,
|
||
})
|
||
return
|
||
}
|
||
defer client.Close()
|
||
|
||
// Prepare criteria
|
||
criteria := req.Criteria
|
||
if criteria == "" {
|
||
criteria = `你是一名语文老师。你正在给学生的作文打分。根据以下中考作文评分标准,给作文打分。
|
||
## 评分总分值:100分。
|
||
### 88-100分 符合题意;写作目的和对象明确;思考充分,立意深刻,感情真挚;选材精当,内容充实;中心突出,条理清晰;表达准确,语言流畅。
|
||
### 75-87分 符合题意;写作目的和对象较明确;思考较充分,立意清楚,感情真实;选材合理,内容具体;中心明确,有一定条理;表达较准确,语言通畅。
|
||
### 60-74分 符合题意;写作目的和对象较模糊;有一定思考,感情真实;有一定内容;结构基本完整;语言尚通畅。
|
||
### 60分以下 不符合题意;缺乏写作目的和对象;基本没有思考,感情虚假;内容空洞;结构混乱;不成篇。`
|
||
}
|
||
writing_requirement := req.WritingRequirement
|
||
if writing_requirement == "" {
|
||
writing_requirement = "写一篇不少于600字的作文,体裁不限。"
|
||
}
|
||
|
||
// 规定输出格式是json,包含rate, summary, detailed_review,放入prompt的最后
|
||
format := `请按照以下JSON格式输出:
|
||
{
|
||
"rate": 分数, // 最多100分制的分数,int类型
|
||
"summary": "总体评价", // 100字以内的总体评价,string类型
|
||
"detailed_review": "详细点评" // 300字以内的详细点评,包含优点和建议,string类型
|
||
}`
|
||
// Prepare prompt
|
||
prompt := "作文要求:\n" + writing_requirement + "\n\n" + "评分标准:\n" + criteria + format + "\n\n" + "\n\n作文内容:\n" + req.Content
|
||
|
||
// Generate content
|
||
model := client.GenerativeModel("gemini-2.0-flash-exp")
|
||
resp, err := model.GenerateContent(ctx, genai.Text(prompt))
|
||
if err != nil {
|
||
c.JSON(http.StatusInternalServerError, RateResponse{
|
||
Success: false,
|
||
})
|
||
return
|
||
}
|
||
|
||
if len(resp.Candidates) > 0 && len(resp.Candidates[0].Content.Parts) > 0 {
|
||
if textPart, ok := resp.Candidates[0].Content.Parts[0].(genai.Text); ok {
|
||
// Parse the response to extract rate, summary, and detailed review
|
||
result := parseRateResponse(string(textPart))
|
||
|
||
c.JSON(http.StatusOK, RateResponse{
|
||
Rate: result.Rate,
|
||
Summary: result.Summary,
|
||
DetailedReview: result.Detailed,
|
||
Success: true,
|
||
})
|
||
return
|
||
}
|
||
}
|
||
|
||
c.JSON(http.StatusInternalServerError, RateResponse{
|
||
Success: false,
|
||
})
|
||
}
|
||
|
||
type rateResult struct {
|
||
Rate int `json:"rate"`
|
||
Summary string `json:"summary"`
|
||
Detailed string `json:"detailed_review"`
|
||
}
|
||
|
||
func parseRateResponse(response string) rateResult {
|
||
var result rateResult
|
||
//去除所有\n
|
||
response = strings.ReplaceAll(response, "\n", "")
|
||
//去除所有\t
|
||
response = strings.ReplaceAll(response, "\t", "")
|
||
// 去除response中的```json前缀和```后缀
|
||
response = strings.TrimSpace(response)
|
||
response = strings.TrimPrefix(response, "```json")
|
||
response = strings.TrimSuffix(response, "```")
|
||
|
||
|
||
// 检查response是否是json格式
|
||
if !strings.HasPrefix(response, "{") {
|
||
return rateResult{
|
||
Rate: 0,
|
||
Summary: "解析失败",
|
||
Detailed: "没有左括号",
|
||
}
|
||
}
|
||
if !strings.HasSuffix(response, "}") {
|
||
return rateResult{
|
||
Rate: 0,
|
||
Summary: "解析失败",
|
||
Detailed: "没有右括号",
|
||
}
|
||
}
|
||
|
||
// 解析json
|
||
err := json.Unmarshal([]byte(response), &result)
|
||
if err != nil {
|
||
return rateResult{
|
||
Rate: 0,
|
||
Summary: "解析失败",
|
||
Detailed: "反序列化失败",
|
||
}
|
||
}
|
||
|
||
// 合并所有验证条件
|
||
if result.Rate <= 0 || result.Rate > 100 ||
|
||
result.Summary == "" || result.Detailed == "" {
|
||
return rateResult{
|
||
Rate: 0,
|
||
Summary: "解析失败",
|
||
Detailed: "字段验证条件不满足",
|
||
}
|
||
}
|
||
|
||
return result
|
||
} |