pedicab 0.3.1 → 0.3.3
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/API.md +401 -0
- data/EXAMPLES.md +884 -0
- data/Gemfile.lock +10 -24
- data/INSTALLATION.md +652 -0
- data/README.md +329 -10
- data/lib/pedicab/#city.rb# +27 -0
- data/lib/pedicab/ride.rb +60 -81
- data/lib/pedicab/version.rb +1 -1
- data/lib/pedicab.py +3 -8
- data/lib/pedicab.rb +141 -133
- metadata +6 -89
- data/#README.md# +0 -51
- data/books/Arnold_Bennett-How_to_Live_on_24_Hours_a_Day.txt +0 -1247
- data/books/Edward_L_Bernays-crystallizing_public_opinion.txt +0 -4422
- data/books/Emma_Goldman-Anarchism_and_Other_Essays.txt +0 -7654
- data/books/Office_of_Strategic_Services-Simple_Sabotage_Field_Manual.txt +0 -1057
- data/books/Sigmund_Freud-Group_Psychology_and_The_Analysis_of_The_Ego.txt +0 -2360
- data/books/Steve_Hassan-The_Bite_Model.txt +0 -130
- data/books/Steve_Hassan-The_Bite_Model.txt~ +0 -132
- data/books/Sun_Tzu-Art_of_War.txt +0 -159
- data/books/Sun_Tzu-Art_of_War.txt~ +0 -166
- data/books/US-Constitution.txt +0 -502
- data/books/US-Constitution.txt~ +0 -502
- data/books/cia-kubark.txt +0 -4637
- data/books/machiavelli-the_prince.txt +0 -4599
- data/books/sun_tzu-art_of_war.txt +0 -1017
- data/books/us_army-bayonette.txt +0 -843
- data/lib/pedicab/calc.rb~ +0 -8
- data/lib/pedicab/link.rb +0 -38
- data/lib/pedicab/link.rb~ +0 -14
- data/lib/pedicab/mark.rb +0 -9
- data/lib/pedicab/mark.rb~ +0 -5
- data/lib/pedicab/on.rb +0 -6
- data/lib/pedicab/on.rb~ +0 -6
- data/lib/pedicab/poke.rb +0 -14
- data/lib/pedicab/poke.rb~ +0 -15
- data/lib/pedicab/query.rb +0 -92
- data/lib/pedicab/query.rb~ +0 -93
- data/lib/pedicab/rank.rb +0 -92
- data/lib/pedicab/rank.rb~ +0 -89
- data/lib/pedicab/ride.rb~ +0 -101
- data/lib/pedicab.sh~ +0 -3
data/README.md
CHANGED
|
@@ -1,23 +1,342 @@
|
|
|
1
1
|
# Pedicab
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A lightweight Ruby framework for conversational AI interfaces using local LLM models. Pedicab provides a clean, intuitive API for building AI-powered applications with context management and structured responses.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Pedicab is designed to be "the fastest LLMs in the west" - a streamlined interface for local language model inference. It focuses on the essential mechanics of conversational AI while maintaining simplicity and performance.
|
|
8
|
+
|
|
9
|
+
### Core Features
|
|
10
|
+
|
|
11
|
+
- **Local LLM Integration**: Uses GGUF model files with Python llama-cpp backend
|
|
12
|
+
- **Context Management**: Automatic conversation context tracking and management
|
|
13
|
+
- **Elegant Syntax**: Intuitive `[]` and `<<` operators for different interaction patterns
|
|
14
|
+
- **State Management**: Persistent conversation state with reset capabilities
|
|
15
|
+
- **Performance Tracking**: Built-in benchmarking and timing information
|
|
16
|
+
- **Conditional Logic**: Support for boolean conditions and flow control
|
|
6
17
|
|
|
7
18
|
## Installation
|
|
8
19
|
|
|
9
|
-
|
|
20
|
+
### Prerequisites
|
|
21
|
+
|
|
22
|
+
1. **Ruby** >= 2.6.0
|
|
23
|
+
2. **Python** with llama-cpp-python package
|
|
24
|
+
3. **Local LLM Models** in GGUF format
|
|
25
|
+
|
|
26
|
+
### Setup
|
|
27
|
+
|
|
28
|
+
1. Install the gem:
|
|
29
|
+
```bash
|
|
30
|
+
gem install pedicab
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
2. Install Python dependencies:
|
|
34
|
+
```bash
|
|
35
|
+
pip install llama-cpp-python
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
3. Download LLM models to `/models/` directory:
|
|
39
|
+
```bash
|
|
40
|
+
# Example: Download a model
|
|
41
|
+
wget https://example.com/model.gguf -O /models/qwen.gguf
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
4. Set up the Python backend (included with the gem)
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
### Sample Pry Console
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
require 'pry'
|
|
52
|
+
require "bundler/setup"
|
|
53
|
+
# 1. include the Pedicab module
|
|
54
|
+
require 'pedicab'
|
|
55
|
+
|
|
56
|
+
# 2. create local Pedicab
|
|
57
|
+
@me = Pedicab["me"]
|
|
58
|
+
|
|
59
|
+
if File.exist? 'me.txt'
|
|
60
|
+
# 3. use the me.txt file to predefine context.
|
|
61
|
+
@me[File.read('me.txt')]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# 4. start interactive session
|
|
65
|
+
Pry.start
|
|
66
|
+
# ... that's it.
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Basic Usage
|
|
70
|
+
|
|
71
|
+
```ruby
|
|
72
|
+
require 'pedicab'
|
|
73
|
+
|
|
74
|
+
# Create a new conversation instance
|
|
75
|
+
ai = Pedicab['my_assistant']
|
|
76
|
+
|
|
77
|
+
# Start a fresh conversation
|
|
78
|
+
response = ai["Hello, how are you?"]
|
|
79
|
+
puts response.out
|
|
80
|
+
# => "I'm doing well, thank you for asking!"
|
|
81
|
+
|
|
82
|
+
# Continue the conversation with context
|
|
83
|
+
response = ai["Tell me about Ruby programming"]
|
|
84
|
+
puts response.out
|
|
85
|
+
# => "Ruby is a dynamic, object-oriented programming language..."
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Context Management
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
# Reset conversation context
|
|
92
|
+
ai.reset!
|
|
93
|
+
|
|
94
|
+
# The [] operator starts fresh
|
|
95
|
+
ai["What's the capital of France?"] # New conversation
|
|
96
|
+
|
|
97
|
+
# The << operator continues with context
|
|
98
|
+
ai["What about Germany?"] # Knows we're discussing countries
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Custom Handlers
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
# Define custom response handling
|
|
105
|
+
ai.handle do |response|
|
|
106
|
+
puts "AI Response: #{response.out}"
|
|
107
|
+
puts "Processing time: #{response.took}s"
|
|
108
|
+
response
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
ai["Explain quantum computing"]
|
|
112
|
+
# => AI Response: Quantum computing is a revolutionary...
|
|
113
|
+
# => Processing time: 1.23s
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Core API
|
|
117
|
+
|
|
118
|
+
### Pedicab::P Class
|
|
119
|
+
|
|
120
|
+
The main interface for AI conversations.
|
|
121
|
+
|
|
122
|
+
#### Methods
|
|
123
|
+
|
|
124
|
+
- `initialize(id)` - Create new conversation instance
|
|
125
|
+
- `reset!` - Clear conversation context and state
|
|
126
|
+
- `[](prompt)` - Start fresh conversation with prompt
|
|
127
|
+
- `<<(prompt)` - Continue conversation with context
|
|
128
|
+
- `handle(&block)` - Set custom response handler
|
|
129
|
+
- `life()` - Total processing time for all requests
|
|
130
|
+
|
|
131
|
+
#### Attributes
|
|
132
|
+
|
|
133
|
+
- `took` - Time taken for last request
|
|
134
|
+
- `prompt` - Last prompt sent
|
|
135
|
+
- `response` - Array of all responses
|
|
136
|
+
- `out` - Last response content
|
|
137
|
+
- `last` - Array of previous prompts
|
|
138
|
+
- `thoughts` - LLM thinking process (if available)
|
|
139
|
+
- `context` - Current conversation context
|
|
140
|
+
- `handler` - Response handler lambda
|
|
141
|
+
|
|
142
|
+
### Pedicab::Ride Class
|
|
143
|
+
|
|
144
|
+
Low-level LLM interface for direct model interaction.
|
|
145
|
+
|
|
146
|
+
#### Methods
|
|
147
|
+
|
|
148
|
+
- `go(prompt, &block)` - Send prompt to model, optionally process each line
|
|
149
|
+
- `if?(condition, &block)` - Evaluate boolean condition, optionally execute block
|
|
150
|
+
- `reset!` - Clear ride state
|
|
151
|
+
- `[](key)` - Access state value
|
|
152
|
+
- `[]=(key, value)` - Set state value
|
|
153
|
+
- `to_h` - Get state as hash
|
|
154
|
+
|
|
155
|
+
#### State
|
|
156
|
+
|
|
157
|
+
The ride maintains internal state including:
|
|
158
|
+
- `:content` - Model response content
|
|
159
|
+
- `:thought` - Model thinking process
|
|
160
|
+
- `:action` - Current action description
|
|
161
|
+
- `:yes` - Boolean result for conditions
|
|
162
|
+
- `:took` - Processing time
|
|
163
|
+
|
|
164
|
+
### Module Methods
|
|
165
|
+
|
|
166
|
+
- `Pedicab.[](id)` - Create new conversation instance
|
|
167
|
+
- `Pedicab.models` - List available models in `/models/`
|
|
168
|
+
- `Pedicab.ride(id)` - Create new ride instance
|
|
169
|
+
|
|
170
|
+
## Advanced Usage
|
|
171
|
+
|
|
172
|
+
### Conditional Processing
|
|
173
|
+
|
|
174
|
+
```ruby
|
|
175
|
+
ai = Pedicab['conditional_bot']
|
|
176
|
+
|
|
177
|
+
# Use conditional logic
|
|
178
|
+
if ai.ride.if?("the user wants programming help")
|
|
179
|
+
ai["I'll help you with programming!"]
|
|
180
|
+
else
|
|
181
|
+
ai["How can I assist you today?"]
|
|
182
|
+
end
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Iterating Over Responses
|
|
186
|
+
|
|
187
|
+
```ruby
|
|
188
|
+
# Process each line of a response
|
|
189
|
+
ai.ride.go("List 3 programming languages") do |line|
|
|
190
|
+
puts "Language: #{line[:for]}"
|
|
191
|
+
end
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### State Management
|
|
195
|
+
|
|
196
|
+
```ruby
|
|
197
|
+
ride = Pedicab.ride['stateful_bot']
|
|
198
|
+
|
|
199
|
+
# Store custom state
|
|
200
|
+
ride[:user_preference] = "detailed"
|
|
201
|
+
ride[:last_topic] = "Ruby"
|
|
202
|
+
|
|
203
|
+
# Access state later
|
|
204
|
+
puts ride[:user_preference] # => "detailed"
|
|
205
|
+
puts ride.to_h # => { user_preference: "detailed", last_topic: "Ruby" }
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Performance Monitoring
|
|
209
|
+
|
|
210
|
+
```ruby
|
|
211
|
+
ai = Pedicab['monitored_bot']
|
|
212
|
+
|
|
213
|
+
ai["First question"] # Processes
|
|
214
|
+
puts ai.took # Time for last request: 0.85s
|
|
215
|
+
|
|
216
|
+
ai["Follow up question"] # Processes
|
|
217
|
+
puts ai.life # Total time: 1.67s
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Configuration
|
|
221
|
+
|
|
222
|
+
### Environment Variables
|
|
223
|
+
|
|
224
|
+
- `MODEL` - Default model name (default: 'qwen')
|
|
225
|
+
- `DEBUG` - Debug level (0=off, 1=basic, 2=verbose)
|
|
226
|
+
|
|
227
|
+
### Model Management
|
|
228
|
+
|
|
229
|
+
```ruby
|
|
230
|
+
# List available models
|
|
231
|
+
puts Pedicab.models
|
|
232
|
+
# => ["qwen", "llama2", "mistral"]
|
|
233
|
+
|
|
234
|
+
# Models should be placed in /models/ directory as .gguf files
|
|
235
|
+
# /models/qwen.gguf
|
|
236
|
+
# /models/llama2.gguf
|
|
237
|
+
# /models/mistral.gguf
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Architecture
|
|
241
|
+
|
|
242
|
+
### Core Components
|
|
243
|
+
|
|
244
|
+
1. **Ruby Interface** (`lib/pedicab.rb`)
|
|
245
|
+
- Main API and conversation management
|
|
246
|
+
- Context tracking and state management
|
|
247
|
+
- Elegant operator interface
|
|
248
|
+
|
|
249
|
+
2. **Ride Layer** (`lib/pedicab/ride.rb`)
|
|
250
|
+
- Low-level LLM communication
|
|
251
|
+
- JSON-based protocol with Python backend
|
|
252
|
+
- State management and error handling
|
|
253
|
+
|
|
254
|
+
3. **Python Backend** (`lib/pedicab.py`)
|
|
255
|
+
- llama-cpp-python integration
|
|
256
|
+
- Model loading and inference
|
|
257
|
+
- Grammar-based constrained outputs
|
|
258
|
+
|
|
259
|
+
### Communication Flow
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
Ruby P Class -> Ride Class -> Python Backend -> LLM Model -> Response
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
1. Ruby sends JSON request to Python process
|
|
266
|
+
2. Python processes with llama-cpp-python
|
|
267
|
+
3. Response includes content and thinking process
|
|
268
|
+
4. Ruby parses and manages state
|
|
269
|
+
|
|
270
|
+
## Error Handling
|
|
271
|
+
|
|
272
|
+
```ruby
|
|
273
|
+
begin
|
|
274
|
+
ai = Pedicab['test_bot']
|
|
275
|
+
response = ai["Some question"]
|
|
276
|
+
rescue Pedicab::Error => e
|
|
277
|
+
puts "Pedicab error: #{e.message}"
|
|
278
|
+
rescue => e
|
|
279
|
+
puts "Unexpected error: #{e.message}"
|
|
280
|
+
end
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## Debugging
|
|
284
|
+
|
|
285
|
+
Enable debug output:
|
|
286
|
+
|
|
287
|
+
```ruby
|
|
288
|
+
# In your shell
|
|
289
|
+
export DEBUG=1 # Basic debugging
|
|
290
|
+
export DEBUG=2 # Verbose debugging
|
|
291
|
+
|
|
292
|
+
# Or in Ruby
|
|
293
|
+
ENV['DEBUG'] = '1'
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Debug output includes:
|
|
297
|
+
- Action descriptions
|
|
298
|
+
- Processing times
|
|
299
|
+
- Full state information
|
|
300
|
+
- Error details
|
|
301
|
+
|
|
302
|
+
## Performance Tips
|
|
303
|
+
|
|
304
|
+
1. **Model Selection**: Choose appropriate model size for your use case
|
|
305
|
+
2. **Context Management**: Reset conversations when starting new topics
|
|
306
|
+
3. **Batch Processing**: Use the iteration methods for list responses
|
|
307
|
+
4. **Monitoring**: Track processing times with `took` and `life` methods
|
|
308
|
+
|
|
309
|
+
## Contributing
|
|
310
|
+
|
|
311
|
+
1. Fork the repository
|
|
312
|
+
2. Create a feature branch
|
|
313
|
+
3. Make your changes
|
|
314
|
+
4. Add tests if applicable
|
|
315
|
+
5. Submit a pull request
|
|
316
|
+
|
|
317
|
+
## License
|
|
318
|
+
|
|
319
|
+
MIT License - see LICENSE file for details.
|
|
320
|
+
|
|
321
|
+
## Changelog
|
|
322
|
+
|
|
323
|
+
### Version 0.3.2
|
|
10
324
|
|
|
11
|
-
|
|
325
|
+
- Simplified core architecture
|
|
326
|
+
- Removed auxiliary modules for focus on essential mechanics
|
|
327
|
+
- Improved performance and reduced dependencies
|
|
328
|
+
- Enhanced error handling and debugging capabilities
|
|
12
329
|
|
|
13
|
-
|
|
330
|
+
### Previous Versions
|
|
14
331
|
|
|
15
|
-
|
|
332
|
+
See git history for detailed changelog.
|
|
16
333
|
|
|
17
|
-
##
|
|
334
|
+
## Support
|
|
18
335
|
|
|
19
|
-
|
|
336
|
+
For issues and questions:
|
|
337
|
+
- GitHub Issues: https://github.com/xorgnak/pedicab/issues
|
|
338
|
+
- Documentation: https://github.com/xorgnak/pedicab
|
|
20
339
|
|
|
21
|
-
|
|
340
|
+
---
|
|
22
341
|
|
|
23
|
-
|
|
342
|
+
*Pedicab: A better way to go with local LLMs*
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Pedicab
|
|
2
|
+
module City
|
|
3
|
+
class C
|
|
4
|
+
attr_accessor :data
|
|
5
|
+
def initialize(i)
|
|
6
|
+
@id = i
|
|
7
|
+
@data = {}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_markdown
|
|
11
|
+
@carpet.to_markdown(@data)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def to_html
|
|
15
|
+
@carpet.to_html(@data)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.[](k)
|
|
20
|
+
C.new(k)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.city
|
|
25
|
+
City
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/pedicab/ride.rb
CHANGED
|
@@ -1,109 +1,88 @@
|
|
|
1
1
|
module Pedicab
|
|
2
|
-
@@Ride = Hash.new { |h,k| h[k] = Ride.new(k) }
|
|
3
2
|
class Ride
|
|
4
|
-
attr_accessor :state, :
|
|
5
|
-
def initialize
|
|
3
|
+
attr_accessor :state, :model
|
|
4
|
+
def initialize(k)
|
|
6
5
|
@id = k
|
|
7
|
-
@model = '
|
|
6
|
+
@model = ENV['MODEL'] || 'qwen'
|
|
8
7
|
reset!
|
|
9
8
|
end
|
|
9
|
+
|
|
10
10
|
def reset!
|
|
11
11
|
@state = {}
|
|
12
|
-
@ride = []
|
|
13
|
-
@path = []
|
|
14
|
-
@info = ""
|
|
15
12
|
end
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
|
|
14
|
+
def go(prompt, &b)
|
|
15
|
+
@state[:action] = "respond: #{prompt}"
|
|
16
|
+
rider(role: 'user', model: @model, content: prompt)
|
|
17
|
+
def each &b
|
|
18
|
+
@state[:content].split("\n").each { |e| @state[:for] = e; b.call(self) }
|
|
19
|
+
end
|
|
20
|
+
if block_given?
|
|
21
|
+
b.call(self)
|
|
25
22
|
else
|
|
26
|
-
|
|
23
|
+
@state[:content]
|
|
27
24
|
end
|
|
28
25
|
end
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
# process input.
|
|
32
|
-
def go i
|
|
33
|
-
@path << "go #{i}"
|
|
34
|
-
@state[:action] = "go"
|
|
35
|
-
@state[:input] = i
|
|
36
|
-
# puts %[#===============[work]>\n#{i}\n#===============[work]];
|
|
37
|
-
Pedicab.on[:work].call(self)
|
|
38
|
-
@state[:output] = rider(role: 'user', model: 'work', content: "#{@info}#{tale}#{i}")
|
|
39
|
-
@ride << @state
|
|
40
|
-
@state[:output].gsub(/\n+/, "\n")
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
##
|
|
44
|
-
# process condition
|
|
45
|
-
def go? i
|
|
46
|
-
@path << "go? #{i}"
|
|
47
|
-
@state[:action] = "go?"
|
|
48
|
-
@state[:input] = i
|
|
26
|
+
def if?(condition, &b)
|
|
27
|
+
@state[:action] = "gate: #{condition}"
|
|
49
28
|
@state[:yes] = false
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
29
|
+
gate_prompt = "If the following statement is true respond 'yes', otherwise respond 'no':\n#{condition}"
|
|
30
|
+
rider(role: 'system', model: @model, content: gate_prompt)
|
|
31
|
+
@state[:yes] = (@state[:content] == 'yes')
|
|
32
|
+
if block_given? && @state[:yes] == true
|
|
33
|
+
b.call(self)
|
|
34
|
+
else
|
|
35
|
+
@state[:yes]
|
|
55
36
|
end
|
|
56
|
-
@ride << @state
|
|
57
|
-
@state[:yes]
|
|
58
37
|
end
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
@state[
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
Pedicab.on[:with].call(self);
|
|
71
|
-
b.call(e.strip);
|
|
72
|
-
end;
|
|
73
|
-
}
|
|
74
|
-
@ride << @state
|
|
75
|
-
@state[:list]
|
|
38
|
+
|
|
39
|
+
def [] k
|
|
40
|
+
@state[k]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def []= k,v
|
|
44
|
+
@state[k] = v
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def to_h
|
|
48
|
+
@state
|
|
76
49
|
end
|
|
77
50
|
|
|
78
51
|
private
|
|
79
52
|
|
|
80
|
-
def rider
|
|
53
|
+
def rider(h = {})
|
|
81
54
|
@state[:content] = "I don't know."
|
|
82
|
-
|
|
83
|
-
|
|
55
|
+
if ENV['DEBUG'].to_i > 1
|
|
56
|
+
puts "# #{@state[:action]}"
|
|
57
|
+
end
|
|
58
|
+
|
|
84
59
|
@state[:took] = Benchmark.realtime do
|
|
85
60
|
Open3.popen3("pedicab /models/#{h[:model]}.gguf") do |stdin, stdout, stderr, wait_thread|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
61
|
+
stdin.puts(JSON.generate(h))
|
|
62
|
+
response = stdout.gets
|
|
63
|
+
|
|
64
|
+
if response && response.strip.length > 0
|
|
65
|
+
content = JSON.parse(response)['content']
|
|
66
|
+
if match = /<think>([\s\S]*)<\/think>([\s\S]*)/.match(content)
|
|
67
|
+
@state[:thought] = match[1].strip.gsub(/\n+/, "\n").gsub('\\n', "\n")
|
|
68
|
+
@state[:content] = match[2].strip.gsub(/\n+/, "\n").gsub('\\n', "\n")
|
|
69
|
+
else
|
|
70
|
+
@state[:thought] = h[:content].gsub('\\n', "\n")
|
|
71
|
+
@state[:content] = content.strip.gsub(/\n+/, "\n").gsub('\\n', "\n")
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
rescue => e
|
|
75
|
+
@state[:content] = "Error: #{e}"
|
|
95
76
|
end
|
|
96
77
|
end
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
return b.call(self).gsub(/\n+/, "\n")
|
|
101
|
-
else
|
|
102
|
-
return @state[:content].gsub(/\n+/, "\n")
|
|
78
|
+
|
|
79
|
+
if ENV['DEBUG'].to_i > 0
|
|
80
|
+
@state.each_pair { |k, v| puts "#{k}: #{v}" }
|
|
103
81
|
end
|
|
104
82
|
end
|
|
105
83
|
end
|
|
106
|
-
|
|
107
|
-
|
|
84
|
+
|
|
85
|
+
def self.ride(k)
|
|
86
|
+
Ride.new(k)
|
|
108
87
|
end
|
|
109
88
|
end
|
data/lib/pedicab/version.rb
CHANGED
data/lib/pedicab.py
CHANGED
|
@@ -5,19 +5,15 @@ import json
|
|
|
5
5
|
|
|
6
6
|
llm = Llama(
|
|
7
7
|
model_path=sys.argv[1],
|
|
8
|
-
# model_path="/models/planner.gguf",
|
|
9
|
-
# model_path="/models/smollm.gguf",
|
|
10
8
|
verbose=False,
|
|
11
9
|
errors="ignore",
|
|
12
10
|
n_ctx=8192
|
|
13
11
|
)
|
|
14
12
|
|
|
15
|
-
__sys = "A conversation between a curious Human and an all knowing Assistant who responds only to what was asked in simple terms and never repeats itself.\n\nWhen asked to respond with a single value, respond with only that value.\nWhen asked to list items
|
|
13
|
+
__sys = "A conversation between a curious Human and an all knowing Assistant who responds only to what was asked in simple terms and never repeats itself.\n\nWhen asked to respond with a single value, respond with only that value.\nWhen asked to respond with an empty list, respond only with an empty string.\nWhen asked to list items respond with the list of items sepearated by a newline only and again - never repeat yourself.\nWhen asked to respond with a mathmatical formula, respond with only the bare formula in the format necessary to be evaluated by the ruby eqn gem.\nOtherwise, respond with a single level outline and NEVER repeat yourself."
|
|
16
14
|
#__sys = "A conversation between a Human and an all knowing Llama."
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
prompt = __sys
|
|
20
|
-
convo = [{ "role": "system", "content": prompt }]
|
|
16
|
+
convo = [{ "role": "system", "content": __sys }]
|
|
21
17
|
grammars = {
|
|
22
18
|
"bool": 'root ::= ("yes" | "no")',
|
|
23
19
|
"number": "root ::= (\"-\"?([0-9]+))",
|
|
@@ -30,8 +26,7 @@ while True:
|
|
|
30
26
|
user = json.loads(input(""))
|
|
31
27
|
|
|
32
28
|
if (user["role"] == "assistant"):
|
|
33
|
-
convo
|
|
34
|
-
convo.append({ "role": "assistant", "content": user["response"] })
|
|
29
|
+
convo = [{ "role": "system", "content": user["content"] }]
|
|
35
30
|
|
|
36
31
|
if (user["role"] == "system"):
|
|
37
32
|
output = llm( user["content"], stop=["\n"], echo=False, temperature=0.0, grammar=LlamaGrammar.from_string(grammars[user['response']]))["choices"][0]["text"]
|