Compare commits

...

40 Commits

Author SHA1 Message Date
github-actions[bot]
525f972d22 Update version to v1.4.60 and commit 2024-10-12 15:27:28 +00:00
Eugen Eisler
161ce65ae6 fix: IsChatRequest rule; Close #1042 is 2024-10-12 18:27:04 +03:00
github-actions[bot]
72f1429db9 Update version to v1.4.59 and commit 2024-10-11 22:59:41 +00:00
Daniel Miessler
b5fe3f2ad8 Added ctw to Raycast. 2024-10-11 15:59:26 -07:00
github-actions[bot]
2155ff9fc0 Update version to v1.4.58 and commit 2024-10-11 20:30:50 +00:00
Eugen Eisler
d33175e5b6 chore: we don't need tp configure DryRun vendor 2024-10-11 23:28:56 +03:00
Eugen Eisler
6dbd24e541 fix: Close #1040. Configure vendors separately that were not configured yet 2024-10-11 23:25:33 +03:00
github-actions[bot]
d1c527c421 Update version to v1.4.57 and commit 2024-10-11 19:27:41 +00:00
Eugen Eisler
c0bd61ba49 docs: Close #1035, provide better example for pattern variables 2024-10-11 22:27:20 +03:00
github-actions[bot]
8f0cc85742 Update version to v1.4.56 and commit 2024-10-11 18:54:25 +00:00
Eugen Eisler
7275dfbd6b Merge pull request #1039 from hallelujah-shih/feature/set-default-lang
Feature/set default lang
2024-10-11 20:54:10 +02:00
hallelujah-shih
9f94cfb718 fmt 2024-10-10 19:45:39 +08:00
hallelujah-shih
e1fa674a3f support set default output language
# Conflicts:
#	cli/cli.go
#	core/fabric.go
2024-10-10 19:37:51 +08:00
github-actions[bot]
34f804be3a Update version to v1.4.55 and commit 2024-10-09 09:29:17 +00:00
Eugen Eisler
83cd8a1912 fix: Close #1036 2024-10-09 12:29:02 +03:00
github-actions[bot]
d347ef0dcc Update version to v1.4.54 and commit 2024-10-07 16:44:19 +00:00
Eugen Eisler
44cc9bbcac Merge pull request #1021 from joshuafuller/main
Corrected spelling and grammatical errors for consistency and clarity for transcribe_minutes
2024-10-07 18:44:06 +02:00
github-actions[bot]
4aa0b99c74 Update version to v1.4.53 and commit 2024-10-07 09:17:11 +00:00
Eugen Eisler
d90e8081ac fix: fix NP if response is empty, close #1026, #1027 2024-10-07 11:16:57 +02:00
github-actions[bot]
70d43c5252 Update version to v1.4.52 and commit 2024-10-06 19:50:30 +00:00
Daniel Miessler
fd8216f1bd Merge branch 'main' of github.com:danielmiessler/fabric 2024-10-06 12:50:12 -07:00
Daniel Miessler
ae0c9009d9 Added extract_core_message. 2024-10-06 12:50:05 -07:00
Joshua Fuller
bad01040e3 Corrected spelling and grammatical errors for consistency and clarity
Description:

Changed "agreed within the meeting" to "agreed upon within the meeting" to improve grammatical accuracy.

Added missing periods to ensure consistency across list items.

Corrected the spelling of "highliting" to "highlighting."

Fixed the spelling of "exxactly" to "exactly."

Updated phrasing in "Write NEXT STEPS a 2-3 sentences" to "Write NEXT STEPS as 2-3 sentences" for grammatical correctness.

These changes improve the readability and consistency of the document, ensuring all instructions are clear and error-free.
2024-10-05 17:29:12 -05:00
github-actions[bot]
0b26b930f9 Update version to v1.4.51 and commit 2024-10-05 16:48:46 +00:00
Eugen Eisler
5dbaf4f28f fix: tests 2024-10-05 18:48:22 +02:00
github-actions[bot]
1d9cce5adf Update version to v1.4.50 and commit 2024-10-05 16:44:19 +00:00
Eugen Eisler
76622105e2 fix: windows release 2024-10-05 18:43:54 +02:00
github-actions[bot]
e6e3e34f53 Update version to v1.4.49 and commit 2024-10-05 16:42:19 +00:00
Eugen Eisler
7192ddbaa6 fix: windows release 2024-10-05 18:41:58 +02:00
github-actions[bot]
b5206d1923 Update version to v1.4.48 and commit 2024-10-05 15:54:01 +00:00
Eugen Eisler
81d60b4292 feat: Add 'meta' role to store meta info to session, like source of input content. 2024-10-05 17:53:48 +02:00
github-actions[bot]
ca6660585d Update version to v1.4.47 and commit 2024-10-05 15:43:21 +00:00
Eugen Eisler
d70e7c570d feat: Add 'meta' role to store meta info to session, like source of input content. 2024-10-05 17:42:57 +02:00
Eugen Eisler
4fb965ec9d feat: Add 'meta' role to store meta info to session, like source of input content. 2024-10-05 17:33:27 +02:00
github-actions[bot]
a5544cb67c Update version to v1.4.46 and commit 2024-10-04 23:05:49 +00:00
Eugen Eisler
679a852c1c feat: Close #1018 2024-10-05 01:05:31 +02:00
Eugen Eisler
c685b4f810 feat: implement print session and context 2024-10-05 01:02:06 +02:00
Eugen Eisler
9452d6bd2a feat: implement print session and context 2024-10-05 00:57:11 +02:00
github-actions[bot]
a6eeff2c91 Update version to v1.4.45 and commit 2024-10-04 20:39:13 +00:00
Eugen Eisler
3eb314320e feat: Setup for specific vendor, e.g. --setup-vendor=OpenAI 2024-10-04 22:38:43 +02:00
19 changed files with 436 additions and 224 deletions

View File

@@ -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 }}

View File

@@ -207,48 +207,52 @@ fabric -h
```
```bash
usage: fabric -h
Usage:
fabric [OPTIONS]
Application Options:
-p, --pattern= Choose a pattern
-v, --variable= Values for pattern variables, e.g. -v=$name:John -v=$age:30
-C, --context= Choose a context
--session= Choose a session
-S, --setup Run setup
--setup-skip-update-patterns Skip update patterns at setup
-t, --temperature= Set temperature (default: 0.7)
-T, --topp= Set top P (default: 0.9)
-s, --stream Stream
-P, --presencepenalty= Set presence penalty (default: 0.0)
-r, --raw Use the defaults of the model without sending chat options (like temperature etc.) and use the user role instead of the system role for patterns
-F, --frequencypenalty= Set frequency penalty (default: 0.0)
-l, --listpatterns List all patterns
-L, --listmodels List all available models
-x, --listcontexts List all contexts
-X, --listsessions List all sessions
-U, --updatepatterns Update patterns
-c, --copy Copy to clipboard
-m, --model= Choose model
-o, --output= Output to 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
--transcript Grab transcript from YouTube video and send to chat (it used per default).
--comments Grab comments from YouTube video and send to chat
-g, --language= Specify the Language Code for the chat, e.g. -g=en -g=zh
-u, --scrape_url= Scrape website URL to markdown using Jina AI
-q, --scrape_question= Search question using Jina AI
-e, --seed= Seed to be used for LMM generation
-w, --wipecontext= Wipe context
-W, --wipesession= Wipe session
--readability Convert HTML input into a clean, readable view
--dry-run Show what would be sent to the model without actually sending it
--version Print current version
-p, --pattern= Choose a pattern from the available patterns
-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
-S, --setup Run setup for all reconfigurable parts of fabric
--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
-P, --presencepenalty= Set presence penalty (default: 0.0)
-r, --raw Use the defaults of the model without sending chat options (like temperature etc.) and use the user role instead of the system role for patterns.
-F, --frequencypenalty= Set frequency penalty (default: 0.0)
-l, --listpatterns List all patterns
-L, --listmodels List all available models
-x, --listcontexts List all contexts
-X, --listsessions List all sessions
-U, --updatepatterns Update patterns
-c, --copy Copy to clipboard
-m, --model= Choose model
-o, --output= Output to file
--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
--transcript Grab transcript from YouTube video and send to chat (it used per default).
--comments Grab comments from YouTube video and send to chat
-g, --language= Specify the Language Code for the chat, e.g. -g=en -g=zh
-u, --scrape_url= Scrape website URL to markdown using Jina AI
-q, --scrape_question= Search question using Jina AI
-e, --seed= Seed to be used for LMM generation
-w, --wipecontext= Wipe context
-W, --wipesession= Wipe session
--printcontext= Print context
--printsession= Print session
--readability Convert HTML input into a clean, readable view
--dry-run Show what would be sent to the model without actually sending it
--version Print current version
Help Options:
-h, --help Show this help message
-h, --help Show this help message
```
@@ -289,7 +293,7 @@ pbpaste | fabric --stream --pattern analyze_claims
3. Run the `extract_wisdom` Pattern with the `--stream` option to get immediate and streaming results from any Youtube video (much like in the original introduction video).
```bash
fabric -y "https://youtube.com/watch?v=uXs-zPc63kM" | --stream --pattern extract_wisdom
fabric -y "https://youtube.com/watch?v=uXs-zPc63kM" --stream --pattern extract_wisdom
```
4. Create patterns- you must create a .md file with the pattern and save it to ~/.config/fabric/patterns/[yourpatternname].

View File

@@ -13,7 +13,7 @@ import (
)
// Cli Controls the cli. It takes in the flags and runs the appropriate functions
func Cli(version string) (message string, err error) {
func Cli(version string) (err error) {
var currentFlags *Flags
if currentFlags, err = Init(); err != nil {
return
@@ -32,16 +32,20 @@ func Cli(version string) (message string, err error) {
fabricDb := db.NewDb(filepath.Join(homedir, ".config/fabric"))
// if the setup flag is set, run the setup function
if currentFlags.Setup {
if currentFlags.Setup || currentFlags.SetupSkipPatterns || currentFlags.SetupVendor != "" {
_ = fabricDb.Configure()
_, err = Setup(fabricDb, currentFlags.SetupSkipUpdatePatterns)
if currentFlags.SetupVendor != "" {
_, err = SetupVendor(fabricDb, currentFlags.SetupVendor)
} else {
_, err = Setup(fabricDb, currentFlags.SetupSkipPatterns)
}
return
}
var fabric *core.Fabric
if err = fabricDb.Configure(); err != nil {
fmt.Println("init is failed, run start the setup procedure", err)
if fabric, err = Setup(fabricDb, currentFlags.SetupSkipUpdatePatterns); err != nil {
if fabric, err = Setup(fabricDb, currentFlags.SetupSkipPatterns); err != nil {
return
}
} else {
@@ -51,7 +55,6 @@ func Cli(version string) (message string, err error) {
}
}
// if the update patterns flag is set, run the update patterns function
if currentFlags.UpdatePatterns {
err = fabric.PopulateDB()
return
@@ -62,7 +65,6 @@ func Cli(version string) (message string, err error) {
return
}
// if the latest patterns flag is set, run the latest patterns function
if currentFlags.LatestPatterns != "0" {
var parsedToInt int
if parsedToInt, err = strconv.Atoi(currentFlags.LatestPatterns); err != nil {
@@ -75,42 +77,46 @@ func Cli(version string) (message string, err error) {
return
}
// if the list patterns flag is set, run the list all patterns function
if currentFlags.ListPatterns {
err = fabricDb.Patterns.ListNames()
return
}
// if the list all models flag is set, run the list all models function
if currentFlags.ListAllModels {
fabric.GetModels().Print()
return
}
// if the list all contexts flag is set, run the list all contexts function
if currentFlags.ListAllContexts {
err = fabricDb.Contexts.ListNames()
return
}
// if the list all sessions flag is set, run the list all sessions function
if currentFlags.ListAllSessions {
err = fabricDb.Sessions.ListNames()
return
}
// if the wipe context flag is set, run the wipe context function
if currentFlags.WipeContext != "" {
err = fabricDb.Contexts.Delete(currentFlags.WipeContext)
return
}
// if the wipe session flag is set, run the wipe session function
if currentFlags.WipeSession != "" {
err = fabricDb.Sessions.Delete(currentFlags.WipeSession)
return
}
if currentFlags.PrintSession != "" {
err = fabricDb.Sessions.PrintSession(currentFlags.PrintSession)
return
}
if currentFlags.PrintContext != "" {
err = fabricDb.Contexts.PrintContext(currentFlags.PrintContext)
return
}
if currentFlags.HtmlReadability {
if msg, cleanErr := converter.HtmlReadability(currentFlags.Message); cleanErr != nil {
fmt.Println("use original input, because can't apply html readability", err)
@@ -140,15 +146,17 @@ func Cli(version string) (message string, err error) {
if !currentFlags.YouTubeComments || currentFlags.YouTubeTranscript {
var transcript string
var language = "en"
if currentFlags.Language != "" {
language = currentFlags.Language
if currentFlags.Language != "" || fabric.DefaultLanguage.Value != "" {
if currentFlags.Language != "" {
language = currentFlags.Language
} else {
language = fabric.DefaultLanguage.Value
}
}
if transcript, err = fabric.YouTube.GrabTranscript(videoId, language); err != nil {
return
}
// fmt.Println(transcript)
currentFlags.AppendMessage(transcript)
}
@@ -160,12 +168,10 @@ func Cli(version string) (message string, err error) {
commentsString := strings.Join(comments, "\n")
// fmt.Println(commentsString)
currentFlags.AppendMessage(commentsString)
}
if currentFlags.Pattern == "" {
if !currentFlags.IsChatRequest() {
// if the pattern flag is not set, we wanted only to grab the transcript or comments
fmt.Println(currentFlags.Message)
return
@@ -175,27 +181,25 @@ func Cli(version string) (message string, err error) {
if (currentFlags.ScrapeURL != "" || currentFlags.ScrapeQuestion != "") && fabric.Jina.IsConfigured() {
// Check if the scrape_url flag is set and call ScrapeURL
if currentFlags.ScrapeURL != "" {
if message, err = fabric.Jina.ScrapeURL(currentFlags.ScrapeURL); err != nil {
var website string
if website, err = fabric.Jina.ScrapeURL(currentFlags.ScrapeURL); err != nil {
return
}
//fmt.Println(message)
currentFlags.AppendMessage(message)
currentFlags.AppendMessage(website)
}
// Check if the scrape_question flag is set and call ScrapeQuestion
if currentFlags.ScrapeQuestion != "" {
if message, err = fabric.Jina.ScrapeQuestion(currentFlags.ScrapeQuestion); err != nil {
var website string
if website, err = fabric.Jina.ScrapeQuestion(currentFlags.ScrapeQuestion); err != nil {
return
}
//fmt.Println(message)
currentFlags.AppendMessage(message)
currentFlags.AppendMessage(website)
}
if currentFlags.Pattern == "" {
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(currentFlags.Message)
return
@@ -207,24 +211,37 @@ func Cli(version string) (message string, err error) {
return
}
if message, err = chatter.Send(currentFlags.BuildChatRequest(), currentFlags.BuildChatOptions()); err != nil {
var session *db.Session
chatReq := currentFlags.BuildChatRequest(strings.Join(os.Args[1:], " "))
if chatReq.Language == "" {
chatReq.Language = fabric.DefaultLanguage.Value
}
if session, err = chatter.Send(chatReq, currentFlags.BuildChatOptions()); err != nil {
return
}
result := session.GetLastMessage().Content
if !currentFlags.Stream {
fmt.Println(message)
// print the result if it was not streamed already
fmt.Println(result)
}
// if the copy flag is set, copy the message to the clipboard
if currentFlags.Copy {
if err = fabric.CopyToClipboard(message); err != nil {
if err = fabric.CopyToClipboard(result); err != nil {
return
}
}
// if the output flag is set, create an output file
if currentFlags.Output != "" {
err = fabric.CreateOutputFile(message, currentFlags.Output)
if currentFlags.OutputSession {
sessionAsString := session.String()
err = fabric.CreateOutputFile(sessionAsString, currentFlags.Output)
} else {
err = fabric.CreateOutputFile(result, currentFlags.Output)
}
}
return
}
@@ -244,3 +261,9 @@ func Setup(db *db.Db, skipUpdatePatterns bool) (ret *core.Fabric, err error) {
ret = instance
return
}
func SetupVendor(db *db.Db, vendorName string) (ret *core.Fabric, err error) {
ret = core.NewFabricForSetup(db)
err = ret.SetupVendor(vendorName)
return
}

View File

@@ -15,10 +15,9 @@ func TestCli(t *testing.T) {
defer func() { os.Args = originalArgs }()
os.Args = []string{os.Args[0]}
message, err := Cli("test")
err := Cli("test")
assert.Error(t, err)
assert.Equal(t, core.NoSessionPatternUserMessages, err.Error())
assert.Empty(t, message)
}
func TestSetup(t *testing.T) {

View File

@@ -14,41 +14,45 @@ 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:""`
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"`
Setup bool `short:"S" long:"setup" description:"Run setup"`
SetupSkipUpdatePatterns bool `long:"setup-skip-update-patterns" description:"Skip update patterns at setup"`
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"`
PresencePenalty float64 `short:"P" long:"presencepenalty" description:"Set presence penalty" default:"0.0"`
Raw bool `short:"r" long:"raw" description:"Use the defaults of the model without sending chat options (like temperature etc.) and use the user role instead of the system role for patterns."`
FrequencyPenalty float64 `short:"F" long:"frequencypenalty" description:"Set frequency penalty" default:"0.0"`
ListPatterns bool `short:"l" long:"listpatterns" description:"List all patterns"`
ListAllModels bool `short:"L" long:"listmodels" description:"List all available models"`
ListAllContexts bool `short:"x" long:"listcontexts" description:"List all contexts"`
ListAllSessions bool `short:"X" long:"listsessions" description:"List all sessions"`
UpdatePatterns bool `short:"U" long:"updatepatterns" description:"Update patterns"`
Message string `hidden:"true" description:"Message to send to chat"`
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:""`
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"`
YouTubeTranscript bool `long:"transcript" description:"Grab transcript from YouTube video and send to chat (it used per default)."`
YouTubeComments bool `long:"comments" description:"Grab comments from YouTube video and send to chat"`
Language string `short:"g" long:"language" description:"Specify the Language Code for the chat, e.g. -g=en -g=zh" default:""`
ScrapeURL string `short:"u" long:"scrape_url" description:"Scrape website URL to markdown using Jina AI"`
ScrapeQuestion string `short:"q" long:"scrape_question" description:"Search question using Jina AI"`
Seed int `short:"e" long:"seed" description:"Seed to be used for LMM generation"`
WipeContext string `short:"w" long:"wipecontext" description:"Wipe context"`
WipeSession string `short:"W" long:"wipesession" description:"Wipe session"`
HtmlReadability bool `long:"readability" description:"Convert HTML input into a clean, readable view"`
DryRun bool `long:"dry-run" description:"Show what would be sent to the model without actually sending it"`
Version bool `long:"version" description:"Print current version"`
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=#role:expert -v=#points:30"`
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 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"`
PresencePenalty float64 `short:"P" long:"presencepenalty" description:"Set presence penalty" default:"0.0"`
Raw bool `short:"r" long:"raw" description:"Use the defaults of the model without sending chat options (like temperature etc.) and use the user role instead of the system role for patterns."`
FrequencyPenalty float64 `short:"F" long:"frequencypenalty" description:"Set frequency penalty" default:"0.0"`
ListPatterns bool `short:"l" long:"listpatterns" description:"List all patterns"`
ListAllModels bool `short:"L" long:"listmodels" description:"List all available models"`
ListAllContexts bool `short:"x" long:"listcontexts" description:"List all contexts"`
ListAllSessions bool `short:"X" long:"listsessions" description:"List all sessions"`
UpdatePatterns bool `short:"U" long:"updatepatterns" description:"Update patterns"`
Message string `hidden:"true" description:"Message to send to chat"`
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:""`
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"`
YouTubeTranscript bool `long:"transcript" description:"Grab transcript from YouTube video and send to chat (it used per default)."`
YouTubeComments bool `long:"comments" description:"Grab comments from YouTube video and send to chat"`
Language string `short:"g" long:"language" description:"Specify the Language Code for the chat, e.g. -g=en -g=zh" default:""`
ScrapeURL string `short:"u" long:"scrape_url" description:"Scrape website URL to markdown using Jina AI"`
ScrapeQuestion string `short:"q" long:"scrape_question" description:"Search question using Jina AI"`
Seed int `short:"e" long:"seed" description:"Seed to be used for LMM generation"`
WipeContext string `short:"w" long:"wipecontext" description:"Wipe context"`
WipeSession string `short:"W" long:"wipesession" description:"Wipe session"`
PrintContext string `long:"printcontext" description:"Print context"`
PrintSession string `long:"printsession" description:"Print session"`
HtmlReadability bool `long:"readability" description:"Convert HTML input into a clean, readable view"`
DryRun bool `long:"dry-run" description:"Show what would be sent to the model without actually sending it"`
Version bool `long:"version" description:"Print current version"`
}
// Init Initialize flags. returns a Flags struct and an error
@@ -109,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)
@@ -134,3 +139,8 @@ func (o *Flags) AppendMessage(message string) {
}
return
}
func (o *Flags) IsChatRequest() (ret bool) {
ret = (o.Message != "" || o.Context != "") && (o.Session != "" || o.Pattern != "")
return
}

View File

@@ -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)
}

View File

@@ -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 {

View File

@@ -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 {
@@ -19,14 +20,8 @@ type Chatter struct {
vendor vendors.Vendor
}
func (o *Chatter) Send(request *common.ChatRequest, opts *common.ChatOptions) (message string, err error) {
var chatRequest *Chat
if chatRequest, err = o.NewChat(request); err != nil {
return
}
var session *db.Session
if session, err = chatRequest.BuildChatSession(opts.Raw); err != nil {
func (o *Chatter) Send(request *common.ChatRequest, opts *common.ChatOptions) (session *db.Session, err error) {
if session, err = o.BuildSession(request, opts.Raw); err != nil {
return
}
@@ -34,10 +29,12 @@ func (o *Chatter) Send(request *common.ChatRequest, opts *common.ChatOptions) (m
opts.Model = o.model
}
message := ""
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()
}
}()
@@ -47,41 +44,52 @@ func (o *Chatter) Send(request *common.ChatRequest, opts *common.ChatOptions) (m
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
}
}
if chatRequest.Session != nil && message != "" {
chatRequest.Session.Append(&common.Message{Role: goopenai.ChatMessageRoleAssistant, Content: message})
err = o.db.Sessions.SaveSession(chatRequest.Session)
if message == "" {
session = nil
err = fmt.Errorf("empty response")
return
}
session.Append(&common.Message{Role: goopenai.ChatMessageRoleAssistant, Content: message})
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 {
@@ -90,18 +98,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
}

View File

@@ -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")
}
}

View File

@@ -5,20 +5,18 @@ import (
"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"
"github.com/danielmiessler/fabric/jina"
"github.com/danielmiessler/fabric/lang"
"github.com/danielmiessler/fabric/vendors/anthropic"
"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"
@@ -53,6 +51,7 @@ func NewFabricBase(db *db.Db) (ret *Fabric) {
VendorsAll: NewVendorsManager(),
PatternsLoader: NewPatternsLoader(db.Patterns),
YouTube: youtube.NewYouTube(),
Language: lang.NewLanguage(),
Jina: jina.NewClient(),
}
@@ -68,7 +67,7 @@ func NewFabricBase(db *db.Db) (ret *Fabric) {
"Enter the index the name of your default model")
ret.VendorsAll.AddVendors(openai.NewClient(), azure.NewClient(), ollama.NewClient(), groq.NewClient(),
gemini.NewClient(), anthropic.NewClient(), siliconcloud.NewClient(), openrouter.NewClient(), mistral.NewClient(), dryrun.NewClient())
gemini.NewClient(), anthropic.NewClient(), siliconcloud.NewClient(), openrouter.NewClient(), mistral.NewClient())
return
}
@@ -79,6 +78,7 @@ type Fabric struct {
VendorsAll *VendorsManager
*PatternsLoader
*youtube.YouTube
*lang.Language
Jina *jina.Client
Db *db.Db
@@ -105,6 +105,7 @@ func (o *Fabric) SaveEnvFile() (err error) {
o.YouTube.SetupFillEnvFileContent(&envFileContent)
o.Jina.SetupFillEnvFileContent(&envFileContent)
o.Language.SetupFillEnvFileContent(&envFileContent)
err = o.Db.SaveEnv(envFileContent.String())
return
@@ -129,6 +130,10 @@ func (o *Fabric) Setup() (err error) {
return
}
if err = o.Language.SetupOrSkip(); err != nil {
return
}
err = o.SaveEnvFile()
return
@@ -182,6 +187,14 @@ func (o *Fabric) SetupVendors() (err error) {
return
}
func (o *Fabric) SetupVendor(vendorName string) (err error) {
if err = o.VendorsAll.SetupVendor(vendorName, o.Vendors); err != nil {
return
}
err = o.SaveEnvFile()
return
}
// Configure buildClient VendorsController based on the environment variables
func (o *Fabric) configure() (err error) {
for _, vendor := range o.VendorsAll.Vendors {
@@ -196,6 +209,7 @@ func (o *Fabric) configure() (err error) {
//YouTube and Jina are not mandatory, so ignore not configured error
_ = o.YouTube.Configure()
_ = o.Jina.Configure()
_ = o.Language.Configure()
return
}
@@ -249,39 +263,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
}

View File

@@ -90,16 +90,31 @@ func (o *VendorsManager) Setup() (ret map[string]vendors.Vendor, err error) {
ret = map[string]vendors.Vendor{}
for _, vendor := range o.Vendors {
fmt.Println()
if vendorErr := vendor.Setup(); vendorErr == nil {
fmt.Printf("[%v] configured\n", vendor.GetName())
ret[vendor.GetName()] = vendor
} else {
fmt.Printf("[%v] skipped\n", vendor.GetName())
}
o.setupVendorTo(vendor, ret)
}
return
}
func (o *VendorsManager) setupVendorTo(vendor vendors.Vendor, configuredVendors map[string]vendors.Vendor) {
if vendorErr := vendor.Setup(); vendorErr == nil {
fmt.Printf("[%v] configured\n", vendor.GetName())
configuredVendors[vendor.GetName()] = vendor
} else {
delete(configuredVendors, vendor.GetName())
fmt.Printf("[%v] skipped\n", vendor.GetName())
}
}
func (o *VendorsManager) SetupVendor(vendorName string, configuredVendors map[string]vendors.Vendor) (err error) {
vendor := o.FindByName(vendorName)
if vendor == nil {
err = fmt.Errorf("vendor %s not found", vendorName)
return
}
o.setupVendorTo(vendor, configuredVendors)
return
}
type modelResult struct {
vendorName string
models []string

View File

@@ -1,5 +1,7 @@
package db
import "fmt"
type Contexts struct {
*Storage
}
@@ -15,6 +17,15 @@ func (o *Contexts) GetContext(name string) (ret *Context, err error) {
return
}
func (o *Contexts) PrintContext(name string) (err error) {
var context *Context
if context, err = o.GetContext(name); err != nil {
return
}
fmt.Println(context.Content)
return
}
type Context struct {
Name string
Content string

View File

@@ -20,6 +20,16 @@ func (o *Sessions) GetOrCreateSession(name string) (session *Session, err error)
return
}
func (o *Sessions) PrintSession(name string) (err error) {
if o.Exists(name) {
var session Session
if err = o.LoadAsJson(name, &session.Messages); err == nil {
fmt.Println(session.String())
}
}
return
}
func (o *Sessions) SaveSession(session *Session) (err error) {
return o.SaveAsJson(session.Name, session.Messages)
}
@@ -27,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 {
@@ -34,5 +46,43 @@ 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) {
if len(o.Messages) > 0 {
ret = o.Messages[len(o.Messages)-1]
}
return
}
func (o *Session) String() (ret string) {
for _, message := range o.Messages {
ret += fmt.Sprintf("\n--- \n[%v]\n\n%v", message.Role, message.Content)
}
return
}

41
lang/language.go Normal file
View File

@@ -0,0 +1,41 @@
package lang
import (
"github.com/danielmiessler/fabric/common"
"golang.org/x/text/language"
)
func NewLanguage() (ret *Language) {
label := "Language"
ret = &Language{}
ret.Configurable = &common.Configurable{
Label: label,
EnvNamePrefix: common.BuildEnvVariablePrefix(label),
ConfigureCustom: ret.configure,
}
ret.DefaultLanguage = ret.Configurable.AddSetupQuestionCustom("Output", false,
"Enter your default want output lang (for example: zh_CN)")
return
}
type Language struct {
*common.Configurable
DefaultLanguage *common.SetupQuestion
}
func (o *Language) configure() error {
if o.DefaultLanguage.Value != "" {
langTag, err := language.Parse(o.DefaultLanguage.Value)
if err == nil {
o.DefaultLanguage.Value = langTag.String()
} else {
o.DefaultLanguage.Value = ""
}
}
return nil
}

View File

@@ -9,7 +9,7 @@ import (
)
func main() {
_, err := cli.Cli(version)
err := cli.Cli(version)
if err != nil && !flags.WroteHelp(err) {
fmt.Printf("%s\n", err)
os.Exit(1)

View File

@@ -0,0 +1,39 @@
# IDENTITY
You are an expert at looking at a presentation, an essay, or a full body of lifetime work, and clearly and accurately articulating what the core message is.
# GOAL
- Produce a clear sentence that perfectly articulates the core message as presented in a given text or body of work.
# EXAMPLE
If the input is all of Victor Frankl's work, then the core message would be:
Finding meaning in suffering is key to human resilience, purpose, and enduring lifes challenges.
END EXAMPLE
# STEPS
- Fully digest the input.
- Determine if the input is a single text or a body of work.
- Based on which it is, parse the thing that's supposed to be parsed.
- Extract the core message from the parsed text into a single sentence.
# OUTPUT
- Output a single, 15-word sentence that perfectly articulates the core message as presented in the input.
# OUTPUT INSTRUCTIONS
- The sentence should be a single sentence that is 15 words or fewer, with no special formatting or anything else.
- Do not include any setup to the sentence, e.g., "The core message is to…", etc. Just list the core message and nothing else.
- ONLY OUTPUT THE CORE MESSAGE, not a setup to it, commentary on it, or anything else.
- Do not ask questions or complain in any way about the task.

View File

@@ -0,0 +1,27 @@
#!/bin/bash
# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Capture Thinkers Work
# @raycast.mode fullOutput
# Optional parameters:
# @raycast.icon 🧠
# @raycast.argument1 { "type": "text", "placeholder": "Input text", "optional": false, "percentEncoded": true}
# Documentation:
# @raycast.description Run fabric capture_thinkers_work on the input text
# @raycast.author Daniel Miessler
# @raycast.authorURL https://github.com/danielmiessler
# Set PATH to include common locations and $HOME/go/bin
PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$HOME/go/bin:$PATH"
# Use the PATH to find and execute fabric
if command -v fabric >/dev/null 2>&1; then
fabric -sp capture_thinkers_work "${1}"
else
echo "Error: fabric command not found in PATH"
echo "Current PATH: $PATH"
exit 1
fi

View File

@@ -8,15 +8,15 @@ Take a step back and think step-by-step about how to achieve the best possible r
- Fully digest the content provided.
- Extract all actionables agreed within the meeting.
- Extract all actionables agreed upon within the meeting.
- Extract any interesting ideas brought up in the meeting.
- In a section called TITLE, write a 1 to 5 word title for the meeting
- In a section called TITLE, write a 1 to 5 word title for the meeting.
- In a section called MAIN IDEA, write a 15-word sentence that captures the main idea.
- In a section called MINUTES, write 20 to 50 bullet points, highliting of the most surprising, insightful, and/or interesting ideas that come up in the conversation. If there are less than 50 then collect all of them. Make sure you extract at least 20.
- In a section called MINUTES, write 20 to 50 bullet points, highlighting of the most surprising, insightful, and/or interesting ideas that come up in the conversation. If there are less than 50 then collect all of them. Make sure you extract at least 20.
- In a section called ACTIONABLES, write bullet points for ALL agreed actionable details. This includes cases where a speaker agrees to do or look into something. If there is a deadline mentioned, include it here.
@@ -24,16 +24,16 @@ Take a step back and think step-by-step about how to achieve the best possible r
- In a section called CHALLENGES, identify and document any challenges or issues discussed during the meeting. Note any potential solutions or strategies proposed to address these challenges.
- In a section caled NEXT STEPS, outline the next steps and actions to be taken after the meeting
- In a section called NEXT STEPS, outline the next steps and actions to be taken after the meeting.
# OUTPUT INSTRUCTIONS
- Only output Markdown.
- Write MINUTES as exxactly 15 words.
- Write MINUTES as exactly 15 words.
- Write ACTIONABLES as exactly 15 words.
- Write DECISIONS as exactly 15 words.
- Write CHALLENGES as 2-3 sentences.
- Write NEXT STEPS a 2-3 sentences.
- Write NEXT STEPS as 2-3 sentences.
- Do not give warnings or notes; only output the requested sections.
- Do not repeat ideas, quotes, facts, or resources.
- You use bulleted lists for output, not numbered lists.

View File

@@ -1,3 +1,3 @@
package main
var version = "v1.4.44"
var version = "v1.4.60"