This commit is contained in:
maxwell 2025-01-15 11:11:08 +08:00
parent 361c133c9c
commit 82848d4dc3
3 changed files with 183 additions and 1 deletions

View File

@ -15,7 +15,7 @@ func main() {
log.Fatalf("Failed to load configuration: %v", err) log.Fatalf("Failed to load configuration: %v", err)
} }
// Initialize handler // Initialize handlers
ocrHandler := handler.NewOCRHandler( ocrHandler := handler.NewOCRHandler(
cfg.TencentSecretID, cfg.TencentSecretID,
cfg.TencentSecretKey, cfg.TencentSecretKey,
@ -23,11 +23,17 @@ func main() {
cfg.APIKey, cfg.APIKey,
) )
rateHandler := handler.NewRateHandler(
cfg.GeminiAPIKey,
cfg.APIKey,
)
// Setup Gin router // Setup Gin router
r := gin.Default() r := gin.Default()
// Register routes // Register routes
r.POST("/ocr", ocrHandler.HandleOCR) r.POST("/ocr", ocrHandler.HandleOCR)
r.POST("/rate", rateHandler.HandleRate)
// Start server // Start server
if err := r.Run("localhost:8080"); err != nil { if err := r.Run("localhost:8080"); err != nil {

176
pkg/handler/rate.go Normal file
View File

@ -0,0 +1,176 @@
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
}

BIN
rate Executable file

Binary file not shown.