Skip to content

JavaScript&Python节点

使用场景

Javascript/Python节点支持我们使用代码的方式完成很多复杂的功能,对于开发者用户来说,这是一个令人兴奋的特性,你可以完全解放你的编码能力做出更复杂更优秀的应用,得益于Code的的灵活性,该节点可以完全覆盖下面的业务场景:

  1. 我想自定义一个Plugin,但是平台提供的节点和Plugin不包含我的需求
  2. 我想做一个非常复杂的Flow,但是可视化的逻辑控制和循环控制可读性太差了
  3. 我希望通过Flow来为Agent实现持久化的记忆
  4. ...

输入与输出

前置节点中的变量,比如Start节点中定义的表单字段、前置节点的输出变量都已经内置在当前代码的执行环境中了,你可以直接使用,无需重新声明,或者从参数中获取,举个例子:

python
async def main():
    # 假设message是start节点定义的一个变量
    # 编辑器中可以直接通过start表单中定义的变量名使用该变量
    print(message)
    
    # 如果你想使用节点的返回结果
    # 你可以直接通过节点的命名去使用
    # 这里假设你有一个名为llm_1的LLM节点
    print(llm_1)
    
    return message
javascript
async function main() {
/**
 * 假设message是start节点定义的一个变量
 * 编辑器中可以直接通过start表单中定义的变量名使用该变量
 */
console.log(message);

/**
 * 如果你想使用节点的返回结果
 * 你可以直接通过节点的命名去使用
 * 这里假设你有一个名为llm_1的LLM节点
 */
console.log(llm_1)

return message;
}

当前节点的输出即为当前节点里面main函数的输出,所以你必须要保证编写的代码中有一个入口main函数,如果代码中没有main函数则运行会出错,如果main函数没有return,则默认当前节点输出为null。

💡 Javascript/Python节点的输出必须是一个可序列化的值,所以你不能return正则、函数或者其他不可序列化的值。

全局变量

Flow的执行环境支持设置当前Flow运行时的全局变量,该变量在整个Flow的运行生命周期中,都可访问,不会受所在节点的位置约束,eg:在多个逻辑分支中可以通过全局变量共享数据。

python
async def main():
    # 设置全局变量
    betterAI.store.set("value", 123);
    betterAI.store.set("json", {});
    # 获取全局变量
    betterAI.store.get("value"); # 123
    betterAI.store.get("json"); # {}
    
    # 其他节点可以可以访问该全局变量,比如LLM中,可以通过 {{betterAI.store.get("value")}} 访问
typescript
async function main() {
  // 设置全局变量
  betterAI.store.set("value", 123);
  betterAI.store.set("json", {});
  // 获取全局变量
  betterAI.store.get("value"); // 123
  betterAI.store.get("json"); // {}

  // 其他节点可以可以访问该全局变量,比如LLM中,可以通过 {{betterAI.store.get("value")}} 访问
}

💡 在其他节点中,也可以通过betterAI.store.get获取全局变量,以LLM为例,可以通过betterAI.store.get("value")的表达式获取全局变量,其中value为其他节点通过betterAI.store.set("value")设置的全局变量。

内置包

Javascript/Python的执行环境中,平台内置了很多开发包,来帮助我们更轻松的完成复杂需求,在使用之前我们可以通过语言的导入语法先引入包之后才能使用,但是Javascript只能使用CommonJS的导入语法,不能使用ES Module 的导入语法;

下面以一个示例来演示如何使用环境中的内置包:

python
# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    import datetime

    # 获取当前日期和时间
    now = datetime.datetime.now()
    print("当前日期和时间:", now)

    # 获取明天的日期
    tomorrow = now + datetime.timedelta(days=1)
    print("明天的日期:", tomorrow)

    # 日期格式化输出
    formatted_date = now.strftime("%Y-%m-%d %H:%M:%S")
    print("格式化日期:", formatted_date)
javascript
const axios = require('axios');
const dayjs = require('dayjs');
const crypto = require('crypto');

async function main() {
  // 示例一:使用内置axios包发起一个http请求
  const res = await axios.get('https://resource.bantouyan.com/betteryeah/chat/test_api.json');
  console.log("接口的响应为:", res.data);

  // 示例二:使用内置dayjs的包,获取当前时间并格式化
  const date = dayjs().format('YYYY-MM-DD HH:mm:ss');
  console.log("格式化的日期为:", date);

  // 示例三:使用crypto对下面的参数进行加签
  const params = `api=/example&appKey=test&data=${JSON.stringify({ keyworkd: "母婴" })}&timestamp=${Math.floor(new Date().getTime() / 1000)}`;
  const base64Str = Buffer.from(params).toString('base64');
  const sha1Hash = crypto.createHash('sha1');
  sha1Hash.update(base64Str);
  const sign = sha1Hash.digest('hex');
  console.log("加签后的参数为:", sign);
}

更多平台内置的包,可以在编辑器左侧的内置包模块中找到

image

BetterYeah SDK

SDK作为内置包安装在Javascript/Python的执行环境中了,所以无需重复安装,该SDK封装了Flow中Node节点的能力,可以让你通过代码的方式自由的使用Flow的节点,完成更复杂的业务需求

快速开始

以构建一个从用户输入向LLM提问,LLM回答用户的案例开始,了解SDK的功能

python
from betteryeah import BetterYeah, Model
better_yeah = BetterYeah()

async def main():
    res = better_yeah.llm.chat(system_prompt="你好", model=Model.qwen_plus)
    if not res.success:
        raise Exception(message="执行失败")
    return res.data
typescript
const Betteryeah = require('betteryeah').default
const { LLMModel } = require('betteryeah')
const betteryeah = new Betteryeah()

async function main() {
  const res = await betteryeah.llm.chat({
    systemPrompt: '你好',
    model: LLMModel.qwen_plus,
  })

  if (!res.success) {
    throw new Error(res.message)
  }
  return res.data
}

导入和实例化

python
# 导入SDK
from betteryeah import BetterYeah, Model

# 实例化SDK
better_yeah = BetterYeah()
typescript
// 导入SDK
const Betteryeah = require('betteryeah').default

// 实例化SDK
const betteryeah = new Betteryeah()

SDK实例介绍

模块列表:

模块名称模块说明
llm封装了LLM节点的能力,可以基于此模块使用各种大模型的能力
knowledge封装了知识库节点的能力,可以基于此模块查询/插入知识库
database封装了数据库节点的能力,可以基于此模块使用数据库节点的能力
plugin封装了平台插件的能力,可以基于此使用平台的插件
subFlow封装了子流程节点的能力,可以通过Code调用其他Flow

LLM 模块

模块方法:

方法名称描述参数返回值
chat发起一次会话LLMOptionsPromise<ApiResponse<string | object>>

示例代码:

python
from betteryeah import BetterYeah, Model
betteryeah = BetterYeah()

message_history = [
    {
        "role": "user", 
        "content": "你好"
    },
    {
        "role": "assistant", 
        "content": "你好,有什么可以帮助您?"
    }
]

message_history = []

result = betteryeah.llm.chat(
    '中国的汉朝有几位皇帝',
    json_mode=False,
    model=Model.qwen_plus,
    messages=message_history,
    temperature=0.7
)
print(result.json())
typescript
const Betteryeah = require('betteryeah').default
const { LLMModel } = require('betteryeah');

const betteryeah = new Betteryeah()

async function main() {
  const res = await betteryeah.llm.chat({
    systemPrompt: "你是一个电商客服",
    model: LLMModel.qwen_plus,
    jsonMode: false,
    temperature: 0.7,
    messages: [
        {
            role: "user",
            content: "你好",
        },
        {
            role: "assistant",
            content: "你好,有什么可以帮助你的?"
        },
        {
            role: "user",
            content: "请问外省一般几天发货?"
        }
    ]
  })

  if (!res.success) {
    throw new Error(res.message ?? 'llm执行出错')
  }

  return res.data
}

LLMOptions

Llm chat 方法的参数

字段名称类型是否必填描述
systemPromptstring必填传给LLM节点的系统提示词
modelLLMModel必填要使用的模型名称,可以从SDK中导入选项
jsonModeboolean非必填控制模型是否以JSON格式输出,注意目前只有部分模型支持此参数
messagesMessage[]非必填传给模型的对话上下文
temperaturenumber非必填0 ~ 1, 控制模型的创造性

Message

模型对话上下文的具体属性

属性名称类型描述
role"user" | "assistant"user表示用户角色,assistant表示模型角色
contentstring消息内容

Knowledge模块

模块方法:

方法名称描述参数返回值
insertKnowledge插入内容到知识库InsertKnowledgeOptionsPromise<ApiResponse<InsertKnowledgeResult>
searchKnowledge查询知识库内容SearchKnowledgeOptionsPromise<ApiResponse<SearchKnowledgeResult | string>

示例代码:

python
from betteryeah import BetterYeah, OutPutType, HitStrategyType
betteryeah = BetterYeah()

async def main():
    # 插入知识库
    # partition_id为知识库的id,file_id为知识库文件的file_id 获取方式见资源获取方式
    insert_result = betteryeah.knowledge.insert_knowledge("测试", partition_id="知识库的partition_id", file_id='文件的_file_id')

    print(insert_result.data)

    # 查询知识库
    search_result = betteryeah.knowledge.search_knowledge(
        search_content="测试",
        partition_id="知识库的partition_id",
        tags=[],
        file_ids=['文件的_file_id','文件的_file_id'],
        output_type=OutPutType.JSON,
        hit_strategy=HitStrategyType.MIX,
        max_result_num=3,
        ranking_strategy=False)

    print(result.data)
typescript
const Betteryeah = require('betteryeah').default
const { HitStrategyType } = require('betteryeah');

const betteryeah = new Betteryeah()

async function main() {
  // 插入知识库
  const res = await betteryeah.knowledge.insertKnowledge({
    content: message, // 插入内容,这里直接将用户的输入插入
    partitionId: -1, // 知识库id,你可以在左侧资源树中找到你要插入的知识库,点击其右侧复制按钮复制id
    fileId: -1, // 需要插入的文件id,可以在右侧资源树中点击复制id
  })

  if (!res.success) {
    throw new Error(res.message ?? '插入知识库出错')
  }

  // 查询知识库
  const res2 = await betteryeah.knowledge.searchKnowledge({
    partitionId: -1, // 知识id,需要在左侧资源中,点击知识库模块,选择想要查询的知识库,然后点击知识库条目右侧的复制,来复制知识库id
    fileIds: [-1, -1], // 要查询的知识库文件,可以在左侧资源中找到,如果不传就是查询所有文件
    searchContent: message, // 查询内容,这里使用用户输入的message作为查询内容
    tags: ["标签一"], // 要搜索知识库的标签,如果为空,或者空数组,则查询所有内容,如果不为空则根据传入的标签查询
    outputType: "json", // 输出格式
    hitStrategy: HitStrategyType.MIX, // 查询方式
    maxResultNum: 3, // 最大查询结果
    rankingStrategy: false, // 是否开启重排
  })

  if (!res2.success) {
    throw new Error(res.message ?? '知识库节点查询出错')
  }

  console.log("知识库的查询结果为:", res2.data)
}

InsertKnowledgeOptions

插入知识库方法的参数

字段名称类型是否必填描述
partitionIdnumber非必填要插入的知识库的id,可以在编辑器左侧资源模块找到
fileIdnumber必填要插入的知识库下面的文件id,可以在编辑器左侧资源模块找到
contentstring必填插入知识库的内容

InsertKnowledgeResult

插入知识库方法的响应结果

字段名称类型描述
vector_idstring向量id
file_idnumber插入的知识库的文件id
chunk_idnumber插入的知识库的段落id
contentstring插入的内容
keywordsstring[]插入知识库后,根据插入内容生产的段落关键词
sort_ordernumber段落在文档中的排序
enableboolean该段落是否启用了

SearchKnowledgeOptions

查询知识库方法的参数

字段名称类型是否必填描述
partitionIdnumber必填要查询的知识库的id,可以在编辑器左侧资源模块找到
searchContentstring必填要用于搜索知识库的文本
fileIdsnumber[]非必填具体要搜索的知识库下面的文件id,可以在编辑器左侧资源模块找到
如果为空则查询整个知识库
tagsstring[]非必填要搜索知识库的标签,如果为空,或者空数组,则查询所有内容,如果不为空则根据传入的标签查询
outputType"text" | "json"非必填输出类型
"text": 文本类型输出,可以非常简单的给大模型使用
"json": 带数据格式的输出,拥有非常丰富的字段,可以用于自定义代码逻辑处理后给大模型,比如我想根据查询结果的相关性二次过滤等等
hitStrategyHitStrategyType非必填搜索知识库的方式,默认是混合模式,HitStrategyType.MIX
该选项可以从SDK导入使用
maxResultNumnumber非必填搜索知识库的最大结果数,默认为3
rankingStrategyboolean非必填是否开启重排策略,默认不开启

HitStrategyType

知识库搜索方式

属性名称描述
MIX混合检索
KEY关键词检索
SEMANTICS语义检索

SearchKnowledgeResult

字段名称类型描述
cost_timenumber查询耗时,ms
match_contentsKnowledgeMatchContent[]知识库的匹配结果

KnowledgeMatchContent

字段名称类型描述
vector_idstring向量id
file_idnumber命中段落所在的文件id
file_typeFileType命中文档的类型
mimetypeString | null文档的mimetype
chunk_idnumber该段落在文档中的id
contentstring如果是QA类型的文件,该内容为命中的QA的问题如果是其他类型文件,该内容为命中的段落内容
keywordsstring[]命中的段落的所有关键词
extra_infoobject | null如果是QA类型文件,该值存在,里面键值对表示命中的QA的答案,比如{ "答案一": "你好", "答案二": "你好啊" }
matched_keywordsstring[]如果是关键词匹配,该值为命中段落的关键词
relevance_score-命中的评分信息,可以用来判断相关性

Database模块

方法名称描述参数返回值
executeDatabase在给定的database中执行SQL语句ExecuteDatabaseOptionsPromise<ApiResponse<ExecuteDatabaseResult>>

代码示例:

python
from betteryeah import BetterYeah, Model
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
def main():
    # 在使用此示例之前确保自己有一个数据库,并且新建一个名为 「测试数据表」 的数据表
    # - user 文本类型
    # - age 整数类型
    # base_id为数据库id,获取方式见资源获取方式,注意,查询语句必须加限制条数语句
    result = better_yeah.database.query_database(
        base_id="对应数据库的base_id",
        executable_sql="select * from test limit 100"
    )
    
    if not result.success:
        raise Exception(message=result.message)
        
    print(result.data)
typescript
const Betteryeah = require('betteryeah').default;
const betteryeah = new Betteryeah();

async function main() {
  /**
   * 在使用此示例之前确保自己有一个数据库,并且新建一个名为 「测试数据表」 的数据表
   * - user 文本类型
   * - age 整数类型
   */

  const databaseId = ''; // databaseId 可以在左侧资源树中找到,点击资源项目右侧的复制按钮复制id

  // 演示向数据库中插入一条数据
  // 数据库表名可以在左侧资源树中复制
  const insertRes = await betteryeah.database.executeDatabase({
    databaseId, 
    executableSql: `
      INSERT INTO 测试数据表 ("user", "age") VALUES ('BetterYeah', 3);
    `
  });

  if (!insertRes.success) {
    throw new Error(insertRes.message ?? '插入数据库出错')
  }
}

ExecuteDatabaseOptions

字段名称类型是否必填描述
databaseIdstring必填要操作的数据库id,可以在编辑器左侧资源模块找到
executableSqlstring必填要执行的SQL命令

ExecuteDatabaseResult

字段名称类型描述
commandstring执行的SQL命令
rowCountnumber该SQL命令影响的数据行数
dataany[]SQL命令的执行结果

Plugin模块

模块方法列表

AI识图

python
from betteryeah import BetterYeah, GenerateImageModel
better_yeah = BetterYeah()

async def main():
    result = await better_yeah.plugin.image.vision(
        image_path="https://resource.bantouyan.com/betteryeah/temp/FIlP_1716862566510.jpg",  # 图片地址
        prompt="图片中的物体是什么",
        model=GenerateImageModel.gpt_4o
    )
    print(result)
typescript
const { GenerateImageModel } = require('betteryeah');
const BetterYeah = require('betteryeah').default;
const betteryeah = new BetterYeah()

async function main() {
  const result = await betteryeah.plugin.image.vision({
    imagePath: ["https://resource.bantouyan.com/betteryeah/temp/FIlP_1716862566510.jpg"], // 要识别的图片地址
    model: GenerateImageModel.GPT_4O, // 选择识图模型
    prompt: '图片中的物体是什么', // 识图提示词
  })

  if (!result.success) {
    throw new Error(result.message ?? 'AI识图失败')
  }

  return result.data
}

AI生图

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

async def main():
    result = await better_yeah.plugin.image.generate(prompt="生成一座唐代的宝塔")
    print(result)
typescript
const BetterYeah = require('betteryeah').default;
const betteryeah = new BetterYeah()

async function main() {
  const result = await betteryeah.plugin.image.generate('生成一座唐代宝塔')

  if (!result.success) {
    throw new Error(result.message ?? 'AI生图失败')
  }

  return result.data
}

OCR识图

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    result = await better_yeah.plugin.image.ocr("https://resource.bantouyan.com/betteryeah/temp/example.png")
    print(result)
    return result
typescript
const BetterYeah = require('betteryeah').default;
const betteryeah = new BetterYeah()

async function main() {
  const result = await betteryeah.plugin.image.ocr('https://resource.bantouyan.com/betteryeah/temp/example.png')

  if (!result.success) {
    throw new Error(result.message ?? 'ocr 识图失败')
  }

  return result.data
}

谷歌搜索

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

async def main():
    result = await better_yeah.plugin.search.google(question="汉朝皇帝列表")
    print(result)
    # 指定域名搜索
    result = await better_yeah.plugin.search.google(question="汉朝皇帝列表", parse_web_count=2, domain_name="zhihu.com")
    print(result)
typescript
const BetterYeah = require('betteryeah').default;
const betteryeah = new BetterYeah()

async function main() {
  const result = await betteryeah.plugin.search.googleSearch({
    question: '中国有多少个朝代', // 要搜索的问题
    domainName: '', // (可选)限定搜索的域名
    parseWebCount: 3, // 可选)解析网页的数量
  })
  
  if (!result.success) {
    throw new Error(result.message ?? '搜索失败')
  }

  return result.data
}

Bing搜索

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

async def main():
    result = await better_yeah.plugin.search.bing("汉朝皇帝列表")
    print(result)
    # 指定域名搜索
    result = await better_yeah.plugin.search.bing("汉朝皇帝列表", parse_web_count=2, domain_name="zhihu.com")
    print(result)
typescript
const BetterYeah = require('betteryeah').default;
const betteryeah = new BetterYeah()

async function main() {
  const result = await betteryeah.plugin.search.bingSearch({
    question: '中国有多少个朝代', // 要搜索的问题
    domainName: '', // (可选)限定搜索的域名
    parseWebCount: 3, // 可选)解析网页的数量
  })
  
  if (!result.success) {
    throw new Error(result.message ?? '搜索失败')
  }

  return result.data
}

网页解析

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

async def main():
    result = await better_yeah.plugin.parsing.web(["https://www.betteryeah.com", "https://www.betteryeah.com/solution"])
    print(result)
typescript
const BetterYeah = require('betteryeah').default;
const betteryeah = new BetterYeah();

async function main() {
  // 网页解析
  const result = await betteryeah.plugin.parsing.web(['https://www.betteryeah.com', 'https://www.betteryeah.com/solution']);

  if (!result.success) {
    throw new Error(result.message ?? '多网页解析失败');
  }

  return result.data
}

Excel解析

python
from betteryeah import BetterYeah, ExcelOutputType
better_yeah = BetterYeah()

async def main():
    # URL为Excel的文件地址
    result = await better_yeah.plugin.parsing.excel("https://resource.bantouyan.com/betteryeah/temp/example.xlsx",
                                                    output_format=ExcelOutputType.JSON)
    print(result)
typescript
const { ExcelOutputType } = require('betteryeah');

const BetterYeah = require('betteryeah').default;
const betteryeah = new BetterYeah()

async function main() {
  // 参数为excel的URl地址
  // 默认以JSON格式返回,可以配置解析结果以HTML格式返回
  const result = await betteryeah.plugin.parsing.excel(
    'https://resource.bantouyan.com/betteryeah/temp/example.xlsx',
    ExcelOutputType.JSON
  )
  
  if (!result.success) {
    throw new Error(result.message ?? '解析失败')
  }

  return result.data
}

音频解析

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

async def main():
    result = await better_yeah.plugin.parsing.audio(
      "https://resource.bantouyan.com/betteryeah/temp/example.wav",
      False
    )
    print(result)
typescript
const BetterYeah = require('betteryeah').default;
const betteryeah = new BetterYeah()

async function main() {
  /**
   * 第一个参数:音频文件的URl地址
   * 第二个参数:是否启用智能分轨
   */
  const result = await betteryeah.plugin.parsing.audio('https://resource.bantouyan.com/betteryeah/temp/example.wav', false)
  
  if (!result.success) {
    throw new Error(result.message ?? '解析失败')
  }

  return result.data
}

长文本解析

python
from betteryeah import BetterYeah, ArticleParsingModel
better_yeah = BetterYeah()

async def main():
    result = await better_yeah.plugin.parsing.article([
        "https://resource.bantouyan.com/betteryeah/temp/example.txt",
    ], analysis_description="请根据url进行解析", model=ArticleParsingModel.Claude)
    print(result)
typescript
const { default: BetterYeah, ArticleParsingModel } = require('betteryeah');
const betteryeah = new BetterYeah()

async function main() {
  const result = await betteryeah.plugin.parsing.article({
    longTextUrlList: ['https://resource.bantouyan.com/betteryeah/temp/example.txt'], // 要解析的文本
    analysisDescription: '', // (可选)分析描述。
    modelType: ArticleParsingModel.Kimi, // (可选)模型类型。
  })

  if (!result.success) {
    throw new Error(result.message ?? '解析失败')
  }

  return result.data
}

视频解析

python
from betteryeah import BetterYeah, Model , AnalysisModeType
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    result = await better_yeah.plugin.parsing.video("https://resource.bantouyan.com/betteryeah/temp/example.mp4",AnalysisModeType.OnlyAudio)
    print(result)
    return result
typescript
const { VideoAnalyzeMode } = require('betteryeah');
const BetterYeah = require('betteryeah').default;
const betteryeah = new BetterYeah()

async function main() {
  /**
   * 第一个参数:视频文件的URl地址
   * 第二个参数(选填):解析方式,默认解析视频 + 音频,可以配置仅解析音频
   */
  const result = await betteryeah.plugin.parsing.video('https://resource.bantouyan.com/betteryeah/temp/example.mp4', VideoAnalyzeMode.ScreenshotAndAudio)
  
  if (!result.success) {
    throw new Error(result.message ?? '解析失败')
  }

  return result.data
}

小红书笔记封面批量查询

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.xiaohongshu.search_covers(urls=["https://www.xiaohongshu.com/explore/665e53b60000000005005991"])
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  /**
   * 参数为小红书笔记地址,可以多个
   */
  const result = await betteryeah.plugin.xiaohongshu.searchCovers(['https://www.xiaohongshu.com/explore/6663fb060000000015009218'])

  if (!result.success) {
    throw new Error(result.message ?? '查询失败');
  }

  return result
}

小红书笔记评论批量查询

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.xiaohongshu.search_comments(urls=["https://www.xiaohongshu.com/explore/665e53b60000000005005991"],count=1)
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  /**
   * 第一个参数为小红书笔记地址,可以多个
   * 第二个参数为每篇笔记要获取的评论数
   */
  const result = await betteryeah.plugin.xiaohongshu.searchComments(
    ['https://www.xiaohongshu.com/explore/6663fb060000000015009218'], 
    2
  );

  if (!result.success) {
    throw new Error(result.message ?? '查询失败');
  }

  return result;
}

小红书评论洞察

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.xiaohongshu.get_hot_topic_comments(keyword="中国")
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  /**
   * 参数为要搜索的关键词
   */
  const result = await betteryeah.plugin.xiaohongshu.getHotTopicComments('咖啡')

  if (!result.success) {
    throw new Error(result.message ?? '查询失败');
  }

  return result
}

小红书笔记评论查询

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.xiaohongshu.get_comments(url="https://www.xiaohongshu.com/explore/665e53b60000000005005991")
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  /**
   * 参数为小红书笔记地址
   */
  const result = await betteryeah.plugin.xiaohongshu.getComments('https://www.xiaohongshu.com/explore/6663fb060000000015009218')

  if (!result.success) {
    throw new Error(result.message ?? '查询失败');
  }

  return result
}

小红书获取笔记详情

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.xiaohongshu.get_note_details(url="https://www.xiaohongshu.com/explore/665e53b60000000005005991")
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  /**
   * 参数为小红书笔记地址
   */
  const result = await betteryeah.plugin.xiaohongshu.getNoteDetails('https://www.xiaohongshu.com/explore/6663fb060000000015009218')

  if (!result.success) {
    throw new Error(result.message ?? '查询失败');
  }

  return result
}

小红书笔记搜索

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.xiaohongshu.search_notes(question="中国")
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  /**
   * 参数为搜索关键词
   */
  const result = await betteryeah.plugin.xiaohongshu.searchNotes('咖啡')

  if (!result.success) {
    throw new Error(result.message ?? '查询失败');
  }

  return result
}

小红书爆款笔记搜索

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.xiaohongshu.search_popular_notes(keyword="中国",count=1)
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  /**
   * 第一个参数为搜索关键词
   * 第二个参数为要获取的笔记数量
   */
  const result = await betteryeah.plugin.xiaohongshu.searchPopularNotes('鸡蛋', 1);

  if (!result.success) {
    throw new Error(result.message ?? '查询失败');
  }

  return result;
}

小红书低粉爆款笔记查询

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.xiaohongshu.search_low_follower_popular_notes(keyword="滑板车", count=1)
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  /**
   * 第一个参数为搜索关键词
   * 第二个参数为要获取的笔记数量
   */
  const result = await betteryeah.plugin.xiaohongshu.searchLowFollowerPopularNotes('鸡蛋', 1);

  if (!result.success) {
    throw new Error(result.message ?? '查询失败');
  }

  return result;
}

小红书查询指定账号下的热门笔记

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 第一个参数为小红书博主账号id, 可以在博主的个人中心页面查看
async def main():
    res = await better_yeah.plugin.xiaohongshu.search_account_notes(author_id="7283179518", count=1)
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  /**
   * 第一个参数为小红书博主账号id, 可以在博主的个人中心页面查看
   * 第二个参数为要获取的笔记数量
   */
  const result = await betteryeah.plugin.xiaohongshu.searchAccountNotes('7283179518', 1);

  if (!result.success) {
    throw new Error(result.message ?? '查询失败');
  }

  return result;
}

获取小红书实时热点

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.xiaohongshu.get_hot_topics()
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  const result = await betteryeah.plugin.xiaohongshu.getHotTopics()

  if (!result.success) {
    throw new Error(result.message ?? '查询失败');
  }

  return result
}

抖音视频分析

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.douyin.analyze_video(url="https://v.douyin.com/ijpRaosx/")
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  /**
   * 参数为要分析的视屏短连接
   */
  const result = await betteryeah.plugin.douyin.analyzeVideo('https://v.douyin.com/ijpDh74e')

  if (!result.success) {
    throw new Error(result.message ?? '分析失败');
  }

  return result;
}

抖音实时热榜

python
from betteryeah import BetterYeah,DouyinHotspotsType
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.douyin.get_hot_topics(type=DouyinHotspotsType.society)
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  /**
   * 参数为榜单类型,可选:'热榜' | '娱乐榜' | '社会榜' | '挑战榜'
   */
  const result = await betteryeah.plugin.douyin.getHotTopics('热榜')

  if (!result.success) {
    throw new Error(result.message ?? '获取失败');
  }

  return result;
}

获取哔哩哔哩实时热榜

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.bilibili.get_hot_topics()
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  const result = await betteryeah.plugin.bilibili.getHotTopics()

  if (!result.success) {
    throw new Error(result.message ?? '查询失败');
  }

  return result
}

获取知乎实时热榜

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.zhihu.get_hot_topics()
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  const result = await betteryeah.plugin.zhihu.getHotTopics()

  if (!result.success) {
    throw new Error(result.message ?? '查询失败');
  }

  return result
}

获取微博实时热榜

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.weibo.get_hot_topics()
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  const result = await betteryeah.plugin.weibo.getHotTopics()

  if (!result.success) {
    throw new Error(result.message ?? '查询失败');
  }

  return result
}

获取今日头条实时热榜

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    res = await better_yeah.plugin.toutiao.get_hot_topics()
    return res
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  const result = await betteryeah.plugin.toutiao.getHotTopics()

  if (!result.success) {
    throw new Error(result.message ?? '查询失败');
  }

  return result
}

图表绘制

python
import json
from betteryeah import BetterYeah
better_yeah = BetterYeah()

# 必须保证节点中存在一个main函数
# 你的代码应该在main函数中编写
# main函数的返回值为当前节点的返回值
async def main():
    # 本插件可以使用直接数据或者文件进行图表绘制
    data = {
        "Apple": 98,
        "XiaoMi": 90,
        "HuaWei": 92,
        "Oppo": 88
    }
    result = await better_yeah.plugin.generic.chart_plotting(requirements="按照各个手机品牌的受欢迎统计数据绘制一个柱形图",
                                                             data_desc="各个手机品牌受欢迎程度统计结果数据",
                                                             data=json.dumps(data))
    print(result)

    # 使用excel文件进行解析
    result = await better_yeah.plugin.generic.chart_plotting(requirements="按照各个手机品牌的受欢迎统计数据绘制一个柱形图",
                                                             data_desc="各个手机品牌受欢迎程度统计结果数据",
                                                             excel_file="https://resource.bantouyan.com/betteryeah/temp/data_example.xlsx")
    print(result)
typescript
const { default: BetterYeah } = require('betteryeah');
const betteryeah = new BetterYeah();

async function main() {
  const result = await betteryeah.plugin.generic.chartPlotting({
    // 图表绘制的需求描述,包含图表类型(折线、柱状等)、数据维度、工具栏等等图表细节信息
    requirements: "按照各个手机品牌的受欢迎统计数据绘制一个柱形图",
    // 数据描述,即针对数据的解释,包含数据含义整体描述、字段含义、数据间逻辑关系等等信息
    dataDesc: "各个手机品牌受欢迎程度统计结果数据",
    // 用于生成图表的自定义数据源,可以是任意格式的json数据
    data: {
      "Apple": 98,
      "XiaoMi": 90,
      "HuaWei": 92,
      "Oppo": 88
    },
    // 可是使用data通过JSON传入数据,也可以通过一个excel地址传入数据,data和excelFile的数据传入方式选其一即可。
    // excelFile: "https://resource.bantouyan.com/betteryeah/temp/data_example.xlsx"
  });

  if (!result.success) {
    throw new Error(result.message ?? '绘制失败');
  }

  return result;
}

Subflow模块

Subflow 模块允许你通过 SDK 调用 BetterYeah AI 应用开发平台中已发布的其他工作流,从而提高流程的复用率。对于一些简单的工作流,你可以通过平台搭建这些工作流以提高工作效率,然后使用 Subflow 模块将其集成到你的代码中。

调用子流程示例

python
from betteryeah import BetterYeah
better_yeah = BetterYeah()

async def main():
    # flow_id 可以在左侧资源列表中找到
    # parameter 为子流程入参,也可以在左侧资源列表查看
    result = await better_yeah.sub_flow.execute(
      flow_id="a50739fc30534178a8a8028ca660fdad", 
      parameter={"message": "你好"}
    )
    print(result)
typescript
const BetterYeah = require('betteryeah').default;
const betteryeah = new BetterYeah()

async function main() {
  /**
   * 第一个参数:flow_id 可以在左侧资源列表中找到
   * 第二个参数:parameter 为子流程入参,也可以在左侧资源列表查看
   */
  const result = await betteryeah.subFlow.execute('flow_id', { message: '你好' })

  if (!result.success) {
    throw new Error(result.message ?? '子流程调用失败')
  }

  return result.data // 子流程调用结果的返回值
}

响应结果

typescript
interface ApiResponse<T> {
    code: number; // 响应状态码
    success: boolean; // 响应结果,true表示成功,false,表示失败
    message: string; // 失败时的错误内容
    data?: T; // 响应结果,当响应结果success为false时,该值可能为null或者undefined
    now_time: number;
    usage: { // 本次调用的耗费信息
      consume: number; // 本次调用耗费Yeah积分信息
    }
}

各种ID的获取

image

错误处理

在返回结果的包装类型中,success字段为true表示执行成功可以获取到最终SDK函数的执行结果,如果为false表示执行出错,我们需要根据响应的message字段来判断和处理错误,以LLM为例举一个例子:

python
from betteryeah import BetterYeah, Model
better_yeah = BetterYeah()

async def main():
    res = better_yeah.llm.chat(system_prompt="你好", model=Model.qwen_plus)
    # 处理错误
    if not res.success:
        raise Exception(message="执行失败")
    
    return res.data
typescript
const Betteryeah = require('betteryeah').default
const { LLMModel } = require('betteryeah');

const betteryeah = new Betteryeah()

async function main() {
  const res = await betteryeah.llm.chat({
    systemPrompt: "你好",
    model: LLMModel.qwen_plus,
  })

  // 处理错误
  if (!res.success) {
    throw new Error(res.message ?? 'llm执行出错')
  }

  return res.data
}

内置方法

执行环境的上下文中内置了一个名为betterAI的命名空间,该命名空间下提供了一系列和平台交互的变量、函数;

❗ 比较遗憾的是,目前Javascript节点的执行环境支持该命名空间,Python仅支持命名空间的store模块,session模块暂不支持。

命名空间功能介绍:

typescript
betterAI: {
  /**
   * @description 用于联动平台Agent模块
   */
  agent: {
    chat: {
      /**
       * @description 向指定Agent以Assistant的身份推送一条消息
       * @param { AgentPushMessageOptions } pushMsgOptions 推送消息的必填参数
       *   - agentId: string 指定agent的agentID
       *   - conversationId: string 会话ID
       *   - content: string 会话推送消息的内容
       */
      pushMsg: (pushMsgOptions: AgentPushMessageOptions) => Promise<any>

      /**
       * @description 发送通知消息,客户端右上角提示
       * @param { AgentSendNotifMsgOptions } sendNotifMsgOptions 发送通知消息的参数
       *   - conversationId: string 会话ID
       *   - title: string 通知标题
       *   - content: string 通知内容
       */
      sendNotifMsg: (sendNotifMsgOptions: AgentSendNotifMsgOptions) => Promise<any>

      /**
       * @description 推送消息并发送通知消息
       * @param { AgentPushMsgAndSendNotifOptions } pushMsgAndSendNotifOptions 推送和发送通知的参数
       *   - agentId: string 指定agent的agentID
       *   - conversationId: string 会话ID
       *   - content: string 会话推送消息的内容
       *   - notifTitle: string 通知的标题
       *   - notifContent: string 通知的内容
       */
      pushMsgAndSendNotif: (pushMsgAndSendNotifOptions: AgentPushMsgAndSendNotifOptions) => Promise<any>
      
      /**
       * @description 同步自定义消息到agent当前回复中
       * @param { AgentSyncMsgOptions } syncMsgOptions 推送和发送通知的参数
       *   - message: string 用户自定义内容
       */
      syncMsg: (syncMsgOptions: AgentSyncMsgOptions) => Promise<any>

    },
  },
   /**
   * @description 当Agent调用Flow时,这个对象中存储Agent的一些元信息
   * @description 可以使用此对象和调用Flow的Agent做交互
   */
  session: {
    /**
    * @description 调用当前flow的Agent的会话id,会话和用户相关联
    */
    conversationId?: string
    /**
     * @description 会话中的session
     * @description 一般情况一个会话只有一个session,运行调试中可以有多个session
     * @description session可以作为唯一会话标识
     */
    sessionId?: string
     /**
     * @description 用户在调用Agent时设置的Agent中的变量
     */
    agentInput?: Record<string, any>
    /**
     * @description 一个JSON数据,可以在Agent执行过程中调用betterAI.session.setMetaData设置/修改值
     * @description 此字段可以作为Agent的持久化记忆
     */
    metaData?: any
    /**
     * @description 调用此函数更新metaData的值
     * @param data 需要存储的值,任意类型, ex: { step: 1 }
     */
    setMetaData: (data: any) => Promise<void>
    /**
     * @description 在没有Agent调用Flow的情况下,此函数可以使用一个sessionId模拟Agent调用的效果
     * @description 这个函数一般用于调试Agent调用flow做持久化记忆
     */
    initSessionData: ({ sessionId: string }) => Promise<void>
    /**
     * @description 向Agent聊天中追加一条聊天记录
     */
    addChatRecord: (params: {
      session_id: string,
      content: string
    }) => Promise<void>
    /**
     * @description 获取当前聊天的上下文
     * @param conversationId 会话 session id
     * @param limit 限制查询多少条记录
     * @returns { type: MessageRecord[] } 消息记录
     */
    getChatRecord: (sessionId: string, limit: number) => any[]
  },
   /**
   * @description workflow运行时全局变量模块,可以设置和获取运行时的全局变量
   */
  store: {
    /***
     * @description 设置运行时全局变量
     */
    set: (key: string, value: any) => void,
    /**
     * @description 根据key获取运行时设置的全局变量
     */
    get: (key: string) => any
  }
};

代码示例:

javascript
// 向调用当前flow的Agent会话session中插入一条Assistant身份的数据
await betterAI.session.addChatRecord({
    "session_id": betterAI.session.sessionId,
    "content": "冬日暖阳4"
})

// 获取调用当前flow的agnet会话session的聊天记录
const record = await betterAI.session. getChatRecord(betterAI.session.sessionId, 10)

/**
* 如果是在当前flow中调试Agent调用flow的情况,你可以使用一个真实的sessionId,通过initSessionData的方法先初始化session
* 初始化sessionData,仅在非Agent调用时模拟session调用以便调试
*/
const sessionId = ''; // 请使用你真实的sessionId,如果没有,可以先用Agent调用一次,从日志中获取
await betterAI.session.initSessionData({
sessionId,
})

await betterAI.session.setMetaData({name: 'xiaoli', age: 20})