mirror of
https://github.com/danielmiessler/Fabric.git
synced 2026-01-11 07:18:03 -05:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b26b930f9 | ||
|
|
5dbaf4f28f | ||
|
|
1d9cce5adf | ||
|
|
76622105e2 | ||
|
|
e6e3e34f53 | ||
|
|
7192ddbaa6 | ||
|
|
b5206d1923 | ||
|
|
81d60b4292 | ||
|
|
ca6660585d | ||
|
|
d70e7c570d | ||
|
|
4fb965ec9d |
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@@ -94,11 +94,19 @@ jobs:
|
||||
path: fabric-windows-${{ matrix.arch }}.exe
|
||||
|
||||
- name: Get latest tag
|
||||
if: matrix.os != 'windows-latest'
|
||||
id: get_latest_tag
|
||||
run: |
|
||||
latest_tag=$(git tag --sort=-creatordate | head -n 1)
|
||||
echo "latest_tag=$latest_tag" >> $GITHUB_ENV
|
||||
|
||||
- name: Get latest tag
|
||||
if: matrix.os == 'windows-latest'
|
||||
id: get_latest_tag_windows
|
||||
run: |
|
||||
$latest_tag = git tag --sort=-creatordate | Select-Object -First 1
|
||||
Add-Content -Path $env:GITHUB_ENV -Value "latest_tag=$latest_tag"
|
||||
|
||||
- name: Create release if it doesn't exist
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
15
README.md
15
README.md
@@ -208,18 +208,17 @@ fabric -h
|
||||
|
||||
```bash
|
||||
|
||||
usage: fabric -h
|
||||
Usage:
|
||||
fabric [OPTIONS]
|
||||
|
||||
Application Options:
|
||||
-p, --pattern= Choose a pattern
|
||||
-p, --pattern= Choose a pattern from the available patterns
|
||||
-v, --variable= Values for pattern variables, e.g. -v=$name:John -v=$age:30
|
||||
-C, --context= Choose a context
|
||||
--session= Choose a session
|
||||
-C, --context= Choose a context from the available contexts
|
||||
--session= Choose a session from the available sessions
|
||||
-S, --setup Run setup for all reconfigurable parts of fabric
|
||||
--setup-skip-patterns Run Setup for specific vendor, one of Ollama, OpenAI, Anthropic, Azure, Gemini, Groq, Mistral, OpenRouter, SiliconCloud. E.g. fabric --setup-vendor=OpenAI
|
||||
--setup-vendor= Run Setup for specific vendor. E.g. --setup-vendor=OpenAI
|
||||
--setup-skip-patterns Run Setup for all reconfigurable parts of fabric except patterns update
|
||||
--setup-vendor= Run Setup for specific vendor, one of Ollama, OpenAI, Anthropic, Azure, Gemini, Groq, Mistral, OpenRouter, SiliconCloud. E.g. fabric --setup-vendor=OpenAI
|
||||
-t, --temperature= Set temperature (default: 0.7)
|
||||
-T, --topp= Set top P (default: 0.9)
|
||||
-s, --stream Stream
|
||||
@@ -234,7 +233,7 @@ Application Options:
|
||||
-c, --copy Copy to clipboard
|
||||
-m, --model= Choose model
|
||||
-o, --output= Output to file
|
||||
--output-prompt Output the used prompt (or entire session) before the result
|
||||
--output-session Output the entire session (also a temporary one) to the output file
|
||||
-n, --latest= Number of latest patterns to list (default: 0)
|
||||
-d, --changeDefaultModel Change default model
|
||||
-y, --youtube= YouTube video "URL" to grab transcript, comments from it and send to chat
|
||||
@@ -253,7 +252,7 @@ Application Options:
|
||||
--version Print current version
|
||||
|
||||
Help Options:
|
||||
-h, --help Show this help message
|
||||
-h, --help Show this help message
|
||||
|
||||
```
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ func Cli(version string) (err error) {
|
||||
}
|
||||
|
||||
var session *db.Session
|
||||
if session, err = chatter.Send(currentFlags.BuildChatRequest(), currentFlags.BuildChatOptions()); err != nil {
|
||||
if session, err = chatter.Send(currentFlags.BuildChatRequest(strings.Join(os.Args[1:], " ")), currentFlags.BuildChatOptions()); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ func Cli(version string) (err error) {
|
||||
|
||||
// if the output flag is set, create an output file
|
||||
if currentFlags.Output != "" {
|
||||
if currentFlags.OutputPrompt {
|
||||
if currentFlags.OutputSession {
|
||||
sessionAsString := session.String()
|
||||
err = fabric.CreateOutputFile(sessionAsString, currentFlags.Output)
|
||||
} else {
|
||||
|
||||
15
cli/flags.go
15
cli/flags.go
@@ -14,13 +14,13 @@ import (
|
||||
|
||||
// Flags create flags struct. the users flags go into this, this will be passed to the chat struct in cli
|
||||
type Flags struct {
|
||||
Pattern string `short:"p" long:"pattern" description:"Choose a pattern" default:""`
|
||||
Pattern string `short:"p" long:"pattern" description:"Choose a pattern from the available patterns" default:""`
|
||||
PatternVariables map[string]string `short:"v" long:"variable" description:"Values for pattern variables, e.g. -v=$name:John -v=$age:30"`
|
||||
Context string `short:"C" long:"context" description:"Choose a context" default:""`
|
||||
Session string `long:"session" description:"Choose a session"`
|
||||
Context string `short:"C" long:"context" description:"Choose a context from the available contexts" default:""`
|
||||
Session string `long:"session" description:"Choose a session from the available sessions"`
|
||||
Setup bool `short:"S" long:"setup" description:"Run setup for all reconfigurable parts of fabric"`
|
||||
SetupSkipPatterns bool `long:"setup-skip-patterns" description:"Run Setup for specific vendor, one of Ollama, OpenAI, Anthropic, Azure, Gemini, Groq, Mistral, OpenRouter, SiliconCloud. E.g. fabric --setup-vendor=OpenAI"`
|
||||
SetupVendor string `long:"setup-vendor" description:"Run Setup for specific vendor. E.g. --setup-vendor=OpenAI"`
|
||||
SetupSkipPatterns bool `long:"setup-skip-patterns" description:"Run Setup for all reconfigurable parts of fabric except patterns update"`
|
||||
SetupVendor string `long:"setup-vendor" description:"Run Setup for specific vendor, one of Ollama, OpenAI, Anthropic, Azure, Gemini, Groq, Mistral, OpenRouter, SiliconCloud. E.g. fabric --setup-vendor=OpenAI"`
|
||||
Temperature float64 `short:"t" long:"temperature" description:"Set temperature" default:"0.7"`
|
||||
TopP float64 `short:"T" long:"topp" description:"Set top P" default:"0.9"`
|
||||
Stream bool `short:"s" long:"stream" description:"Stream"`
|
||||
@@ -36,7 +36,7 @@ type Flags struct {
|
||||
Copy bool `short:"c" long:"copy" description:"Copy to clipboard"`
|
||||
Model string `short:"m" long:"model" description:"Choose model"`
|
||||
Output string `short:"o" long:"output" description:"Output to file" default:""`
|
||||
OutputPrompt bool `long:"output-prompt" description:"Output the used prompt (or entire session) before the result"`
|
||||
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"`
|
||||
ChangeDefaultModel bool `short:"d" long:"changeDefaultModel" description:"Change default model"`
|
||||
YouTube string `short:"y" long:"youtube" description:"YouTube video \"URL\" to grab transcript, comments from it and send to chat"`
|
||||
@@ -113,13 +113,14 @@ func (o *Flags) BuildChatOptions() (ret *common.ChatOptions) {
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Flags) BuildChatRequest() (ret *common.ChatRequest) {
|
||||
func (o *Flags) BuildChatRequest(Meta string) (ret *common.ChatRequest) {
|
||||
ret = &common.ChatRequest{
|
||||
ContextName: o.Context,
|
||||
SessionName: o.Session,
|
||||
PatternName: o.Pattern,
|
||||
PatternVariables: o.PatternVariables,
|
||||
Message: o.Message,
|
||||
Meta: Meta,
|
||||
}
|
||||
if o.Language != "" {
|
||||
langTag, err := language.Parse(o.Language)
|
||||
|
||||
@@ -101,7 +101,8 @@ func TestBuildChatRequest(t *testing.T) {
|
||||
SessionName: "test-session",
|
||||
PatternName: "test-pattern",
|
||||
Message: "test-message",
|
||||
Meta: "test",
|
||||
}
|
||||
request := flags.BuildChatRequest()
|
||||
request := flags.BuildChatRequest("test")
|
||||
assert.Equal(t, expectedRequest, request)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package common
|
||||
|
||||
import goopenai "github.com/sashabaranov/go-openai"
|
||||
|
||||
const ChatMessageRoleMeta = "meta"
|
||||
|
||||
type Message struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
@@ -14,6 +16,7 @@ type ChatRequest struct {
|
||||
PatternVariables map[string]string
|
||||
Message string
|
||||
Language string
|
||||
Meta string
|
||||
}
|
||||
|
||||
type ChatOptions struct {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/danielmiessler/fabric/db"
|
||||
"github.com/danielmiessler/fabric/vendors"
|
||||
goopenai "github.com/sashabaranov/go-openai"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Chatter struct {
|
||||
@@ -20,12 +21,7 @@ type Chatter struct {
|
||||
}
|
||||
|
||||
func (o *Chatter) Send(request *common.ChatRequest, opts *common.ChatOptions) (session *db.Session, err error) {
|
||||
var chatRequest *Chat
|
||||
if chatRequest, err = o.NewChat(request); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if session, err = chatRequest.BuildChatSession(opts.Raw); err != nil {
|
||||
if session, err = o.BuildSession(request, opts.Raw); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -38,7 +34,7 @@ func (o *Chatter) Send(request *common.ChatRequest, opts *common.ChatOptions) (s
|
||||
if o.Stream {
|
||||
channel := make(chan string)
|
||||
go func() {
|
||||
if streamErr := o.vendor.SendStream(session.Messages, opts, channel); streamErr != nil {
|
||||
if streamErr := o.vendor.SendStream(session.GetVendorMessages(), opts, channel); streamErr != nil {
|
||||
channel <- streamErr.Error()
|
||||
}
|
||||
}()
|
||||
@@ -48,7 +44,7 @@ func (o *Chatter) Send(request *common.ChatRequest, opts *common.ChatOptions) (s
|
||||
fmt.Print(response)
|
||||
}
|
||||
} else {
|
||||
if message, err = o.vendor.Send(context.Background(), session.Messages, opts); err != nil {
|
||||
if message, err = o.vendor.Send(context.Background(), session.GetVendorMessages(), opts); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -60,35 +56,39 @@ func (o *Chatter) Send(request *common.ChatRequest, opts *common.ChatOptions) (s
|
||||
|
||||
session.Append(&common.Message{Role: goopenai.ChatMessageRoleAssistant, Content: message})
|
||||
|
||||
if chatRequest.Session != nil {
|
||||
if session.Name != "" {
|
||||
err = o.db.Sessions.SaveSession(session)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Chatter) NewChat(request *common.ChatRequest) (ret *Chat, err error) {
|
||||
ret = &Chat{
|
||||
Language: request.Language,
|
||||
}
|
||||
|
||||
if request.ContextName != "" {
|
||||
var ctx *db.Context
|
||||
if ctx, err = o.db.Contexts.GetContext(request.ContextName); err != nil {
|
||||
err = fmt.Errorf("could not find context %s: %v", request.ContextName, err)
|
||||
return
|
||||
}
|
||||
ret.Context = ctx.Content
|
||||
}
|
||||
|
||||
func (o *Chatter) BuildSession(request *common.ChatRequest, raw bool) (session *db.Session, err error) {
|
||||
if request.SessionName != "" {
|
||||
var sess *db.Session
|
||||
if sess, err = o.db.Sessions.GetOrCreateSession(request.SessionName); err != nil {
|
||||
err = fmt.Errorf("could not find session %s: %v", request.SessionName, err)
|
||||
return
|
||||
}
|
||||
ret.Session = sess
|
||||
session = sess
|
||||
} else {
|
||||
session = &db.Session{}
|
||||
}
|
||||
|
||||
if request.Meta != "" {
|
||||
session.Append(&common.Message{Role: common.ChatMessageRoleMeta, Content: request.Meta})
|
||||
}
|
||||
|
||||
var contextContent string
|
||||
if request.ContextName != "" {
|
||||
var ctx *db.Context
|
||||
if ctx, err = o.db.Contexts.GetContext(request.ContextName); err != nil {
|
||||
err = fmt.Errorf("could not find context %s: %v", request.ContextName, err)
|
||||
return
|
||||
}
|
||||
contextContent = ctx.Content
|
||||
}
|
||||
|
||||
var patternContent string
|
||||
if request.PatternName != "" {
|
||||
var pattern *db.Pattern
|
||||
if pattern, err = o.db.Patterns.GetPattern(request.PatternName, request.PatternVariables); err != nil {
|
||||
@@ -97,18 +97,34 @@ func (o *Chatter) NewChat(request *common.ChatRequest) (ret *Chat, err error) {
|
||||
}
|
||||
|
||||
if pattern.Pattern != "" {
|
||||
ret.Pattern = pattern.Pattern
|
||||
patternContent = pattern.Pattern
|
||||
}
|
||||
}
|
||||
|
||||
ret.Message = request.Message
|
||||
systemMessage := strings.TrimSpace(contextContent) + strings.TrimSpace(patternContent)
|
||||
if request.Language != "" {
|
||||
systemMessage = fmt.Sprintf("%s. Please use the language '%s' for the output.", systemMessage, request.Language)
|
||||
}
|
||||
userMessage := strings.TrimSpace(request.Message)
|
||||
|
||||
if raw {
|
||||
// use the user role instead of the system role in raw mode
|
||||
message := systemMessage + userMessage
|
||||
if message != "" {
|
||||
session.Append(&common.Message{Role: goopenai.ChatMessageRoleUser, Content: message})
|
||||
}
|
||||
} else {
|
||||
if systemMessage != "" {
|
||||
session.Append(&common.Message{Role: goopenai.ChatMessageRoleSystem, Content: systemMessage})
|
||||
}
|
||||
if userMessage != "" {
|
||||
session.Append(&common.Message{Role: goopenai.ChatMessageRoleUser, Content: userMessage})
|
||||
}
|
||||
}
|
||||
|
||||
if session.IsEmpty() {
|
||||
session = nil
|
||||
err = fmt.Errorf(NoSessionPatternUserMessages)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type Chat struct {
|
||||
Context string
|
||||
Pattern string
|
||||
Message string
|
||||
Session *db.Session
|
||||
Language string
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBuildChatSession(t *testing.T) {
|
||||
chat := &Chat{
|
||||
Context: "test context",
|
||||
Pattern: "test pattern",
|
||||
Message: "test message",
|
||||
}
|
||||
session, err := chat.BuildChatSession(false)
|
||||
if err != nil {
|
||||
t.Fatalf("BuildChatSession() error = %v", err)
|
||||
}
|
||||
|
||||
if session == nil {
|
||||
t.Fatalf("BuildChatSession() returned nil session")
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,6 @@ package core
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/danielmiessler/fabric/vendors/groq"
|
||||
"github.com/danielmiessler/fabric/vendors/mistral"
|
||||
goopenai "github.com/sashabaranov/go-openai"
|
||||
|
||||
"github.com/atotto/clipboard"
|
||||
"github.com/danielmiessler/fabric/common"
|
||||
"github.com/danielmiessler/fabric/db"
|
||||
@@ -19,12 +11,16 @@ import (
|
||||
"github.com/danielmiessler/fabric/vendors/azure"
|
||||
"github.com/danielmiessler/fabric/vendors/dryrun"
|
||||
"github.com/danielmiessler/fabric/vendors/gemini"
|
||||
"github.com/danielmiessler/fabric/vendors/groq"
|
||||
"github.com/danielmiessler/fabric/vendors/mistral"
|
||||
"github.com/danielmiessler/fabric/vendors/ollama"
|
||||
"github.com/danielmiessler/fabric/vendors/openai"
|
||||
"github.com/danielmiessler/fabric/vendors/openrouter"
|
||||
"github.com/danielmiessler/fabric/vendors/siliconcloud"
|
||||
"github.com/danielmiessler/fabric/youtube"
|
||||
"github.com/pkg/errors"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const DefaultPatternsGitRepoUrl = "https://github.com/danielmiessler/fabric.git"
|
||||
@@ -257,39 +253,3 @@ func (o *Fabric) CreateOutputFile(message string, fileName string) (err error) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Chat) BuildChatSession(raw bool) (ret *db.Session, err error) {
|
||||
// new messages will be appended to the session and used to send the message
|
||||
if o.Session != nil {
|
||||
ret = o.Session
|
||||
} else {
|
||||
ret = &db.Session{}
|
||||
}
|
||||
|
||||
systemMessage := strings.TrimSpace(o.Context) + strings.TrimSpace(o.Pattern)
|
||||
if o.Language != "" {
|
||||
systemMessage = fmt.Sprintf("%s. Please use the language '%s' for the output.", systemMessage, o.Language)
|
||||
}
|
||||
userMessage := strings.TrimSpace(o.Message)
|
||||
|
||||
if raw {
|
||||
// use the user role instead of the system role in raw mode
|
||||
message := systemMessage + userMessage
|
||||
if message != "" {
|
||||
ret.Append(&common.Message{Role: goopenai.ChatMessageRoleUser, Content: message})
|
||||
}
|
||||
} else {
|
||||
if systemMessage != "" {
|
||||
ret.Append(&common.Message{Role: goopenai.ChatMessageRoleSystem, Content: systemMessage})
|
||||
}
|
||||
if userMessage != "" {
|
||||
ret.Append(&common.Message{Role: goopenai.ChatMessageRoleUser, Content: userMessage})
|
||||
}
|
||||
}
|
||||
|
||||
if ret.IsEmpty() {
|
||||
ret = nil
|
||||
err = fmt.Errorf(NoSessionPatternUserMessages)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ func (o *Sessions) SaveSession(session *Session) (err error) {
|
||||
type Session struct {
|
||||
Name string
|
||||
Messages []*common.Message
|
||||
|
||||
vendorMessages []*common.Message
|
||||
}
|
||||
|
||||
func (o *Session) IsEmpty() bool {
|
||||
@@ -44,7 +46,31 @@ func (o *Session) IsEmpty() bool {
|
||||
}
|
||||
|
||||
func (o *Session) Append(messages ...*common.Message) {
|
||||
o.Messages = append(o.Messages, messages...)
|
||||
if o.vendorMessages != nil {
|
||||
for _, message := range messages {
|
||||
o.Messages = append(o.Messages, message)
|
||||
o.appendVendorMessage(message)
|
||||
}
|
||||
} else {
|
||||
o.Messages = append(o.Messages, messages...)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Session) GetVendorMessages() (ret []*common.Message) {
|
||||
if o.vendorMessages == nil {
|
||||
o.vendorMessages = []*common.Message{}
|
||||
for _, message := range o.Messages {
|
||||
o.appendVendorMessage(message)
|
||||
}
|
||||
}
|
||||
ret = o.vendorMessages
|
||||
return
|
||||
}
|
||||
|
||||
func (o *Session) appendVendorMessage(message *common.Message) {
|
||||
if message.Role != common.ChatMessageRoleMeta {
|
||||
o.vendorMessages = append(o.vendorMessages, message)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Session) GetLastMessage() (ret *common.Message) {
|
||||
@@ -56,7 +82,7 @@ func (o *Session) GetLastMessage() (ret *common.Message) {
|
||||
|
||||
func (o *Session) String() (ret string) {
|
||||
for _, message := range o.Messages {
|
||||
ret += fmt.Sprintf("\n\n\n[%v]>> \n\n\n%v", message.Role, message.Content)
|
||||
ret += fmt.Sprintf("\n--- \n[%v]\n\n%v", message.Role, message.Content)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
package main
|
||||
|
||||
var version = "v1.4.46"
|
||||
var version = "v1.4.51"
|
||||
|
||||
Reference in New Issue
Block a user