summaryrefslogtreecommitdiff
path: root/flake.nix
blob: a70e64e2a91abb50fecc5f358a8af78fd27fd144 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
{
  description = "slopbot - Zulip bot with stock price lookups and LLM replies";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    agentd = {
      url = "git+file:///home/ben/src/bsima/agentd";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };

  outputs = { self, nixpkgs, agentd }:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};

      pythonEnv = pkgs.python3.withPackages (ps: [
        ps.zulip
        ps.yfinance
        ps.openai
        ps.requests
      ]);

      agent = pkgs.rustPlatform.buildRustPackage {
        pname = "agent";
        version = "0.1.0";
        src = agentd;
        cargoLock.lockFile = "${agentd}/Cargo.lock";
        cargoBuildFlags = [ "-p" "agent" ];
        doCheck = false;
      };

      researchPython = pkgs.python3.withPackages (ps: [
        ps.trafilatura
      ]);

      slopSearch = pkgs.writeShellApplication {
        name = "slop-search";
        runtimeInputs = [ pkgs.curl pkgs.jq pkgs.python3 ];
        text = ''
          if [ "$#" -eq 0 ]; then
            echo "usage: slop-search QUERY" >&2
            exit 2
          fi
          if [ -z "''${KAGI_API_KEY:-}" ]; then
            echo "error: KAGI_API_KEY is not set" >&2
            exit 1
          fi

          query="$*"
          encoded="$(${pkgs.python3}/bin/python -c 'import sys, urllib.parse; print(urllib.parse.urlencode({"q": " ".join(sys.argv[1:])}))' "$@")"

          curl -fsS \
            -H "Authorization: Bot ''${KAGI_API_KEY}" \
            -H "Accept: application/json" \
            "https://kagi.com/api/v0/search?''${encoded}" \
          | jq -r --arg query "$query" '
              "QUERY: \($query)",
              "",
              (.data // [])
              | map(select((.t // .type // "") == "search_result" or has("url")))
              | .[:8]
              | to_entries[]
              | "[\(.key + 1)] \(.value.title // "untitled")\nURL: \(.value.url)\nSNIPPET: \(.value.snippet // .value.description // "")\n"
            '
        '';
      };

      slopFetch = pkgs.writeShellApplication {
        name = "slop-fetch";
        runtimeInputs = [ pkgs.curl researchPython ];
        text = ''
          if [ "$#" -ne 1 ]; then
            echo "usage: slop-fetch URL" >&2
            exit 2
          fi
          url="$1"
          tmp="$(mktemp)"
          trap 'rm -f "$tmp"' EXIT
          curl -fsSL --max-time 20 -A 'slopbot/1.0' "$url" -o "$tmp"
          ${researchPython}/bin/python - "$url" "$tmp" <<'PY'
import sys
import trafilatura

url, path = sys.argv[1], sys.argv[2]
html = open(path, "rb").read()
text = trafilatura.extract(html, url=url, include_comments=False, include_tables=False)
if not text:
    print(f"error: could not extract readable text from {url}", file=sys.stderr)
    sys.exit(1)
print(text[:12000])
PY
        '';
      };

      slopTools = pkgs.symlinkJoin {
        name = "slopbot-agent-tools";
        paths = [ slopSearch slopFetch ];
      };
    in
    {
      devShells.${system}.default = pkgs.mkShell {
        buildInputs = [ pythonEnv agent slopTools ];
        shellHook = ''
          echo "slopbot dev shell ready"
          echo "Run: python main.py"
        '';
      };

      packages.${system} = rec {
        default = slopbot;
        slopbot = pkgs.writeShellScriptBin "slopbot" ''
          cd /home/ben/src/bsima/slopbot
          export PATH=${slopTools}/bin
          export SLOPBOT_AGENT=${agent}/bin/agent
          export SLOPBOT_AGENT_PATH=${slopTools}/bin
          exec ${pythonEnv}/bin/python ${./main.py}
        '';
        inherit agent slopTools slopSearch slopFetch;
      };
    };
}