package comm import ( "context" "yunyan/pb" ) // 本文件集中定义「模块对外接口」。 // // 一个模块若要把能力开放给其它模块调用,在此定义一个接口;目标模块的实现类型 // 实现该接口即可。调用方在启动阶段通过 service.GetModule(模块名) 取到模块实例, // 断言为对应接口后调用——业务模块之间因此无需直接 import 对方的包。 // ===================== 统计模块 analyze ===================== // StatEventType 埋点事件类型。 type StatEventType int32 const ( StatEventUnknown StatEventType = 0 StatEventLogin StatEventType = 1 // 用户登录 StatEventRegister StatEventType = 2 // 新用户注册 StatEventDeviceActive StatEventType = 3 // 设备激活 StatEventDeviceBind StatEventType = 4 // 设备绑定账号 StatEventOrderCreate StatEventType = 5 // 创建订单 StatEventOrderPaid StatEventType = 6 // 订单支付完成 StatEventOrderFailed StatEventType = 7 // 订单失败 StatEventTranslate StatEventType = 8 // 翻译使用 StatEventMeeting StatEventType = 9 // 会议使用 StatEventAiChat StatEventType = 10 // AI 聊天 StatEventResourceGrant StatEventType = 11 // 资源发放 StatEventQRCodeActive StatEventType = 12 // 二维码(公码)激活:用户扫公码领奖成功一次计一次 ) // StatEvent 统一埋点对象:业务模块通过 IAnalyze.Report 投递,一个对象走天下, // 靠 Type 区分语义,公共数值字段按需填写。 type StatEvent struct { Type StatEventType ProductId uint32 // 产品ID:设备类事件填设备产品;订单/发放/消耗类事件填用户最后绑定产品(DBUser.Lastbindproductid);无绑定填 0 ChannelId string // 渠道商ID(短码):设备类事件填该设备授权码上的渠道商;其余事件填用户最后绑定设备的渠道商(DBUser.Lastbindchannelid);无归属填 "" Uid string // 触发用户;用于登录/活跃/付费用户的去重统计 Count int64 // 通用次数:0 视为未指定按 1 计;负数保留,用于冲正(如解绑 -1) Amount int64 // 金额(分):订单类事件 Second int64 // 时长(秒):翻译 / 会议 Words int64 // 字数:翻译 UpToken int64 // 上行 token:AI DnToken int64 // 下行 token:AI // 资源发放(StatEventResourceGrant) GrantVipDay int64 GrantAiIntegral int64 GrantTradeSecond int64 GrantMeetSecond int64 } // StatSnapshotKind 是 StatSnapshot.Kind 的固定取值,供消费端识别快照消息、 // 区分(并丢弃)管道里可能残留的历史逐事件消息。 const StatSnapshotKind = "snapshot" // StatSnapshot 是业务侧 analyze 推送到 NATS 统计管道的「当日某分区绝对快照」 // (发送端 analyze 与 console 统计消费端共享)。 // // 设计:业务侧 analyze 始终把埋点实时累加到本地 Redis(崩溃不丢);同步器在【启动时 / 每个 // 同步周期 / 0 点】把 Redis 里 app×region×product×day 各分区的【当日绝对聚合】打包成本结构推送。 // console 收到后直接以绝对值覆盖 upsert 到 stats_global_day—— // - 绝对值幂等:重复/乱序投递、重启重放都收敛到最新值,不会重复计数; // - 自愈:偶发丢消息由下一次快照补回,业务重启时的启动快照即完成对账; // - 去重人数(HLL)在业务侧本地算好,随 Row.*UserCount 以整数带过来,console 不再维护 HLL。 // // Row 即一行 stats_global_day(含复合主键维度 app_id/region/product_id/stat_day 与全部指标), // 直接复用以避免维度/字段两处定义漂移。Row.AppId 须与 console 注册表中的应用名称完全一致, // 否则 console 视为未注册、不落库。 type StatSnapshot struct { Kind string `json:"kind"` // 固定 StatSnapshotKind Ts int64 `json:"ts"` // 快照生成时间(unix 秒);与接收时间差大=迟到 Row *pb.StatsGlobalDay `json:"row"` // 该分区当日绝对聚合,直接落 stats_global_day } // IAnalyze 是统计模块 analyze 对外暴露的埋点接口。 // // 用法:业务模块在 Start 阶段获取并缓存—— // // if m, err := service.GetModule(comm.ModuleAnalyze); err == nil { // this.analyze, _ = m.(comm.IAnalyze) // } // // 之后在业务流程中调用 this.analyze.Report(...) 投递埋点(注意判空)。 type IAnalyze interface { // Report 投递一个埋点事件。非阻塞,失败即丢弃,不阻断业务主流程。 Report(e *StatEvent) } // MeetSummaryService 会议记录可选的总结大模型项(下发给客户端选择)。 type MeetSummaryService struct { SvcId string `json:"svc_id"` // 服务 id(starttask/summary 的 summary_svc_id 传它) Name string `json:"name"` // 显示名 IsDefault bool `json:"is_default"` // 是否后台默认模型 } // MeetCapabilities 会议记录当前可用的能力:识别/翻译支持的语言 + 可选总结大模型。 // 全部由后台「第三方服务配置 + 会议记录服务编排」决定,客户端不写死。 // AnyLanguage=true 表示该段存在未限定 languages 的服务(= 不限语言),此时语言列表只是 // 「明确声明过的」,客户端不能拿它当白名单去禁用其他语言。 type MeetCapabilities struct { TranscribeLanguages []string `json:"transcribe_languages"` TranscribeAnyLanguage bool `json:"transcribe_any_language"` TranslateLanguages []string `json:"translate_languages"` TranslateAnyLanguage bool `json:"translate_any_language"` SummaryClientChoice bool `json:"summary_client_choice"` // 后台是否允许客户端指定总结模型 SummaryServices []MeetSummaryService `json:"summary_services"` } // IEchomeet 是会议记录模块 echomeet 对外暴露的能力查询接口,供同进程的其他模块 // (user 的 v3 配置下发)一次性取会议记录能力,避免客户端多跑一趟接口。 // // 用法与 IAnalyze 相同,在 Start 阶段获取并缓存: // // if m, err := service.GetModule(comm.ModuleEchomeet); err == nil { // this.echomeet, _ = m.(comm.IEchomeet) // } // // 注意判空:echomeet 未随本服务装载时取不到,调用方应把会议记录能力留空而不是报错。 type IEchomeet interface { // MeetCapabilities 返回当前编排快照下的会议记录能力。读内存快照,不查库。 MeetCapabilities() MeetCapabilities // ChatLLM 用后台编排选出的总结模型跑一次对话,返回文本与实际用到的服务 id。 // // 开这个口子是为了让别的模块(memory 的周报生成、会议待办抽取)也能走同一套 // 编排选路,而不是各自 import "yunyan/sys/doubao" 写死服务商——allhelp/summary.go // 就是写死的,后果是海外应用照样去调国内豆包、后台换模型也换不掉它。 // svcId 传空则按编排取默认。 ChatLLM(ctx context.Context, svcId, systemPrompt, userContent string) (text string, usedSvcId string, err error) } // ===================== 记忆中心 memory ===================== // IMemory 记忆中心(拾忆)对外开放的能力。 // // 目前只有一个:让 echomeet 在纪要生成完之后把待办抽出来落进 memory_item。 // 反向调用(memory → echomeet 的 ChatLLM)走 IEchomeet,两边都不直接 import 对方。 type IMemory interface { // ExtractMeetingTodos 从会议纪要抽取待办并落库。 // // **调用方必须另起 goroutine**:它内部要跑一次 LLM,同步调会把会议流水线卡住。 // 实现里已做 panic 兜底与失败隔离——抽取失败只记日志,绝不回头改会议记录的状态。 // // 「第几轮」由 memory 自己按 source_id 现有的最大 gen_round 推出来,不从这里传: // 调用方(echomeet)没有地方存轮次计数器,硬编码成 1 会让第二次「重新生成」 // 的清理条件 gen_round < 1 一条都匹配不上,旧待办从此永远留在库里。 ExtractMeetingTodos(ctx context.Context, uid, recordID, summary, meetingDate, llmSvcID string) }