Module: ObsidianFetch

Defined in:
lib/obsidian_fetch.rb,
lib/obsidian_fetch/logic.rb,
lib/obsidian_fetch/vault.rb,
lib/obsidian_fetch/version.rb,
lib/obsidian_fetch/vault_manager.rb,
sig/obsidian_fetch.rbs

Defined Under Namespace

Classes: Error, Result, Vault, VaultManager

Constant Summary collapse

MAX_LIST_SIZE =
20
VERSION =

Returns:

  • (String)
"1.2.0"

Class Method Summary collapse

Class Method Details



103
104
105
106
107
108
109
110
# File 'lib/obsidian_fetch/logic.rb', line 103

def self.list_links(name, preface, vault)
  <<~EOS
    #{preface}
    Note not found: #{name}
    However, I found other notes linked to this note.
    #{vault.links_by_file_name[name].shuffle.map { |file_path| "- #{File.basename(file_path, '.md')}" }.join("\n")}
  EOS
end

.list_notes(vault, name) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/obsidian_fetch/logic.rb', line 59

def self.list_notes(vault, name)
  name = ObsidianFetch.normalize_note_name(name)
  split_name = name.split(/[\t \u3000]+/)
  # 空白文字で検索された場合は失敗した旨を返す
  # 仮に全ノートからランダムなMAX_LIST_SIZEを返してしまうと、LLMが誤って呼び出した場合に偽の関連性を持ってしまうため
  if split_name.empty?
    return Result.new(text: <<~EOS, error: true)
      It cannot be listed in a blank string.
    EOS
  end
  matched_notes = vault.notes.select do |note_name, _file_pathes|
    split_name.map { |name_part| note_name.include?(name_part) }.all?
  end
  # 名前で検索したが見つからない場合
  if matched_notes.empty?
    has_found_link = vault.links_by_file_name[name] && !vault.links_by_file_name[name].empty?
    return Result.new(text: <<~EOS, error: true) unless has_found_link
      Note not found: #{name}
      Search again with a substring or a string with a different notation.
    EOS
    return Result.new(text: <<~EOS, error: true)
      Note not found: #{name}
      However, I found other notes linked to this note.
      #{vault.links_by_file_name[name].shuffle.map { |file_path| "- #{File.basename(file_path, '.md')}" }.join("\n")}
    EOS
  end
  # マッチした名前の数が多すぎる場合は、ランダムにMAX_LIST_SIZE個選ぶ
  preface = "Notes matching '#{name}' are as follows.\n"
  if matched_notes.size > MAX_LIST_SIZE
    matched_notes = matched_notes.to_a.sample(MAX_LIST_SIZE).to_h
    preface = "Too many notes matched. I will show you only #{MAX_LIST_SIZE} of them.\n" + preface
  end
  # マッチした名前のリストで返す
  list = matched_notes.keys.shuffle.map { |note_name| "- #{note_name}" }.join("\n")
  Result.new(text: preface + list)
end

.normalize_note_name(note_name) ⇒ Object

ノート名を正規化する ファイル名に使えない文字については除去しない。aliasで設定されている場合もあるため。



15
16
17
# File 'lib/obsidian_fetch/logic.rb', line 15

def self.normalize_note_name(note_name)
  note_name.gsub(/[\[\]\#\^|]/, '')
end

.note_not_found(name) ⇒ Object

--- ヘルパーメソッド ---



97
98
99
100
101
# File 'lib/obsidian_fetch/logic.rb', line 97

def self.note_not_found(name)
  <<~EOS
    Note not found: #{name}
  EOS
end

.open_file(name, file_pathes, preface, vault) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/obsidian_fetch/logic.rb', line 112

def self.open_file(name, file_pathes, preface, vault)
  # 複数のファイルがある場合は、---とファイル名で区切って返す
  result = file_pathes.map do |file_path|
    content = open(file_path) { |f| f.read.force_encoding('UTF-8') }
    link_notes = if vault.links_by_file_path[file_path].nil?
      ""
    else
      <<~EOS
        This note is linked by the following notes:
        #{(vault.links_by_file_path[file_path] || []).shuffle.map { |file_path| "- #{File.basename(file_path, '.md')}" }.join("\n")}
      EOS
    end
     = <<~EOS
      The contents of the note '#{name}' is as follows.
      #{link_notes}
      ---
    EOS
     + content
  end.join("\n\n---\n\n")
  preface + result
end

.read_note(vault, name) ⇒ Object

--- ツールロジック ---



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/obsidian_fetch/logic.rb', line 20

def self.read_note(vault, name)
  name = ObsidianFetch.normalize_note_name(name)
  file_pathes = vault.notes[name]

  preface = ""
  # 名前のノートが見つからないが、nameがパスっぽい場合は、パスを修正したうえでもう一度試す
  if file_pathes.nil? && name.include?('/')
    fixed_name = File.basename(name, '.md')
    file_pathes = vault.notes[fixed_name]
    if file_pathes.nil?
      # もしも名前で見つからなければ、リンクにも存在しないか確認する
      link_pathes = vault.links_by_file_name[fixed_name]
      if link_pathes.nil?
        return Result.new(text: note_not_found(name), error: true)
      else
        # リンク先のノートが見つかった場合は、prefaceを追加する
        preface = <<~EOS
          Presumably a path was specified. The process was automatically renamed and processed.
        EOS
        return Result.new(text: list_links(fixed_name, preface, vault), error: true)
      end
    else
      # ノート名が見つかった場合は、prefaceを追加する
      preface = <<~EOS
        Presumably a path was specified. The process was automatically renamed and processed.
      EOS
      return Result.new(text: open_file(fixed_name, file_pathes, preface, vault))
    end
  end

  # 名前のノートが存在しない場合
  if file_pathes.nil?
    return Result.new(text: note_not_found(name), error: true) if vault.links_by_file_name[name].nil?
    return Result.new(text: list_links(name, preface, vault), error: true)
  end

  Result.new(text: open_file(name, file_pathes, preface, vault))
end