npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ollflow

v0.0.6

Published

```javascript const { WorkflowEngine, ollama,tools, toolImplementations } = require('ollflow');

Downloads

277

Readme

使用示例

const { WorkflowEngine, ollama,tools, toolImplementations } = require('ollflow');

const engine = new WorkflowEngine({
  "name": "模拟法庭开庭工作流",
  "steps": [
    {
      "id": "step1",
      "action": "useTools",
      "params": {
        "prompt": "创建一个案件文件,描述一个简单的民事纠纷案件。包括案件编号、原告、被告、案件简述。",
        "tools": tools
      },
      "next": "step2"
    },
    {
      "id": "step2",
      "action": "useTools",
      "params": {
        "prompt": "阅读案件文件,并创建一个开庭通知,包括开庭时间、地点、参与人员等信息。",
        "tools": tools
      },
      "next": "step3"
    },
    {
      "id": "step3",
      "action": "useTools",
      "params": {
        "prompt": "模拟开庭过程,创建一个庭审记录文件,记录法官、原告、被告的陈述。",
        "tools": tools
      },
      "next": "step4"
    },
    {
      "id": "step4",
      "action": "useTools",
      "params": {
        "prompt": "模拟证据展示环节,在庭审记录中添加双方提交的证据信息。",
        "tools": tools
      },
      "next": "step5"
    },
    {
      "id": "step5",
      "action": "useTools",
      "params": {
        "prompt": "模拟辩论环节,在庭审记录中添加双方律师的辩论内容。",
        "tools": tools
      },
      "next": "step6"
    },
    {
      "id": "step6",
      "action": "useTools",
      "params": {
        "prompt": "法官总结案情,并在一个新的判决书文件中写出判决结果和理由。",
        "tools": tools
      },
      "next": "step7"
    },
    {
      "id": "step7",
      "action": "useTools",
      "params": {
        "prompt": "创建一个案件归档文件,总结整个案件的处理过程和结果。",
        "tools": tools
      },
      "next": "step8"
    },
    {
      "id": "step8",
      "action": "useTools",
      "params": {
        "prompt": "列出所有创建的文件,并提供一个简短的案件处理总结。",
        "tools": tools
      },
      "next": null
    }
  ]
});

// 注册工具实现
Object.keys(toolImplementations).forEach(toolName => {
  engine.registerAction(toolName, async (params) => {
    const result = await toolImplementations[toolName](params);
    console.log(`Tool ${toolName} result:`, result);
    return result;
  });
});

// 注册 useTools 动作
engine.registerAction("useTools", async (step, context) => {
  const result = await ollama.useTools(step, JSON.stringify(context));
  console.log("useTools result:", result);
  return result;
});

// 运行工作流
engine.run().then(() => {
  console.log("模拟法庭开庭工作流完成");
}).catch(error => {
  console.error("工作流执行出错:", error);
});

agent 使用示例

ollama的工具方法并不好用,还是使用 json 示例输出有效果。

import { promises as fs } from 'fs';
import path from 'path';
import { Agent } from 'ollflows';

// 创建编程 Agent 实例
const agentOptions = {
    name: 'programmingAgent',
};
const agent = new Agent(agentOptions);



function processResponse(responseText) {
    // 首先尝试直接解析 JSON
    try {
        return JSON.parse(responseText);
    } catch (error) {
        // JSON 解析失败,继续后续处理
    }

    // 尝试匹配 markdown 代码块
    const codeBlockPattern = /```(?:\w*)\n([\s\S]*?)\n```/;
    const match = responseText.match(codeBlockPattern);

    if (match) {
        // 提取代码块内容并处理
        const codeContent = match[1]
            .split('\n')
            .map(line => line.trim())  // 去除每行的首尾空格
            .join('')                   // 合并所有行
            .replace(/\s/g, '');        // 去除所有空白字符

        // 尝试将处理后的内容解析为 JSON
        try {
            return JSON.parse(codeContent);
        } catch (error) {
            // JSON 解析失败,继续后续处理
        }
    }

    // 如果所有尝试都失败,返回原始数据
    return responseText;
}

function extractFirstCodeBlock(markdownText) {
    // 匹配代码块的正则表达式,支持可选的语言标识
    const codeBlockPattern = /```(?:\w*)\n([\s\S]*?)\n```/;
    const match = markdownText.match(codeBlockPattern);

    // 如果找到代码块,返回其内容;否则返回空字符串
    return match ? match[1] : '';
}

async function readFileContent(filePath) {
    try {
        // 获取当前工作目录
        const currentDir = process.cwd();
        const fullPath = path.join(currentDir, filePath);

        // 检查文件是否存在
        try {
            await fs.access(fullPath);
        } catch (error) {
            console.error(`File '${filePath}' not found in ${currentDir}`, error);
            return null;
        }

        // 读取文件内容
        const content = await fs.readFile(fullPath, 'utf-8');
        return content;
    } catch (error) {
        console.error('Error reading file:', error);
        return null;
    }
}

async function findFilesInDirectory(directoryName) {
    try {
        // 获取当前工作目录
        const currentDir = process.cwd();
        console.log("当前运行目录", currentDir)
        const targetDir = path.join(currentDir, directoryName);
        const results = [];

        // 检查目录是否存在
        try {
            await fs.access(targetDir);
        } catch (error) {
            console.error(`Directory '${directoryName}' not found in ${currentDir}`,error);
            return results;
        }

        // 递归遍历目录的辅助函数
        async function traverseDirectory(dir) {
            const entries = await fs.readdir(dir, { withFileTypes: true });

            for (const entry of entries) {
                const fullPath = path.join(dir, entry.name);

                if (entry.isDirectory()) {
                    // 如果是目录,递归遍历
                    await traverseDirectory(fullPath);
                } else {
                    // 如果是文件,添加到结果数组
                    const relativePath = path.relative(targetDir, fullPath);
                    results.push({
                        file: relativePath
                    });
                }
            }
        }

        // 开始遍历
        await traverseDirectory(targetDir);
        return results;
    } catch (error) {
        console.error('Error while finding files:', error);
        return [];
    }
}

const fileslist = await findFilesInDirectory('temp');
console.log(fileslist);

async function main(fileslist) {

    // 循环遍历文件列表读取内容
    for (const file of fileslist) {
        try {
            // 构建完整的文件路径
            const filePath = path.join('temp', file.file);
  
            // 读取文件内容
            const content = await fs.readFile(filePath, 'utf8');
            console.log(`添加向量数据库文件 ${file.file}`);
            await agent.addToMemory(content);
            console.log('-------------------');
        } catch (error) {
            console.error(`读取文件 ${file.file} 时出错:`, error);
        }
    }


    await agent.addToMemory('next.js最新版本是v15');
    await agent.addToMemory('next.js最新版本是v15');


    const response = await agent.action({
        type: 'text',
        task: "生成一个 Next.js 14 使用app router,使用 sqlite 数据库,支持注册登录发布博客文章并管理的项目的文件结构。",
        prompt: `补充完善 Next.js 项目中页面和路由文件结构。输出格式为 JSON 数组,每个对象包含 file 和 description 两个字段,分别表示文件的绝对路径和文件的功能和作用,项目使用Tailwindcss和shadcn。以下为已经存在的文件${JSON.stringify(fileslist)},已经存在的文件除非需要修改负责不需要重新列出;
  

示例输出:
[
    { "file": "/app/page.tsx", "description": "网站首页文件" },
    { "file": "/app/api/login/route.ts", "description": "关于登录有关的API接口" },
    { "file": "/components/Header.tsx", "description": "头部组件文件" }
]
`
    });


    async function code(item) {

        return agent.action({
            type: 'text',
            task: `开发以下文件的代码:${item.file},功能说明${item.description}`,
            prompt: `你是一个专业的Next.js开发工程师,专注于根据用户的具体要求生成特定文件的代码。你的任务是提供精确、高质量且符合最佳实践的Next.js代码,仅针对指定的文件进行编写。确保代码专注于用户请求的文件,不包含任何额外内容。考虑代码的性能、可维护性以及与项目其他部分的交互。输出应仅包含代码并添加中文注释,确保代码可以直接集成到项目中使用。项目中使用Tailwindcss和shadcn。`,
            input:`${item.description}`
        })

    }
    const list = processResponse(response);
    //开始循环
    // 确保 list 是数组
    if (Array.isArray(list)) {
        // 遍历文件列表
        for (const item of list) {
            try {
                const res = await code(item);
                // 
                // 使用 fs.promises 的方法
                await fs.mkdir('temp', { recursive: true });

                // 构建完整的文件路径
                const filePath = path.join('temp', item.file);

                // 使用 fs.promises 创建目录
                await fs.mkdir(path.dirname(filePath), { recursive: true });

                // 使用 fs.promises 写入文件
                await fs.writeFile(filePath, extractFirstCodeBlock(res), 'utf8');
                console.log(`文件 ${item.file} 处理完成`);

            } catch (error) {
                console.error(`处理文件 ${item.file} 时出错:`, error);
            }
        }
        // 
    } else {
        console.error('响应格式错误: 预期是数组但收到', typeof list);
    }
}


main(fileslist)