llmed 0.3.19 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +27 -0
- data/exe/llmed.literate +68 -0
- data/lib/llmed/application.rb +1 -1
- data/lib/llmed/literate_programming/markdown.rb +3 -1
- data/lib/llmed/literate_programming/markdown.rb.r1ruby.cache +24 -0
- data/lib/llmed/literate_programming/markdown.rb.release +24 -0
- data/lib/llmed/literate_programming/markdown.rb.statistics +37 -0
- data/lib/llmed/literate_programming.rb +47 -0
- metadata +7 -3
- data/lib/llmed/markdown.rb.statistics +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 26dd1afcf05c5f3a999d02d330f1888f15fadb57546cea5f793d3aa942f22a0f
|
4
|
+
data.tar.gz: 8e387a3afa41e2caa5def2241a49e59b85b893f76028f2d317d085e01a0f3826
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12a72fca1b9f9a8678dcc753c66a5c8cfe58086326b8232f89a19310c6227d3775daa402e7586ab2ce457611265b751b01b7345dee5a19b5784590cf3c9dbc0c
|
7
|
+
data.tar.gz: 9b2f6abe791e5c969975675a06385bbf996ef6bf5826e64f7093715f56ef3aa60e8e55a236b1051cc71392b5c3972aaeffd0d241b14c14213f8d5312ffeabc39
|
data/README.md
CHANGED
@@ -39,6 +39,33 @@ application "MINI COUNTER", release: nil, language: :node, output_file: "minicou
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
+
```
|
43
|
+
|
44
|
+
Since version 0.4.0, literate programming was introduced, and it is now possible to write code using a markdown-like syntax.
|
45
|
+
|
46
|
+
```md
|
47
|
+
#!language ruby
|
48
|
+
#% increase release once you agree with the change
|
49
|
+
#!environment release
|
50
|
+
#!environment output_file minicounter.rb
|
51
|
+
|
52
|
+
# Dependencies
|
53
|
+
|
54
|
+
* Must use only the standard/native library.
|
55
|
+
* Must not use external dependencies.
|
56
|
+
|
57
|
+
# API
|
58
|
+
|
59
|
+
API Server listening port 3007.
|
60
|
+
Expose the following endpoints:
|
61
|
+
- GET /count
|
62
|
+
- return the latest count.
|
63
|
+
- POST /count
|
64
|
+
- increase the count by 1.
|
65
|
+
add CORS endpoints.
|
66
|
+
```
|
67
|
+
then compile using command `llmed.literate`.
|
68
|
+
|
42
69
|
## Programming flow
|
43
70
|
|
44
71
|
* Cycle
|
data/exe/llmed.literate
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
#!/bin/env ruby
|
2
|
+
# Copyright 2025 Jovany Leandro G.C <bit4bit@riseup.net>
|
3
|
+
# frozen_string_literal: true
|
4
|
+
require 'optparse'
|
5
|
+
require 'llmed'
|
6
|
+
|
7
|
+
logger = Logger.new(STDERR)
|
8
|
+
output_dir = './llmed-out'
|
9
|
+
release_dir = output_dir
|
10
|
+
language = 'ruby'
|
11
|
+
provider = :like_openai
|
12
|
+
provider_api_key = ENV.fetch('LLMED_PROVIDER_API_KEY', nil)
|
13
|
+
provider_model = ENV.fetch('LLMED_PROVIDER_MODEL', 'Qwen/Qwen2.5-Coder-32B-Instruct')
|
14
|
+
provider_uri_base = ENV.fetch('LLMED_PROVIDER_URI_BASE', 'https://api.together.xyz/v1')
|
15
|
+
output_file = 'a.out.ollmed'
|
16
|
+
|
17
|
+
template = <<~TMP
|
18
|
+
# Main
|
19
|
+
|
20
|
+
Show to user 'hi world!'.
|
21
|
+
TMP
|
22
|
+
|
23
|
+
OptionParser.new do |parser|
|
24
|
+
parser.banner = "Usage: llmed.literate [options] <application file .llmed.literate or stdin>"
|
25
|
+
parser.on_tail("-h", "--help", "Show this message") do
|
26
|
+
puts parser
|
27
|
+
puts "\n# Website\nhttps://github.com/bit4bit/llm-labs/tree/main/llmed"
|
28
|
+
puts "\n# Examples\nhttps://github.com/bit4bit/llm-labs/tree/main/llmed/examples"
|
29
|
+
puts "Environment vars:\nLLMED_PROVIDER_API_KEY\nLLMED_PROVIDER_MODEL=#{provider_model}\nLLMED_PROVIDER_URI_BASE=#{provider_uri_base}"
|
30
|
+
exit
|
31
|
+
end
|
32
|
+
|
33
|
+
parser.on('-t', '--template PATH', String, 'Create template') do |path|
|
34
|
+
File.write path, template
|
35
|
+
exit
|
36
|
+
end
|
37
|
+
|
38
|
+
parser.on('-c', '--compile PATH', String, 'Output compiled') do |path|
|
39
|
+
output_file = path
|
40
|
+
end
|
41
|
+
|
42
|
+
parser.on('--output-dir DIR', String) do |path|
|
43
|
+
output_dir = path
|
44
|
+
end
|
45
|
+
|
46
|
+
parser.on('--release-dir DIR', String) do |path|
|
47
|
+
release_dir = path
|
48
|
+
end
|
49
|
+
|
50
|
+
parser.on('-l', '--language LANGUAGE', String, 'Programming Language: ruby, python') do |lang|
|
51
|
+
language = lang
|
52
|
+
end
|
53
|
+
|
54
|
+
parser.on('-q', '--quiet') do
|
55
|
+
logger.level = :error
|
56
|
+
end
|
57
|
+
end.parse!
|
58
|
+
|
59
|
+
source_code = ARGF.read
|
60
|
+
if ARGF.respond_to?(:path)
|
61
|
+
release_dir = File.dirname(ARGF.path)
|
62
|
+
end
|
63
|
+
|
64
|
+
llmed = LLMed.new(logger: logger, output_dir: output_dir, release_dir: release_dir)
|
65
|
+
llmed.set_language language
|
66
|
+
llmed.set_llm provider: provider, api_key: provider_api_key, model: provider_model, options: {uri_base: provider_uri_base}
|
67
|
+
LLMed::LiterateProgramming.execute(llmed, 'literate_programming', source_code, output_file: output_file)
|
68
|
+
llmed.compile()
|
data/lib/llmed/application.rb
CHANGED
@@ -57,7 +57,7 @@ class LLMed
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def prepare
|
60
|
-
@logger.info("APPLICATION #{@name} COMPILING FOR #{@language}")
|
60
|
+
@logger.info("APPLICATION #{@name} COMPILING FOR #{@language} RELEASE #{@release}")
|
61
61
|
return unless @output_file.is_a?(String)
|
62
62
|
return unless @release
|
63
63
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#<llmed-code context='Library LLMed::LiterateProgramming::Markdown' digest='
|
1
|
+
#<llmed-code context='Library LLMed::LiterateProgramming::Markdown' digest='9c0e3f61ab4cdc3c56c29230a800487dd1a7ef0d929c843fd2461907d0831ab2' after=''>
|
2
2
|
class LLMed::LiterateProgramming::Markdown
|
3
3
|
def parse(input)
|
4
4
|
contexts = []
|
@@ -12,6 +12,8 @@ class LLMed::LiterateProgramming::Markdown
|
|
12
12
|
current_context[:content] << { type: :link, content: Regexp.last_match(1), reference: Regexp.last_match(2) }
|
13
13
|
elsif line.strip =~ /^#% (.+)$/
|
14
14
|
current_context[:content] << { type: :comment, content: Regexp.last_match(1) + "\n" }
|
15
|
+
elsif line.strip =~ /^#!environment\s+(\w+)\s+(.+)$/
|
16
|
+
current_context[:content] << { type: :environment, name: Regexp.last_match(1), value: Regexp.last_match(2) }
|
15
17
|
else
|
16
18
|
current_context[:content] << { type: :string, content: line }
|
17
19
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#<llmed-code context='Library LLMed::LiterateProgramming::Markdown' digest='18aa5391a8a334f24a80542620a277bb9c085762cb88b7dbcafa26a532a48027' after=''>
|
2
|
+
class LLMed::LiterateProgramming::Markdown
|
3
|
+
def parse(input)
|
4
|
+
contexts = []
|
5
|
+
current_context = { type: :context, title: "_default", content: [] }
|
6
|
+
|
7
|
+
input.each_line do |line|
|
8
|
+
if line.strip =~ /^# (.+)$/
|
9
|
+
contexts << current_context unless current_context[:content].empty?
|
10
|
+
current_context = { type: :context, title: Regexp.last_match(1), content: [] }
|
11
|
+
elsif line.strip =~ /^\[(.+)\]\((.+)\)$/
|
12
|
+
current_context[:content] << { type: :link, content: Regexp.last_match(1), reference: Regexp.last_match(2) }
|
13
|
+
elsif line.strip =~ /^#% (.+)$/
|
14
|
+
current_context[:content] << { type: :comment, content: Regexp.last_match(1) + "\n" }
|
15
|
+
else
|
16
|
+
current_context[:content] << { type: :string, content: line }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
contexts << current_context unless current_context[:content].empty?
|
21
|
+
contexts
|
22
|
+
end
|
23
|
+
end
|
24
|
+
#</llmed-code>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#<llmed-code context='Library LLMed::LiterateProgramming::Markdown' digest='18aa5391a8a334f24a80542620a277bb9c085762cb88b7dbcafa26a532a48027' after=''>
|
2
|
+
class LLMed::LiterateProgramming::Markdown
|
3
|
+
def parse(input)
|
4
|
+
contexts = []
|
5
|
+
current_context = { type: :context, title: "_default", content: [] }
|
6
|
+
|
7
|
+
input.each_line do |line|
|
8
|
+
if line.strip =~ /^# (.+)$/
|
9
|
+
contexts << current_context unless current_context[:content].empty?
|
10
|
+
current_context = { type: :context, title: Regexp.last_match(1), content: [] }
|
11
|
+
elsif line.strip =~ /^\[(.+)\]\((.+)\)$/
|
12
|
+
current_context[:content] << { type: :link, content: Regexp.last_match(1), reference: Regexp.last_match(2) }
|
13
|
+
elsif line.strip =~ /^#% (.+)$/
|
14
|
+
current_context[:content] << { type: :comment, content: Regexp.last_match(1) + "\n" }
|
15
|
+
else
|
16
|
+
current_context[:content] << { type: :string, content: line }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
contexts << current_context unless current_context[:content].empty?
|
21
|
+
contexts
|
22
|
+
end
|
23
|
+
end
|
24
|
+
#</llmed-code>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
{"inserted_at":1750948592,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o-mini","release":null,"total_tokens":801,"duration_seconds":7}
|
2
|
+
{"inserted_at":1750948631,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o-mini","release":null,"total_tokens":802,"duration_seconds":10}
|
3
|
+
{"inserted_at":1750948668,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o-mini","release":null,"total_tokens":802,"duration_seconds":8}
|
4
|
+
{"inserted_at":1750948715,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o-mini","release":null,"total_tokens":789,"duration_seconds":7}
|
5
|
+
{"inserted_at":1750948827,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o-mini","release":null,"total_tokens":815,"duration_seconds":9}
|
6
|
+
{"inserted_at":1750948952,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":752,"duration_seconds":7}
|
7
|
+
{"inserted_at":1750948976,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":799,"duration_seconds":5}
|
8
|
+
{"inserted_at":1750949014,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":766,"duration_seconds":6}
|
9
|
+
{"inserted_at":1750949045,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":810,"duration_seconds":5}
|
10
|
+
{"inserted_at":1750949073,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":765,"duration_seconds":5}
|
11
|
+
{"inserted_at":1750949098,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":761,"duration_seconds":5}
|
12
|
+
{"inserted_at":1750949120,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":794,"duration_seconds":6}
|
13
|
+
{"inserted_at":1750949132,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":764,"duration_seconds":4}
|
14
|
+
{"inserted_at":1750949163,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":772,"duration_seconds":4}
|
15
|
+
{"inserted_at":1750949215,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":793,"duration_seconds":7}
|
16
|
+
{"inserted_at":1750949230,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":793,"duration_seconds":6}
|
17
|
+
{"inserted_at":1750949263,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":786,"duration_seconds":5}
|
18
|
+
{"inserted_at":1750949274,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":790,"duration_seconds":5}
|
19
|
+
{"inserted_at":1750949300,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":809,"duration_seconds":11}
|
20
|
+
{"inserted_at":1750949341,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":767,"duration_seconds":5}
|
21
|
+
{"inserted_at":1750949462,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":749,"duration_seconds":4}
|
22
|
+
{"inserted_at":1750949604,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":761,"duration_seconds":5}
|
23
|
+
{"inserted_at":1750949637,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":735,"duration_seconds":7}
|
24
|
+
{"inserted_at":1750949713,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":756,"duration_seconds":4}
|
25
|
+
{"inserted_at":1750949955,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":null,"total_tokens":1021,"duration_seconds":5}
|
26
|
+
{"inserted_at":1750950487,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":1,"total_tokens":1575,"duration_seconds":5}
|
27
|
+
{"inserted_at":1750950574,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":1,"total_tokens":1571,"duration_seconds":5}
|
28
|
+
{"inserted_at":1750948249,"name":"Literate Programming Markdown","provider":"like_openai","model":"Qwen/Qwen2.5-Coder-32B-Instruct","release":null,"total_tokens":825,"duration_seconds":6}
|
29
|
+
{"inserted_at":1751277383,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o-mini","release":1,"total_tokens":2438,"duration_seconds":17}
|
30
|
+
{"inserted_at":1751277514,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o-mini","release":1,"total_tokens":2438,"duration_seconds":19}
|
31
|
+
{"inserted_at":1751277672,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o-mini","release":1,"total_tokens":2417,"duration_seconds":18}
|
32
|
+
{"inserted_at":1751277767,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o-mini","release":1,"total_tokens":1833,"duration_seconds":9}
|
33
|
+
{"inserted_at":1751278515,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o-mini","release":1,"total_tokens":2416,"duration_seconds":19}
|
34
|
+
{"inserted_at":1751278535,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o-mini","release":1,"total_tokens":2396,"duration_seconds":13}
|
35
|
+
{"inserted_at":1751278560,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o-mini","release":1,"total_tokens":2416,"duration_seconds":18}
|
36
|
+
{"inserted_at":1751278598,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o-mini","release":1,"total_tokens":2416,"duration_seconds":15}
|
37
|
+
{"inserted_at":1751278618,"name":"Literate Programming Markdown","provider":"openai","model":"gpt-4o","release":1,"total_tokens":1830,"duration_seconds":6}
|
@@ -1,6 +1,53 @@
|
|
1
|
+
require 'open-uri'
|
1
2
|
|
2
3
|
class LLMed
|
3
4
|
class LiterateProgramming
|
5
|
+
def self.execute(llmed, application_name, code, **application_args)
|
6
|
+
md = LLMed::LiterateProgramming::Markdown.new()
|
7
|
+
contexts = []
|
8
|
+
|
9
|
+
md.parse(code).each do |item|
|
10
|
+
context = {}
|
11
|
+
|
12
|
+
if item[:title] == "_default"
|
13
|
+
item[:content].each do |item_content|
|
14
|
+
case item_content[:type]
|
15
|
+
when :environment
|
16
|
+
name = item_content[:name].strip.to_sym
|
17
|
+
value = item_content[:value].strip
|
18
|
+
if [:language, :release, :output_file, :output_dir, :release_dir].include?(name) && !value.empty?
|
19
|
+
application_args[name] = value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
next
|
24
|
+
end
|
25
|
+
|
26
|
+
case item[:type]
|
27
|
+
when :context
|
28
|
+
context[:title] = item[:title]
|
29
|
+
context[:content] = ''
|
30
|
+
|
31
|
+
item[:content].each do |item_content|
|
32
|
+
case item_content[:type]
|
33
|
+
when :comment
|
34
|
+
next
|
35
|
+
when :string
|
36
|
+
context[:content] += item_content[:content]
|
37
|
+
when :link
|
38
|
+
context[:content] += "#{URI.open(item_content[:reference]).read}\n"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
contexts << context
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
llmed.application(application_name, **application_args) do
|
46
|
+
contexts.each do |lcontext|
|
47
|
+
context(lcontext[:title]) { lcontext[:content] }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
4
51
|
end
|
5
52
|
end
|
6
53
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: llmed
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jovany Leandro G.C
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-06-
|
11
|
+
date: 2025-06-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: langchainrb
|
@@ -86,12 +86,14 @@ description: Use this 'compiler' to build software using LLMs in a controlled wa
|
|
86
86
|
email: bit4bit@riseup.net
|
87
87
|
executables:
|
88
88
|
- llmed
|
89
|
+
- llmed.literate
|
89
90
|
extensions: []
|
90
91
|
extra_rdoc_files: []
|
91
92
|
files:
|
92
93
|
- LICENSE
|
93
94
|
- README.md
|
94
95
|
- exe/llmed
|
96
|
+
- exe/llmed.literate
|
95
97
|
- lib/literate_programming.llmed~
|
96
98
|
- lib/llm.rb
|
97
99
|
- lib/llm.rb~
|
@@ -108,7 +110,9 @@ files:
|
|
108
110
|
- lib/llmed/literate_programming.rb
|
109
111
|
- lib/llmed/literate_programming.rb~
|
110
112
|
- lib/llmed/literate_programming/markdown.rb
|
111
|
-
- lib/llmed/markdown.rb.
|
113
|
+
- lib/llmed/literate_programming/markdown.rb.r1ruby.cache
|
114
|
+
- lib/llmed/literate_programming/markdown.rb.release
|
115
|
+
- lib/llmed/literate_programming/markdown.rb.statistics
|
112
116
|
- lib/llmed/release.rb
|
113
117
|
- lib/llmed/release.rb~
|
114
118
|
homepage: https://github.com/bit4bit/llmed
|
@@ -1 +0,0 @@
|
|
1
|
-
{"inserted_at":1750948249,"name":"Literate Programming Markdown","provider":"like_openai","model":"Qwen/Qwen2.5-Coder-32B-Instruct","release":null,"total_tokens":825,"duration_seconds":6}
|