...
This commit is contained in:
52
aiprompts/ai_instruct/documentation_from_v.md
Normal file
52
aiprompts/ai_instruct/documentation_from_v.md
Normal file
@@ -0,0 +1,52 @@
|
||||
params:
|
||||
|
||||
- filepath: /Users/despiegk/code/github/freeflowuniverse/herolib/lib/clients/openai
|
||||
|
||||
make a dense overview of the code above, easy to understand for AI
|
||||
|
||||
the result is 1 markdown file called codeoverview.md and is stored in $filepath
|
||||
|
||||
try to figure out which functions are more important and which are less important, so that the most important functions are at the top of section you are working on
|
||||
|
||||
the template is as follows
|
||||
|
||||
```md
|
||||
# the name of the module
|
||||
|
||||
2-5 liner description
|
||||
|
||||
## factory
|
||||
|
||||
is there factory, which one and quick example how to call, don’t say in which file not relevant
|
||||
show how to import the module is as follows: import freeflowuniverse.herolib.
|
||||
and then starting from lib e.g. lib/clients/mycelium would result in import freeflowuniverse.herolib. clients.mycelium
|
||||
|
||||
## overview
|
||||
|
||||
quick overview as list with identations, of the structs and its methods
|
||||
|
||||
## structs
|
||||
|
||||
### structname
|
||||
|
||||
now list the methods & arguments, for arguments use table
|
||||
|
||||
for each method show the arguments needed to call the method, and what it returns
|
||||
|
||||
### methods
|
||||
|
||||
- if any methods which are on module
|
||||
- only show public methods, don't show the get/set/exists methods on module level as part of factory.
|
||||
|
||||
|
||||
```
|
||||
|
||||
don't mention what we don't show because of rules above.
|
||||
|
||||
the only output we want is markdown file as follows
|
||||
|
||||
===WRITE===
|
||||
$filepath
|
||||
===CONTENT===
|
||||
$the content of the generated markdown file
|
||||
===END===
|
||||
22
aiprompts/ai_instruct/documentation_from_v_md.md
Normal file
22
aiprompts/ai_instruct/documentation_from_v_md.md
Normal file
@@ -0,0 +1,22 @@
|
||||
remove all navigation elements, and index
|
||||
for each method, move the args as used in the methods to the method section so its easier to read
|
||||
|
||||
start of output file is:
|
||||
|
||||
# the name of the module
|
||||
|
||||
2-5 liner description
|
||||
|
||||
## factory
|
||||
|
||||
is there factory, which one and quick example how to call, don’t say in which file not relevant
|
||||
show how to import the module is as follows: import freeflowuniverse.herolib.
|
||||
and then starting from lib e.g. lib/clients/mycelium would result in import freeflowuniverse.herolib. clients.mycelium
|
||||
|
||||
## structs and methods
|
||||
|
||||
quick overview as list with identations, of the structs and its methods
|
||||
|
||||
|
||||
ONLY OUTPUT THE MARKDOWN FILE, NOTHING ELSE
|
||||
|
||||
11
doc.vsh
11
doc.vsh
@@ -36,6 +36,11 @@ if os.system('v doc -m -f html . -readme -comments -no-timestamp -o ../docs') !=
|
||||
panic('Failed to generate HTML documentation')
|
||||
}
|
||||
|
||||
if os.system('v doc -m -f md . -no-color -o ../vdocs/') != 0 {
|
||||
panic('Failed to generate Hero markdown documentation')
|
||||
}
|
||||
|
||||
|
||||
os.chdir(abs_dir_of_script) or {
|
||||
panic('Failed to change directory to abs_dir_of_script: ${err}')
|
||||
}
|
||||
@@ -47,9 +52,9 @@ println('Generating Markdown documentation...')
|
||||
// panic('Failed to generate V markdown documentation')
|
||||
// }
|
||||
|
||||
if os.system('v doc -m -no-color -f md -o vdocs/') != 0 {
|
||||
panic('Failed to generate Hero markdown documentation')
|
||||
}
|
||||
// if os.system('v doc -m -no-color -f md . -o vdocs/') != 0 {
|
||||
// panic('Failed to generate Hero markdown documentation')
|
||||
// }
|
||||
|
||||
// Open documentation in browser on non-Linux systems
|
||||
$if !linux {
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
import freeflowuniverse.herolib.biz.bizmodel
|
||||
import os
|
||||
|
||||
|
||||
heroscript := os.join_path(os.dir(@FILE), 'examples/complete.heroscript')
|
||||
|
||||
// Execute the script and print results
|
||||
bizmodel.play(heroscript_path:heroscript)!
|
||||
mut bm := bizmodel.get("threefold")!
|
||||
bizmodel.play(heroscript_path: heroscript)!
|
||||
mut bm := bizmodel.get('threefold')!
|
||||
bm.sheet.pprint(nr_columns: 10)!
|
||||
|
||||
@@ -12,10 +12,9 @@ import os
|
||||
|
||||
heroscript := os.join_path(os.dir(@FILE), 'examples/complete.heroscript')
|
||||
// Execute the script and print results
|
||||
bizmodel.play(heroscript_path:heroscript)!
|
||||
bizmodel.play(heroscript_path: heroscript)!
|
||||
|
||||
|
||||
mut bm := bizmodel.get("threefold")!
|
||||
mut bm := bizmodel.get('threefold')!
|
||||
bm.sheet.pprint(nr_columns: 10)!
|
||||
|
||||
// buildpath := '${os.home_dir()}/hero/var/mdbuild/bizmodel'
|
||||
@@ -32,5 +31,5 @@ bm.sheet.pprint(nr_columns: 10)!
|
||||
bm.export(
|
||||
name: 'example_report'
|
||||
title: 'Example Business Model'
|
||||
path: '/tmp/bizmodel_export'
|
||||
path: '/tmp/bizmodel_export'
|
||||
)!
|
||||
|
||||
@@ -3,10 +3,9 @@
|
||||
import freeflowuniverse.herolib.biz.bizmodel
|
||||
import os
|
||||
|
||||
|
||||
heroscript := os.join_path(os.dir(@FILE), 'examples/full')
|
||||
|
||||
// Execute the script and print results
|
||||
bizmodel.play(heroscript_path:heroscript)!
|
||||
mut bm := bizmodel.get("threefold")!
|
||||
bizmodel.play(heroscript_path: heroscript)!
|
||||
mut bm := bizmodel.get('threefold')!
|
||||
bm.sheet.pprint(nr_columns: 25)!
|
||||
|
||||
@@ -49,4 +49,4 @@ bizmodel.play(heroscript: heroscript)!
|
||||
|
||||
mut bm := bizmodel.get('test')!
|
||||
|
||||
bm.sheet.pprint(nr_columns: 20)!
|
||||
bm.sheet.pprint(nr_columns: 20)!
|
||||
|
||||
@@ -21,4 +21,4 @@ bizmodel.play(heroscript: heroscript)!
|
||||
|
||||
mut bm := bizmodel.get('test')!
|
||||
|
||||
bm.sheet.pprint(nr_columns: 20)!
|
||||
bm.sheet.pprint(nr_columns: 20)!
|
||||
|
||||
20
examples/clients/aiclient_example.vsh
Executable file
20
examples/clients/aiclient_example.vsh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib.clients.openai
|
||||
import freeflowuniverse.herolib.core.playcmds
|
||||
|
||||
playcmds.run(
|
||||
heroscript: '
|
||||
!!openai.configure name: "default" key: "" url: "https://openrouter.ai/api/v1" model_default: "gpt-oss-120b"
|
||||
'
|
||||
)!
|
||||
|
||||
// name:'default' is the default, you can change it to whatever you want
|
||||
mut client := openai.get()!
|
||||
|
||||
mut r := client.chat_completion(
|
||||
model: 'gpt-3.5-turbo'
|
||||
message: 'Hello, world!'
|
||||
temperature: 0.5
|
||||
max_completion_tokens: 1024
|
||||
)!
|
||||
@@ -4,7 +4,7 @@ import freeflowuniverse.herolib.core.generator.generic as generator
|
||||
import freeflowuniverse.herolib.core.pathlib
|
||||
|
||||
mut args := generator.GeneratorArgs{
|
||||
path: '~/code/github/freeflowuniverse/herolib/lib/clients/postgresql_client'
|
||||
path: '~/code/github/freeflowuniverse/herolib/lib/clients/postgresql_client'
|
||||
force: true
|
||||
}
|
||||
|
||||
@@ -13,5 +13,4 @@ mut args := generator.GeneratorArgs{
|
||||
// force: true
|
||||
// }
|
||||
|
||||
|
||||
generator.scan(args)!
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#!/usr/bin/env -S v -cg -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
import freeflowuniverse.herolib...
|
||||
import compress.gzip
|
||||
|
||||
// Define some sample data to compress
|
||||
@@ -18,12 +17,12 @@ println('Compressed Data Length: ${compressed_data.len}')
|
||||
// Decompress the data
|
||||
decompressed_data := gzip.decompress(compressed_data)!
|
||||
|
||||
println('Decompressed Data: "${decompressed_data.string()}"')
|
||||
println('Decompressed Data: "${decompressed_data.bytestr()}"')
|
||||
println('Decompressed Data Length: ${decompressed_data.len}')
|
||||
|
||||
// Verify if the decompressed data matches the original data
|
||||
if data.bytes() == decompressed_data {
|
||||
println('Compression and decompression successful! Data matches.')
|
||||
println('Compression and decompression successful! Data matches.')
|
||||
} else {
|
||||
println('Error: Decompressed data does not match original data.')
|
||||
}
|
||||
println('Error: Decompressed data does not match original data.')
|
||||
}
|
||||
|
||||
@@ -1,30 +1,27 @@
|
||||
#!/usr/bin/env -S v -n -cg -w -gc none -cc tcc -d use_openssl -enable-globals run
|
||||
|
||||
// #!/usr/bin/env -S v -n -w -enable-globals run
|
||||
import freeflowuniverse.herolib.clients.postgresql_client
|
||||
import freeflowuniverse.herolib.core.playbook
|
||||
import freeflowuniverse.herolib.hero.models.circle
|
||||
import freeflowuniverse.herolib.core.playcmds
|
||||
import freeflowuniverse.herolib.hero.db.hero_db
|
||||
|
||||
import db.pg
|
||||
|
||||
// psql -h /tmp -U myuser -d mydb
|
||||
|
||||
mut db := pg.connect(pg.Config{
|
||||
host: '/tmp'
|
||||
port: 5432
|
||||
user: 'myuser'
|
||||
password: 'mypassword'
|
||||
dbname: 'mydb'
|
||||
})!
|
||||
host: '/tmp'
|
||||
port: 5432
|
||||
user: 'myuser'
|
||||
password: 'mypassword'
|
||||
dbname: 'mydb'
|
||||
})!
|
||||
|
||||
mut r:=db.exec("select * from users;")!
|
||||
mut r := db.exec('select * from users;')!
|
||||
|
||||
println(r)
|
||||
|
||||
|
||||
|
||||
|
||||
// // Configure PostgreSQL client
|
||||
// heroscript := "
|
||||
// !!postgresql_client.configure
|
||||
@@ -50,7 +47,6 @@ heroscript := "
|
||||
mut plbook := playbook.new(text: heroscript)!
|
||||
postgresql_client.play(mut plbook)!
|
||||
|
||||
|
||||
// //Get the configured client
|
||||
mut db_client := postgresql_client.get(name: 'aaa')!
|
||||
|
||||
@@ -78,7 +74,6 @@ mut db_client := postgresql_client.get(name: 'aaa')!
|
||||
|
||||
// println('Database and table setup completed successfully!')
|
||||
|
||||
|
||||
// // Create HeroDB for Circle type
|
||||
// mut circle_db := hero_db.new[circle.Circle]()!
|
||||
|
||||
@@ -112,5 +107,4 @@ mut db_client := postgresql_client.get(name: 'aaa')!
|
||||
// // Search circles by status
|
||||
// active_circles := circle_db.search_by_index("status", "active")!
|
||||
|
||||
|
||||
//https://www.moncefbelyamani.com/how-to-install-postgresql-on-a-mac-with-homebrew-and-lunchy/
|
||||
// https://www.moncefbelyamani.com/how-to-install-postgresql-on-a-mac-with-homebrew-and-lunchy/
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
import freeflowuniverse.herolib.core.playcmds
|
||||
|
||||
mut plbook := heroscript.new(heroscript: '
|
||||
mut plbook := heroscript.new(
|
||||
heroscript: '
|
||||
|
||||
!!docusaurus.define
|
||||
path_build: "/tmp/docusaurus_build"
|
||||
@@ -18,6 +19,5 @@ mut plbook := heroscript.new(heroscript: '
|
||||
git_pull:1
|
||||
|
||||
!!docusaurus.build
|
||||
')!
|
||||
|
||||
|
||||
'
|
||||
)!
|
||||
|
||||
@@ -84,12 +84,12 @@ pub fn (mut m BizModel) export_overview_action(action Action) !Action {
|
||||
}
|
||||
|
||||
fn (mut m BizModel) new_report_action(action Action) !Action {
|
||||
mut p:=action.params
|
||||
mut p := action.params
|
||||
path := p.get_default('path', '')!
|
||||
name := p.get_default('name', '')!
|
||||
title := p.get_default('title', '')!
|
||||
description := p.get_default('description', '')!
|
||||
m.export(path:path,name:name,title:title,description:description)!
|
||||
m.export(path: path, name: name, title: title, description: description)!
|
||||
return action
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ pub fn (b BizModel) export(args ExportArgs) ! {
|
||||
// b.export_fundraising(export)
|
||||
}
|
||||
|
||||
|
||||
pub fn (model BizModel) write_introduction(args ExportArgs) ! {
|
||||
mut index_page := pathlib.get_file(path: '${args.path}/introduction.md')!
|
||||
// mut tmpl_index := $tmpl('templates/index.md')
|
||||
|
||||
@@ -13,9 +13,7 @@ import math
|
||||
// costcenter:'marketing_cc'
|
||||
// cost_percent_revenue:'1%'
|
||||
fn (mut m BizModel) cost_define_action(action Action) !Action {
|
||||
mut name := action.params.get('name') or {
|
||||
return error('Cost name is required.')
|
||||
}
|
||||
mut name := action.params.get('name') or { return error('Cost name is required.') }
|
||||
mut descr := action.params.get_default('descr', '')!
|
||||
if descr.len == 0 {
|
||||
descr = action.params.get_default('description', '')!
|
||||
@@ -32,7 +30,8 @@ fn (mut m BizModel) cost_define_action(action Action) !Action {
|
||||
return error('Costcenter `${costcenter}` not found. Please define it first.')
|
||||
}
|
||||
|
||||
cost_percent_revenue := action.params.get_percentage_default('cost_percent_revenue','0%')!
|
||||
cost_percent_revenue := action.params.get_percentage_default('cost_percent_revenue',
|
||||
'0%')!
|
||||
|
||||
indexation := action.params.get_percentage_default('indexation', '0%')!
|
||||
|
||||
@@ -55,7 +54,6 @@ fn (mut m BizModel) cost_define_action(action Action) !Action {
|
||||
)!
|
||||
cost_row = cost_row.action(action: .reverse)!
|
||||
|
||||
|
||||
if cost_percent_revenue > 0 {
|
||||
// println(cost_row)
|
||||
mut revtotal := m.sheet.row_get('revenue_total')!
|
||||
@@ -73,9 +71,6 @@ fn (mut m BizModel) cost_define_action(action Action) !Action {
|
||||
return action
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fn (mut sim BizModel) cost_total() ! {
|
||||
sim.sheet.group2row(
|
||||
name: 'cost_total'
|
||||
|
||||
@@ -9,9 +9,7 @@ import freeflowuniverse.herolib.core.texttools
|
||||
// descr:'Marketing Cost Center'
|
||||
// department:'marketing'
|
||||
fn (mut m BizModel) costcenter_define_action(action Action) !Action {
|
||||
mut name := action.params.get('name') or {
|
||||
return error('Costcenter name is required.')
|
||||
}
|
||||
mut name := action.params.get('name') or { return error('Costcenter name is required.') }
|
||||
mut descr := action.params.get_default('descr', '')!
|
||||
if descr.len == 0 {
|
||||
descr = action.params.get_default('description', '')!
|
||||
|
||||
@@ -102,7 +102,6 @@ fn (mut m BizModel) employee_define_action(action Action) !Action {
|
||||
return action
|
||||
}
|
||||
|
||||
|
||||
fn (mut sim BizModel) hrcost_total() ! {
|
||||
sim.sheet.group2row(
|
||||
name: 'hr_cost_total'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module bizmodel
|
||||
|
||||
import arrays
|
||||
import freeflowuniverse.herolib.core.playbook { Action, PlayBook }
|
||||
import freeflowuniverse.herolib.core.playbook
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
|
||||
// revenue_total calculates and aggregates the total revenue and cost of goods sold (COGS) for the business model
|
||||
@@ -22,5 +22,4 @@ fn (mut sim BizModel) pl_total() ! {
|
||||
// println(pl_total)
|
||||
|
||||
// if true{panic("sdsd")}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,5 +28,4 @@ fn (mut sim BizModel) revenue_total() ! {
|
||||
// println(revenue_total)
|
||||
// println(cogs_total)
|
||||
// println(margin_total)
|
||||
|
||||
}
|
||||
|
||||
19
lib/clients/openai/audio/README.md
Normal file
19
lib/clients/openai/audio/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Quick Example: Transcribing Audio
|
||||
|
||||
```v
|
||||
|
||||
import freeflowuniverse.herolib.clients.openai
|
||||
|
||||
mut client:= openai.get()! //will be the default client, key is in `AIKEY` on environment variable or `OPENROUTER_API_KEY`
|
||||
|
||||
// Assuming you have an audio file named 'audio.mp3' in the same directory
|
||||
// For a real application, handle file paths dynamically
|
||||
audio_file_path := 'audio.mp3'
|
||||
|
||||
resp := client.audio.create_transcription(
|
||||
file: audio_file_path,
|
||||
model: 'whisper-1'
|
||||
)!
|
||||
|
||||
```
|
||||
|
||||
@@ -1,9 +1,88 @@
|
||||
module openai
|
||||
module audio
|
||||
|
||||
import json
|
||||
import freeflowuniverse.herolib.core.httpconnection
|
||||
import os
|
||||
import net.http
|
||||
import freeflowuniverse.herolib.clients.openai { OpenAI }
|
||||
|
||||
type OpenAIAlias = OpenAI
|
||||
|
||||
pub enum Voice {
|
||||
alloy
|
||||
ash
|
||||
coral
|
||||
echo
|
||||
fable
|
||||
onyx
|
||||
nova
|
||||
sage
|
||||
shimmer
|
||||
}
|
||||
|
||||
fn voice_str(x Voice) string {
|
||||
return match x {
|
||||
.alloy {
|
||||
'alloy'
|
||||
}
|
||||
.ash {
|
||||
'ash'
|
||||
}
|
||||
.coral {
|
||||
'coral'
|
||||
}
|
||||
.echo {
|
||||
'echo'
|
||||
}
|
||||
.fable {
|
||||
'fable'
|
||||
}
|
||||
.onyx {
|
||||
'onyx'
|
||||
}
|
||||
.nova {
|
||||
'nova'
|
||||
}
|
||||
.sage {
|
||||
'sage'
|
||||
}
|
||||
.shimmer {
|
||||
'shimmer'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum AudioFormat {
|
||||
mp3
|
||||
opus
|
||||
aac
|
||||
flac
|
||||
wav
|
||||
pcm
|
||||
}
|
||||
|
||||
fn audio_format_str(x AudioFormat) string {
|
||||
return match x {
|
||||
.mp3 {
|
||||
'mp3'
|
||||
}
|
||||
.opus {
|
||||
'opus'
|
||||
}
|
||||
.aac {
|
||||
'aac'
|
||||
}
|
||||
.flac {
|
||||
'flac'
|
||||
}
|
||||
.wav {
|
||||
'wav'
|
||||
}
|
||||
.pcm {
|
||||
'pcm'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum AudioRespType {
|
||||
json
|
||||
@@ -44,6 +123,7 @@ fn audio_resp_type_str(i AudioRespType) string {
|
||||
}
|
||||
}
|
||||
|
||||
@[params]
|
||||
pub struct AudioArgs {
|
||||
pub mut:
|
||||
filepath string
|
||||
@@ -60,17 +140,17 @@ pub mut:
|
||||
|
||||
// create transcription from an audio file
|
||||
// supported audio formats are mp3, mp4, mpeg, mpga, m4a, wav, or webm
|
||||
pub fn (mut f OpenAI) create_transcription(args AudioArgs) !AudioResponse {
|
||||
pub fn (mut f OpenAIAlias) create_transcription(args AudioArgs) !AudioResponse {
|
||||
return f.create_audio_request(args, 'audio/transcriptions')
|
||||
}
|
||||
|
||||
// create translation to english from an audio file
|
||||
// supported audio formats are mp3, mp4, mpeg, mpga, m4a, wav, or webm
|
||||
pub fn (mut f OpenAI) create_tranlation(args AudioArgs) !AudioResponse {
|
||||
pub fn (mut f OpenAIAlias) create_tranlation(args AudioArgs) !AudioResponse {
|
||||
return f.create_audio_request(args, 'audio/translations')
|
||||
}
|
||||
|
||||
fn (mut f OpenAI) create_audio_request(args AudioArgs, endpoint string) !AudioResponse {
|
||||
fn (mut f OpenAIAlias) create_audio_request(args AudioArgs, endpoint string) !AudioResponse {
|
||||
file_content := os.read_file(args.filepath)!
|
||||
ext := os.file_ext(args.filepath)
|
||||
mut file_mime_type := ''
|
||||
@@ -131,7 +211,7 @@ pub:
|
||||
speed f32
|
||||
}
|
||||
|
||||
pub fn (mut f OpenAI) create_speech(args CreateSpeechArgs) ! {
|
||||
pub fn (mut f OpenAIAlias) create_speech(args CreateSpeechArgs) ! {
|
||||
mut output_file := os.open_file(args.output_path, 'w+')!
|
||||
|
||||
req := CreateSpeechRequest{
|
||||
26
lib/clients/openai/audio/audio_test.v
Normal file
26
lib/clients/openai/audio/audio_test.v
Normal file
@@ -0,0 +1,26 @@
|
||||
module audio_test
|
||||
|
||||
import os
|
||||
import clients.openai
|
||||
import clients.openai.audio
|
||||
import clients.openai.openai_factory_ { get }
|
||||
import freeflowuniverse.crystallib.osal { play }
|
||||
|
||||
fn test_audio() {
|
||||
key := os.getenv('OPENAI_API_KEY')
|
||||
heroscript := '!!openai.configure api_key: "${key}"'
|
||||
|
||||
play(heroscript: heroscript)!
|
||||
|
||||
mut client := get()!
|
||||
|
||||
// create speech
|
||||
client.create_speech(
|
||||
input: 'the quick brown fox jumps over the lazy dog'
|
||||
output_path: '/tmp/output.mp3'
|
||||
voice: audio.Voice.alloy
|
||||
response_format: audio.AudioFormat.mp3
|
||||
)!
|
||||
|
||||
assert os.exists('/tmp/output.mp3')
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
module openai
|
||||
|
||||
import os
|
||||
import openai.audio
|
||||
import openai.files
|
||||
import openai.finetune
|
||||
import openai.images
|
||||
|
||||
fn test_chat_completion() {
|
||||
mut client := get()!
|
||||
@@ -24,83 +28,3 @@ fn test_chat_completion() {
|
||||
|
||||
assert res.choices[0].message.content == 'AI is getting out of hand'
|
||||
}
|
||||
|
||||
// fn test_embeddings() {
|
||||
// key := os.getenv('OPENAI_API_KEY')
|
||||
// heroscript := '!!openai.configure api_key: "${key}"'
|
||||
|
||||
// play(heroscript: heroscript)!
|
||||
|
||||
// mut client := get()!
|
||||
|
||||
// res := client.create_embeddings(
|
||||
// input: ['The food was delicious and the waiter..']
|
||||
// model: .text_embedding_ada
|
||||
// )!
|
||||
|
||||
// assert res.data.len == 1
|
||||
// assert res.data[0].embedding.len == 1536
|
||||
// }
|
||||
|
||||
// fn test_files() {
|
||||
// key := os.getenv('OPENAI_API_KEY')
|
||||
// heroscript := '!!openai.configure api_key: "${key}"'
|
||||
|
||||
// play(heroscript: heroscript)!
|
||||
|
||||
// mut client := get()!
|
||||
// uploaded_file := client.upload_file(
|
||||
// filepath: '${os.dir(@FILE) + '/testdata/testfile.txt'}'
|
||||
// purpose: .assistants
|
||||
// )!
|
||||
|
||||
// assert uploaded_file.filename == 'testfile.txt'
|
||||
// assert uploaded_file.purpose == 'assistants'
|
||||
|
||||
// got_file := client.get_file(uploaded_file.id)!
|
||||
// assert got_file == uploaded_file
|
||||
|
||||
// uploaded_file2 := client.upload_file(
|
||||
// filepath: '${os.dir(@FILE) + '/testdata/testfile2.txt'}'
|
||||
// purpose: .assistants
|
||||
// )!
|
||||
|
||||
// assert uploaded_file2.filename == 'testfile2.txt'
|
||||
// assert uploaded_file2.purpose == 'assistants'
|
||||
|
||||
// mut got_list := client.list_files()!
|
||||
|
||||
// assert got_list.data.len >= 2 // there could be other older files
|
||||
|
||||
// mut ids := []string{}
|
||||
// for file in got_list.data {
|
||||
// ids << file.id
|
||||
// }
|
||||
|
||||
// assert uploaded_file.id in ids
|
||||
// assert uploaded_file2.id in ids
|
||||
|
||||
// for file in got_list.data {
|
||||
// client.delete_file(file.id)!
|
||||
// }
|
||||
|
||||
// got_list = client.list_files()!
|
||||
// assert got_list.data.len == 0
|
||||
// }
|
||||
|
||||
// fn test_audio() {
|
||||
// key := os.getenv('OPENAI_API_KEY')
|
||||
// heroscript := '!!openai.configure api_key: "${key}"'
|
||||
|
||||
// play(heroscript: heroscript)!
|
||||
|
||||
// mut client := get()!
|
||||
|
||||
// // create speech
|
||||
// client.create_speech(
|
||||
// input: 'the quick brown fox jumps over the lazy dog'
|
||||
// output_path: '/tmp/output.mp3'
|
||||
// )!
|
||||
|
||||
// assert os.exists('/tmp/output.mp3')
|
||||
// }
|
||||
|
||||
@@ -2,63 +2,61 @@ module openai
|
||||
|
||||
import json
|
||||
|
||||
pub struct ChatCompletion {
|
||||
pub mut:
|
||||
id string
|
||||
object string
|
||||
created u32
|
||||
choices []Choice
|
||||
usage Usage
|
||||
}
|
||||
|
||||
pub struct Choice {
|
||||
pub mut:
|
||||
index int
|
||||
message MessageRaw
|
||||
finish_reason string
|
||||
}
|
||||
|
||||
pub struct Message {
|
||||
pub mut:
|
||||
role RoleType
|
||||
content string
|
||||
}
|
||||
|
||||
pub struct Usage {
|
||||
pub mut:
|
||||
prompt_tokens int
|
||||
completion_tokens int
|
||||
total_tokens int
|
||||
}
|
||||
|
||||
pub struct Messages {
|
||||
pub mut:
|
||||
messages []Message
|
||||
}
|
||||
|
||||
pub struct MessageRaw {
|
||||
pub mut:
|
||||
role string
|
||||
content string
|
||||
}
|
||||
|
||||
struct ChatMessagesRaw {
|
||||
mut:
|
||||
model string
|
||||
messages []MessageRaw
|
||||
temperature f64 = 0.5
|
||||
max_completion_tokens int = 32000
|
||||
}
|
||||
|
||||
@[params]
|
||||
pub struct CompletionArgs {
|
||||
pub mut:
|
||||
model string
|
||||
msgs Messages
|
||||
temperature f64 = 0.5
|
||||
messages []Message // optional because we can use message, which means we just pass a string
|
||||
message string
|
||||
temperature f64 = 0.2
|
||||
max_completion_tokens int = 32000
|
||||
}
|
||||
|
||||
struct Message {
|
||||
mut:
|
||||
role RoleType
|
||||
content string
|
||||
}
|
||||
|
||||
pub enum RoleType {
|
||||
system
|
||||
user
|
||||
assistant
|
||||
function
|
||||
}
|
||||
|
||||
fn roletype_str(x RoleType) string {
|
||||
return match x {
|
||||
.system {
|
||||
'system'
|
||||
}
|
||||
.user {
|
||||
'user'
|
||||
}
|
||||
.assistant {
|
||||
'assistant'
|
||||
}
|
||||
.function {
|
||||
'function'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Usage {
|
||||
mut:
|
||||
prompt_tokens int
|
||||
completion_tokens int
|
||||
total_tokens int
|
||||
}
|
||||
|
||||
struct ChatCompletion {
|
||||
mut:
|
||||
id string
|
||||
created u32
|
||||
result string
|
||||
usage Usage
|
||||
}
|
||||
|
||||
// creates a new chat completion given a list of messages
|
||||
// each message consists of message content and the role of the author
|
||||
pub fn (mut f OpenAI) chat_completion(args_ CompletionArgs) !ChatCompletion {
|
||||
@@ -71,19 +69,38 @@ pub fn (mut f OpenAI) chat_completion(args_ CompletionArgs) !ChatCompletion {
|
||||
temperature: args.temperature
|
||||
max_completion_tokens: args.max_completion_tokens
|
||||
}
|
||||
for msg in args.msgs.messages {
|
||||
for msg in args.messages {
|
||||
mr := MessageRaw{
|
||||
role: roletype_str(msg.role)
|
||||
content: msg.content
|
||||
}
|
||||
m.messages << mr
|
||||
}
|
||||
if args.message != '' {
|
||||
mr := MessageRaw{
|
||||
role: 'user'
|
||||
content: args.message
|
||||
}
|
||||
m.messages << mr
|
||||
}
|
||||
data := json.encode(m)
|
||||
// println('data: ${data}')
|
||||
mut conn := f.connection()!
|
||||
r := conn.post_json_str(prefix: 'chat/completions', data: data)!
|
||||
// println('res: ${r}')
|
||||
|
||||
res := json.decode(ChatCompletion, r)!
|
||||
return res
|
||||
res := json.decode(ChatCompletionRaw, r)!
|
||||
|
||||
mut result := ''
|
||||
for choice in res.choices {
|
||||
result += choice.message.content
|
||||
}
|
||||
|
||||
mut chat_completion_result := ChatCompletion{
|
||||
id: res.id
|
||||
created: res.created
|
||||
result: result
|
||||
usage: res.usage
|
||||
}
|
||||
return chat_completion_result
|
||||
}
|
||||
|
||||
17
lib/clients/openai/embeddings/README.md
Normal file
17
lib/clients/openai/embeddings/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
# Quick Example: Creating Embeddings
|
||||
|
||||
```v
|
||||
|
||||
import freeflowuniverse.herolib.clients.openai
|
||||
|
||||
mut client:= openai.get()! //will be the default client, key is in `AIKEY` on environment variable or `OPENROUTER_API_KEY`
|
||||
|
||||
text_to_embed := 'The quick brown fox jumps over the lazy dog.'
|
||||
|
||||
resp := client.embeddings.create_embedding(
|
||||
input: text_to_embed,
|
||||
model: 'text-embedding-ada-002'
|
||||
)!
|
||||
|
||||
```
|
||||
@@ -1,6 +1,9 @@
|
||||
module openai
|
||||
module embeddings
|
||||
|
||||
import json
|
||||
import freeflowuniverse.herolib.clients.openai { OpenAI, Usage }
|
||||
|
||||
type OpenAIAlias = OpenAI
|
||||
|
||||
pub enum EmbeddingModel {
|
||||
text_embedding_ada
|
||||
@@ -42,7 +45,7 @@ pub mut:
|
||||
usage Usage
|
||||
}
|
||||
|
||||
pub fn (mut f OpenAI) create_embeddings(args EmbeddingCreateArgs) !EmbeddingResponse {
|
||||
pub fn (mut f OpenAIAlias) create_embeddings(args EmbeddingCreateArgs) !EmbeddingResponse {
|
||||
req := EmbeddingCreateRequest{
|
||||
input: args.input
|
||||
model: embedding_model_str(args.model)
|
||||
24
lib/clients/openai/embeddings/embeddings_test.v
Normal file
24
lib/clients/openai/embeddings/embeddings_test.v
Normal file
@@ -0,0 +1,24 @@
|
||||
module embeddings_test
|
||||
|
||||
import os
|
||||
import clients.openai
|
||||
import clients.openai.embeddings
|
||||
import clients.openai.openai_factory_ { get }
|
||||
import freeflowuniverse.crystallib.osal { play }
|
||||
|
||||
fn test_embeddings() {
|
||||
key := os.getenv('OPENAI_API_KEY')
|
||||
heroscript := '!!openai.configure api_key: "${key}"'
|
||||
|
||||
play(heroscript: heroscript)!
|
||||
|
||||
mut client := get()!
|
||||
|
||||
res := client.create_embeddings(
|
||||
input: ['The food was delicious and the waiter..']
|
||||
model: embeddings.EmbeddingModel.text_embedding_ada
|
||||
)!
|
||||
|
||||
assert res.data.len == 1
|
||||
assert res.data[0].embedding.len == 1536
|
||||
}
|
||||
25
lib/clients/openai/files/README.md
Normal file
25
lib/clients/openai/files/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
# Example: Uploading a File
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.clients.openai
|
||||
|
||||
mut client:= openai.get()! //will be the default client, key is in `AIKEY` on environment variable or `OPENROUTER_API_KEY`
|
||||
|
||||
// Assuming you have a file named 'mydata.jsonl' in the same directory
|
||||
// For a real application, handle file paths dynamically
|
||||
file_path := 'mydata.jsonl'
|
||||
|
||||
resp := client.files.upload_file(
|
||||
file: file_path,
|
||||
purpose: 'fine-tune' // or 'assistants', 'batch', 'vision'
|
||||
)
|
||||
|
||||
if resp.id.len > 0 {
|
||||
println('File uploaded successfully with ID: ${resp.id}')
|
||||
} else {
|
||||
eprintln('Failed to upload file.')
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
@@ -1,9 +1,12 @@
|
||||
module openai
|
||||
module files
|
||||
|
||||
import json
|
||||
import freeflowuniverse.herolib.core.httpconnection
|
||||
import os
|
||||
import net.http
|
||||
import freeflowuniverse.herolib.clients.openai { OpenAI }
|
||||
|
||||
type OpenAIAlias = OpenAI
|
||||
|
||||
const jsonl_mime_type = 'text/jsonl'
|
||||
|
||||
@@ -44,7 +47,7 @@ pub mut:
|
||||
}
|
||||
|
||||
// upload file to client org, usually used for fine tuning
|
||||
pub fn (mut f OpenAI) upload_file(args FileUploadArgs) !File {
|
||||
pub fn (mut f OpenAIAlias) upload_file(args FileUploadArgs) !File {
|
||||
file_content := os.read_file(args.filepath)!
|
||||
|
||||
file_data := http.FileData{
|
||||
@@ -74,28 +77,28 @@ pub fn (mut f OpenAI) upload_file(args FileUploadArgs) !File {
|
||||
}
|
||||
|
||||
// list all files in client org
|
||||
pub fn (mut f OpenAI) list_files() !Files {
|
||||
pub fn (mut f OpenAIAlias) list_files() !Files {
|
||||
mut conn := f.connection()!
|
||||
r := conn.get(prefix: 'files')!
|
||||
return json.decode(Files, r)!
|
||||
}
|
||||
|
||||
// deletes a file
|
||||
pub fn (mut f OpenAI) delete_file(file_id string) !DeleteResp {
|
||||
pub fn (mut f OpenAIAlias) delete_file(file_id string) !DeleteResp {
|
||||
mut conn := f.connection()!
|
||||
r := conn.delete(prefix: 'files/' + file_id)!
|
||||
return json.decode(DeleteResp, r)!
|
||||
}
|
||||
|
||||
// returns a single file metadata
|
||||
pub fn (mut f OpenAI) get_file(file_id string) !File {
|
||||
pub fn (mut f OpenAIAlias) get_file(file_id string) !File {
|
||||
mut conn := f.connection()!
|
||||
r := conn.get(prefix: 'files/' + file_id)!
|
||||
return json.decode(File, r)!
|
||||
}
|
||||
|
||||
// returns the content of a specific file
|
||||
pub fn (mut f OpenAI) get_file_content(file_id string) !string {
|
||||
pub fn (mut f OpenAIAlias) get_file_content(file_id string) !string {
|
||||
mut conn := f.connection()!
|
||||
r := conn.get(prefix: 'files/' + file_id + '/content')!
|
||||
return r
|
||||
1
lib/clients/openai/files/files_test.v
Normal file
1
lib/clients/openai/files/files_test.v
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
22
lib/clients/openai/finetune/README.md
Normal file
22
lib/clients/openai/finetune/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# OpenAI Fine-tuning Client
|
||||
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.clients.openai
|
||||
|
||||
mut client:= openai.get()! //will be the default client, key is in `AIKEY` on environment variable or `OPENROUTER_API_KEY`
|
||||
|
||||
// Assuming you have a training file ID from the Files API
|
||||
training_file_id := 'file-xxxxxxxxxxxxxxxxxxxxxxxxx'
|
||||
|
||||
resp := client.finetune.create_fine_tune(
|
||||
training_file: training_file_id,
|
||||
model: 'gpt-3.5-turbo'
|
||||
)
|
||||
|
||||
if resp.id.len > 0 {
|
||||
println('Fine-tuning job created with ID: ${resp.id}')
|
||||
} else {
|
||||
eprintln('Failed to create fine-tuning job.')
|
||||
}
|
||||
```
|
||||
@@ -1,7 +1,11 @@
|
||||
module openai
|
||||
module finetune
|
||||
|
||||
import freeflowuniverse.herolib.clients.openai { OpenAI }
|
||||
import freeflowuniverse.herolib.clients.openai.files { File }
|
||||
import json
|
||||
|
||||
type OpenAIAlias = OpenAI
|
||||
|
||||
pub struct FineTune {
|
||||
pub:
|
||||
id string
|
||||
@@ -61,7 +65,7 @@ pub mut:
|
||||
}
|
||||
|
||||
// creates a new fine-tune based on an already uploaded file
|
||||
pub fn (mut f OpenAI) create_fine_tune(args FineTuneCreateArgs) !FineTune {
|
||||
pub fn (mut f OpenAIAlias) create_fine_tune(args FineTuneCreateArgs) !FineTune {
|
||||
data := json.encode(args)
|
||||
mut conn := f.connection()!
|
||||
r := conn.post_json_str(prefix: 'fine-tunes', data: data)!
|
||||
@@ -70,28 +74,28 @@ pub fn (mut f OpenAI) create_fine_tune(args FineTuneCreateArgs) !FineTune {
|
||||
}
|
||||
|
||||
// returns all fine-tunes in this account
|
||||
pub fn (mut f OpenAI) list_fine_tunes() !FineTuneList {
|
||||
pub fn (mut f OpenAIAlias) list_fine_tunes() !FineTuneList {
|
||||
mut conn := f.connection()!
|
||||
r := conn.get(prefix: 'fine-tunes')!
|
||||
return json.decode(FineTuneList, r)!
|
||||
}
|
||||
|
||||
// get a single fine-tune information
|
||||
pub fn (mut f OpenAI) get_fine_tune(fine_tune string) !FineTune {
|
||||
pub fn (mut f OpenAIAlias) get_fine_tune(fine_tune string) !FineTune {
|
||||
mut conn := f.connection()!
|
||||
r := conn.get(prefix: 'fine-tunes/' + fine_tune)!
|
||||
return json.decode(FineTune, r)!
|
||||
}
|
||||
|
||||
// cancel a fine-tune that didn't finish yet
|
||||
pub fn (mut f OpenAI) cancel_fine_tune(fine_tune string) !FineTune {
|
||||
pub fn (mut f OpenAIAlias) cancel_fine_tune(fine_tune string) !FineTune {
|
||||
mut conn := f.connection()!
|
||||
r := conn.post_json_str(prefix: 'fine-tunes/' + fine_tune + '/cancel')!
|
||||
return json.decode(FineTune, r)!
|
||||
}
|
||||
|
||||
// returns all events for a fine tune in this account
|
||||
pub fn (mut f OpenAI) list_fine_tune_events(fine_tune string) !FineTuneEventList {
|
||||
pub fn (mut f OpenAIAlias) list_fine_tune_events(fine_tune string) !FineTuneEventList {
|
||||
mut conn := f.connection()!
|
||||
r := conn.get(prefix: 'fine-tunes/' + fine_tune + '/events')!
|
||||
return json.decode(FineTuneEventList, r)!
|
||||
21
lib/clients/openai/images/README.md
Normal file
21
lib/clients/openai/images/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
# Example: Creating an Image
|
||||
|
||||
```v
|
||||
|
||||
import freeflowuniverse.herolib.clients.openai
|
||||
|
||||
mut client:= openai.get()! //will be the default client, key is in `AIKEY` on environment variable or `OPENROUTER_API_KEY`
|
||||
|
||||
resp := client.images.create_image(
|
||||
prompt: 'A futuristic city at sunset',
|
||||
n: 1,
|
||||
size: '1024x1024'
|
||||
)
|
||||
|
||||
if resp.data.len > 0 {
|
||||
println('Image created. URL: ${resp.data[0].url}')
|
||||
} else {
|
||||
eprintln('Failed to create image.')
|
||||
}
|
||||
```
|
||||
@@ -4,6 +4,9 @@ import json
|
||||
import net.http
|
||||
import os
|
||||
import freeflowuniverse.herolib.core.httpconnection
|
||||
import freeflowuniverse.herolib.clients.openai { OpenAI }
|
||||
|
||||
type OpenAIAlias = OpenAI
|
||||
|
||||
const image_mine_type = 'image/png'
|
||||
|
||||
@@ -43,6 +46,7 @@ fn image_resp_type_str(i ImageRespType) string {
|
||||
}
|
||||
}
|
||||
|
||||
@[params]
|
||||
pub struct ImageCreateArgs {
|
||||
pub mut:
|
||||
prompt string
|
||||
@@ -95,7 +99,7 @@ pub mut:
|
||||
|
||||
// Create new images generation given a prompt
|
||||
// the amount of images returned is specified by `num_images`
|
||||
pub fn (mut f OpenAI) create_image(args ImageCreateArgs) !Images {
|
||||
pub fn (mut f OpenAIAlias) create_image(args ImageCreateArgs) !Images {
|
||||
image_size := image_size_str(args.size)
|
||||
response_format := image_resp_type_str(args.format)
|
||||
request := ImageRequest{
|
||||
@@ -115,7 +119,7 @@ pub fn (mut f OpenAI) create_image(args ImageCreateArgs) !Images {
|
||||
// image needs to be in PNG format and transparent or else a mask of the same size needs
|
||||
// to be specified to indicate where the image should be in the generated image
|
||||
// the amount of images returned is specified by `num_images`
|
||||
pub fn (mut f OpenAI) create_edit_image(args ImageEditArgs) !Images {
|
||||
pub fn (mut f OpenAIAlias) create_edit_image(args ImageEditArgs) !Images {
|
||||
image_content := os.read_file(args.image_path)!
|
||||
image_file := http.FileData{
|
||||
filename: os.base(args.image_path)
|
||||
@@ -160,7 +164,7 @@ pub fn (mut f OpenAI) create_edit_image(args ImageEditArgs) !Images {
|
||||
// create variations of the given image
|
||||
// image needs to be in PNG format
|
||||
// the amount of images returned is specified by `num_images`
|
||||
pub fn (mut f OpenAI) create_variation_image(args ImageVariationArgs) !Images {
|
||||
pub fn (mut f OpenAIAlias) create_variation_image(args ImageVariationArgs) !Images {
|
||||
image_content := os.read_file(args.image_path)!
|
||||
image_file := http.FileData{
|
||||
filename: os.base(args.image_path)
|
||||
@@ -1,101 +0,0 @@
|
||||
module openai
|
||||
|
||||
pub enum RoleType {
|
||||
system
|
||||
user
|
||||
assistant
|
||||
function
|
||||
}
|
||||
|
||||
fn roletype_str(x RoleType) string {
|
||||
return match x {
|
||||
.system {
|
||||
'system'
|
||||
}
|
||||
.user {
|
||||
'user'
|
||||
}
|
||||
.assistant {
|
||||
'assistant'
|
||||
}
|
||||
.function {
|
||||
'function'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Voice {
|
||||
alloy
|
||||
ash
|
||||
coral
|
||||
echo
|
||||
fable
|
||||
onyx
|
||||
nova
|
||||
sage
|
||||
shimmer
|
||||
}
|
||||
|
||||
fn voice_str(x Voice) string {
|
||||
return match x {
|
||||
.alloy {
|
||||
'alloy'
|
||||
}
|
||||
.ash {
|
||||
'ash'
|
||||
}
|
||||
.coral {
|
||||
'coral'
|
||||
}
|
||||
.echo {
|
||||
'echo'
|
||||
}
|
||||
.fable {
|
||||
'fable'
|
||||
}
|
||||
.onyx {
|
||||
'onyx'
|
||||
}
|
||||
.nova {
|
||||
'nova'
|
||||
}
|
||||
.sage {
|
||||
'sage'
|
||||
}
|
||||
.shimmer {
|
||||
'shimmer'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum AudioFormat {
|
||||
mp3
|
||||
opus
|
||||
aac
|
||||
flac
|
||||
wav
|
||||
pcm
|
||||
}
|
||||
|
||||
fn audio_format_str(x AudioFormat) string {
|
||||
return match x {
|
||||
.mp3 {
|
||||
'mp3'
|
||||
}
|
||||
.opus {
|
||||
'opus'
|
||||
}
|
||||
.aac {
|
||||
'aac'
|
||||
}
|
||||
.flac {
|
||||
'flac'
|
||||
}
|
||||
.wav {
|
||||
'wav'
|
||||
}
|
||||
.pcm {
|
||||
'pcm'
|
||||
}
|
||||
}
|
||||
}
|
||||
31
lib/clients/openai/model_models_completion.v
Normal file
31
lib/clients/openai/model_models_completion.v
Normal file
@@ -0,0 +1,31 @@
|
||||
module openai
|
||||
|
||||
struct ChatCompletionRaw {
|
||||
mut:
|
||||
id string
|
||||
object string
|
||||
created u32
|
||||
choices []ChoiceRaw
|
||||
usage Usage
|
||||
}
|
||||
|
||||
struct ChoiceRaw {
|
||||
mut:
|
||||
index int
|
||||
message MessageRaw
|
||||
finish_reason string
|
||||
}
|
||||
|
||||
struct MessageRaw {
|
||||
mut:
|
||||
role string
|
||||
content string
|
||||
}
|
||||
|
||||
struct ChatMessagesRaw {
|
||||
mut:
|
||||
model string
|
||||
messages []MessageRaw
|
||||
temperature f64 = 0.5
|
||||
max_completion_tokens int = 32000
|
||||
}
|
||||
30
lib/clients/openai/moderation/README.md
Normal file
30
lib/clients/openai/moderation/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# OpenAI Moderation Client
|
||||
|
||||
This directory contains the V client for OpenAI's Moderation API.
|
||||
|
||||
|
||||
```v
|
||||
|
||||
import freeflowuniverse.herolib.clients.openai
|
||||
|
||||
mut client:= openai.get()! //will be the default client, key is in `AIKEY` on environment variable or `OPENROUTER_API_KEY`
|
||||
|
||||
text_to_moderate := 'I want to kill them all.'
|
||||
|
||||
resp := client.moderation.create_moderation(
|
||||
input: text_to_moderate
|
||||
)
|
||||
|
||||
if resp.results.len > 0 {
|
||||
if resp.results[0].flagged {
|
||||
println('Text was flagged for moderation.')
|
||||
println('Categories: ${resp.results[0].categories}')
|
||||
} else {
|
||||
println('Text passed moderation.')
|
||||
}
|
||||
} else {
|
||||
eprintln('Failed to get moderation result.')
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
module openai
|
||||
module moderation
|
||||
|
||||
import json
|
||||
import freeflowuniverse.herolib.clients.openai { OpenAI }
|
||||
|
||||
type OpenAIAlias = OpenAI
|
||||
|
||||
pub enum ModerationModel {
|
||||
text_moderation_latest
|
||||
@@ -69,7 +72,7 @@ pub mut:
|
||||
results []ModerationResult
|
||||
}
|
||||
|
||||
pub fn (mut f OpenAI) create_moderation(input string, model ModerationModel) !ModerationResponse {
|
||||
pub fn (mut f OpenAIAlias) create_moderation(input string, model ModerationModel) !ModerationResponse {
|
||||
req := ModerationRequest{
|
||||
input: input
|
||||
model: moderation_model_str(model)
|
||||
@@ -8,57 +8,42 @@ pub const version = '0.0.0'
|
||||
const singleton = false
|
||||
const default = true
|
||||
|
||||
// THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED
|
||||
|
||||
// @[heap]
|
||||
// pub struct OpenAIBase {
|
||||
// pub mut:
|
||||
// name string = 'default'
|
||||
// api_key string
|
||||
// url string
|
||||
// model_default string
|
||||
// }
|
||||
|
||||
@[heap]
|
||||
pub struct OpenAI {
|
||||
pub mut:
|
||||
name string = 'default'
|
||||
api_key string
|
||||
url string
|
||||
model_default string
|
||||
url string = 'https://openrouter.ai/api/v1'
|
||||
model_default string = 'gpt-oss-120b'
|
||||
conn ?&httpconnection.HTTPConnection @[skip; str: skip]
|
||||
}
|
||||
|
||||
// your checking & initialization code if needed
|
||||
fn obj_init(mycfg_ OpenAI) !OpenAI {
|
||||
mut mycfg := mycfg_
|
||||
if mycfg.model_default == '' {
|
||||
k := os.getenv('AIMODEL')
|
||||
if k != '' {
|
||||
mycfg.model_default = k
|
||||
}
|
||||
}
|
||||
|
||||
if mycfg.url == '' {
|
||||
k := os.getenv('AIURL')
|
||||
if k != '' {
|
||||
mycfg.url = k
|
||||
}
|
||||
}
|
||||
if mycfg.api_key == '' {
|
||||
mut k := os.getenv('AIKEY')
|
||||
k := os.getenv('AIKEY')
|
||||
if k != '' {
|
||||
mycfg.api_key = k
|
||||
k = os.getenv('AIURL')
|
||||
if k != '' {
|
||||
mycfg.url = k
|
||||
} else {
|
||||
return error('found AIKEY in env, but not AIURL')
|
||||
}
|
||||
k = os.getenv('AIMODEL')
|
||||
if k != '' {
|
||||
mycfg.model_default = k
|
||||
}
|
||||
return mycfg
|
||||
}
|
||||
mycfg.url = 'https://api.openai.com/v1/models'
|
||||
k = os.getenv('OPENAI_API_KEY')
|
||||
if k != '' {
|
||||
mycfg.api_key = k
|
||||
return mycfg
|
||||
}
|
||||
k = os.getenv('OPENROUTER_API_KEY')
|
||||
if k != '' {
|
||||
mycfg.api_key = k
|
||||
mycfg.url = 'https://openrouter.ai/api/v1'
|
||||
return mycfg
|
||||
if k == '' {
|
||||
k2 := os.getenv('OPENROUTER_API_KEY')
|
||||
if k2 != '' {
|
||||
mycfg.api_key = k2
|
||||
}
|
||||
}
|
||||
}
|
||||
return mycfg
|
||||
|
||||
@@ -4,21 +4,27 @@ To get started
|
||||
|
||||
```vlang
|
||||
|
||||
|
||||
|
||||
import freeflowuniverse.herolib.clients.openai
|
||||
import freeflowuniverse.herolib.core.playcmds
|
||||
|
||||
playcmds.run(
|
||||
heroscript:'
|
||||
!!openai.configure name: "default" key: "" url: "https://openrouter.ai/api/v1" model_default: "gpt-oss-120b"
|
||||
'
|
||||
heroscript_path:''
|
||||
reset: false
|
||||
)!
|
||||
|
||||
//name:'default' is the default, you can change it to whatever you want
|
||||
mut client:= openai.get()!
|
||||
|
||||
client...
|
||||
|
||||
|
||||
|
||||
mut r:=client.chat_completion(
|
||||
model: "gpt-3.5-turbo",
|
||||
message: 'Hello, world!'
|
||||
temperature: 0.5
|
||||
max_completion_tokens: 1024
|
||||
)!
|
||||
|
||||
```
|
||||
|
||||
## example heroscript
|
||||
|
||||
```hero
|
||||
!!openai.configure key
|
||||
```
|
||||
if key empty then will try to get it from environment variable `AIKEY` or `OPENROUTER_API_KEY`
|
||||
|
||||
1
lib/clients/openai/testdata/testfile.txt
vendored
1
lib/clients/openai/testdata/testfile.txt
vendored
@@ -1 +0,0 @@
|
||||
hello world
|
||||
1
lib/clients/openai/testdata/testfile2.txt
vendored
1
lib/clients/openai/testdata/testfile2.txt
vendored
@@ -1 +0,0 @@
|
||||
testfile2 content
|
||||
@@ -163,68 +163,47 @@ fn cmd_docusaurus_execute(cmd Command) ! {
|
||||
mut builddevpublish := cmd.flags.get_bool('builddevpublish') or { false }
|
||||
mut dev := cmd.flags.get_bool('dev') or { false }
|
||||
|
||||
// Process heroscript files from the ebook directory to get proper site configuration
|
||||
mut plbook := playbook.new(path: heroscript_config_dir)!
|
||||
|
||||
// Dynamically add ebook configuration files
|
||||
config_file := '${heroscript_config_dir}/config.heroscript'
|
||||
if os.exists(config_file) {
|
||||
plbook.add(path: config_file)!
|
||||
}
|
||||
// // Get the site configuration that was processed from the heroscript files
|
||||
// // The site.play() function processes the heroscript and creates sites in the global websites map
|
||||
// // We need to get the site by name from the processed configuration
|
||||
// config_actions := plbook.find(filter: 'site.config')!
|
||||
// if config_actions.len == 0 {
|
||||
// return error('No site.config found in heroscript files. Make sure config.heroscript contains !!site.config.')
|
||||
// }
|
||||
|
||||
menus_file := '${heroscript_config_dir}/menus.heroscript'
|
||||
if os.exists(menus_file) {
|
||||
plbook.add(path: menus_file)!
|
||||
}
|
||||
// // Get the site name from the first site.config action
|
||||
// site_name := config_actions[0].params.get('name') or {
|
||||
// return error('site.config must specify a name parameter')
|
||||
// }
|
||||
|
||||
pages_dir := '${heroscript_config_dir}/pages'
|
||||
if os.exists(pages_dir) && os.is_dir(pages_dir) {
|
||||
plbook.add(path: pages_dir)!
|
||||
}
|
||||
// // Get the processed site configuration
|
||||
// mut generic_site := site.get(name: site_name)!
|
||||
|
||||
playcmds.run(plbook: plbook)!
|
||||
// // Add docusaurus site
|
||||
// mut dsite := docusaurus.dsite_add(
|
||||
// site: generic_site
|
||||
// path_src: url // Use URL as source path for now
|
||||
// path_build: build_path
|
||||
// path_publish: publish_path
|
||||
// reset: false
|
||||
// template_update: update
|
||||
// install: init
|
||||
// )!
|
||||
|
||||
// Process site pages to generate the actual documentation files
|
||||
site.play(mut plbook)!
|
||||
// // Conditional site actions based on flags
|
||||
// if buildpublish {
|
||||
// dsite.build_publish()!
|
||||
// } else if builddevpublish {
|
||||
// dsite.build_dev_publish()!
|
||||
// } else if dev {
|
||||
// dsite.dev(host: 'localhost', port: 3000, open: open)!
|
||||
// } else if open {
|
||||
// dsite.open('localhost', 3000)!
|
||||
// } else {
|
||||
// // If no specific action (build/dev/open) is requested, just generate the site
|
||||
// dsite.generate()!
|
||||
// }
|
||||
|
||||
// Get the site configuration that was processed from the heroscript files
|
||||
// The site.play() function processes the heroscript and creates sites in the global websites map
|
||||
// We need to get the site by name from the processed configuration
|
||||
config_actions := plbook.find(filter: 'site.config')!
|
||||
if config_actions.len == 0 {
|
||||
return error('No site.config found in heroscript files. Make sure config.heroscript contains !!site.config.')
|
||||
}
|
||||
|
||||
// Get the site name from the first site.config action
|
||||
site_name := config_actions[0].params.get('name') or {
|
||||
return error('site.config must specify a name parameter')
|
||||
}
|
||||
|
||||
// Get the processed site configuration
|
||||
mut generic_site := site.get(name: site_name)!
|
||||
|
||||
// Add docusaurus site
|
||||
mut dsite := docusaurus.add(
|
||||
site: generic_site
|
||||
path_src: url // Use URL as source path for now
|
||||
path_build: build_path
|
||||
path_publish: publish_path
|
||||
reset: false
|
||||
template_update: update
|
||||
install: init
|
||||
)!
|
||||
|
||||
// Conditional site actions based on flags
|
||||
if buildpublish {
|
||||
dsite.build_publish()!
|
||||
} else if builddevpublish {
|
||||
dsite.build_dev_publish()!
|
||||
} else if dev {
|
||||
dsite.dev(host: 'localhost', port: 3000, open: open)!
|
||||
} else if open {
|
||||
dsite.open('localhost', 3000)!
|
||||
} else {
|
||||
// If no specific action (build/dev/open) is requested, just generate the site
|
||||
dsite.generate()!
|
||||
}
|
||||
panic("implement")
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ module herocmds
|
||||
|
||||
// import freeflowuniverse.herolib.web.starlight
|
||||
import os
|
||||
import cli { Command, Flag }
|
||||
import cli
|
||||
|
||||
// pub fn cmd_starlight(mut cmdroot Command) {
|
||||
// mut cmd_run := Command{
|
||||
|
||||
@@ -92,7 +92,6 @@ pub fn (mut plbook PlayBook) find(args FindArgs) ![]&Action {
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
pub fn (mut plbook PlayBook) exists_once(args FindArgs) bool {
|
||||
mut res := plbook.find(args) or { [] }
|
||||
return res.len == 1
|
||||
|
||||
@@ -73,7 +73,7 @@ pub fn (mut plbook PlayBook) actions_sorted(args SortArgs) ![]&Action {
|
||||
}
|
||||
action_ids := plbook.priorities[nr] or { panic('bug') }
|
||||
for id in action_ids {
|
||||
mut a := plbook.actions[id-1] or { panic("bug in actions sorted") }
|
||||
mut a := plbook.actions[id - 1] or { panic('bug in actions sorted') }
|
||||
res << a
|
||||
}
|
||||
}
|
||||
@@ -99,7 +99,7 @@ pub fn (mut plbook PlayBook) heroscript(args HeroScriptArgs) !string {
|
||||
// out += '${plbook.othertext}'
|
||||
// }
|
||||
out = texttools.remove_empty_js_blocks(out)
|
||||
out +="\n\n"
|
||||
out += '\n\n'
|
||||
return out
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ pub fn (mut plbook PlayBook) add(args_ PlayBookNewArgs) ! {
|
||||
|
||||
if args.git_url.len > 0 {
|
||||
mut git_path_args := gittools.GitPathGetArgs{
|
||||
git_url: args.git_url
|
||||
git_pull: args.git_pull
|
||||
git_url: args.git_url
|
||||
git_pull: args.git_pull
|
||||
git_reset: args.git_reset
|
||||
}
|
||||
args.path = gittools.path(git_path_args)!.path
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# heroscript
|
||||
|
||||
is our small language which allows us to run parser
|
||||
|
||||
Our heroscript is a simple way to execute commands in a playbook. It allows you to define a series of actions that can be executed in sequence, making it easy to automate tasks and workflows.
|
||||
|
||||
## execute a playbook
|
||||
|
||||
@@ -25,7 +24,6 @@ playcmds.run(mut plbook)!
|
||||
|
||||
|
||||
```
|
||||
|
||||
## execute a heroscript and make executable
|
||||
|
||||
```bash
|
||||
@@ -39,54 +37,8 @@ playcmds.run(mut plbook)!
|
||||
you can now just execute this script and hero will interprete the content
|
||||
|
||||
|
||||
## parser
|
||||
|
||||
are text based representatsions of parser which need to be executed
|
||||
|
||||
example
|
||||
|
||||
```js
|
||||
!!tflibrary.circlesmanager.circle_add
|
||||
gitsource:'books'
|
||||
path:'technology/src'
|
||||
name:technology
|
||||
```
|
||||
|
||||
the first one is the action, the rest are the params
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.core.playbook
|
||||
|
||||
mut plbook := playbook.new(text: "....")!
|
||||
|
||||
```
|
||||
## way how to use for a module
|
||||
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.core.playbook
|
||||
|
||||
// !!hr.employee_define
|
||||
// descr:'Junior Engineer'
|
||||
// growth:'1:5,60:30' cost:'4000USD' indexation:'5%'
|
||||
// department:'engineering'
|
||||
|
||||
|
||||
// populate the params for hr
|
||||
fn (mut m BizModel) hr_actions(actions playbook.PlayBook) ! {
|
||||
mut actions2 := actions.find('hr.*,vm.start')!
|
||||
for action in actions2 {
|
||||
if action.name == 'employee_define' {
|
||||
mut name := action.params.get_default('name', '')!
|
||||
mut descr := action.params.get_default('descr', '')!
|
||||
//...
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## we can also use the filtersort
|
||||
## filtersort
|
||||
|
||||
```v
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@ import freeflowuniverse.herolib.core.playbook { PlayBook }
|
||||
import freeflowuniverse.herolib.data.doctree
|
||||
import freeflowuniverse.herolib.biz.bizmodel
|
||||
import freeflowuniverse.herolib.web.docusaurus
|
||||
import freeflowuniverse.herolib.clients.openai
|
||||
|
||||
|
||||
// import freeflowuniverse.herolib.hero.publishing
|
||||
// import freeflowuniverse.herolib.threefold.grid4.gridsimulator
|
||||
// import freeflowuniverse.herolib.installers.sysadmintools.daguserver
|
||||
@@ -48,6 +51,7 @@ pub fn run(args_ PlayArgs) ! {
|
||||
bizmodel.play(mut plbook)!
|
||||
doctree.play(mut plbook)!
|
||||
docusaurus.play(mut plbook)!
|
||||
openai.play(mut plbook)!
|
||||
|
||||
// slides.play(mut plbook)!
|
||||
// base_install(play(mut plbook)!
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
module playcmds
|
||||
|
||||
import freeflowuniverse.herolib.develop.gittools
|
||||
import freeflowuniverse.herolib.core.playbook {PlayBook}
|
||||
import freeflowuniverse.herolib.core.playbook { PlayBook }
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
|
||||
fn play_git(mut plbook PlayBook) ! {
|
||||
|
||||
// Handle !!git.define action first to configure GitStructure
|
||||
define_actions := plbook.find(filter: 'git.define')!
|
||||
mut gs := if define_actions.len > 0 {
|
||||
@@ -150,6 +149,4 @@ fn play_git(mut plbook PlayBook) ! {
|
||||
gs = gittools.new(coderoot: coderoot)!
|
||||
gs.load(true)! // Force reload
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
module playcmds
|
||||
|
||||
import freeflowuniverse.herolib.develop.luadns
|
||||
import freeflowuniverse.herolib.core.playbook {PlayBook}
|
||||
import freeflowuniverse.herolib.core.playbook { PlayBook }
|
||||
// import os
|
||||
|
||||
fn play_luadns(mut plbook PlayBook) ! {
|
||||
|
||||
// Variables below are not used, commenting them out
|
||||
// mut buildroot := '${os.home_dir()}/hero/var/mdbuild'
|
||||
// mut publishroot := '${os.home_dir()}/hero/www/info'
|
||||
@@ -34,6 +33,4 @@ fn play_luadns(mut plbook PlayBook) ! {
|
||||
dns.set_domain(domain, ip)!
|
||||
action.done = true
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
module playcmds
|
||||
|
||||
import freeflowuniverse.herolib.osal.sshagent
|
||||
import freeflowuniverse.herolib.core.playbook {PlayBook}
|
||||
import freeflowuniverse.herolib.core.playbook { PlayBook }
|
||||
|
||||
fn play_ssh(mut plbook PlayBook) ! {
|
||||
|
||||
mut agent := sshagent.new()!
|
||||
for mut action in plbook.find(filter: 'sshagent.*')! {
|
||||
mut p := action.params
|
||||
@@ -20,5 +19,4 @@ fn play_ssh(mut plbook PlayBook) ! {
|
||||
}
|
||||
action.done = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,49 +1,13 @@
|
||||
# how to use the playcmds
|
||||
|
||||
```v
|
||||
import freeflowuniverse.herolib.core.playbook
|
||||
import freeflowuniverse.herolib.core.base
|
||||
import freeflowuniverse.herolib.core.playcmds
|
||||
|
||||
mut s:=base.session_new(
|
||||
coderoot:'/tmp/code'
|
||||
interactive:true
|
||||
playcmds.run(
|
||||
heroscript:''
|
||||
heroscript_path:''
|
||||
reset: false
|
||||
//plbook ?PlayBook
|
||||
)!
|
||||
|
||||
|
||||
// Path to the code execution directory
|
||||
path string
|
||||
|
||||
// Command text to execute (e.g., "ls -la")
|
||||
text string
|
||||
|
||||
// Git repository URL for version control
|
||||
git_url string
|
||||
|
||||
// Pull latest changes from git
|
||||
git_pull bool
|
||||
|
||||
// Git branch to use
|
||||
git_branch string
|
||||
|
||||
// Reset repository before pull
|
||||
git_reset bool
|
||||
|
||||
// Execute command after setup
|
||||
execute bool = true
|
||||
|
||||
// Optional session object for state management
|
||||
session ?&base.Session
|
||||
|
||||
mut plbook := playbook.new(text: "....",session:s) or { panic(err) }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
## some core play commands
|
||||
|
||||
```heroscript
|
||||
|
||||
```
|
||||
@@ -1,7 +1,7 @@
|
||||
module playmacros
|
||||
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
import freeflowuniverse.herolib.core.playbook {PlayBook, Action}
|
||||
import freeflowuniverse.herolib.core.playbook { Action, PlayBook }
|
||||
import freeflowuniverse.herolib.threefold.grid4.gridsimulator
|
||||
import freeflowuniverse.herolib.threefold.grid4.farmingsimulator
|
||||
import freeflowuniverse.herolib.biz.bizmodel
|
||||
|
||||
@@ -19,7 +19,7 @@ fn decode_struct[T](_ T, data string) !T {
|
||||
mut typ := T{}
|
||||
// println(data)
|
||||
$if T is $struct {
|
||||
obj_name := texttools.snake_case(T.name.all_after_last('.'))
|
||||
obj_name := T.name.all_after_last('.').to_lower()
|
||||
mut action_name := '${obj_name}.define'
|
||||
if !data.contains(action_name) {
|
||||
action_name = '${obj_name}.configure'
|
||||
|
||||
@@ -118,7 +118,7 @@ pub fn (mut e Encoder) encode_struct[T](t T) ! {
|
||||
mut mytype := reflection.type_of[T](t)
|
||||
struct_attrs := attrs_get_reflection(mytype)
|
||||
|
||||
mut action_name := texttools.snake_case(T.name.all_after_last('.'))
|
||||
mut action_name := T.name.all_after_last('.').to_lower()
|
||||
// println('action_name: ${action_name} ${T.name}')
|
||||
if 'alias' in struct_attrs {
|
||||
action_name = struct_attrs['alias'].to_lower()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module encoderhero
|
||||
|
||||
|
||||
pub struct PostgresqlClient {
|
||||
pub mut:
|
||||
name string = 'default'
|
||||
@@ -11,14 +10,13 @@ pub mut:
|
||||
dbname string = 'postgres'
|
||||
}
|
||||
|
||||
|
||||
const postgres_client_blank = '!!postgresql_client.configure'
|
||||
const postgres_client_full = '!!postgresql_client.configure name:production user:app_user port:5433 host:db.example.com password:secret123 dbname:myapp'
|
||||
const postgres_client_partial = '!!postgresql_client.configure name:dev host:localhost password:devpass'
|
||||
|
||||
const postgres_client_complex = "
|
||||
const postgres_client_complex = '
|
||||
!!postgresql_client.configure name:staging user:stage_user port:5434 host:staging.db.com password:stagepass dbname:stagingdb
|
||||
"
|
||||
'
|
||||
|
||||
fn test_postgres_client_decode_blank() ! {
|
||||
mut client := decode[PostgresqlClient](postgres_client_blank)!
|
||||
@@ -63,14 +61,14 @@ fn test_postgres_client_decode_complex() ! {
|
||||
fn test_postgres_client_encode_decode_roundtrip() ! {
|
||||
// Test encoding and decoding roundtrip
|
||||
original := PostgresqlClient{
|
||||
name: 'testdb'
|
||||
user: 'testuser'
|
||||
port: 5435
|
||||
host: 'test.host.com'
|
||||
name: 'testdb'
|
||||
user: 'testuser'
|
||||
port: 5435
|
||||
host: 'test.host.com'
|
||||
password: 'testpass123'
|
||||
dbname: 'testdb'
|
||||
dbname: 'testdb'
|
||||
}
|
||||
|
||||
|
||||
// Encode to heroscript
|
||||
encoded := encode[PostgresqlClient](original)!
|
||||
|
||||
@@ -78,10 +76,10 @@ fn test_postgres_client_encode_decode_roundtrip() ! {
|
||||
// if true {
|
||||
// panic("sss")
|
||||
// }
|
||||
|
||||
|
||||
// Decode back from heroscript
|
||||
decoded := decode[PostgresqlClient](encoded)!
|
||||
|
||||
|
||||
// Verify roundtrip
|
||||
assert decoded.name == original.name
|
||||
assert decoded.user == original.user
|
||||
@@ -95,35 +93,35 @@ fn test_postgres_client_encode() ! {
|
||||
// Test encoding with different configurations
|
||||
test_cases := [
|
||||
PostgresqlClient{
|
||||
name: 'minimal'
|
||||
user: 'root'
|
||||
port: 5432
|
||||
host: 'localhost'
|
||||
name: 'minimal'
|
||||
user: 'root'
|
||||
port: 5432
|
||||
host: 'localhost'
|
||||
password: ''
|
||||
dbname: 'postgres'
|
||||
dbname: 'postgres'
|
||||
},
|
||||
PostgresqlClient{
|
||||
name: 'full_config'
|
||||
user: 'admin'
|
||||
port: 5433
|
||||
host: 'remote.server.com'
|
||||
name: 'full_config'
|
||||
user: 'admin'
|
||||
port: 5433
|
||||
host: 'remote.server.com'
|
||||
password: 'securepass'
|
||||
dbname: 'production'
|
||||
dbname: 'production'
|
||||
},
|
||||
PostgresqlClient{
|
||||
name: 'localhost_dev'
|
||||
user: 'dev'
|
||||
port: 5432
|
||||
host: '127.0.0.1'
|
||||
name: 'localhost_dev'
|
||||
user: 'dev'
|
||||
port: 5432
|
||||
host: '127.0.0.1'
|
||||
password: 'devpassword'
|
||||
dbname: 'devdb'
|
||||
}
|
||||
dbname: 'devdb'
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
for client in test_cases {
|
||||
encoded := encode[PostgresqlClient](client)!
|
||||
decoded := decode[PostgresqlClient](encoded)!
|
||||
|
||||
|
||||
assert decoded.name == client.name
|
||||
assert decoded.user == client.user
|
||||
assert decoded.port == client.port
|
||||
@@ -134,7 +132,7 @@ fn test_postgres_client_encode() ! {
|
||||
}
|
||||
|
||||
// Play script for interactive testing
|
||||
const play_script = "
|
||||
const play_script = '
|
||||
# PostgresqlClient Encode/Decode Play Script
|
||||
# This script demonstrates encoding and decoding PostgresqlClient configurations
|
||||
|
||||
@@ -149,35 +147,35 @@ const play_script = "
|
||||
|
||||
# Default configuration (all defaults)
|
||||
!!postgresql_client.configure
|
||||
"
|
||||
'
|
||||
|
||||
fn test_play_script() ! {
|
||||
// Test the play script with multiple configurations
|
||||
lines := play_script.split_into_lines().filter(fn (line string) bool {
|
||||
return line.trim(' ') != '' && !line.starts_with('#')
|
||||
})
|
||||
|
||||
|
||||
mut clients := []PostgresqlClient{}
|
||||
|
||||
|
||||
for line in lines {
|
||||
if line.starts_with('!!postgresql_client.configure') {
|
||||
client := decode[PostgresqlClient](line)!
|
||||
clients << client
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
assert clients.len == 3
|
||||
|
||||
|
||||
// First client: full configuration
|
||||
assert clients[0].name == 'playground'
|
||||
assert clients[0].user == 'play_user'
|
||||
assert clients[0].port == 5432
|
||||
|
||||
|
||||
// Second client: partial configuration
|
||||
assert clients[1].name == 'quick_test'
|
||||
assert clients[1].host == '127.0.0.1'
|
||||
assert clients[1].user == 'root' // default
|
||||
|
||||
|
||||
// Third client: defaults only
|
||||
assert clients[2].name == 'default'
|
||||
assert clients[2].host == 'localhost'
|
||||
@@ -188,48 +186,48 @@ fn test_play_script() ! {
|
||||
pub fn run_play_script() ! {
|
||||
println('=== PostgresqlClient Encode/Decode Play Script ===')
|
||||
println('Testing encoding and decoding of PostgresqlClient configurations...')
|
||||
|
||||
|
||||
// Test 1: Basic encoding
|
||||
println('\n1. Testing basic encoding...')
|
||||
client := PostgresqlClient{
|
||||
name: 'example'
|
||||
user: 'example_user'
|
||||
port: 5432
|
||||
host: 'example.com'
|
||||
name: 'example'
|
||||
user: 'example_user'
|
||||
port: 5432
|
||||
host: 'example.com'
|
||||
password: 'example_pass'
|
||||
dbname: 'example_db'
|
||||
dbname: 'example_db'
|
||||
}
|
||||
|
||||
|
||||
encoded := encode[PostgresqlClient](client)!
|
||||
println('Encoded: ${encoded}')
|
||||
|
||||
|
||||
decoded := decode[PostgresqlClient](encoded)!
|
||||
println('Decoded name: ${decoded.name}')
|
||||
println('Decoded host: ${decoded.host}')
|
||||
|
||||
|
||||
// Test 2: Play script
|
||||
println('\n2. Testing play script...')
|
||||
test_play_script()!
|
||||
println('Play script test passed!')
|
||||
|
||||
|
||||
// Test 3: Edge cases
|
||||
println('\n3. Testing edge cases...')
|
||||
edge_client := PostgresqlClient{
|
||||
name: 'edge'
|
||||
user: ''
|
||||
port: 0
|
||||
host: ''
|
||||
name: 'edge'
|
||||
user: ''
|
||||
port: 0
|
||||
host: ''
|
||||
password: ''
|
||||
dbname: ''
|
||||
dbname: ''
|
||||
}
|
||||
|
||||
|
||||
edge_encoded := encode[PostgresqlClient](edge_client)!
|
||||
edge_decoded := decode[PostgresqlClient](edge_encoded)!
|
||||
|
||||
|
||||
assert edge_decoded.name == 'edge'
|
||||
assert edge_decoded.user == ''
|
||||
assert edge_decoded.port == 0
|
||||
println('Edge cases test passed!')
|
||||
|
||||
|
||||
println('\n=== All tests completed successfully! ===')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
module elements
|
||||
|
||||
|
||||
//TODO: def is broken, way how we do it is bad
|
||||
// TODO: def is broken, way how we do it is bad
|
||||
|
||||
@[heap]
|
||||
pub struct Def {
|
||||
|
||||
@@ -39,7 +39,7 @@ fn (self Paragraph) html() !string {
|
||||
mut out := self.DocBase.html()! // the children should have all the content
|
||||
if self.children.len == 1 {
|
||||
if out.trim_space() != '' {
|
||||
if self.children[0] or { panic("bug") } is Link {
|
||||
if self.children[0] or { panic('bug') } is Link {
|
||||
return out
|
||||
} else {
|
||||
return out
|
||||
|
||||
@@ -26,13 +26,13 @@ struct TestChild {
|
||||
}
|
||||
|
||||
const test_child = TestChild{
|
||||
child_name: 'test_child'
|
||||
child_number: 3
|
||||
child_yesno: false
|
||||
child_liststr: ['three', 'four']
|
||||
child_listint: [3, 4]
|
||||
child_name: 'test_child'
|
||||
child_number: 3
|
||||
child_yesno: false
|
||||
child_liststr: ['three', 'four']
|
||||
child_listint: [3, 4]
|
||||
child_listbool: [true, false]
|
||||
child_listu32: [u32(5), u32(6)]
|
||||
child_listu32: [u32(5), u32(6)]
|
||||
}
|
||||
|
||||
const test_struct = TestStruct{
|
||||
@@ -51,7 +51,6 @@ const test_struct = TestStruct{
|
||||
child: test_child
|
||||
}
|
||||
|
||||
|
||||
const test_child_params = Params{
|
||||
params: [
|
||||
Param{
|
||||
@@ -116,7 +115,6 @@ const test_params = Params{
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
fn test_encode_struct() {
|
||||
encoded_struct := encode[TestStruct](test_struct)!
|
||||
assert encoded_struct == test_params
|
||||
|
||||
@@ -8,24 +8,23 @@ __global (
|
||||
gsinstances map[string]&GitStructure
|
||||
)
|
||||
|
||||
|
||||
@[params]
|
||||
pub struct GetRepoArgs{
|
||||
pub struct GetRepoArgs {
|
||||
pub mut:
|
||||
path string //if used will check if path exists if yes, just return
|
||||
git_url string
|
||||
git_pull bool
|
||||
path string // if used will check if path exists if yes, just return
|
||||
git_url string
|
||||
git_pull bool
|
||||
git_reset bool
|
||||
}
|
||||
|
||||
// get_repo_path implements the GitUrlResolver interface
|
||||
pub fn get_repo_path(args GetRepoArgs) !string {
|
||||
if os.exists(args.path){
|
||||
pub fn get_repo_path(args GetRepoArgs) !string {
|
||||
if os.exists(args.path) {
|
||||
return args.path
|
||||
}
|
||||
mut gs := get()!
|
||||
mut repo := gs.get_repo(
|
||||
url: args.git_url
|
||||
url: args.git_url
|
||||
pull: args.git_pull
|
||||
reset: args.git_reset
|
||||
)!
|
||||
|
||||
@@ -45,9 +45,9 @@ pub fn (mut gs GitStructure) do(args_ ReposActionsArgs) !string {
|
||||
mut args := args_
|
||||
// console.print_debug('git do ${args.cmd}')
|
||||
|
||||
if args.path == '' && args.url == '' && args.repo == '' && args.account == '' && args.provider == '' && args.filter == ''{
|
||||
if args.path == '' && args.url == '' && args.repo == '' && args.account == ''
|
||||
&& args.provider == '' && args.filter == '' {
|
||||
args.path = os.getwd()
|
||||
|
||||
}
|
||||
|
||||
if args.path != '' {
|
||||
@@ -84,7 +84,7 @@ pub fn (mut gs GitStructure) do(args_ ReposActionsArgs) !string {
|
||||
)!
|
||||
|
||||
// reset the status for the repo
|
||||
if args.reload || args.cmd == 'reload'{
|
||||
if args.reload || args.cmd == 'reload' {
|
||||
for mut repo in repos {
|
||||
repo.cache_last_load_clear()!
|
||||
}
|
||||
|
||||
@@ -85,9 +85,7 @@ pub fn (mut repo GitRepo) commit(msg string) ! {
|
||||
return error('Commit message is empty.')
|
||||
}
|
||||
repo_path := repo.path()
|
||||
repo.exec('git add . -A') or {
|
||||
return error('Cannot add to repo: ${repo_path}. Error: ${err}')
|
||||
}
|
||||
repo.exec('git add . -A') or { return error('Cannot add to repo: ${repo_path}. Error: ${err}') }
|
||||
repo.exec('git commit -m "${msg}"') or {
|
||||
return error('Cannot commit repo: ${repo_path}. Error: ${err}')
|
||||
}
|
||||
|
||||
@@ -136,5 +136,5 @@ pub fn (self GitRepo) get_last_local_commit() !string {
|
||||
if self.status_local.branch in self.status_local.branches {
|
||||
return self.status_local.branches[self.status_local.branch]
|
||||
}
|
||||
return ""
|
||||
return ''
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import freeflowuniverse.herolib.core.texttools
|
||||
// Generic database interface for Hero root objects
|
||||
pub struct HeroDB[T] {
|
||||
pub mut:
|
||||
db pg.DB
|
||||
db pg.DB
|
||||
table_name string
|
||||
}
|
||||
|
||||
@@ -22,14 +22,12 @@ pub fn new[T]() !HeroDB[T] {
|
||||
table_name = '${dirname}_${texttools.snake_case(T.name)}'
|
||||
}
|
||||
|
||||
mut dbclient:=postgresql_client.get()!
|
||||
mut dbclient := postgresql_client.get()!
|
||||
|
||||
mut dbcl := dbclient.db() or { return error('Failed to connect to database') }
|
||||
|
||||
mut dbcl:=dbclient.db() or {
|
||||
return error('Failed to connect to database')
|
||||
}
|
||||
|
||||
return HeroDB[T]{
|
||||
db: dbcl
|
||||
db: dbcl
|
||||
table_name: table_name
|
||||
}
|
||||
}
|
||||
@@ -38,13 +36,13 @@ pub fn new[T]() !HeroDB[T] {
|
||||
pub fn (mut self HeroDB[T]) ensure_table() ! {
|
||||
// Get index fields from struct reflection
|
||||
index_fields := self.get_index_fields()
|
||||
|
||||
|
||||
// Build index column definitions
|
||||
mut index_cols := []string{}
|
||||
for field in index_fields {
|
||||
index_cols << '${field} varchar(255)'
|
||||
}
|
||||
|
||||
|
||||
// Create table with JSON storage
|
||||
create_sql := '
|
||||
CREATE TABLE IF NOT EXISTS ${self.table_name} (
|
||||
@@ -54,11 +52,9 @@ pub fn (mut self HeroDB[T]) ensure_table() ! {
|
||||
created_at timestamp DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at timestamp DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
'
|
||||
|
||||
// self.db.exec(create_sql)!
|
||||
|
||||
' // self.db.exec(create_sql)!
|
||||
// Create indexes on index fields
|
||||
|
||||
for field in index_fields {
|
||||
index_sql := 'CREATE INDEX IF NOT EXISTS idx_${self.table_name}_${field} ON ${self.table_name}(${field})'
|
||||
// self.db.exec(index_sql)!
|
||||
@@ -80,22 +76,22 @@ fn (self HeroDB[T]) get_index_fields() []string {
|
||||
pub fn (mut self HeroDB[T]) save(obj T) ! {
|
||||
// Get index values from object
|
||||
index_data := self.extract_index_values(obj)
|
||||
|
||||
|
||||
// Serialize to JSON
|
||||
json_data := json.encode_pretty(obj)
|
||||
|
||||
|
||||
// Check if object already exists
|
||||
mut query := 'SELECT id FROM ${self.table_name} WHERE '
|
||||
mut params := []string{}
|
||||
|
||||
|
||||
// Build WHERE clause for unique lookup
|
||||
for key, value in index_data {
|
||||
params << '${key} = \'${value}\''
|
||||
}
|
||||
query += params.join(' AND ')
|
||||
|
||||
existing :=self.db.exec(query)!
|
||||
|
||||
|
||||
existing := self.db.exec(query)!
|
||||
|
||||
if existing.len > 0 {
|
||||
// Update existing record
|
||||
id_val := existing[0].vals[0] or { return error('no id') }
|
||||
@@ -114,22 +110,21 @@ pub fn (mut self HeroDB[T]) save(obj T) ! {
|
||||
// Insert new record
|
||||
mut columns := []string{}
|
||||
mut values := []string{}
|
||||
|
||||
|
||||
// Add index columns
|
||||
for key, value in index_data {
|
||||
columns << key
|
||||
values << "'${value}'"
|
||||
}
|
||||
|
||||
|
||||
// Add JSON data
|
||||
columns << 'data'
|
||||
values << "'${json_data}'"
|
||||
|
||||
|
||||
insert_sql := '
|
||||
INSERT INTO ${self.table_name} (${columns.join(', ')})
|
||||
VALUES (${values.join(', ')})
|
||||
'
|
||||
// self.db.exec(insert_sql)!
|
||||
' // self.db.exec(insert_sql)!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +132,7 @@ pub fn (mut self HeroDB[T]) save(obj T) ! {
|
||||
pub fn (mut self HeroDB[T]) get_by_index(index_values map[string]string) !T {
|
||||
mut query := 'SELECT data FROM ${self.table_name} WHERE '
|
||||
mut params := []string{}
|
||||
|
||||
|
||||
for key, value in index_values {
|
||||
params << '${key} = \'${value}\''
|
||||
}
|
||||
@@ -147,16 +142,16 @@ pub fn (mut self HeroDB[T]) get_by_index(index_values map[string]string) !T {
|
||||
if rows.len == 0 {
|
||||
return error('${T.name} not found with index values: ${index_values}')
|
||||
}
|
||||
|
||||
|
||||
json_data_val := rows[0].vals[0] or { return error('no data') }
|
||||
println('json_data_val: ${json_data_val}')
|
||||
if true{
|
||||
if true {
|
||||
panic('sd2221')
|
||||
}
|
||||
// mut obj := json.decode(T, json_data_val) or {
|
||||
// return error('Failed to decode JSON: ${err}')
|
||||
// }
|
||||
|
||||
|
||||
// return &obj
|
||||
return T{}
|
||||
}
|
||||
@@ -165,7 +160,7 @@ pub fn (mut self HeroDB[T]) get_by_index(index_values map[string]string) !T {
|
||||
// pub fn (mut self HeroDB[T]) get_all() ![]T {
|
||||
// query := 'SELECT data FROM ${self.table_name} ORDER BY id DESC'
|
||||
// rows := self.db_client.db()!.exec(query)!
|
||||
|
||||
|
||||
// mut results := []T{}
|
||||
// for row in rows {
|
||||
// json_data_val := row.vals[0] or { continue }
|
||||
@@ -176,7 +171,7 @@ pub fn (mut self HeroDB[T]) get_by_index(index_values map[string]string) !T {
|
||||
// }
|
||||
// results << &obj
|
||||
// }
|
||||
|
||||
|
||||
// return results
|
||||
// }
|
||||
|
||||
@@ -184,7 +179,7 @@ pub fn (mut self HeroDB[T]) get_by_index(index_values map[string]string) !T {
|
||||
// pub fn (mut self HeroDB[T]) search_by_index(field_name string, value string) ![]T {
|
||||
// query := 'SELECT data FROM ${self.table_name} WHERE ${field_name} = \'${value}\' ORDER BY id DESC'
|
||||
// rows := self.db_client.db()!.exec(query)!
|
||||
|
||||
|
||||
// mut results := []T{}
|
||||
// for row in rows {
|
||||
// json_data_val := row.vals[0] or { continue }
|
||||
@@ -194,7 +189,7 @@ pub fn (mut self HeroDB[T]) get_by_index(index_values map[string]string) !T {
|
||||
// }
|
||||
// results << &obj
|
||||
// }
|
||||
|
||||
|
||||
// return results
|
||||
// }
|
||||
|
||||
@@ -202,12 +197,12 @@ pub fn (mut self HeroDB[T]) get_by_index(index_values map[string]string) !T {
|
||||
// pub fn (mut self HeroDB[T]) delete_by_index(index_values map[string]string) ! {
|
||||
// mut query := 'DELETE FROM ${self.table_name} WHERE '
|
||||
// mut params := []string{}
|
||||
|
||||
|
||||
// for key, value in index_values {
|
||||
// params << '${key} = \'${value}\''
|
||||
// }
|
||||
// query += params.join(' AND ')
|
||||
|
||||
|
||||
// self.db_client.db()!.exec(query)!
|
||||
// }
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ fn install() ! {
|
||||
return error('only support linux for now')
|
||||
}
|
||||
|
||||
release_url := 'https://github.com/threefoldtech/zinit/releases/download/v0.2.14/zinit'
|
||||
release_url := 'https://github.com/threefoldtech/zinit/releases/download/v0.2.25/zinit'
|
||||
|
||||
mut dest := osal.download(
|
||||
url: release_url
|
||||
|
||||
@@ -41,9 +41,9 @@ pub:
|
||||
// HttpConfig holds HTTP-specific configuration
|
||||
pub struct HttpConfig {
|
||||
pub:
|
||||
port int = 8080 // Port to listen on
|
||||
host string = 'localhost' // Host to bind to
|
||||
protocol HttpMode = .both // Which HTTP protocols to support
|
||||
port int = 8080 // Port to listen on
|
||||
host string = 'localhost' // Host to bind to
|
||||
protocol HttpMode = .both // Which HTTP protocols to support
|
||||
}
|
||||
|
||||
// HttpMode defines which HTTP protocols the server should support
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module core
|
||||
module core
|
||||
|
||||
fn test_done_set() ! {
|
||||
done_set('mykey', 'myvalue')!
|
||||
|
||||
@@ -18,7 +18,7 @@ pub mut:
|
||||
path_build pathlib.Path
|
||||
errors []SiteError
|
||||
config Configuration
|
||||
website sitemodule.Site
|
||||
website sitemodule.Site
|
||||
}
|
||||
|
||||
pub fn (mut s DocSite) build() ! {
|
||||
|
||||
@@ -13,14 +13,14 @@ import freeflowuniverse.herolib.core.playbook
|
||||
@[params]
|
||||
pub struct AddArgs {
|
||||
pub mut:
|
||||
sitename string //needs to exist in web.site module
|
||||
path string //site of the docusaurus site with the config as is needed to populate the docusaurus site
|
||||
git_url string
|
||||
git_reset bool
|
||||
git_root string
|
||||
git_pull bool
|
||||
sitename string // needs to exist in web.site module
|
||||
path string // site of the docusaurus site with the config as is needed to populate the docusaurus site
|
||||
git_url string
|
||||
git_reset bool
|
||||
git_root string
|
||||
git_pull bool
|
||||
path_publish string
|
||||
play bool = true
|
||||
play bool = true
|
||||
}
|
||||
|
||||
pub fn dsite_add(args_ AddArgs) !&DocSite {
|
||||
@@ -29,10 +29,9 @@ pub fn dsite_add(args_ AddArgs) !&DocSite {
|
||||
|
||||
console.print_header('Add Docusaurus Site: ${args.sitename}')
|
||||
|
||||
if args.sitename in docusaurus_sites {
|
||||
return error('Docusaurus site ${args.sitename} already exists, returning existing.')
|
||||
|
||||
}
|
||||
if args.sitename in docusaurus_sites {
|
||||
return error('Docusaurus site ${args.sitename} already exists, returning existing.')
|
||||
}
|
||||
|
||||
mut path := gittools.path(
|
||||
path: args.path
|
||||
@@ -47,7 +46,7 @@ pub fn dsite_add(args_ AddArgs) !&DocSite {
|
||||
return error('path is not a directory')
|
||||
}
|
||||
|
||||
if ! os.exists('${args.path}/cfg') {
|
||||
if !os.exists('${args.path}/cfg') {
|
||||
return error('config directory for docusaurus does not exist in ${args.path}/cfg.\n${args}')
|
||||
}
|
||||
|
||||
@@ -66,13 +65,13 @@ pub fn dsite_add(args_ AddArgs) !&DocSite {
|
||||
|
||||
mut website := site.get(name: args.sitename)!
|
||||
|
||||
mut myconfig := new_configuration(website.siteconfig)! //go from site.SiteConfig to docusaurus.Configuration
|
||||
mut myconfig := new_configuration(website.siteconfig)! // go from site.SiteConfig to docusaurus.Configuration
|
||||
|
||||
if myconfig.main.name.len == 0 {
|
||||
return error('main.name is not set in the site configuration')
|
||||
}
|
||||
|
||||
mut f:=factory_get()!
|
||||
mut f := factory_get()!
|
||||
|
||||
if args.path_publish == '' {
|
||||
args.path_publish = '${f.path_publish.path}/${args.sitename}'
|
||||
@@ -80,37 +79,33 @@ pub fn dsite_add(args_ AddArgs) !&DocSite {
|
||||
|
||||
path_build_ := '${f.path_build.path}/${args.sitename}'
|
||||
|
||||
//get our website
|
||||
// get our website
|
||||
mut mysite := site.new(name: args.sitename)!
|
||||
if site.exists(name: args.sitename) {
|
||||
console.print_debug('Docusaurus site ${args.sitename} already exists, using existing site.')
|
||||
mysite = site.get(name: args.sitename)!
|
||||
} else {
|
||||
if !args.play{
|
||||
if !args.play {
|
||||
return error('Docusaurus site ${args.sitename} does not exist, please set play to true to create it.')
|
||||
}
|
||||
console.print_debug('Creating new Docusaurus site ${args.sitename}.')
|
||||
mut plbook := playbook.new(path: "${args.path}/cfg")!
|
||||
mut plbook := playbook.new(path: '${args.path}/cfg')!
|
||||
site.play(mut plbook)!
|
||||
mysite = site.get(name: args.sitename) or {
|
||||
return error('Failed to get site after playing playbook: ${args.sitename}')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create the DocSite instance
|
||||
mut dsite := &DocSite{
|
||||
name: args.sitename
|
||||
path_src: pathlib.get_dir(path: args.path, create: false)!
|
||||
path_publish: pathlib.get_dir(path: args.path_publish, create: true)!
|
||||
path_build: pathlib.get_dir(path: path_build_, create: true)!
|
||||
config: new_configuration(website.siteconfig)!
|
||||
// Create the DocSite instance
|
||||
mut dsite := &DocSite{
|
||||
name: args.sitename
|
||||
path_src: pathlib.get_dir(path: args.path, create: false)!
|
||||
path_publish: pathlib.get_dir(path: args.path_publish, create: true)!
|
||||
path_build: pathlib.get_dir(path: path_build_, create: true)!
|
||||
config: new_configuration(website.siteconfig)!
|
||||
website: mysite
|
||||
}
|
||||
}
|
||||
|
||||
docusaurus_sites[args.sitename] = dsite
|
||||
return dsite
|
||||
docusaurus_sites[args.sitename] = dsite
|
||||
return dsite
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ module docusaurus
|
||||
|
||||
import freeflowuniverse.herolib.web.site
|
||||
|
||||
//IS THE ONE AS USED BY DOCUSAURUS
|
||||
// IS THE ONE AS USED BY DOCUSAURUS
|
||||
|
||||
pub struct Configuration {
|
||||
pub mut:
|
||||
|
||||
@@ -12,13 +12,11 @@ import freeflowuniverse.herolib.core.texttools.regext
|
||||
import freeflowuniverse.herolib.web.site as sitegen
|
||||
|
||||
pub fn (mut site DocSite) generate() ! {
|
||||
|
||||
mut f:=factory_get()!
|
||||
mut f := factory_get()!
|
||||
|
||||
console.print_header(' site generate: ${site.name} on ${f.path_build.path}')
|
||||
console.print_header(' site source on ${site.path_src.path}')
|
||||
|
||||
|
||||
// lets make sure we remove the cfg dir so we rebuild
|
||||
cfg_path := os.join_path(f.path_build.path, 'cfg')
|
||||
osal.rm(cfg_path)!
|
||||
|
||||
@@ -8,71 +8,72 @@ import freeflowuniverse.herolib.osal.core as osal
|
||||
import freeflowuniverse.herolib.installers.web.bun
|
||||
|
||||
__global (
|
||||
docusaurus_sites map[string]&DocSite
|
||||
docusaurus_factory ?DocSiteFactory
|
||||
docusaurus_sites map[string]&DocSite
|
||||
docusaurus_factory []DocSiteFactory
|
||||
)
|
||||
|
||||
pub struct DocSiteFactory{
|
||||
pub struct DocSiteFactory {
|
||||
pub mut:
|
||||
path_publish pathlib.Path
|
||||
path_build pathlib.Path
|
||||
path_build pathlib.Path
|
||||
}
|
||||
|
||||
@[params]
|
||||
pub struct DocSiteFactoryArgs {
|
||||
pub mut:
|
||||
path_build string
|
||||
path_publish string
|
||||
install bool
|
||||
reset bool
|
||||
template_update bool
|
||||
path_build string
|
||||
path_publish string
|
||||
install bool
|
||||
reset bool
|
||||
template_update bool
|
||||
}
|
||||
|
||||
pub fn factory_get(args_ DocSiteFactoryArgs) !DocSiteFactory {
|
||||
mut args:= args_
|
||||
mut f:= docusaurus_factory or {
|
||||
mut factory:=factory_set(args)!
|
||||
factory
|
||||
}
|
||||
return f
|
||||
mut args := args_
|
||||
if docusaurus_factory.len > 1 {
|
||||
panic("multiple docusaurus factories found, please specify which one to use")
|
||||
}
|
||||
if docusaurus_factory.len > 0 {
|
||||
return docusaurus_factory[0]
|
||||
}
|
||||
return factory_set(args)!
|
||||
}
|
||||
|
||||
pub fn factory_set(args_ DocSiteFactoryArgs) !DocSiteFactory {
|
||||
mut args:= args_
|
||||
if args.path_build == '' {
|
||||
args.path_build = '${os.home_dir()}/hero/var/docusaurus/build'
|
||||
}
|
||||
if args.path_publish == '' {
|
||||
args.path_publish = '${os.home_dir()}/hero/var/docusaurus/publish'
|
||||
}
|
||||
mut factory := DocSiteFactory{
|
||||
path_publish: pathlib.get_dir(path:args.path_publish,create:true)!
|
||||
path_build: pathlib.get_dir(path:args.path_build,create:true)!
|
||||
}
|
||||
mut args := args_
|
||||
if args.path_build == '' {
|
||||
args.path_build = '${os.home_dir()}/hero/var/docusaurus/build'
|
||||
}
|
||||
if args.path_publish == '' {
|
||||
args.path_publish = '${os.home_dir()}/hero/var/docusaurus/publish'
|
||||
}
|
||||
mut factory := DocSiteFactory{
|
||||
path_publish: pathlib.get_dir(path: args.path_publish, create: true)!
|
||||
path_build: pathlib.get_dir(path: args.path_build, create: true)!
|
||||
}
|
||||
|
||||
if !os.exists('${args.path_build}/node_modules') {
|
||||
args.install = true
|
||||
}
|
||||
if !os.exists('${args.path_build}/node_modules') {
|
||||
args.install = true
|
||||
}
|
||||
|
||||
if args.install {
|
||||
factory.install(args.reset, args.template_update)!
|
||||
}
|
||||
|
||||
docusaurus_factory << factory
|
||||
|
||||
if args.install {
|
||||
factory.install(args.reset, args.template_update)!
|
||||
}
|
||||
return factory
|
||||
}
|
||||
|
||||
|
||||
pub fn dsite_get(name_ string) !&DocSite {
|
||||
name := texttools.name_fix(name_)
|
||||
return docusaurus_sites[name] or {
|
||||
return error('docusaurus site with name "${name}" does not exist')
|
||||
}
|
||||
name := texttools.name_fix(name_)
|
||||
return docusaurus_sites[name] or {
|
||||
return error('docusaurus site with name "${name}" does not exist')
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dsite_exists(name_ string) !bool {
|
||||
name := texttools.name_fix(name_)
|
||||
d := docusaurus_sites[name] or {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
name := texttools.name_fix(name_)
|
||||
d := docusaurus_sites[name] or { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,11 @@ module docusaurus
|
||||
|
||||
import freeflowuniverse.herolib.core.pathlib
|
||||
import freeflowuniverse.herolib.web.doctreeclient
|
||||
import freeflowuniverse.herolib.web.site {Site, Page, Section}
|
||||
import freeflowuniverse.herolib.web.site { Page, Section, Site }
|
||||
import freeflowuniverse.herolib.data.markdown.tools as markdowntools
|
||||
// import freeflowuniverse.herolib.ui.console
|
||||
|
||||
//THIS CODE GENERATES A DOCUSAURUS SITE FROM A DOCTREECLIENT AND SITE DEFINITION
|
||||
|
||||
// THIS CODE GENERATES A DOCUSAURUS SITE FROM A DOCTREECLIENT AND SITE DEFINITION
|
||||
|
||||
struct SiteGenerator {
|
||||
mut:
|
||||
@@ -15,7 +14,7 @@ mut:
|
||||
path pathlib.Path
|
||||
client &doctreeclient.DocTreeClient
|
||||
flat bool // if flat then won't use sitenames as subdir's
|
||||
site Site
|
||||
site Site
|
||||
}
|
||||
|
||||
@[params]
|
||||
@@ -36,7 +35,7 @@ fn generate(args SiteGeneratorArgs) ! {
|
||||
path: pathlib.get_dir(path: path, create: true)!
|
||||
client: doctreeclient.new()!
|
||||
flat: args.flat
|
||||
site: args.site
|
||||
site: args.site
|
||||
}
|
||||
|
||||
for section in gen.site.sections {
|
||||
|
||||
@@ -6,7 +6,6 @@ import freeflowuniverse.herolib.develop.gittools
|
||||
import freeflowuniverse.herolib.osal.core as osal
|
||||
import freeflowuniverse.herolib.installers.web.bun
|
||||
|
||||
|
||||
fn (mut f DocSiteFactory) install(reset bool, template_update bool) ! {
|
||||
mut gs := gittools.new()!
|
||||
|
||||
@@ -23,19 +22,18 @@ fn (mut f DocSiteFactory) install(reset bool, template_update bool) ! {
|
||||
|
||||
mut template_path0 := pathlib.get_dir(path: template_path, create: false)!
|
||||
|
||||
template_path0.copy(dest: f.path_build.path, delete:reset)! // Changed args.delete to args.reset
|
||||
template_path0.copy(dest: f.path_build.path, delete: reset)! // Changed args.delete to args.reset
|
||||
|
||||
// install bun
|
||||
mut installer := bun.get()!
|
||||
installer.install()!
|
||||
osal.exec(
|
||||
// always stay in the context of the build directory
|
||||
cmd: '
|
||||
// install bun
|
||||
mut installer := bun.get()!
|
||||
installer.install()!
|
||||
osal.exec(
|
||||
// always stay in the context of the build directory
|
||||
cmd: '
|
||||
${osal.profile_path_source_and()!}
|
||||
export PATH=${f.path_build.path}/node_modules/.bin::${os.home_dir()}/.bun/bin/:\$PATH
|
||||
cd ${f.path_build.path}
|
||||
bun install
|
||||
'
|
||||
)!
|
||||
|
||||
}
|
||||
)!
|
||||
}
|
||||
|
||||
@@ -4,48 +4,55 @@ import freeflowuniverse.herolib.core.playbook { PlayBook }
|
||||
import freeflowuniverse.herolib.web.site
|
||||
|
||||
pub fn play(mut plbook PlayBook) ! {
|
||||
|
||||
if !plbook.exists_once(filter: 'docusaurus.') {
|
||||
return
|
||||
}
|
||||
|
||||
// 1. Process generic site configuration first.
|
||||
// This populates the global `site.websites` map.
|
||||
site.play(mut plbook)!
|
||||
|
||||
// check if docusaurus.define exists, if not, we create a default factory
|
||||
mut f:=DocSiteFactory{}
|
||||
if plbook.exists_once(filter: 'docusaurus.define'){
|
||||
mut a:=plbook.get(filter: 'docusaurus.define') or {
|
||||
mut f := DocSiteFactory{}
|
||||
if plbook.exists_once(filter: 'docusaurus.define') {
|
||||
mut a := plbook.get(filter: 'docusaurus.define') or {
|
||||
panic('docusaurus.define action not found, this should not happen.')
|
||||
}
|
||||
mut p:=a.params
|
||||
f=factory_set(
|
||||
path_build: p.get_default('path_build', '')!
|
||||
path_publish: p.get_default('path_publish', '')!
|
||||
reset: p.get_default_false('reset')
|
||||
template_update: p.get_default_false('template_update')
|
||||
install: p.get_default_false('install')
|
||||
)!
|
||||
a.done = true
|
||||
}else{
|
||||
f=factory_get()!
|
||||
mut p := a.params
|
||||
f = factory_set(
|
||||
path_build: p.get_default('path_build', '')!
|
||||
path_publish: p.get_default('path_publish', '')!
|
||||
reset: p.get_default_false('reset')
|
||||
template_update: p.get_default_false('template_update')
|
||||
install: p.get_default_false('install')
|
||||
)!
|
||||
a.done = true
|
||||
} else {
|
||||
f = factory_get()!
|
||||
}
|
||||
|
||||
// 3. Process `docusaurus.add` actions to create sites.
|
||||
for mut action in plbook.find(filter: 'docusaurus.add')! {
|
||||
mut p := action.params
|
||||
site_name := p.get('sitename') or { return error('In docusaurus.add, param "sitename" is required.') }
|
||||
site_name := p.get('sitename') or {
|
||||
return error('In docusaurus.add, param "sitename" is required.')
|
||||
}
|
||||
|
||||
dsite_add(
|
||||
sitename: site_name
|
||||
path: p.get('path')!
|
||||
git_url: p.get('git_url')!
|
||||
git_reset: p.get_default_false('git_reset')
|
||||
git_root: p.get('git_root')!
|
||||
git_pull: p.get_default_false('git_pull')
|
||||
sitename: site_name
|
||||
path: p.get('path')!
|
||||
git_url: p.get('git_url')!
|
||||
git_reset: p.get_default_false('git_reset')
|
||||
git_root: p.get('git_root')!
|
||||
git_pull: p.get_default_false('git_pull')
|
||||
path_publish: p.get_default('path_publish', f.path_publish.path)!
|
||||
play:false //need to make sure we don't play again
|
||||
play: false // need to make sure we don't play again
|
||||
)!
|
||||
action.done = true
|
||||
}
|
||||
|
||||
mut actions_dev:=plbook.find(filter: 'docusaurus.dev')!
|
||||
mut actions_dev := plbook.find(filter: 'docusaurus.dev')!
|
||||
if actions_dev.len > 1 {
|
||||
return error('Multiple "docusaurus.dev" actions found. Only one is allowed.')
|
||||
}
|
||||
@@ -54,15 +61,15 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
site_name := p.get('site')!
|
||||
mut dsite := dsite_get(site_name)!
|
||||
dsite.dev(
|
||||
host: p.get_default('host', 'localhost')!
|
||||
port: p.get_int_default('port', 3000)!
|
||||
open: p.get_default_false('open')
|
||||
host: p.get_default('host', 'localhost')!
|
||||
port: p.get_int_default('port', 3000)!
|
||||
open: p.get_default_false('open')
|
||||
watch_changes: p.get_default_false('watch_changes')
|
||||
)!
|
||||
action.done = true
|
||||
}
|
||||
|
||||
mut actions_build:=plbook.find(filter: 'docusaurus.build')!
|
||||
mut actions_build := plbook.find(filter: 'docusaurus.build')!
|
||||
if actions_build.len > 1 {
|
||||
return error('Multiple "docusaurus.build" actions found. Only one is allowed.')
|
||||
}
|
||||
@@ -73,5 +80,4 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
dsite.build()!
|
||||
action.done = true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,13 @@ module site
|
||||
import freeflowuniverse.herolib.core.texttools
|
||||
|
||||
__global (
|
||||
websites map[string]&Site
|
||||
websites map[string]&Site
|
||||
)
|
||||
|
||||
@[params]
|
||||
pub struct FactoryArgs {
|
||||
pub mut:
|
||||
name string = "default"
|
||||
name string = 'default'
|
||||
}
|
||||
|
||||
pub fn new(args FactoryArgs) !&Site {
|
||||
@@ -19,29 +19,24 @@ pub fn new(args FactoryArgs) !&Site {
|
||||
name: name
|
||||
}
|
||||
}
|
||||
return get(name:name)!
|
||||
return get(name: name)!
|
||||
}
|
||||
|
||||
pub fn get(args FactoryArgs) !&Site {
|
||||
name := texttools.name_fix(args.name)
|
||||
mut sc := websites[name] or {
|
||||
return error('siteconfig with name "${name}" does not exist')
|
||||
}
|
||||
mut sc := websites[name] or { return error('siteconfig with name "${name}" does not exist') }
|
||||
return sc
|
||||
}
|
||||
|
||||
|
||||
pub fn exists(args FactoryArgs) bool {
|
||||
name := texttools.name_fix(args.name)
|
||||
mut sc := websites[name] or {
|
||||
return false
|
||||
}
|
||||
mut sc := websites[name] or { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
pub fn default() !&Site {
|
||||
if websites.len == 0 {
|
||||
return new(name:'default')!
|
||||
return new(name: 'default')!
|
||||
}
|
||||
return get()!
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
module site
|
||||
|
||||
|
||||
@[heap]
|
||||
pub struct Site {
|
||||
pub mut:
|
||||
pages []Page
|
||||
sections []Section
|
||||
pages []Page
|
||||
sections []Section
|
||||
siteconfig SiteConfig
|
||||
|
||||
}
|
||||
|
||||
pub struct Page {
|
||||
@@ -17,10 +15,10 @@ pub mut:
|
||||
draft bool
|
||||
position int
|
||||
hide_title bool
|
||||
src string @[required] //always in format collection:page_name
|
||||
src string @[required] // always in format collection:page_name
|
||||
path string @[required]
|
||||
title_nr int
|
||||
slug string
|
||||
slug string
|
||||
}
|
||||
|
||||
pub struct Section {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
module site
|
||||
|
||||
import os
|
||||
// Combined config structure
|
||||
|
||||
@[heap]
|
||||
pub struct SiteConfig {
|
||||
pub mut:
|
||||
|
||||
@@ -15,7 +15,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
// Process each site configuration separately
|
||||
for mut config_action in config_actions {
|
||||
mut website := play_config_single(mut config_action)!
|
||||
|
||||
|
||||
mut config := &website.siteconfig
|
||||
|
||||
play_import(mut plbook, mut config)!
|
||||
@@ -30,9 +30,7 @@ pub fn play(mut plbook PlayBook) ! {
|
||||
|
||||
fn play_config_single(mut action Action) !&Site {
|
||||
mut p := action.params
|
||||
name := p.get('name') or {
|
||||
return error('need to specify name in site.config.\n${action}')
|
||||
}
|
||||
name := p.get('name') or { return error('need to specify name in site.config.\n${action}') }
|
||||
|
||||
mut website := new(name: name)!
|
||||
mut config := &website.siteconfig
|
||||
|
||||
@@ -2,12 +2,11 @@ module site
|
||||
|
||||
import freeflowuniverse.herolib.core.playbook { PlayBook }
|
||||
|
||||
//plays the sections & pages
|
||||
// plays the sections & pages
|
||||
fn play_pages(mut plbook PlayBook, mut site Site) ! {
|
||||
|
||||
// mut siteconfig := &site.siteconfig
|
||||
|
||||
//if only 1 doctree is specified, then we use that as the default doctree name
|
||||
// if only 1 doctree is specified, then we use that as the default doctree name
|
||||
mut doctreename := 'main'
|
||||
if plbook.exists(filter: 'site.doctree') {
|
||||
if plbook.exists_once(filter: 'site.doctree') {
|
||||
|
||||
Reference in New Issue
Block a user