package main
import (
"bufio"
"bytes"
"context"
"crypto/md5"
"encoding/base64"
"encoding/json"
"flag"
"fmt"
"io"
"log"
"net/http"
"os"
"os/signal"
"regexp"
"strings"
"syscall"
"time"
"errors"
)
// main.go — 完整实现(含字段注释)
// 功能:
// - 从控制台读取用户输入(支持交互式或管道输入)
// - 构造严格类型的请求体发送到百度 conversation SSE 接口
// - 自定义 SSE 解析器,按 event/data 分块处理
// - 使用强类型结构体解析 data 字段(避免 map/any),保留未知字段为 RawMessage
// - 实时输出 content.generator.data.value 字段内容
// - 支持超时与优雅退出(Ctrl+C)
// ---------------------------
// Request side structs(带字段注释)
// ---------------------------
// TextQuery 表示单个文本查询的内部结构
type TextQuery struct {
Query string `json:"query"` // 用户输入的文本
ExtData string `json:"extData"` // 扩展字段,通常为 JSON 字符串
}
// QueryItemData 包含 TextQuery
type QueryItemData struct {
Text TextQuery `json:"text"` // 包含文本查询
}
// QueryItem 表示查询项(例如:TYPE=TEXT)
type QueryItem struct {
Type string `json:"type"` // 查询类型,例如 "TEXT"
Data QueryItemData `json:"data"` // 查询数据
}
// AgentInfo 表示 agent 相关信息
type AgentInfo struct {
AgentID []string `json:"agent_id"` // agent id 列表
Params string `json:"params"` // agent 参数,通常是字符串化 JSON
}
// UsedModelFunction 表示用于选择模型的功能开关
type UsedModelFunction struct {
InternetSearch string `json:"internetSearch"` // 是否允许互联网检索
DeepSearch string `json:"deepSearch"` // 是否允许深度检索
}
// UsedModel 表示所使用的模型信息
type UsedModel struct {
ModelName string `json:"modelName"` // 模型名
ModelFunction UsedModelFunction `json:"modelFunction"` // 模型功能配置
}
// ChatParams 表示与会话相关的参数
type ChatParams struct {
Setype string `json:"setype"` // 会话类型
ChatSamples string `json:"chat_samples"` // 示例或模板标识
ChatToken string `json:"chat_token"` // 会话使用的 token
Scene string `json:"scene"` // 场景(可空)
}
// SearchInfo 表示搜索与会话上下文配置
type SearchInfo struct {
Srcid string `json:"srcid"` // 来源 id
Order string `json:"order"` // 排序字段(可空)
Tplname string `json:"tplname"` // 模板名
DqaKey string `json:"dqaKey"` // 数据质量 key
ReRank string `json:"re_rank"` // 重排序标志
OriLid string `json:"ori_lid"` // 原始 lid
Sa string `json:"sa"` // 来源标识
EnterType string `json:"enter_type"` // 进入类型
ChatParams ChatParams `json:"chatParams"` // 会话参数
UsedModel UsedModel `json:"usedModel"` // 使用的模型信息
LandingPage string `json:"landingPage"` // 登陆页标识
IsInnovate int `json:"isInnovate"` // 创新标志
ShowMindMap bool `json:"showMindMap"` // 是否展示思维导图
}
// AntiExt 表示带有防刷参数的扩展信息
type AntiExt struct {
InputT int `json:"inputT"` // 输入时间戳或计时
Ck1 int `json:"ck1"` // 防刷校验字段1
Ck9 int `json:"ck9"` // 防刷校验字段9
Ck10 int `json:"ck10"` // 防刷校验字段10
}
// MessageContent 是请求体中 message 字段的完整结构
type MessageContent struct {
InputMethod string `json:"inputMethod"` // 输入方式,例如 chat_search
IsRebuild bool `json:"isRebuild"` // 是否为重建对话
Content json.RawMessage `json:"content"` // 原始 content,保留以便降级使用
SearchInfo SearchInfo `json:"searchInfo"` // 搜索/会话上下文
From string `json:"from"` // 来源(可空)
Source string `json:"source"` // 来源标识,例如 pc_csaitab
Query []QueryItem `json:"query"` // 查询项
AntiExt AntiExt `json:"anti_ext"` // 反作弊/检测扩展
}
// RequestBody 为发送到 /conversation 的顶层请求结构
type RequestBody struct {
Message MessageContent `json:"message"` // 会话消息体
Setype string `json:"setype"` // 会话类型
Rank int `json:"rank"` // 优先级或排序(示例中为 1)
}
// ---------------------------
// SSE / Response structs(带字段注释)
// ---------------------------
// BaseEvent 表示 SSE data 部分的一般结构
type BaseEvent struct {
Status int `json:"status"` // 状态码
Qid string `json:"qid,omitempty"` // 查询 id
PkgId string `json:"pkgId,omitempty"` // 包 id
SessionId string `json:"sessionId,omitempty"` // 会话 id
IsDefault int `json:"isDefault,omitempty"` // 是否为默认
IsShow int `json:"isShow,omitempty"` // 是否展示
SeqID int `json:"seq_id,omitempty"` // 序列 id
Product string `json:"product,omitempty"` // 产品标识
Data json.RawMessage `json:"data"` // data 字段原始 JSON,后续解析
}
// MessageWrapper 用于解析 data 中的 message 对象外层包装
type MessageWrapper struct {
Message MessageInner `json:"message"` // 包含 message 的内部结构
}
// MessageInner 表示 message 的内部结构(示例中包含 msgId/metaData/content 等)
type MessageInner struct {
MsgId string `json:"msgId"` // 消息 id
IsRebuild bool `json:"isRebuild"` // 是否为重建消息
UpdateTime string `json:"updateTime"` // 更新时间(字符串格式)
MetaData json.RawMessage `json:"metaData"` // metaData 原始 JSON,可能包含 state 等信息
Content ContentInner `json:"content"` // content 结构体
}
// ContentInner 表示 content 字段,示例中可能包含 generator、searchQuery 或 cacheStatus
type ContentInner struct {
CacheStatus int `json:"cacheStatus,omitempty"` // 缓存状态
SearchQuery json.RawMessage `json:"searchQuery,omitempty"` // 搜索查询相关原始 JSON
Generator *GeneratorWrapper `json:"generator,omitempty"` // 生成器信息(可能不存在)
}
// GeneratorWrapper 描述 content.generator 的具体结构
type GeneratorWrapper struct {
Text string `json:"text"` // 生成器文本(示例中常为空)
Component string `json:"component"` // 组件名,例如 markdown-yiyan
Group int `json:"group"` // 分组 id
NeedClearHistory bool `json:"needClearHistory,omitempty"` // 是否需要清理历史
IsSafe int `json:"isSafe,omitempty"` // 安全标志
IsFinished bool `json:"isFinished,omitempty"` // 本次是否已完成
Data GeneratorData `json:"data"` // generator.data 中的内容
ModelInfo json.RawMessage `json:"modelInfo,omitempty"` // 模型信息原始 JSON
}
// TypingInfo 描述 data.typing 字段(光标、模式、速度)
type TypingInfo struct {
Cursor bool `json:"cursor,omitempty"` // 是否显示光标
Mode string `json:"mode,omitempty"` // 打字模式,例如 "all"
Speed int `json:"speed,omitempty"` // 打字速度
}
// GeneratorData 表示 generator.data 中的结构(我们关注 value)
type GeneratorData struct {
Value string `json:"value"` // 生成器输出的文本(例如从 ``` 开始的文本)
Theme json.RawMessage `json:"theme,omitempty"` // 主题信息(保留)
Typing TypingInfo `json:"typing,omitempty"` // 打字信息
}
// SSEMessageFull 是 parseSSEStream 输出的事件容器
type SSEMessageFull struct {
EventName string // event 名称,如果没有 event 字段则为空
RawData []byte // data 的合并后的原始内容(含换行)
}
// ---------------------------
// Helpers
// ---------------------------
// AiTabFrameBaseData 顶层结构,表示 aiTabFrameBaseData 中的 JSON
type AiTabFrameBaseData struct {
Token string `json:"token"` // token 字段(页面提供的短 token)
Lid string `json:"lid"` // 页面 lid 标识
}
func WrapError(err error, msg string) error {
return errors.New(fmt.Sprintf("%s: %v", msg, err))
}
func getAIBaseData(userInput string) (*AiTabFrameBaseData, error) {
return &AiTabFrameBaseData{
Token: "7a80190d",
Lid: "8270954307407678544",
}, nil
client := &http.Client{
Timeout: 20 * time.Second,
}
req, err := http.NewRequest("GET", "https://chat.baidu.com/", nil)
if err != nil {
return nil, WrapError(err, "创建请求失败")
}
// 模拟浏览器 UA,避免被网站当作 bot 屏蔽
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36")
resp, err := client.Do(req)
if err != nil {
return nil, WrapError(err, "请求失败")
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("非 200 响应: %s\n%s", resp.Status, string(body))
}
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, WrapError(err, "读取响应 Body 失败")
}
html := string(bodyBytes)
jsonText, err := extractAiTabFrameBaseData(html)
if err != nil {
return nil, WrapError(err, "提取 aiTabFrameBaseData 失败")
}
// 有时 HTML 中会包含换行或空格,trim 一下
jsonText = strings.TrimSpace(jsonText)
var data AiTabFrameBaseData
if err := json.Unmarshal([]byte(jsonText), &data); err != nil {
// 为便于调试,如果解析失败,打印前后若干字符
snip := jsonText
if len(jsonText) > 500 {
snip = jsonText[:500] + " ... (truncated)"
}
return nil, WrapError(err, fmt.Sprintf("JSON 解析失败: %v\njson snippet: %s", err, snip))
}
return &data, nil
}
// extractAiTabFrameBaseData 在 HTML 中找到 name="aiTabFrameBaseData" 的 script 标签并返回其内容。
// 使用正则匹配 script 标签内容(带 DOTALL),并返回第一个捕获组。
func extractAiTabFrameBaseData(html string) (string, error) {
// 使用非贪婪匹配,(?s) 允许 . 匹配换行
re := regexp.MustCompile(`(?s)<script[^>]*name=["']aiTabFrameBaseData["'][^>]*>(.*?)</script>`)
m := re.FindStringSubmatch(html)
if len(m) < 2 {
return "", errors.New("未找到 aiTabFrameBaseData script 标签")
}
// 捕获组 1 即 script 内 JSON 文本
return m[1], nil
}
// buildRequestBody 使用严格结构构造请求体,防止使用 map/any。
func buildRequestBody(userInput string, searchframeLid string, token string) (RequestBody, error) {
if strings.TrimSpace(userInput) == "" {
return RequestBody{}, errors.New("empty input")
}
qi := QueryItem{
Type: "TEXT",
}
qi.Data.Text.Query = userInput
qi.Data.Text.ExtData = "{}"
searchInfo := SearchInfo{
Srcid: "",
Order: "",
Tplname: "",
DqaKey: "",
ReRank: "1",
OriLid: "",
Sa: "bkb",
EnterType: "sidebar_dialog",
ChatParams: ChatParams{
Setype: "csaitab",
ChatSamples: "WISE_NEW_CSAITAB",
ChatToken: GetToken(userInput, searchframeLid, token),
Scene: "",
},
UsedModel: UsedModel{
ModelName: "DeepSeek-V3-0324", // smartMode | DeepSeek-R1 | DeepSeek-V3-0324
ModelFunction: UsedModelFunction{
InternetSearch: "0",
DeepSearch: "0",
},
},
LandingPage: "aitab",
IsInnovate: 2,
ShowMindMap: false,
}
anti := AntiExt{
InputT: 3069,
Ck1: 742,
Ck9: 745,
Ck10: 139,
}
mc := MessageContent{
InputMethod: "chat_search",
IsRebuild: false,
SearchInfo: searchInfo,
From: "",
Source: "pc_csaitab",
Query: []QueryItem{qi},
AntiExt: anti,
}
return RequestBody{Message: mc, Setype: "csaitab", Rank: 1}, nil
}
// parseSSEStream 解析 SSE 流并把事件推入 out 通道
// 规则:
// - 按空行分割事件
// - 同一事件内可能包含多行 data: 每行拼接并保留换行
// - 支持 event: 字段记录事件名
func parseSSEStream(ctx context.Context, r io.Reader, out chan<- SSEMessageFull) error {
defer close(out)
reader := bufio.NewReader(r)
var (
currentEvent string
dataBuf bytes.Buffer
)
for {
// 支持 ctx 取消
select {
case <-ctx.Done():
return ctx.Err()
default:
}
line, err := reader.ReadString('\n')
if err != nil {
if errors.Is(err, io.EOF) {
if dataBuf.Len() > 0 {
out <- SSEMessageFull{EventName: currentEvent, RawData: append([]byte(nil), dataBuf.Bytes()...)}
}
return nil
}
return err
}
// 去掉行尾换行符(保留行内空格)
line = strings.TrimRight(line, "\n")
log.Println(line)
// 空行表示事件结束
if line == "" {
if dataBuf.Len() > 0 {
out <- SSEMessageFull{EventName: currentEvent, RawData: append([]byte(nil), dataBuf.Bytes()...)}
}
currentEvent = ""
dataBuf.Reset()
continue
}
// 注释行
if strings.HasPrefix(line, ":") {
continue
}
// event 行
if strings.HasPrefix(line, "event:") {
parts := strings.SplitN(line, ":", 2)
if len(parts) == 2 {
currentEvent = strings.TrimSpace(parts[1])
}
continue
}
// data 行
if strings.HasPrefix(line, "data:") {
parts := strings.SplitN(line, ":", 2)
var d string
if len(parts) == 2 {
d = parts[1]
}
// 去掉 data: 后的首个空格(如果存在)
if strings.HasPrefix(d, " ") {
d = d[1:]
}
if dataBuf.Len() > 0 {
dataBuf.WriteByte('\n')
}
dataBuf.WriteString(d)
continue
}
// 其他字段目前忽略
}
}
// extractValueFromData 从 data JSON 中提取 content.generator.data.value
// 全程使用强类型解析(先 BaseEvent,再 MessageWrapper -> MessageInner)
func extractValueFromData(raw []byte) (string, error) {
trim := bytes.TrimSpace(raw)
if len(trim) == 0 {
return "", nil
}
var be BaseEvent
if err := json.Unmarshal(trim, &be); err != nil {
// 有时 data 直接就是 message 对象,无 base 层,尝试解析为 MessageWrapper
var mw MessageWrapper
if err2 := json.Unmarshal(trim, &mw); err2 == nil {
return extractFromMessageInner(&mw.Message)
}
return "", fmt.Errorf("unmarshal base event: %w", err)
}
if len(be.Data) == 0 {
return "", nil
}
// be.Data 尝试解析为 MessageWrapper
var mw MessageWrapper
if err := json.Unmarshal(be.Data, &mw); err != nil {
// 有时 be.Data 本身可能是 MessageInner
var mi MessageInner
if err2 := json.Unmarshal(be.Data, &mi); err2 == nil {
return extractFromMessageInner(&mi)
}
return "", fmt.Errorf("unmarshal message wrapper: %w", err)
}
return extractFromMessageInner(&mw.Message)
}
// extractFromMessageInner 从 MessageInner 中拿到 value
func extractFromMessageInner(mi *MessageInner) (string, error) {
if mi == nil {
return "", nil
}
c := mi.Content
if c.Generator == nil {
return "", nil
}
return c.Generator.Data.Value, nil
}
// readUserInput 读取用户输入,支持管道和交互式
func readUserInput() (string, error) {
stat, err := os.Stdin.Stat()
if err != nil {
return "", err
}
// 如果有管道数据,读取全部
if (stat.Mode() & os.ModeCharDevice) == 0 {
b, err := io.ReadAll(os.Stdin)
if err != nil {
return "", err
}
return strings.TrimSpace(string(b)), nil
}
// 交互式读取一行输入
reader := bufio.NewReader(os.Stdin)
fmt.Print("请输入要发送给 AI 的内容(回车提交):")
line, err := reader.ReadString('\n')
if err != nil {
return "", err
}
return strings.TrimSpace(line), nil
}
// ---------------------------
// main
// ---------------------------
func main() {
// CLI flags
timeout := flag.Duration("timeout", 120*time.Second, "overall request timeout")
agent := flag.String("agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36", "User-Agent header")
endpoint := flag.String("endpoint", "https://chat.baidu.com/aichat/api/conversation", "SSE endpoint URL")
flag.Parse()
log.SetFlags(log.LstdFlags)
userInput, err := readUserInput()
if err != nil {
log.Fatalf("读取用户输入失败: %v", err)
}
baseData, err := getAIBaseData(userInput)
if err != nil {
log.Fatalf("获取 AI 基础数据失败: %v", err)
}
reqBody, err := buildRequestBody(userInput, baseData.Lid, baseData.Token)
if err != nil {
log.Fatalf("构建请求体失败: %v", err)
}
reqBytes, err := json.Marshal(reqBody)
if err != nil {
log.Fatalf("序列化请求体失败: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), *timeout)
defer cancel()
// 捕获中断信号以便优雅退出
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
go func() {
select {
case s := <-sigCh:
log.Printf("接收到信号 %v,正在取消...", s)
cancel()
case <-ctx.Done():
}
}()
client := &http.Client{}
req, err := http.NewRequestWithContext(ctx, "POST", *endpoint, bytes.NewReader(reqBytes))
if err != nil {
log.Fatalf("创建 HTTP 请求失败: %v", err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("User-Agent", *agent)
req.Header.Set("isDeepseek", "1")
resp, err := client.Do(req)
if err != nil {
log.Fatalf("请求失败: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
b, _ := io.ReadAll(resp.Body)
log.Fatalf("非 200 响应: %s\n%s", resp.Status, string(b))
}
log.Println("连接成功,开始处理 SSE 流(按 Ctrl+C 取消)...")
out := make(chan SSEMessageFull)
go func() {
if err := parseSSEStream(ctx, resp.Body, out); err != nil {
log.Printf("SSE 解析错误: %v", err)
}
}()
// 实时消费并打印 value
for msg := range out {
val, err := extractValueFromData(msg.RawData)
if err != nil {
log.Printf("解析 data 出错: %v\nraw: %s", err, strings.TrimSpace(string(msg.RawData)))
continue
}
if val != "" {
// 直接打印,不自动添加换行,匹配流式输出行为
fmt.Print(val)
}
}
log.Println("SSE 流已结束")
}
// GetToken 生成token,对应JavaScript中的getToken函数
func GetToken(word string, searchframeLid string, token string) string {
query := word // getStrQuery(word)
const VERSION = 3
hashQuery := fmt.Sprintf("%x", md5.Sum([]byte(query)))
timestamp := time.Now().UnixMilli()
tokenStr := fmt.Sprintf("%s|%s|%d|%s", token, hashQuery, timestamp, searchframeLid)
encoded := base64.StdEncoding.EncodeToString([]byte(tokenStr))
return fmt.Sprintf("%s-%s-%d", encoded, searchframeLid, VERSION)
}
package main
import (
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net/http"
"regexp"
"strings"
"time"
)
// Main flow:
// 1. GET https://chat.baidu.com/
// 2. extract <script ... name="aiTabFrameBaseData">...</script>
// 3. unmarshal JSON into strong-typed structs (with field comments)
// 4. print the parsed struct as pretty JSON
func main() {
client := &http.Client{
Timeout: 20 * time.Second,
}
req, err := http.NewRequest("GET", "https://chat.baidu.com/", nil)
if err != nil {
log.Fatalf("创建请求失败: %v", err)
}
// 模拟浏览器 UA,避免被网站当作 bot 屏蔽
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36")
resp, err := client.Do(req)
if err != nil {
log.Fatalf("请求失败: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
log.Fatalf("非 200 响应: %s\n%s", resp.Status, string(body))
}
bodyBytes, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatalf("读取响应 Body 失败: %v", err)
}
html := string(bodyBytes)
jsonText, err := extractAiTabFrameBaseData(html)
if err != nil {
log.Fatalf("提取 aiTabFrameBaseData 失败: %v", err)
}
// 有时 HTML 中会包含换行或空格,trim 一下
jsonText = strings.TrimSpace(jsonText)
var data AiTabFrameBaseData
if err := json.Unmarshal([]byte(jsonText), &data); err != nil {
// 为便于调试,如果解析失败,打印前后若干字符
snip := jsonText
if len(jsonText) > 500 {
snip = jsonText[:500] + " ... (truncated)"
}
log.Fatalf("JSON 解析失败: %v\njson snippet: %s", err, snip)
}
pretty, _ := json.MarshalIndent(data, "", " ")
fmt.Println(string(pretty))
}
// extractAiTabFrameBaseData 在 HTML 中找到 name="aiTabFrameBaseData" 的 script 标签并返回其内容。
// 使用正则匹配 script 标签内容(带 DOTALL),并返回第一个捕获组。
func extractAiTabFrameBaseData(html string) (string, error) {
// 使用非贪婪匹配,(?s) 允许 . 匹配换行
re := regexp.MustCompile(`(?s)<script[^>]*name=["']aiTabFrameBaseData["'][^>]*>(.*?)</script>`)
m := re.FindStringSubmatch(html)
if len(m) < 2 {
return "", errors.New("未找到 aiTabFrameBaseData script 标签")
}
// 捕获组 1 即 script 内 JSON 文本
return m[1], nil
}
// ---------------------------
// 下面是与示例 JSON 对应的强类型结构体定义(含中文注释)
// 结构体字段名和 json tag 尽量与页面 JSON 保持一致
// ---------------------------
// AiTabFrameBaseData 顶层结构,表示 aiTabFrameBaseData 中的 JSON
type AiTabFrameBaseData struct {
Token string `json:"token"` // token 字段(页面提供的短 token)
Lid string `json:"lid"` // 页面 lid 标识
UserInfo UserInfo `json:"userInfo"` // 用户相关信息
TabList []TabItem `json:"tabList"` // 页签列表(数组)
ChatParams ChatParams `json:"chatParams"` // 会话参数(sse_host 等)
HasSearchTag bool `json:"hasSearchTag"` // 是否有搜索标签
LogParams LogParams `json:"logParams"` // 日志相关参数
Sample Sample `json:"sample"` // sample 数据(例如 sids、variables)
UrlInfo UrlInfo `json:"urlInfo"` // url 相关信息(例如 guideWordsUrl)
Path string `json:"path"` // 当前页面 path(例如 "/search")
UsableModel []UsableModelItem `json:"usableModel"` // 可用的模型列表
FusionTips string `json:"fusionEnhanceTips"` // 提示文本
DefaultModel DefaultModel `json:"defaultModel"` // 默认模型信息
ImgWsDegrade bool `json:"imgWsDegrade"` // 图片降级标志
Personified string `json:"personifiedSwitch"` // 人格化开关(字符串)
Weather WeatherInfo `json:"weather"` // 天气信息结构
// 注意:如果页面 JSON 增加字段,需要在此处添加对应字段
}
// UserInfo 表示 userInfo 子对象
type UserInfo struct {
Name string `json:"name"` // 用户名(可能为空)
HeadImg string `json:"headImg"` // 头像 URL
IsUserLogin int `json:"isUserLogin"` // 是否登录(0/1)
Baiduid string `json:"baiduid"` // 百度 id
FontSizeScale string `json:"fontSizeScale"` // 字体缩放比例
}
// TabItem 表示 tabList 中的每一项
type TabItem struct {
Log string `json:"log"` // 日志标识(例如 csaitab、ps、pic...)
Text string `json:"text"` // 标签文本(例如 助手、网页、图片)
OrigLink string `json:"orig_link"` // 原始链接(通常以 // 开头)
TabImgUrl string `json:"tabImgUrl"` // 标签图片 URL(base64 或外链)
TabImgPeakUrl string `json:"tabImgPeakUrl"` // 标签高分辨率图片 URL(base64 或外链)
}
// ChatParams 表示 chatParams 子对象(sse_host、sse_ws_host 等)
type ChatParams struct {
SseHost string `json:"sse_host"` // SSE 主机地址
SseWsHost string `json:"sse_ws_host"` // SSE WebSocket 主机地址
Setype string `json:"setype"` // 会话类型(例如 csaitab)
CardHost string `json:"card_host"` // 卡片服务 host(例如 https://www.baidu.com)
}
// LogParams 表示 logParams 子对象(页面日志相关字段)
type LogParams struct {
Ssid string `json:"ssid"` // 会话 ssid
From string `json:"from"` // 来源
Pu string `json:"pu"` // pu 参数(页面埋点数据)
Pn string `json:"pn"` // 分页 pn
Rn string `json:"rn"` // rn(每页条数)
Ref string `json:"ref"` // ref 字段(可能为空)
Applid string `json:"applid"` // applid(示例中为 lid 值)
}
// Sample 表示 sample 子对象(包含 sids、variable_sid、variables)
type Sample struct {
Sids string `json:"sids"` // sids 字符串(下划线分隔的 id 列表)
VariableSid map[string]string `json:"variable_sid"` // variable_sid 映射(键值对)
Variables map[string]string `json:"variables"` // variables 映射(键值对)
}
// UrlInfo 表示 urlInfo 子对象(例如 guideWordsUrl)
type UrlInfo struct {
GuideWordsUrl string `json:"guideWordsUrl"` // 指南词或引导词接口地址
}
// UsableModelItem 表示 usableModel 数组中的每一项
type UsableModelItem struct {
ModelTitle string `json:"modelTitle"` // 模型标题(中文)
ModelName string `json:"modelName"` // 模型内部名
ModelButton string `json:"modelButton"` // 模型按钮文案(可能为空)
ModelIcon string `json:"modelIcon"` // 模型图标 URL
ModelSubTitle string `json:"modelSubTitle"` // 模型副标题
ModelAvailable bool `json:"modelAvailable"` // 模型是否可用
HasModelPerm bool `json:"hasModelPermissions"` // 是否有模型权限
ModelFunction UsedModelFunction `json:"modelFunction"` // 模型功能开关(internetSearch/deepSearch)
}
// UsedModelFunction 表示模型功能允许情况
type UsedModelFunction struct {
InternetSearch string `json:"internetSearch"` // 是否允许 internet search("0"/"1")
DeepSearch string `json:"deepSearch"` // 是否允许 deep search("0"/"1")
}
// DefaultModel 表示 defaultModel 字段
type DefaultModel struct {
ModelName string `json:"modelName"` // 默认模型名
ModelFunction UsedModelFunction `json:"modelFunction"` // 默认模型的功能配置
}
// WeatherInfo 表示 weather 子对象(页面可能给出天气相关占位字段)
type WeatherInfo struct {
CityCode string `json:"cityCode"` // 城市代码
CityName string `json:"cityName"` // 城市名称
IconImg string `json:"iconImg"` // 天气图标
Pollution string `json:"pollution"` // 污染值
PollutionName string `json:"pollutionName"` // 污染名称
Temp string `json:"temp"` // 温度
WeatherURL string `json:"weatherurl"` // 天气链接
WeatherShowWarning string `json:"weatherShowWarning"` // 天气告警信息
}