Skip to content

Commit 0736fdf

Browse files
committed
Add all the code from the rewrite repo
This is the code from the rewrite that I started writing in August 2023.
1 parent 00bbe54 commit 0736fdf

File tree

313 files changed

+11206
-15524
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

313 files changed

+11206
-15524
lines changed

example/app/lib/ollama.rb

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
class Ollama
2+
DEFAULT_URL = "http://localhost:11434"
3+
DEFAULT_MODEL = "llama2"
4+
5+
GenerateResponse =
6+
Data.define(
7+
:total_duration, # time spent generating the response
8+
:load_duration, # time spent in nanoseconds loading the model
9+
:sample_count, # number of samples generated
10+
:sample_duration, # time spent generating samples
11+
:prompt_eval_count, # number of tokens in the prompt
12+
:prompt_eval_duration, # time spent in nanoseconds evaluating the prompt
13+
:eval_count, # number of tokens the response
14+
:eval_duration, # time in nanoseconds spent generating the response
15+
:model,
16+
:created_at,
17+
:context # an encoding of the conversation used in this response, this can be sent in the next request to keep a conversational memory
18+
)
19+
20+
def initialize(model: DEFAULT_MODEL, url: DEFAULT_URL)
21+
@endpoint =
22+
Async::HTTP::Endpoint.parse(url, protocol: Async::HTTP::Protocol::HTTP2)
23+
@client = Async::HTTP::Client.new(@endpoint)
24+
@model = model
25+
@context = nil
26+
end
27+
28+
def generate(prompt, system: nil, template: nil, options: {})
29+
res =
30+
@client.post(
31+
"/api/generate",
32+
nil,
33+
JSON.generate(
34+
{
35+
model: @model,
36+
prompt:,
37+
context: @context,
38+
template:,
39+
options:,
40+
system:
41+
}
42+
)
43+
)
44+
45+
chunks = []
46+
47+
res.each do |chunk|
48+
parsed = JSON.parse(chunk, symbolize_names: true)
49+
50+
case parsed
51+
in error:
52+
raise error.to_s
53+
in { done: true, context: }
54+
@context = context
55+
in response:
56+
chunks << response
57+
yield response
58+
end
59+
end
60+
61+
chunks.join.strip
62+
end
63+
end

example/app/pages/demos/layout.haml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
LINKS = {
88
"/demos" => "Demos",
99
"/demos/pokemon" => "Pokémon",
10+
"/demos/ollama" => "Ollama chat",
1011
"/demos/tree" => "App tree",
1112
"/demos/form" => "Form elements",
1213
"/demos/images" => "Images",
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
%li{class: $role.to_sym}
2+
%strong= $role
3+
%span= $text
4+
5+
:css
6+
li {
7+
display: block;
8+
padding: .5em;
9+
margin: 0;
10+
}
11+
12+
strong {
13+
&::after {
14+
content: ": ";
15+
}
16+
}
17+
18+
.user {
19+
background: #0063;
20+
}
21+
22+
.model {
23+
background: #0603;
24+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
:ruby
2+
Heading = import("/app/components/Layout/Heading")
3+
Button = import("/app/components/Form/Button")
4+
Message = import("./Message")
5+
6+
MODEL = "llama2"
7+
8+
def self.get_initial_state(**) = {
9+
key: 0,
10+
messages: [],
11+
words: [],
12+
loading: false,
13+
ollama: Ollama.new(model: MODEL, url: ENV["OLLAMA_URL"])
14+
}
15+
16+
def handle_submit(e)
17+
return if state[:loading]
18+
19+
text = e.dig(:currentTarget, :formData, :message)
20+
21+
update do |state|
22+
{
23+
**state,
24+
key: state[:key].succ,
25+
loading: true,
26+
messages: [
27+
*state[:messages],
28+
{ id: SecureRandom.alphanumeric, role: "user", text: }
29+
]
30+
}
31+
end
32+
33+
chunks = []
34+
35+
begin
36+
state[:ollama].generate(text) do |word|
37+
chunks.push(word)
38+
39+
update do |state|
40+
{
41+
**state,
42+
words: [*state[:words], word]
43+
}
44+
end
45+
end
46+
rescue => e
47+
pp e
48+
end
49+
50+
update do |state|
51+
{
52+
**state,
53+
words: [],
54+
messages: [
55+
*state[:messages],
56+
{
57+
id: SecureRandom.alphanumeric,
58+
role: "model",
59+
text: chunks.join.strip
60+
}
61+
]
62+
}
63+
end
64+
ensure
65+
update(loading: false)
66+
end
67+
68+
%section
69+
%Heading(level=2) Ollama chat
70+
71+
.scroller
72+
= if state[:messages].empty?
73+
%p.type-your-message Type a message to chat with #{MODEL}
74+
%ul
75+
= unless state[:words].empty?
76+
%Message.model[:temp]{
77+
role: "model",
78+
text: state[:words].join.strip
79+
}
80+
= state[:messages].reverse.map do |message|
81+
%Message.model[message[:id]]{
82+
role: message[:role],
83+
text: message[:text],
84+
}
85+
%form(onsubmit=handle_submit)
86+
%input[state[:key]]{
87+
autofocus: true,
88+
type: "text",
89+
name: "message",
90+
autocomplete: "off",
91+
placeholder: "Type your message here…"
92+
}
93+
%Button(type="submit"){disabled: state[:loading]} Send
94+
95+
:css
96+
section {
97+
display: grid;
98+
grid-template-rows: auto 1fr auto;
99+
min-height: 20em;
100+
gap: 1em;
101+
}
102+
103+
Heading {
104+
margin-bottom: 0;
105+
}
106+
107+
.scroller {
108+
position: relative;
109+
}
110+
111+
ul {
112+
position: absolute;
113+
inset: 0;
114+
overflow-y: scroll;
115+
font-family: "Roboto Mono";
116+
white-space: pre-wrap;
117+
border: 1px solid #0003;
118+
border-radius: 3px;
119+
display: flex;
120+
flex-direction: column-reverse;
121+
margin: 0;
122+
padding: 0;
123+
}
124+
125+
form {
126+
display: grid;
127+
grid-template-columns: 1fr auto;
128+
gap: 1em;
129+
}
130+
131+
input {
132+
padding: .5em;
133+
}
134+
135+
.type-your-message {
136+
position: absolute;
137+
top: 50%;
138+
left: 50%;
139+
transform: translate(-50%, -50%);
140+
font-weight: bold;
141+
}

example/bin/mayu

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44
require "rubygems"
55
require "bundler/setup"
66

7+
require_relative "../app/lib/ollama"
8+
79
load Gem.bin_path("mayu-live", "mayu")

lib/mayu.rb

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
# typed: strict
2-
3-
require "sorbet-runtime"
41
require_relative "mayu/version"
5-
require_relative "mayu/banner"
62

73
module Mayu
84
end
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
[dev]
2+
secret_key = "dev"
3+
4+
[dev.server]
5+
listen = "https://localhost:9292"
6+
7+
hmr = true
8+
9+
render_exceptions = true
10+
self_signed_cert = true
11+
12+
generate_assets = true
13+
14+
[dev.metrics]
15+
enabled = true
16+
listen = "http://localhost:9293"
17+
18+
[prod]
19+
secret_key = "$SECRET_KEY"
20+
21+
[prod.server]
22+
listen = "http://localhost:3000"
23+
24+
hmr = false
25+
26+
render_exceptions = false
27+
self_signed_cert = false
28+
29+
generate_assets = false
30+
31+
[prod.metrics]
32+
enabled = true
33+
listen = "http://localhost:9091"

lib/mayu/__test__/routes/layout.haml

Whitespace-only changes.

lib/mayu/__test__/routes/not_found.haml

Whitespace-only changes.

lib/mayu/__test__/routes/page.haml

Whitespace-only changes.

0 commit comments

Comments
 (0)