mirror of
https://github.com/danielmiessler/Fabric.git
synced 2026-01-09 22:38:10 -05:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d10c26c5d | ||
|
|
681f1a49a5 | ||
|
|
b750171593 | ||
|
|
02a019632b | ||
|
|
385d381cf1 | ||
|
|
48e8d76f21 | ||
|
|
d5336b2796 | ||
|
|
cb1b2bf5ca | ||
|
|
6c38cd360b | ||
|
|
4c2ca22cb2 | ||
|
|
cd177ff476 | ||
|
|
1ea3b4b3c5 | ||
|
|
8df3a9227f | ||
|
|
583695c228 | ||
|
|
455215290f | ||
|
|
5373345a3c | ||
|
|
e17b96d864 | ||
|
|
3ec4d274c4 | ||
|
|
611f8789da | ||
|
|
8e01d62150 | ||
|
|
f55662300a | ||
|
|
c67fe04d3c | ||
|
|
9b4db98ed9 |
2
.github/ISSUE_TEMPLATE/bug.yml
vendored
2
.github/ISSUE_TEMPLATE/bug.yml
vendored
@@ -34,4 +34,4 @@ body:
|
||||
id: screens
|
||||
attributes:
|
||||
label: Relevant screenshots (optional)
|
||||
description: Please upload any screenshots that may help us reproduce and/or understand the issue.
|
||||
description: Please upload any screenshots that may help us reproduce and/or understand the issue.
|
||||
|
||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -3,8 +3,14 @@ name: Go Build
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
paths-ignore:
|
||||
- 'patterns/**'
|
||||
- '**/*.md'
|
||||
pull_request:
|
||||
branches: ["main"]
|
||||
paths-ignore:
|
||||
- 'patterns/**'
|
||||
- '**/*.md'
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
@@ -4,6 +4,9 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main # Monitor the main branch
|
||||
paths-ignore:
|
||||
- 'patterns/**'
|
||||
- '**/*.md'
|
||||
|
||||
permissions:
|
||||
contents: write # Ensure the workflow has write permissions
|
||||
@@ -38,7 +41,10 @@ jobs:
|
||||
minor=$(echo "$latest_tag" | cut -d. -f2)
|
||||
patch=$(echo "$latest_tag" | cut -d. -f3)
|
||||
new_patch=$((patch + 1))
|
||||
new_tag="v${major}.${minor}.${new_patch}"
|
||||
new_version="${major}.${minor}.${new_patch}"
|
||||
new_tag="v${new_version}"
|
||||
echo "New version is: $new_version"
|
||||
echo "new_version=$new_version" >> $GITHUB_ENV # Save the new version to environment file
|
||||
echo "New tag is: $new_tag"
|
||||
echo "new_tag=$new_tag" >> $GITHUB_ENV # Save the new tag to environment file
|
||||
|
||||
@@ -48,9 +54,14 @@ jobs:
|
||||
echo "" >> version.go
|
||||
echo "var version = \"${{ env.new_tag }}\"" >> version.go
|
||||
|
||||
- name: Update version.nix file
|
||||
run: |
|
||||
echo "\"${{ env.new_version }}\"" > pkgs/fabric/version.nix
|
||||
|
||||
- name: Commit changes
|
||||
run: |
|
||||
git add version.go
|
||||
git add pkgs/fabric/version.nix
|
||||
if ! git diff --staged --quiet; then
|
||||
git commit -m "Update version to ${{ env.new_tag }} and commit $commit_hash"
|
||||
else
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,3 +1,7 @@
|
||||
# Nix
|
||||
.direnv
|
||||
result
|
||||
|
||||
# macOS local stores
|
||||
.DS_Store
|
||||
|
||||
@@ -161,4 +165,4 @@ cython_debug/
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
#.idea/
|
||||
|
||||
@@ -197,7 +197,7 @@ Then [set your environmental variables](#environmental-variables) as shown above
|
||||
|
||||
The great thing about Go is that it's super easy to upgrade. Just run the same command you used to install it in the first place and you'll always get the latest version.
|
||||
```bash
|
||||
go install -ldflags "-X main.version=$(git describe --tags --always)" github.com/danielmiessler/fabric@latest
|
||||
go install github.com/danielmiessler/fabric@latest
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -217,7 +217,7 @@ Application Options:
|
||||
-v, --variable= Values for pattern variables, e.g. -v=#role:expert -v=#points:30"
|
||||
-C, --context= Choose a context from the available contexts
|
||||
--session= Choose a session from the available sessions
|
||||
-a, --attachment= Attachment path or URL (e.g. for OpenAI image recognition messages)
|
||||
-a, --attachment= Attachment path or URL (e.g. for OpenAI image recognition messages)
|
||||
-S, --setup Run setup for all reconfigurable parts of fabric
|
||||
-t, --temperature= Set temperature (default: 0.7)
|
||||
-T, --topp= Set top P (default: 0.9)
|
||||
|
||||
117
cli/cli.go
117
cli/cli.go
@@ -2,16 +2,18 @@ package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/danielmiessler/fabric/plugins/tools/youtube"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/danielmiessler/fabric/common"
|
||||
"github.com/danielmiessler/fabric/core"
|
||||
"github.com/danielmiessler/fabric/plugins/ai"
|
||||
"github.com/danielmiessler/fabric/plugins/db/fsdb"
|
||||
"github.com/danielmiessler/fabric/plugins/tools/converter"
|
||||
"github.com/danielmiessler/fabric/restapi"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Cli Controls the cli. It takes in the flags and runs the appropriate functions
|
||||
@@ -21,6 +23,8 @@ func Cli(version string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
println("Message: " + currentFlags.Message)
|
||||
|
||||
if currentFlags.Version {
|
||||
fmt.Println(version)
|
||||
return
|
||||
@@ -143,40 +147,40 @@ func Cli(version string) (err error) {
|
||||
}
|
||||
|
||||
var videoId string
|
||||
if videoId, err = registry.YouTube.GetVideoId(currentFlags.YouTube); err != nil {
|
||||
var playlistId string
|
||||
if videoId, playlistId, err = registry.YouTube.GetVideoOrPlaylistId(currentFlags.YouTube); err != nil {
|
||||
return
|
||||
} else if videoId == "" && playlistId != "" {
|
||||
if currentFlags.Output != "" {
|
||||
err = registry.YouTube.FetchAndSavePlaylist(playlistId, currentFlags.Output)
|
||||
} else {
|
||||
var videos []*youtube.VideoMeta
|
||||
if videos, err = registry.YouTube.FetchPlaylistVideos(playlistId); err != nil {
|
||||
err = fmt.Errorf("error fetching playlist videos: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, video := range videos {
|
||||
var message string
|
||||
if message, err = processYoutubeVideo(currentFlags, registry, video.Id); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !currentFlags.IsChatRequest() {
|
||||
if err = WriteOutput(message, fmt.Sprintf("%v.md", video.TitleNormalized)); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
messageTools = AppendMessage(messageTools, message)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !currentFlags.YouTubeComments || currentFlags.YouTubeTranscript {
|
||||
var transcript string
|
||||
var language = "en"
|
||||
if currentFlags.Language != "" || registry.Language.DefaultLanguage.Value != "" {
|
||||
if currentFlags.Language != "" {
|
||||
language = currentFlags.Language
|
||||
} else {
|
||||
language = registry.Language.DefaultLanguage.Value
|
||||
}
|
||||
}
|
||||
if transcript, err = registry.YouTube.GrabTranscript(videoId, language); err != nil {
|
||||
return
|
||||
}
|
||||
messageTools = AppendMessage(messageTools, transcript)
|
||||
}
|
||||
|
||||
if currentFlags.YouTubeComments {
|
||||
var comments []string
|
||||
if comments, err = registry.YouTube.GrabComments(videoId); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
commentsString := strings.Join(comments, "\n")
|
||||
|
||||
messageTools = AppendMessage(messageTools, commentsString)
|
||||
}
|
||||
|
||||
messageTools, err = processYoutubeVideo(currentFlags, registry, videoId)
|
||||
if !currentFlags.IsChatRequest() {
|
||||
// if the pattern flag is not set, we wanted only to grab the transcript or comments
|
||||
fmt.Println(messageTools)
|
||||
err = currentFlags.WriteOutput(messageTools)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -202,8 +206,7 @@ func Cli(version string) (err error) {
|
||||
}
|
||||
|
||||
if !currentFlags.IsChatRequest() {
|
||||
// if the pattern flag is not set, we wanted only to grab the url or get the answer to the question
|
||||
fmt.Println(messageTools)
|
||||
err = currentFlags.WriteOutput(messageTools)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -213,7 +216,7 @@ func Cli(version string) (err error) {
|
||||
}
|
||||
|
||||
var chatter *core.Chatter
|
||||
if chatter, err = registry.GetChatter(currentFlags.Model, currentFlags.Stream, currentFlags.DryRun); err != nil {
|
||||
if chatter, err = registry.GetChatter(currentFlags.Model, currentFlags.ModelContextLength, currentFlags.Stream, currentFlags.DryRun); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -255,3 +258,43 @@ func Cli(version string) (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func processYoutubeVideo(
|
||||
flags *Flags, registry *core.PluginRegistry, videoId string) (message string, err error) {
|
||||
|
||||
if !flags.YouTubeComments || flags.YouTubeTranscript {
|
||||
var transcript string
|
||||
var language = "en"
|
||||
if flags.Language != "" || registry.Language.DefaultLanguage.Value != "" {
|
||||
if flags.Language != "" {
|
||||
language = flags.Language
|
||||
} else {
|
||||
language = registry.Language.DefaultLanguage.Value
|
||||
}
|
||||
}
|
||||
if transcript, err = registry.YouTube.GrabTranscript(videoId, language); err != nil {
|
||||
return
|
||||
}
|
||||
message = AppendMessage(message, transcript)
|
||||
}
|
||||
|
||||
if flags.YouTubeComments {
|
||||
var comments []string
|
||||
if comments, err = registry.YouTube.GrabComments(videoId); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
commentsString := strings.Join(comments, "\n")
|
||||
|
||||
message = AppendMessage(message, commentsString)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func WriteOutput(message string, outputFile string) (err error) {
|
||||
fmt.Println(message)
|
||||
if outputFile != "" {
|
||||
err = CreateOutputFile(message, outputFile)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
59
cli/flags.go
59
cli/flags.go
@@ -4,14 +4,15 @@ import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
goopenai "github.com/sashabaranov/go-openai"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/danielmiessler/fabric/common"
|
||||
"github.com/jessevdk/go-flags"
|
||||
goopenai "github.com/sashabaranov/go-openai"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/danielmiessler/fabric/common"
|
||||
)
|
||||
|
||||
// Flags create flags struct. the users flags go into this, this will be passed to the chat struct in cli
|
||||
@@ -36,6 +37,7 @@ type Flags struct {
|
||||
Message string `hidden:"true" description:"Messages to send to chat"`
|
||||
Copy bool `short:"c" long:"copy" description:"Copy to clipboard"`
|
||||
Model string `short:"m" long:"model" description:"Choose model"`
|
||||
ModelContextLength int `long:"modelContextLength" description:"Model context length (only affects ollama)"`
|
||||
Output string `short:"o" long:"output" description:"Output to file" default:""`
|
||||
OutputSession bool `long:"output-session" description:"Output the entire session (also a temporary one) to the output file"`
|
||||
LatestPatterns string `short:"n" long:"latest" description:"Number of latest patterns to list" default:"0"`
|
||||
@@ -70,16 +72,19 @@ func Init() (ret *Flags, err error) {
|
||||
}
|
||||
|
||||
info, _ := os.Stdin.Stat()
|
||||
hasStdin := (info.Mode() & os.ModeCharDevice) == 0
|
||||
pipedToStdin := (info.Mode() & os.ModeCharDevice) == 0
|
||||
|
||||
// takes input from stdin if it exists, otherwise takes input from args (the last argument)
|
||||
if hasStdin {
|
||||
if pipedToStdin {
|
||||
//fmt.Printf("piped: %v\n", args)
|
||||
if message, err = readStdin(); err != nil {
|
||||
return
|
||||
}
|
||||
} else if len(args) > 0 {
|
||||
//fmt.Printf("no piped: %v\n", args)
|
||||
message = args[len(args)-1]
|
||||
} else {
|
||||
//fmt.Printf("no data: %v\n", args)
|
||||
message = ""
|
||||
}
|
||||
ret.Message = message
|
||||
@@ -88,30 +93,30 @@ func Init() (ret *Flags, err error) {
|
||||
}
|
||||
|
||||
// readStdin reads from stdin and returns the input as a string or an error
|
||||
func readStdin() (string, error) {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
var input string
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
return "", fmt.Errorf("error reading from stdin: %w", err)
|
||||
}
|
||||
input += line
|
||||
func readStdin() (ret string, err error) {
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
for scanner.Scan() {
|
||||
ret += scanner.Text() + "\n"
|
||||
}
|
||||
return input, nil
|
||||
if err = scanner.Err(); err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
err = nil
|
||||
} else {
|
||||
err = fmt.Errorf("error reading piped message from stdin: %w", err)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Flags) BuildChatOptions() (ret *common.ChatOptions) {
|
||||
ret = &common.ChatOptions{
|
||||
Temperature: o.Temperature,
|
||||
TopP: o.TopP,
|
||||
PresencePenalty: o.PresencePenalty,
|
||||
FrequencyPenalty: o.FrequencyPenalty,
|
||||
Raw: o.Raw,
|
||||
Seed: o.Seed,
|
||||
Temperature: o.Temperature,
|
||||
TopP: o.TopP,
|
||||
PresencePenalty: o.PresencePenalty,
|
||||
FrequencyPenalty: o.FrequencyPenalty,
|
||||
Raw: o.Raw,
|
||||
Seed: o.Seed,
|
||||
ModelContextLength: o.ModelContextLength,
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -191,6 +196,14 @@ func (o *Flags) IsChatRequest() (ret bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Flags) WriteOutput(message string) (err error) {
|
||||
fmt.Println(message)
|
||||
if o.Output != "" {
|
||||
err = CreateOutputFile(message, o.Output)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func AppendMessage(message string, newMessage string) (ret string) {
|
||||
if message != "" {
|
||||
ret = message + "\n" + newMessage
|
||||
|
||||
@@ -22,6 +22,8 @@ func CreateOutputFile(message string, fileName string) (err error) {
|
||||
defer file.Close()
|
||||
if _, err = file.WriteString(message); err != nil {
|
||||
err = fmt.Errorf("error writing to file: %v", err)
|
||||
} else {
|
||||
fmt.Printf("\n\n... written to %s\n", fileName)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -15,13 +15,14 @@ type ChatRequest struct {
|
||||
}
|
||||
|
||||
type ChatOptions struct {
|
||||
Model string
|
||||
Temperature float64
|
||||
TopP float64
|
||||
PresencePenalty float64
|
||||
FrequencyPenalty float64
|
||||
Raw bool
|
||||
Seed int
|
||||
Model string
|
||||
Temperature float64
|
||||
TopP float64
|
||||
PresencePenalty float64
|
||||
FrequencyPenalty float64
|
||||
Raw bool
|
||||
Seed int
|
||||
ModelContextLength int
|
||||
}
|
||||
|
||||
// NormalizeMessages remove empty messages and ensure messages order user-assist-user
|
||||
|
||||
@@ -3,11 +3,13 @@ package core
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
goopenai "github.com/sashabaranov/go-openai"
|
||||
|
||||
"github.com/danielmiessler/fabric/common"
|
||||
"github.com/danielmiessler/fabric/plugins/ai"
|
||||
"github.com/danielmiessler/fabric/plugins/db/fsdb"
|
||||
goopenai "github.com/sashabaranov/go-openai"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const NoSessionPatternUserMessages = "no session, pattern or user messages provided"
|
||||
@@ -18,8 +20,9 @@ type Chatter struct {
|
||||
Stream bool
|
||||
DryRun bool
|
||||
|
||||
model string
|
||||
vendor ai.Vendor
|
||||
model string
|
||||
modelContextLength int
|
||||
vendor ai.Vendor
|
||||
}
|
||||
|
||||
func (o *Chatter) Send(request *common.ChatRequest, opts *common.ChatOptions) (session *fsdb.Session, err error) {
|
||||
@@ -31,6 +34,10 @@ func (o *Chatter) Send(request *common.ChatRequest, opts *common.ChatOptions) (s
|
||||
opts.Model = o.model
|
||||
}
|
||||
|
||||
if opts.ModelContextLength == 0 {
|
||||
opts.ModelContextLength = o.modelContextLength
|
||||
}
|
||||
|
||||
message := ""
|
||||
|
||||
if o.Stream {
|
||||
|
||||
@@ -3,15 +3,15 @@ package core
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/danielmiessler/fabric/common"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/azure"
|
||||
"github.com/danielmiessler/fabric/plugins/tools"
|
||||
"github.com/samber/lo"
|
||||
"strconv"
|
||||
|
||||
"github.com/samber/lo"
|
||||
|
||||
"github.com/danielmiessler/fabric/common"
|
||||
"github.com/danielmiessler/fabric/plugins"
|
||||
"github.com/danielmiessler/fabric/plugins/ai"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/anthropic"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/azure"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/dryrun"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/gemini"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/groq"
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/danielmiessler/fabric/plugins/ai/openrouter"
|
||||
"github.com/danielmiessler/fabric/plugins/ai/siliconcloud"
|
||||
"github.com/danielmiessler/fabric/plugins/db/fsdb"
|
||||
"github.com/danielmiessler/fabric/plugins/tools"
|
||||
"github.com/danielmiessler/fabric/plugins/tools/jina"
|
||||
"github.com/danielmiessler/fabric/plugins/tools/lang"
|
||||
"github.com/danielmiessler/fabric/plugins/tools/youtube"
|
||||
@@ -164,7 +165,7 @@ func (o *PluginRegistry) Configure() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (o *PluginRegistry) GetChatter(model string, stream bool, dryRun bool) (ret *Chatter, err error) {
|
||||
func (o *PluginRegistry) GetChatter(model string, modelContextLength int, stream bool, dryRun bool) (ret *Chatter, err error) {
|
||||
ret = &Chatter{
|
||||
db: o.Db,
|
||||
Stream: stream,
|
||||
@@ -172,9 +173,20 @@ func (o *PluginRegistry) GetChatter(model string, stream bool, dryRun bool) (ret
|
||||
}
|
||||
|
||||
defaultModel := o.Defaults.Model.Value
|
||||
defaultModelContextLength, err := strconv.Atoi(o.Defaults.ModelContextLength.Value)
|
||||
defaultVendor := o.Defaults.Vendor.Value
|
||||
vendorManager := o.VendorManager
|
||||
|
||||
if err != nil {
|
||||
defaultModelContextLength = 0
|
||||
err = nil
|
||||
}
|
||||
|
||||
ret.modelContextLength = modelContextLength
|
||||
if ret.modelContextLength == 0 {
|
||||
ret.modelContextLength = defaultModelContextLength
|
||||
}
|
||||
|
||||
if dryRun {
|
||||
ret.vendor = dryrun.NewClient()
|
||||
ret.model = model
|
||||
|
||||
119
flake.lock
generated
Normal file
119
flake.lock
generated
Normal file
@@ -0,0 +1,119 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gomod2nix": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1729448365,
|
||||
"narHash": "sha256-oquZeWTYWTr5IxfwEzgsxjtD8SSFZYLdO9DaQb70vNU=",
|
||||
"owner": "nix-community",
|
||||
"repo": "gomod2nix",
|
||||
"rev": "5d387097aa716f35dd99d848dc26d8d5b62a104c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "gomod2nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1729665710,
|
||||
"narHash": "sha256-AlcmCXJZPIlO5dmFzV3V2XF6x/OpNWUV8Y/FMPGd8Z4=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "2768c7d042a37de65bb1b5b3268fc987e534c49d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"gomod2nix": "gomod2nix",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems_2",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1729613947,
|
||||
"narHash": "sha256-XGOvuIPW1XRfPgHtGYXd5MAmJzZtOuwlfKDgxX5KT3s=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "aac86347fb5063960eccb19493e0cadcdb4205ca",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
71
flake.nix
Normal file
71
flake.nix
Normal file
@@ -0,0 +1,71 @@
|
||||
{
|
||||
description = "Fabric is an open-source framework for augmenting humans using AI. It provides a modular framework for solving specific problems using a crowdsourced set of AI prompts that can be used anywhere";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
systems.url = "github:nix-systems/default";
|
||||
|
||||
treefmt-nix = {
|
||||
url = "github:numtide/treefmt-nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
gomod2nix = {
|
||||
url = "github:nix-community/gomod2nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
systems,
|
||||
treefmt-nix,
|
||||
gomod2nix,
|
||||
...
|
||||
}:
|
||||
let
|
||||
forAllSystems = nixpkgs.lib.genAttrs (import systems);
|
||||
|
||||
treefmtEval = forAllSystems (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in
|
||||
treefmt-nix.lib.evalModule pkgs ./treefmt.nix
|
||||
);
|
||||
in
|
||||
{
|
||||
formatter = forAllSystems (system: treefmtEval.${system}.config.build.wrapper);
|
||||
|
||||
checks = forAllSystems (system: {
|
||||
formatting = treefmtEval.${system}.config.build.check self;
|
||||
});
|
||||
|
||||
devShells = forAllSystems (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
goEnv = gomod2nix.legacyPackages.${system}.mkGoEnv { pwd = ./.; };
|
||||
in
|
||||
import ./shell.nix {
|
||||
inherit pkgs goEnv;
|
||||
inherit (gomod2nix.legacyPackages.${system}) gomod2nix;
|
||||
}
|
||||
);
|
||||
|
||||
packages = forAllSystems (
|
||||
system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
in
|
||||
{
|
||||
default = self.packages.${system}.fabric;
|
||||
fabric = pkgs.callPackage ./pkgs/fabric {
|
||||
inherit (gomod2nix.legacyPackages.${system}) buildGoApplication;
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
270
gomod2nix.toml
Normal file
270
gomod2nix.toml
Normal file
@@ -0,0 +1,270 @@
|
||||
schema = 3
|
||||
|
||||
[mod]
|
||||
[mod."cloud.google.com/go"]
|
||||
version = "v0.116.0"
|
||||
hash = "sha256-e62GvNveg3bRi4O+eBARqgQ2sinobx+SVGR9WE7jKgs="
|
||||
[mod."cloud.google.com/go/ai"]
|
||||
version = "v0.8.2"
|
||||
hash = "sha256-UtCuHChDsXlACXdlVSNFo8F/X8vAkmPoJyng3/oEFe0="
|
||||
[mod."cloud.google.com/go/auth"]
|
||||
version = "v0.9.9"
|
||||
hash = "sha256-kUrulQhYPM6cFhInFqTX/Dj1GVi+Ev1Ry7T+hiTmb38="
|
||||
[mod."cloud.google.com/go/auth/oauth2adapt"]
|
||||
version = "v0.2.4"
|
||||
hash = "sha256-GRXPQMHEEgeKhdCOBjoDL7+UW3yBdSei5ULuZGBE4tw="
|
||||
[mod."cloud.google.com/go/compute/metadata"]
|
||||
version = "v0.5.2"
|
||||
hash = "sha256-EtBj20lhjM3SJVKCp70GHMnsItwJ9gOyJOW91wugojc="
|
||||
[mod."cloud.google.com/go/longrunning"]
|
||||
version = "v0.6.2"
|
||||
hash = "sha256-X78JL1/YtXA7upOcTuNezq5TxjQyFxQ6OINrS8zzdEU="
|
||||
[mod."dario.cat/mergo"]
|
||||
version = "v1.0.1"
|
||||
hash = "sha256-wcG6+x0k6KzOSlaPA+1RFxa06/RIAePJTAjjuhLbImw="
|
||||
[mod."github.com/Microsoft/go-winio"]
|
||||
version = "v0.6.2"
|
||||
hash = "sha256-tVNWDUMILZbJvarcl/E7tpSnkn7urqgSHa2Eaka5vSU="
|
||||
[mod."github.com/ProtonMail/go-crypto"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-Gflazvyv+457FpUTtPafJ+SdolYSalpsU0tragTxNi8="
|
||||
[mod."github.com/anaskhan96/soup"]
|
||||
version = "v1.2.5"
|
||||
hash = "sha256-t8yCyK2y7x2qaI/3Yw16q3zVFqu+3acLcPgTr1MIKWg="
|
||||
[mod."github.com/andybalholm/cascadia"]
|
||||
version = "v1.3.2"
|
||||
hash = "sha256-Nc9SkqJO/ecincVcUBFITy24TMmMGj5o0Q8EgdNhrEk="
|
||||
[mod."github.com/araddon/dateparse"]
|
||||
version = "v0.0.0-20210429162001-6b43995a97de"
|
||||
hash = "sha256-UuX84naeRGMsFOgIgRoBHG5sNy1CzBkWPKmd6VbLwFw="
|
||||
[mod."github.com/atotto/clipboard"]
|
||||
version = "v0.1.4"
|
||||
hash = "sha256-ZZ7U5X0gWOu8zcjZcWbcpzGOGdycwq0TjTFh/eZHjXk="
|
||||
[mod."github.com/bytedance/sonic"]
|
||||
version = "v1.12.3"
|
||||
hash = "sha256-cZicMhM/2D7HefuJ0xe7AJKh9du2O38HWs+3RNCpbZM="
|
||||
[mod."github.com/bytedance/sonic/loader"]
|
||||
version = "v0.2.1"
|
||||
hash = "sha256-+gPRZtBOJbAnXp/jdMlPmesc62JGH8akQ1UK9VRI7E4="
|
||||
[mod."github.com/cloudflare/circl"]
|
||||
version = "v1.5.0"
|
||||
hash = "sha256-j7T4cfbfmhlbaO+kNKveTnk95JbkEOX0IVw8D9bGTkQ="
|
||||
[mod."github.com/cloudwego/base64x"]
|
||||
version = "v0.1.4"
|
||||
hash = "sha256-umCZR3iNmHFm+BC76kfpdcRG+pTQd6Jcu/c2kQDnyfw="
|
||||
[mod."github.com/cloudwego/iasm"]
|
||||
version = "v0.2.0"
|
||||
hash = "sha256-TzIP2N3HOesXrKACsRr/ShcoqttwPGZPckIepsTyHOA="
|
||||
[mod."github.com/cyphar/filepath-securejoin"]
|
||||
version = "v0.3.4"
|
||||
hash = "sha256-I9dV5gtKk3hH39taAWxvvJEXMi4YoHSxeESVyjpl1MU="
|
||||
[mod."github.com/davecgh/go-spew"]
|
||||
version = "v1.1.1"
|
||||
hash = "sha256-nhzSUrE1fCkN0+RL04N4h8jWmRFPPPWbCuDc7Ss0akI="
|
||||
[mod."github.com/emirpasic/gods"]
|
||||
version = "v1.18.1"
|
||||
hash = "sha256-hGDKddjLj+5dn2woHtXKUdd49/3xdsqnhx7VEdCu1m4="
|
||||
[mod."github.com/felixge/httpsnoop"]
|
||||
version = "v1.0.4"
|
||||
hash = "sha256-c1JKoRSndwwOyOxq9ddCe+8qn7mG9uRq2o/822x5O/c="
|
||||
[mod."github.com/gabriel-vasile/mimetype"]
|
||||
version = "v1.4.6"
|
||||
hash = "sha256-W/uPcE22Fduw1XmX8Ujf1S9SYVOcEoE1wzK4I0/vapw="
|
||||
[mod."github.com/gin-contrib/sse"]
|
||||
version = "v0.1.0"
|
||||
hash = "sha256-zYbMTao+1F+385Lvsba9roLmmt9eYqr57sUWo0LCVhw="
|
||||
[mod."github.com/gin-gonic/gin"]
|
||||
version = "v1.10.0"
|
||||
hash = "sha256-esJasHrJtuTBwGPGAoc/XSb428J8va+tPGcZ0gTfsgc="
|
||||
[mod."github.com/go-git/gcfg"]
|
||||
version = "v1.5.1-0.20230307220236-3a3c6141e376"
|
||||
hash = "sha256-f4k0gSYuo0/q3WOoTxl2eFaj7WZpdz29ih6CKc8Ude8="
|
||||
[mod."github.com/go-git/go-billy/v5"]
|
||||
version = "v5.6.0"
|
||||
hash = "sha256-Hw+odNozpiixXqmsbahihdV+TBxpusm6/hDLngf7kUg="
|
||||
[mod."github.com/go-git/go-git/v5"]
|
||||
version = "v5.12.0"
|
||||
hash = "sha256-mD8EWOQ25FtKBWVSQhQ8V1Rr0tC/ySFZQ9GMDLRqwQU="
|
||||
[mod."github.com/go-logr/logr"]
|
||||
version = "v1.4.2"
|
||||
hash = "sha256-/W6qGilFlZNTb9Uq48xGZ4IbsVeSwJiAMLw4wiNYHLI="
|
||||
[mod."github.com/go-logr/stdr"]
|
||||
version = "v1.2.2"
|
||||
hash = "sha256-rRweAP7XIb4egtT1f2gkz4sYOu7LDHmcJ5iNsJUd0sE="
|
||||
[mod."github.com/go-playground/locales"]
|
||||
version = "v0.14.1"
|
||||
hash = "sha256-BMJGAexq96waZn60DJXZfByRHb8zA/JP/i6f/YrW9oQ="
|
||||
[mod."github.com/go-playground/universal-translator"]
|
||||
version = "v0.18.1"
|
||||
hash = "sha256-2/B2qP51zfiY+k8G0w0D03KXUc7XpWj6wKY7NjNP/9E="
|
||||
[mod."github.com/go-playground/validator/v10"]
|
||||
version = "v10.22.1"
|
||||
hash = "sha256-EsgeltH0ow6saxLvTFVtIyHVqWI3Fiu1AE2Qmnsmowg="
|
||||
[mod."github.com/go-shiori/dom"]
|
||||
version = "v0.0.0-20230515143342-73569d674e1c"
|
||||
hash = "sha256-4lm9KZfR2XnfZU9KTG+4jqLYZqbfL74AMO4y3dKpIbg="
|
||||
[mod."github.com/go-shiori/go-readability"]
|
||||
version = "v0.0.0-20241012063810-92284fa8a71f"
|
||||
hash = "sha256-NgciyWylVSjzkt5xWF1Xk1Xbxgq3PsHW5PZ8oifjZVY="
|
||||
[mod."github.com/goccy/go-json"]
|
||||
version = "v0.10.3"
|
||||
hash = "sha256-ZOzfwCXh+qp+hp+UnC0t422hUV0Cq5KANXkx8hcLp7s="
|
||||
[mod."github.com/gogs/chardet"]
|
||||
version = "v0.0.0-20211120154057-b7413eaefb8f"
|
||||
hash = "sha256-4MeqBJsh4U+ZEbfdDwdciTYMlQWkCil2KJbUxHjBSIo="
|
||||
[mod."github.com/golang/groupcache"]
|
||||
version = "v0.0.0-20210331224755-41bb18bfe9da"
|
||||
hash = "sha256-7Gs7CS9gEYZkbu5P4hqPGBpeGZWC64VDwraSKFF+VR0="
|
||||
[mod."github.com/google/generative-ai-go"]
|
||||
version = "v0.18.0"
|
||||
hash = "sha256-Ye+1rV3gzb2FG9ATq8cihlUiCynRv0eejMwsSfxOXcM="
|
||||
[mod."github.com/google/s2a-go"]
|
||||
version = "v0.1.8"
|
||||
hash = "sha256-H4jy3iElh82CTujW3UpaSvsdfN7fZHBLJ4Z4M7kiMSk="
|
||||
[mod."github.com/google/uuid"]
|
||||
version = "v1.6.0"
|
||||
hash = "sha256-VWl9sqUzdOuhW0KzQlv0gwwUQClYkmZwSydHG2sALYw="
|
||||
[mod."github.com/googleapis/enterprise-certificate-proxy"]
|
||||
version = "v0.3.4"
|
||||
hash = "sha256-RVHWa0I68CTegjlXnM/GlishoZhmmwG4z+9KBucAJ1A="
|
||||
[mod."github.com/googleapis/gax-go/v2"]
|
||||
version = "v2.13.0"
|
||||
hash = "sha256-p1SEjRjI/SkWSBWjeptQ5M/Tgrcj8IiH/beXBYqRVko="
|
||||
[mod."github.com/jbenet/go-context"]
|
||||
version = "v0.0.0-20150711004518-d14ea06fba99"
|
||||
hash = "sha256-VANNCWNNpARH/ILQV9sCQsBWgyL2iFT+4AHZREpxIWE="
|
||||
[mod."github.com/jessevdk/go-flags"]
|
||||
version = "v1.6.1"
|
||||
hash = "sha256-Q5WFTgRxYio0+ay3sbQeBPKeJAFvOdiDVkaTVn3hoTA="
|
||||
[mod."github.com/joho/godotenv"]
|
||||
version = "v1.5.1"
|
||||
hash = "sha256-kA0osKfsc6Kp+nuGTRJyXZZlJt1D/kuEazKMWYCWcQ8="
|
||||
[mod."github.com/json-iterator/go"]
|
||||
version = "v1.1.12"
|
||||
hash = "sha256-To8A0h+lbfZ/6zM+2PpRpY3+L6725OPC66lffq6fUoM="
|
||||
[mod."github.com/kevinburke/ssh_config"]
|
||||
version = "v1.2.0"
|
||||
hash = "sha256-Ta7ZOmyX8gG5tzWbY2oES70EJPfI90U7CIJS9EAce0s="
|
||||
[mod."github.com/klauspost/cpuid/v2"]
|
||||
version = "v2.2.8"
|
||||
hash = "sha256-/E58BnABQYxO+cmiue7OQqRLWkd/Lh8grX8DjTU4tk8="
|
||||
[mod."github.com/leodido/go-urn"]
|
||||
version = "v1.4.0"
|
||||
hash = "sha256-Q6kplWkY37Tzy6GOme3Wut40jFK4Izun+ij/BJvcEu0="
|
||||
[mod."github.com/liushuangls/go-anthropic/v2"]
|
||||
version = "v2.9.0"
|
||||
hash = "sha256-1bvwuPT5SaYrzKYiXpz0fjDgu3994Hs5MPXZUFPhCLI="
|
||||
[mod."github.com/mattn/go-isatty"]
|
||||
version = "v0.0.20"
|
||||
hash = "sha256-qhw9hWtU5wnyFyuMbKx+7RB8ckQaFQ8D+8GKPkN3HHQ="
|
||||
[mod."github.com/modern-go/concurrent"]
|
||||
version = "v0.0.0-20180306012644-bacd9c7ef1dd"
|
||||
hash = "sha256-OTySieAgPWR4oJnlohaFTeK1tRaVp/b0d1rYY8xKMzo="
|
||||
[mod."github.com/modern-go/reflect2"]
|
||||
version = "v1.0.2"
|
||||
hash = "sha256-+W9EIW7okXIXjWEgOaMh58eLvBZ7OshW2EhaIpNLSBU="
|
||||
[mod."github.com/ollama/ollama"]
|
||||
version = "v0.3.14"
|
||||
hash = "sha256-R+jWZzGokwWimPePIcUoZz6tDG2qHFeClgxhT7SEoqw="
|
||||
[mod."github.com/otiai10/copy"]
|
||||
version = "v1.14.0"
|
||||
hash = "sha256-xsaL1ddkPS544y0Jv7u/INUALBYmYq29ddWvysLXk4A="
|
||||
[mod."github.com/pelletier/go-toml/v2"]
|
||||
version = "v2.2.3"
|
||||
hash = "sha256-fE++SVgnCGdnFZoROHWuYjIR7ENl7k9KKxQrRTquv/o="
|
||||
[mod."github.com/pjbgf/sha1cd"]
|
||||
version = "v0.3.0"
|
||||
hash = "sha256-kX9BdLh2dxtGNaDvc24NORO+C0AZ7JzbrXrtecCdB7w="
|
||||
[mod."github.com/pkg/errors"]
|
||||
version = "v0.9.1"
|
||||
hash = "sha256-mNfQtcrQmu3sNg/7IwiieKWOgFQOVVe2yXgKBpe/wZw="
|
||||
[mod."github.com/pmezard/go-difflib"]
|
||||
version = "v1.0.0"
|
||||
hash = "sha256-/FtmHnaGjdvEIKAJtrUfEhV7EVo5A/eYrtdnUkuxLDA="
|
||||
[mod."github.com/samber/lo"]
|
||||
version = "v1.47.0"
|
||||
hash = "sha256-jMXexVTlPdZ40STRpBLv7b+BIRqdxxra12Pl2Mj7Nz8="
|
||||
[mod."github.com/sashabaranov/go-openai"]
|
||||
version = "v1.32.5"
|
||||
hash = "sha256-T56gcES0qMZCSL3uFi+G9vmfTk00QlMWONsMS+cxwR0="
|
||||
[mod."github.com/sergi/go-diff"]
|
||||
version = "v1.3.2-0.20230802210424-5b0b94c5c0d3"
|
||||
hash = "sha256-UcLU83CPMbSoKI8RLvLJ7nvGaE2xRSL1RjoHCVkMzUM="
|
||||
[mod."github.com/skeema/knownhosts"]
|
||||
version = "v1.3.0"
|
||||
hash = "sha256-piR5IdfqxK9nxyErJ+IRDLnkaeNQwX93ztTFZyPm5MQ="
|
||||
[mod."github.com/stretchr/testify"]
|
||||
version = "v1.9.0"
|
||||
hash = "sha256-uUp/On+1nK+lARkTVtb5RxlW15zxtw2kaAFuIASA+J0="
|
||||
[mod."github.com/twitchyliquid64/golang-asm"]
|
||||
version = "v0.15.1"
|
||||
hash = "sha256-HLk6oUe7EoITrNvP0y8D6BtIgIcmDZYtb/xl/dufIoY="
|
||||
[mod."github.com/ugorji/go/codec"]
|
||||
version = "v1.2.12"
|
||||
hash = "sha256-sp1LJ93UK7mFwgZqG8jxCgTCPgKR74HNU6XxX0Jfjm0="
|
||||
[mod."github.com/xanzy/ssh-agent"]
|
||||
version = "v0.3.3"
|
||||
hash = "sha256-l3pGB6IdzcPA/HLk93sSN6NM2pKPy+bVOoacR5RC2+c="
|
||||
[mod."go.opencensus.io"]
|
||||
version = "v0.24.0"
|
||||
hash = "sha256-4H+mGZgG2c9I1y0m8avF4qmt8LUKxxVsTqR8mKgP4yo="
|
||||
[mod."go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"]
|
||||
version = "v0.56.0"
|
||||
hash = "sha256-nrdJ7CgH3yKhNkMpvhP2BY4+VL/maR5mrjJCO6Dke2s="
|
||||
[mod."go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"]
|
||||
version = "v0.56.0"
|
||||
hash = "sha256-Nw9uF/TUoFnH0488VNHVndgoSX+lxZy1Y93Wryl7qP4="
|
||||
[mod."go.opentelemetry.io/otel"]
|
||||
version = "v1.31.0"
|
||||
hash = "sha256-NQBHyMSRn9vaxSrNHYwv0oX1aJuEpyks/gpYEWHlx6k="
|
||||
[mod."go.opentelemetry.io/otel/metric"]
|
||||
version = "v1.31.0"
|
||||
hash = "sha256-2s5IN8IwPBitqnjIEraOfg8fWd3nIy8jWoKTXa+uUs4="
|
||||
[mod."go.opentelemetry.io/otel/trace"]
|
||||
version = "v1.31.0"
|
||||
hash = "sha256-iVDe3qNzmX1+MQTAoaeIbhnIbu/hnx4OsUIPlxuX1gY="
|
||||
[mod."golang.org/x/arch"]
|
||||
version = "v0.11.0"
|
||||
hash = "sha256-gl4bqDA/Qv6hhqxROIHTWnNGkidMMN0frp1RqcfNXlY="
|
||||
[mod."golang.org/x/crypto"]
|
||||
version = "v0.28.0"
|
||||
hash = "sha256-AYjr0BcWQMwWY1u8c2hzUprtqHUmAH7RNSxHz2hhnZs="
|
||||
[mod."golang.org/x/net"]
|
||||
version = "v0.30.0"
|
||||
hash = "sha256-i1f6wJHfFq0nKtbuY7twZ7uPyUbRYHVjd3uy0SS06mU="
|
||||
[mod."golang.org/x/oauth2"]
|
||||
version = "v0.23.0"
|
||||
hash = "sha256-K1X4ROG88PprttNjZCikDlZw8YYiQIQRdtbZBH3GJgM="
|
||||
[mod."golang.org/x/sync"]
|
||||
version = "v0.8.0"
|
||||
hash = "sha256-usvF0z7gq1vsX58p4orX+8WHlv52pdXgaueXlwj2Wss="
|
||||
[mod."golang.org/x/sys"]
|
||||
version = "v0.26.0"
|
||||
hash = "sha256-YjklsWNhx4g4TaWRWfFe1TMFKujbqiaNvZ38bfI35fM="
|
||||
[mod."golang.org/x/text"]
|
||||
version = "v0.19.0"
|
||||
hash = "sha256-C92pSYLLUQ2NKKcc60wpoSJ5UWAfnWkmd997C13fXdU="
|
||||
[mod."golang.org/x/time"]
|
||||
version = "v0.7.0"
|
||||
hash = "sha256-o1ol/hTpfrc06KUXSepAgm4QUuWmH1S+vqg6kmFad64="
|
||||
[mod."google.golang.org/api"]
|
||||
version = "v0.203.0"
|
||||
hash = "sha256-UlCfDi4LbcBvXVO5gLRWP6/fpfWWHoolRkxzYWGnNqg="
|
||||
[mod."google.golang.org/genproto/googleapis/api"]
|
||||
version = "v0.0.0-20241021214115-324edc3d5d38"
|
||||
hash = "sha256-ASsqfJU1DA57PLRoitSkdlS/p10EEuzl0YuZTdbmMCw="
|
||||
[mod."google.golang.org/genproto/googleapis/rpc"]
|
||||
version = "v0.0.0-20241021214115-324edc3d5d38"
|
||||
hash = "sha256-Fk+cG5bRI3BvnqhWzvMzbU36cC7PM+o2oAOJmvVx9M0="
|
||||
[mod."google.golang.org/grpc"]
|
||||
version = "v1.67.1"
|
||||
hash = "sha256-VqfKp80c2B1MK4m1WtHW4r7ykqdChJbqaMn+gMEYmYc="
|
||||
[mod."google.golang.org/protobuf"]
|
||||
version = "v1.35.1"
|
||||
hash = "sha256-4NtUQoBvlPGFGjo7c+E1EBS/sb8oy50MGy45KGWPpWo="
|
||||
[mod."gopkg.in/warnings.v0"]
|
||||
version = "v0.1.2"
|
||||
hash = "sha256-ATVL9yEmgYbkJ1DkltDGRn/auGAjqGOfjQyBYyUo8s8="
|
||||
[mod."gopkg.in/yaml.v3"]
|
||||
version = "v3.0.1"
|
||||
hash = "sha256-FqL9TKYJ0XkNwJFnq9j0VvJ5ZUU1RvH/52h/f5bkYAU="
|
||||
45
patterns/create_user_story/system.md
Normal file
45
patterns/create_user_story/system.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# IDENTITY and PURPOSE
|
||||
|
||||
You are an expert on writing concise, clear, and illuminating technical user stories for new features in complex software programs
|
||||
|
||||
# OUTPUT INSTRUCTIONS
|
||||
|
||||
Write the users stories in a fashion recognised by other software stakeholders, including product, development, operations and quality assurance
|
||||
|
||||
EXAMPLE USER STORY
|
||||
|
||||
Description
|
||||
As a Highlight developer
|
||||
I want to migrate email templates over to Mustache
|
||||
So that future upgrades to the messenger service can be made easier
|
||||
|
||||
Acceptance Criteria
|
||||
- Migrate the existing alerting email templates from the instance specific databases over to the messenger templates blob storage.
|
||||
- Rename each template to a GUID and store in it's own folder within the blob storage
|
||||
- Store Subject and Body as separate blobs
|
||||
|
||||
- Create an upgrade script to change the value of the Alerting.Email.Template local parameter in all systems to the new template names.
|
||||
- Change the template retrieval and saving for user editing to contact the blob storage rather than the database
|
||||
- Remove the database tables and code that handles the SQL based templates
|
||||
- Highlight sends the template name and the details of the body to the Email queue in Service bus
|
||||
- this is handled by the generic Email Client (if created already)
|
||||
- This email type will be added to the list of email types that are sent to the messenger service (switch to be removed once all email templates are completed)
|
||||
|
||||
- Include domain details as part of payload sent to the messenger service
|
||||
|
||||
Note: ensure that Ops know when this work is being done so they are aware of any changes to existing templates
|
||||
|
||||
# OUTPUT INSTRUCTIONS
|
||||
|
||||
- Write the user story according to the structure above.
|
||||
- That means the user story should be written in a simple, bulleted style, not in a grandiose, conversational or academic style.
|
||||
|
||||
# OUTPUT FORMAT
|
||||
|
||||
- Output a full, user story about the content provided using the instructions above.
|
||||
- The structure should be: Description, Acceptance criteria
|
||||
- Write in a simple, plain, and clear style, not in a grandiose, conversational or academic style.
|
||||
- Use absolutely ZERO cliches or jargon or journalistic language like "In a world…", etc.
|
||||
- Do not use cliches or jargon.
|
||||
- Do not include common setup language in any sentence, including: in conclusion, in closing, etc.
|
||||
- Do not output warnings or notes—just the output requested.
|
||||
25
pkgs/fabric/default.nix
Normal file
25
pkgs/fabric/default.nix
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
lib,
|
||||
buildGoApplication,
|
||||
}:
|
||||
|
||||
buildGoApplication {
|
||||
pname = "fabric-ai";
|
||||
version = import ./version.nix;
|
||||
src = ../../.;
|
||||
pwd = ../../.;
|
||||
modules = ../../gomod2nix.toml;
|
||||
|
||||
ldflags = [
|
||||
"-s"
|
||||
"-w"
|
||||
];
|
||||
|
||||
meta = with lib; {
|
||||
description = "Fabric is an open-source framework for augmenting humans using AI. It provides a modular framework for solving specific problems using a crowdsourced set of AI prompts that can be used anywhere";
|
||||
homepage = "https://github.com/danielmiessler/fabric";
|
||||
license = licenses.mit;
|
||||
platforms = platforms.all;
|
||||
mainProgram = "fabric";
|
||||
};
|
||||
}
|
||||
1
pkgs/fabric/version.nix
Normal file
1
pkgs/fabric/version.nix
Normal file
@@ -0,0 +1 @@
|
||||
"1.4.89"
|
||||
@@ -4,10 +4,11 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/danielmiessler/fabric/plugins"
|
||||
|
||||
goopenai "github.com/sashabaranov/go-openai"
|
||||
|
||||
"github.com/danielmiessler/fabric/common"
|
||||
"github.com/danielmiessler/fabric/plugins"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
@@ -44,6 +45,9 @@ func (c *Client) SendStream(msgs []*goopenai.ChatCompletionMessage, opts *common
|
||||
output += fmt.Sprintf("TopP: %f\n", opts.TopP)
|
||||
output += fmt.Sprintf("PresencePenalty: %f\n", opts.PresencePenalty)
|
||||
output += fmt.Sprintf("FrequencyPenalty: %f\n", opts.FrequencyPenalty)
|
||||
if opts.ModelContextLength != 0 {
|
||||
output += fmt.Sprintf("ModelContextLength: %d\n", opts.ModelContextLength)
|
||||
}
|
||||
|
||||
channel <- output
|
||||
close(channel)
|
||||
@@ -72,6 +76,9 @@ func (c *Client) Send(_ context.Context, msgs []*goopenai.ChatCompletionMessage,
|
||||
fmt.Printf("TopP: %f\n", opts.TopP)
|
||||
fmt.Printf("PresencePenalty: %f\n", opts.PresencePenalty)
|
||||
fmt.Printf("FrequencyPenalty: %f\n", opts.FrequencyPenalty)
|
||||
if opts.ModelContextLength != 0 {
|
||||
fmt.Printf("ModelContextLength: %d\n", opts.ModelContextLength)
|
||||
}
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
@@ -3,16 +3,16 @@ package ollama
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/danielmiessler/fabric/plugins"
|
||||
goopenai "github.com/sashabaranov/go-openai"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/danielmiessler/fabric/common"
|
||||
"github.com/samber/lo"
|
||||
|
||||
ollamaapi "github.com/ollama/ollama/api"
|
||||
"github.com/samber/lo"
|
||||
goopenai "github.com/sashabaranov/go-openai"
|
||||
|
||||
"github.com/danielmiessler/fabric/common"
|
||||
"github.com/danielmiessler/fabric/plugins"
|
||||
)
|
||||
|
||||
func NewClient() (ret *Client) {
|
||||
@@ -110,6 +110,10 @@ func (o *Client) createChatRequest(msgs []*goopenai.ChatCompletionMessage, opts
|
||||
"top_p": opts.TopP,
|
||||
}
|
||||
|
||||
if opts.ModelContextLength != 0 {
|
||||
options["num_ctx"] = opts.ModelContextLength
|
||||
}
|
||||
|
||||
ret = ollamaapi.ChatRequest{
|
||||
Model: opts.Model,
|
||||
Messages: messages,
|
||||
|
||||
@@ -4,9 +4,10 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/danielmiessler/fabric/plugins"
|
||||
"github.com/danielmiessler/fabric/plugins/ai"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func NeeDefaults(getVendorsModels func() (*ai.VendorsModels, error)) (ret *Defaults) {
|
||||
@@ -21,18 +22,23 @@ func NeeDefaults(getVendorsModels func() (*ai.VendorsModels, error)) (ret *Defau
|
||||
}
|
||||
|
||||
ret.Vendor = ret.AddSetting("Vendor", true)
|
||||
|
||||
ret.Model = ret.AddSetupQuestionCustom("Model", true,
|
||||
"Enter the index the name of your default model")
|
||||
|
||||
ret.ModelContextLength = ret.AddSetupQuestionCustom("Model Context Length", false,
|
||||
"Enter model context length")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type Defaults struct {
|
||||
*plugins.PluginBase
|
||||
|
||||
Vendor *plugins.Setting
|
||||
Model *plugins.SetupQuestion
|
||||
GetVendorsModels func() (*ai.VendorsModels, error)
|
||||
Vendor *plugins.Setting
|
||||
Model *plugins.SetupQuestion
|
||||
ModelContextLength *plugins.SetupQuestion
|
||||
GetVendorsModels func() (*ai.VendorsModels, error)
|
||||
}
|
||||
|
||||
func (o *Defaults) Setup() (err error) {
|
||||
|
||||
@@ -2,14 +2,17 @@ package youtube
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/anaskhan96/soup"
|
||||
"github.com/danielmiessler/fabric/plugins"
|
||||
@@ -37,38 +40,56 @@ type YouTube struct {
|
||||
*plugins.PluginBase
|
||||
ApiKey *plugins.SetupQuestion
|
||||
|
||||
service *youtube.Service
|
||||
normalizeRegex *regexp.Regexp
|
||||
service *youtube.Service
|
||||
}
|
||||
|
||||
func (o *YouTube) initService() (err error) {
|
||||
if o.service == nil {
|
||||
o.normalizeRegex = regexp.MustCompile(`[^a-zA-Z0-9]+`)
|
||||
ctx := context.Background()
|
||||
o.service, err = youtube.NewService(ctx, option.WithAPIKey(o.ApiKey.Value))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o *YouTube) GetVideoId(url string) (ret string, err error) {
|
||||
func (o *YouTube) GetVideoOrPlaylistId(url string) (videoId string, playlistId string, err error) {
|
||||
if err = o.initService(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pattern := `(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})`
|
||||
re := regexp.MustCompile(pattern)
|
||||
match := re.FindStringSubmatch(url)
|
||||
if len(match) > 1 {
|
||||
ret = match[1]
|
||||
} else {
|
||||
err = fmt.Errorf("invalid YouTube URL, can't get video ID")
|
||||
// Video ID pattern
|
||||
videoPattern := `(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})`
|
||||
videoRe := regexp.MustCompile(videoPattern)
|
||||
videoMatch := videoRe.FindStringSubmatch(url)
|
||||
if len(videoMatch) > 1 {
|
||||
videoId = videoMatch[1]
|
||||
}
|
||||
|
||||
// Playlist ID pattern
|
||||
playlistPattern := `[?&]list=([a-zA-Z0-9_-]+)`
|
||||
playlistRe := regexp.MustCompile(playlistPattern)
|
||||
playlistMatch := playlistRe.FindStringSubmatch(url)
|
||||
if len(playlistMatch) > 1 {
|
||||
playlistId = playlistMatch[1]
|
||||
}
|
||||
|
||||
if videoId == "" && playlistId == "" {
|
||||
err = fmt.Errorf("invalid YouTube URL, can't get video or playlist ID: '%s'", url)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o *YouTube) GrabTranscriptForUrl(url string, language string) (ret string, err error) {
|
||||
var videoId string
|
||||
if videoId, err = o.GetVideoId(url); err != nil {
|
||||
var playlistId string
|
||||
if videoId, playlistId, err = o.GetVideoOrPlaylistId(url); err != nil {
|
||||
return
|
||||
} else if videoId == "" && playlistId != "" {
|
||||
err = fmt.Errorf("URL is a playlist, not a video")
|
||||
return
|
||||
}
|
||||
|
||||
return o.GrabTranscript(videoId, language)
|
||||
}
|
||||
|
||||
@@ -85,7 +106,7 @@ func (o *YouTube) GrabTranscript(videoId string, language string) (ret string, e
|
||||
textTags := doc.FindAll("text")
|
||||
var textBuilder strings.Builder
|
||||
for _, textTag := range textTags {
|
||||
textBuilder.WriteString(textTag.Text())
|
||||
textBuilder.WriteString(strings.ReplaceAll(textTag.Text(), "'", "'"))
|
||||
textBuilder.WriteString(" ")
|
||||
ret = textBuilder.String()
|
||||
}
|
||||
@@ -172,7 +193,11 @@ func (o *YouTube) GrabDurationForUrl(url string) (ret int, err error) {
|
||||
}
|
||||
|
||||
var videoId string
|
||||
if videoId, err = o.GetVideoId(url); err != nil {
|
||||
var playlistId string
|
||||
if videoId, playlistId, err = o.GetVideoOrPlaylistId(url); err != nil {
|
||||
return
|
||||
} else if videoId == "" && playlistId != "" {
|
||||
err = fmt.Errorf("URL is a playlist, not a video")
|
||||
return
|
||||
}
|
||||
return o.GrabDuration(videoId)
|
||||
@@ -203,7 +228,11 @@ func (o *YouTube) GrabDuration(videoId string) (ret int, err error) {
|
||||
|
||||
func (o *YouTube) Grab(url string, options *Options) (ret *VideoInfo, err error) {
|
||||
var videoId string
|
||||
if videoId, err = o.GetVideoId(url); err != nil {
|
||||
var playlistId string
|
||||
if videoId, playlistId, err = o.GetVideoOrPlaylistId(url); err != nil {
|
||||
return
|
||||
} else if videoId == "" && playlistId != "" {
|
||||
err = fmt.Errorf("URL is a playlist, not a video")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -232,6 +261,109 @@ func (o *YouTube) Grab(url string, options *Options) (ret *VideoInfo, err error)
|
||||
return
|
||||
}
|
||||
|
||||
// FetchPlaylistVideos fetches all videos from a YouTube playlist.
|
||||
func (o *YouTube) FetchPlaylistVideos(playlistID string) (ret []*VideoMeta, err error) {
|
||||
if err = o.initService(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
nextPageToken := ""
|
||||
for {
|
||||
call := o.service.PlaylistItems.List([]string{"snippet"}).PlaylistId(playlistID).MaxResults(50)
|
||||
if nextPageToken != "" {
|
||||
call = call.PageToken(nextPageToken)
|
||||
}
|
||||
|
||||
var response *youtube.PlaylistItemListResponse
|
||||
if response, err = call.Do(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, item := range response.Items {
|
||||
videoID := item.Snippet.ResourceId.VideoId
|
||||
title := item.Snippet.Title
|
||||
ret = append(ret, &VideoMeta{videoID, title, o.normalizeFileName(title)})
|
||||
}
|
||||
|
||||
nextPageToken = response.NextPageToken
|
||||
if nextPageToken == "" {
|
||||
break
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second) // Pause to respect API rate limit
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// SaveVideosToCSV saves the list of videos to a CSV file.
|
||||
func (o *YouTube) SaveVideosToCSV(filename string, videos []*VideoMeta) (err error) {
|
||||
var file *os.File
|
||||
if file, err = os.Create(filename); err != nil {
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
writer := csv.NewWriter(file)
|
||||
defer writer.Flush()
|
||||
|
||||
// Write headers
|
||||
if err = writer.Write([]string{"VideoID", "Title"}); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Write video data
|
||||
for _, record := range videos {
|
||||
if err = writer.Write([]string{record.Id, record.Title}); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// FetchAndSavePlaylist fetches all videos in a playlist and saves them to a CSV file.
|
||||
func (o *YouTube) FetchAndSavePlaylist(playlistID, filename string) (err error) {
|
||||
var videos []*VideoMeta
|
||||
if videos, err = o.FetchPlaylistVideos(playlistID); err != nil {
|
||||
err = fmt.Errorf("error fetching playlist videos: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = o.SaveVideosToCSV(filename, videos); err != nil {
|
||||
err = fmt.Errorf("error saving videos to CSV: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Playlist saved to", filename)
|
||||
return
|
||||
}
|
||||
|
||||
func (o *YouTube) FetchAndPrintPlaylist(playlistID string) (err error) {
|
||||
var videos []*VideoMeta
|
||||
if videos, err = o.FetchPlaylistVideos(playlistID); err != nil {
|
||||
err = fmt.Errorf("error fetching playlist videos: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Playlist: %s\n", playlistID)
|
||||
fmt.Printf("VideoId: Title\n")
|
||||
for _, video := range videos {
|
||||
fmt.Printf("%s: %s\n", video.Id, video.Title)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o *YouTube) normalizeFileName(name string) string {
|
||||
return o.normalizeRegex.ReplaceAllString(name, "_")
|
||||
|
||||
}
|
||||
|
||||
type VideoMeta struct {
|
||||
Id string
|
||||
Title string
|
||||
TitleNormalized string
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
Duration bool
|
||||
Transcript bool
|
||||
|
||||
30
shell.nix
Normal file
30
shell.nix
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
pkgs,
|
||||
gomod2nix,
|
||||
goEnv,
|
||||
}:
|
||||
|
||||
{
|
||||
default = pkgs.mkShell {
|
||||
nativeBuildInputs = [
|
||||
pkgs.go
|
||||
pkgs.gopls
|
||||
pkgs.gotools
|
||||
pkgs.go-tools
|
||||
pkgs.goimports-reviser
|
||||
gomod2nix
|
||||
goEnv
|
||||
|
||||
(pkgs.writeShellScriptBin "update" ''
|
||||
go get -u
|
||||
go mod tidy
|
||||
gomod2nix generate
|
||||
'')
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
echo -e "\033[0;32;4mHeper commands:\033[0m"
|
||||
echo "'update' instead of 'go get -u && go mod tidy'"
|
||||
'';
|
||||
};
|
||||
}
|
||||
11
treefmt.nix
Normal file
11
treefmt.nix
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
projectRootFile = "flake.nix";
|
||||
|
||||
programs = {
|
||||
deadnix.enable = true;
|
||||
statix.enable = true;
|
||||
nixfmt.enable = true;
|
||||
|
||||
gofmt.enable = true;
|
||||
};
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
package main
|
||||
|
||||
var version = "v1.4.82"
|
||||
var version = "v1.4.89"
|
||||
|
||||
Reference in New Issue
Block a user