package chat import ( "context" "encoding/json" "errors" "fmt" "wechat-api/ent" "wechat-api/internal/svc" "wechat-api/internal/types" "wechat-api/internal/utils/compapi" "wechat-api/internal/utils/contextkey" "wechat-api/internal/utils/typekit" "github.com/zeromicro/go-zero/core/logx" ) type baseLogicWorkflow interface { AppendAsyncRequest(apiKeyObj *ent.ApiKey, req *types.CompApiReq) error DoSyncRequest(apiKeyObj *ent.ApiKey, req *types.CompApiReq) (*types.CompOpenApiResp, error) AppendUsageDetailLog(authToken string, req *types.CompApiReq, resp *types.CompOpenApiResp) error AdjustRequest(req *types.CompApiReq, apiKeyObj *ent.ApiKey) } type ChatCompletionsLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } type FastgptChatLogic struct { ChatCompletionsLogic } type MismatchChatLogic struct { ChatCompletionsLogic } type IntentChatLogic struct { ChatCompletionsLogic } /* 扩展LogicChat工厂方法 返回根据不同EventType相关的扩展LogicChat的baseLogicWorkflow接口形式 每增加一个新的扩展LogicChat结构,需要在此函数中增加相应的创建语句 */ func (l *ChatCompletionsLogic) getLogicWorkflow(apiKeyObj *ent.ApiKey, req *types.CompApiReq) (baseLogicWorkflow, error) { var ( err error wf baseLogicWorkflow ) if apiKeyObj.Edges.Agent.Type != 2 { err = fmt.Errorf("api agent type not support(%d)", apiKeyObj.Edges.Agent.Type) } else if req.EventType == "mismatch" { wf = &MismatchChatLogic{ChatCompletionsLogic: *l} } else if req.EventType == "intent" { wf = &IntentChatLogic{ChatCompletionsLogic: *l} } else { wf = &FastgptChatLogic{ChatCompletionsLogic: *l} } return wf, err } func NewChatCompletionsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ChatCompletionsLogic { return &ChatCompletionsLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx} } func (l *ChatCompletionsLogic) ChatCompletions(req *types.CompApiReq) (asyncMode bool, resp *types.CompOpenApiResp, err error) { // todo: add your logic here and delete this line var ( apiKeyObj *ent.ApiKey ok bool ) asyncMode = false //从上下文中获取鉴权中间件埋下的apiAuthInfo apiKeyObj, ok = contextkey.AuthTokenInfoKey.GetValue(l.ctx) if !ok { return asyncMode, nil, errors.New("content get auth info err") } //根据请求产生相关的工作流接口集 wf, err := l.getLogicWorkflow(apiKeyObj, req) if err != nil { return false, nil, err } //请求前临时观察相关参数 //PreChatVars(req, apiKeyObj, wf) //微调部分请求参数 wf.AdjustRequest(req, apiKeyObj) if isAsyncReqest(req) { //异步请求处理模式 asyncMode = true err = wf.AppendAsyncRequest(apiKeyObj, req) } else { //同步请求处理模式 resp, err = wf.DoSyncRequest(apiKeyObj, req) if err == nil && resp != nil && len(resp.Choices) > 0 { wf.AppendUsageDetailLog(apiKeyObj.Key, req, resp) //请求记录 } else if resp != nil && len(resp.Choices) == 0 { err = errors.New("返回结果缺失,请检查访问地址及权限") } } return asyncMode, resp, err } func (l *ChatCompletionsLogic) AdjustRequest(req *types.CompApiReq, apiKeyObj *ent.ApiKey) { if len(req.EventType) == 0 { req.EventType = "fastgpt" } if len(req.Model) == 0 && len(apiKeyObj.Edges.Agent.Model) > 0 { req.Model = apiKeyObj.Edges.Agent.Model } //异步任务相关参数调整 if req.IsBatch { //流模式暂时不支持异步模式 //Callback格式非法则取消批量模式 if req.Stream || !compapi.IsValidURL(&req.Callback, true) { req.IsBatch = false } } } func (l *ChatCompletionsLogic) DoSyncRequest(apiKeyObj *ent.ApiKey, req *types.CompApiReq) (*types.CompOpenApiResp, error) { resp, err := compapi.NewClient(l.ctx, compapi.WithApiBase(apiKeyObj.Edges.Agent.APIBase), compapi.WithApiKey(apiKeyObj.Edges.Agent.APIKey)). Chat(req) if err != nil { return nil, err } //以下临时测试case //humanSeeValidResult(l.ctx, req, resp) return resp, err } func (l *ChatCompletionsLogic) AppendAsyncRequest(apiKeyObj *ent.ApiKey, req *types.CompApiReq) error { rawReqBs, err := json.Marshal(*req) if err != nil { return err } rawReqStr := string(rawReqBs) res, err := l.svcCtx.DB.CompapiAsynctask.Create(). SetNotNilAuthToken(&apiKeyObj.Key). SetNotNilOpenaiBase(&apiKeyObj.Edges.Agent.APIBase). SetNotNilOpenaiKey(&apiKeyObj.Edges.Agent.APIKey). SetNotNilOrganizationID(&apiKeyObj.OrganizationID). SetNotNilEventType(&req.EventType). SetNillableModel(&req.Model). SetNillableChatID(&req.ChatId). SetNillableResponseChatItemID(&req.ResponseChatItemId). SetNotNilRequestRaw(&rawReqStr). SetNotNilCallbackURL(&req.Callback). Save(l.ctx) if err == nil { logx.Infof("appendAsyncRequest succ,get id:%d", res.ID) } return err } func (l *ChatCompletionsLogic) AppendUsageDetailLog(authToken string, req *types.CompApiReq, resp *types.CompOpenApiResp) error { svcCtx := &compapi.ServiceContext{Config: l.svcCtx.Config, DB: l.svcCtx.DB, Rds: l.svcCtx.Rds} return compapi.AppendUsageDetailLog(l.ctx, svcCtx, authToken, req, resp) } func (l *FastgptChatLogic) AdjustRequest(req *types.CompApiReq, apiKeyObj *ent.ApiKey) { l.ChatCompletionsLogic.AdjustRequest(req, apiKeyObj) //先父类的参数调整 if req.EventType != "fastgpt" { return } if len(req.Model) > 0 { if req.Variables == nil { req.Variables = make(map[string]string) } req.Variables["model"] = req.Model } if len(req.ChatId) > 0 && len(req.FastgptChatId) == 0 { req.FastgptChatId = req.ChatId } else if len(req.ChatId) == 0 && len(req.FastgptChatId) > 0 { req.ChatId = req.FastgptChatId } } func humanSeePreChatVars(req *types.CompApiReq, apiKeyObj *ent.ApiKey, wf baseLogicWorkflow) { fmt.Println("=========================================") fmt.Printf("In ChatCompletion Get Token Info:\nKey:'%s'\n", apiKeyObj.Key) fmt.Printf("Auth Token:'%s'\n", apiKeyObj.Key) fmt.Printf("ApiKey AgentID:%d\n", apiKeyObj.AgentID) fmt.Printf("ApiKey APIBase:'%s'\n", apiKeyObj.Edges.Agent.APIBase) fmt.Printf("ApiKey APIKey:'%s'\n", apiKeyObj.Edges.Agent.APIKey) fmt.Printf("ApiKey Type:%d\n", apiKeyObj.Edges.Agent.Type) fmt.Printf("ApiKey Model:'%s'\n", apiKeyObj.Edges.Agent.Model) fmt.Printf("EventType:'%s'\n", req.EventType) fmt.Printf("req.ChatId:'%s VS req.FastgptChatId:'%s'\n", req.ChatId, req.FastgptChatId) fmt.Println("=========================================") switch wf.(type) { case *MismatchChatLogic: fmt.Println("MismatchChatLogic Flow.....") case *IntentChatLogic: fmt.Println("IntentChatLogic Flow.....") case *FastgptChatLogic: fmt.Println("FastgptChatLogic Flow.....") default: fmt.Println("Other Flow.....") } } func humanSeeValidResult(ctx context.Context, req *types.CompApiReq, resp *types.CompOpenApiResp) { clientFace, err := compapi.NewClient(ctx).GetClientActFace(req.EventType) if err != nil { fmt.Println(err) return } taskData := ent.CompapiAsynctask{} taskData.ID = 1234 taskData.ResponseChatItemID = req.ResponseChatItemId taskData.EventType = req.EventType taskData.ChatID = req.ChatId taskData.ResponseRaw, err = resp.ToString() if err != nil { fmt.Println(err) return } var bs []byte bs, err = clientFace.CallbackPrepare(&taskData) if err != nil { fmt.Println(err) } fmt.Printf("当前请求EventType:%s\n", req.EventType) fmt.Printf("当前请求MODEL:%s\n", req.Model) fmt.Println("client.CallbackPrepare结果[]byte版.........") fmt.Println(string(bs)) nres := map[string]any{} err = json.Unmarshal(bs, &nres) if err != nil { fmt.Println(err) } fmt.Println("client.CallbackPrepare结果map[string]any版.........") fmt.Println(typekit.PrettyPrint(nres)) config := compapi.ResponseFormatConfig{} if req.EventType == "mismatch" { clientInst := clientFace.(*compapi.MismatchClient) config = clientInst.ResponseFormatSetting(req) } else if req.EventType == "intent" { clientInst := clientFace.(*compapi.IntentClient) config = clientInst.ResponseFormatSetting(req) } else { return } err = compapi.NewChatResult(resp).ParseContentAs(&config.ResformatStruct) if err != nil { fmt.Println(err) } nres["content"] = config.ResformatStruct fmt.Println("client.CallbackPrepare结果ParseContentAs定制版.........") fmt.Println(typekit.PrettyPrint(nres)) } func isAsyncReqest(req *types.CompApiReq) bool { return req.IsBatch }