From 9fcdcc3affb75e135c39d91dcb4e4c77a1089416 Mon Sep 17 00:00:00 2001 From: kristof Date: Mon, 31 Mar 2025 09:32:58 +0200 Subject: [PATCH] ... --- examples/aiexamples/groq.vsh | 70 ++++++++++ examples/{clients => aiexamples}/jina.vsh | 0 .../aiexamples/openai_chat_completion.vsh | 69 ---------- .../qdrant.vsh} | 4 + examples/clients/groq/.env.example | 1 - examples/clients/groq/README.md | 64 --------- examples/clients/groq/groq_client.vsh | 46 ------- install_v.sh | 12 +- lib/clients/openai/audio.v | 4 +- lib/clients/openai/client_test.v | 127 +++++++++--------- lib/clients/openai/completions.v | 24 +++- lib/clients/openai/model_enums.v | 52 ------- lib/clients/openai/openai_factory_.v | 112 +++++++++++++++ lib/clients/openai/openai_model.v | 93 +++++++++++++ lib/clients/openai/openai_model_.v | 67 --------- lib/clients/openai/readme.md | 7 +- .../templates/objname_factory_.vtemplate | 2 +- lib/mcp/README.md | 19 --- lib/osal/env.v | 9 ++ 19 files changed, 383 insertions(+), 399 deletions(-) create mode 100755 examples/aiexamples/groq.vsh rename examples/{clients => aiexamples}/jina.vsh (100%) delete mode 100755 examples/aiexamples/openai_chat_completion.vsh rename examples/{clients/qdrant_example.vsh => aiexamples/qdrant.vsh} (94%) delete mode 100644 examples/clients/groq/.env.example delete mode 100644 examples/clients/groq/README.md delete mode 100755 examples/clients/groq/groq_client.vsh create mode 100644 lib/clients/openai/openai_factory_.v create mode 100644 lib/clients/openai/openai_model.v delete mode 100644 lib/clients/openai/openai_model_.v diff --git a/examples/aiexamples/groq.vsh b/examples/aiexamples/groq.vsh new file mode 100755 index 00000000..860fe797 --- /dev/null +++ b/examples/aiexamples/groq.vsh @@ -0,0 +1,70 @@ +#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run + +module main + +import freeflowuniverse.herolib.clients.openai +import os + + +fn test1(mut client openai.OpenAI)!{ + + // Create a chat completion request + res := client.chat_completion(msgs:openai.Messages{ + messages: [ + openai.Message{ + role: .user + content: 'What are the key differences between Groq and other AI inference providers?' + }, + ] + })! + + // Print the response + println('\nGroq AI Response:') + println('==================') + println(res.choices[0].message.content) + println('\nUsage Statistics:') + println('Prompt tokens: ${res.usage.prompt_tokens}') + println('Completion tokens: ${res.usage.completion_tokens}') + println('Total tokens: ${res.usage.total_tokens}') + +} + + +fn test2(mut client openai.OpenAI)!{ + + // Create a chat completion request + res := client.chat_completion( + model:"deepseek-r1-distill-llama-70b", + msgs:openai.Messages{ + messages: [ + openai.Message{ + role: .user + content: 'A story of 10 lines?' + }, + ] + })! + + println('\nGroq AI Response:') + println('==================') + println(res.choices[0].message.content) + println('\nUsage Statistics:') + println('Prompt tokens: ${res.usage.prompt_tokens}') + println('Completion tokens: ${res.usage.completion_tokens}') + println('Total tokens: ${res.usage.total_tokens}') + +} + + +println(' +TO USE: +export AIKEY=\'gsk_...\' +export AIURL=\'https://api.groq.com/openai/v1\' +export AIMODEL=\'llama-3.3-70b-versatile\' +') + +mut client:=openai.get(name:"test")! +println(client) + + +// test1(mut client)! +test2(mut client)! diff --git a/examples/clients/jina.vsh b/examples/aiexamples/jina.vsh similarity index 100% rename from examples/clients/jina.vsh rename to examples/aiexamples/jina.vsh diff --git a/examples/aiexamples/openai_chat_completion.vsh b/examples/aiexamples/openai_chat_completion.vsh deleted file mode 100755 index 2eb7125e..00000000 --- a/examples/aiexamples/openai_chat_completion.vsh +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run - -import freeflowuniverse.herolib.clients.jina -import freeflowuniverse.herolib.osal -import os - -// Example of using the Jina client - -fn main() { - // Set environment variable for testing - // In production, you would set this in your environment - // osal.env_set(key: 'JINAKEY', value: 'your-api-key') - - // Check if JINAKEY environment variable exists - if !osal.env_exists('JINAKEY') { - println('JINAKEY environment variable not set. Please set it before running this example.') - exit(1) - } - - // Create a Jina client instance - mut client := jina.get(name: 'default')! - - println('Jina client initialized successfully.') - - // Example: Create embeddings - model := 'jina-embeddings-v3' - texts := ['Hello, world!', 'How are you doing?'] - - println('Creating embeddings for texts: ${texts}') - result := client.create_embeddings(texts, model, 'retrieval.query')! - - println('Embeddings created successfully.') - println('Model: ${result['model']}') - println('Data count: ${result['data'].arr().len}') - - // Example: List classifiers - println('\nListing classifiers:') - classifiers := client.list_classifiers() or { - println('Failed to list classifiers: ${err}') - return - } - - println('Classifiers retrieved successfully.') - - // Example: Create a classifier - println('\nTraining a classifier:') - examples := [ - jina.TrainingExample{ - text: 'This movie was great!' - label: 'positive' - }, - jina.TrainingExample{ - text: 'I did not like this movie.' - label: 'negative' - }, - jina.TrainingExample{ - text: 'The movie was okay.' - label: 'neutral' - }, - ] - - training_result := client.train(examples, model, 'private') or { - println('Failed to train classifier: ${err}') - return - } - - println('Classifier trained successfully.') - println('Classifier ID: ${training_result['classifier_id']}') -} diff --git a/examples/clients/qdrant_example.vsh b/examples/aiexamples/qdrant.vsh similarity index 94% rename from examples/clients/qdrant_example.vsh rename to examples/aiexamples/qdrant.vsh index a7329d03..64dee4e1 100755 --- a/examples/clients/qdrant_example.vsh +++ b/examples/aiexamples/qdrant.vsh @@ -1,9 +1,13 @@ #!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run import freeflowuniverse.herolib.clients.qdrant +import freeflowuniverse.herolib.installers.db.qdrant as qdrant_installer import freeflowuniverse.herolib.core.httpconnection import rand +mut i:=qdrant_installer.get()! +i.install()! + // 1. Get the qdrant client mut qdrant_client := qdrant.get()! diff --git a/examples/clients/groq/.env.example b/examples/clients/groq/.env.example deleted file mode 100644 index 48ccad89..00000000 --- a/examples/clients/groq/.env.example +++ /dev/null @@ -1 +0,0 @@ -export GROQ_API_KEY="your-groq-api-key-here" diff --git a/examples/clients/groq/README.md b/examples/clients/groq/README.md deleted file mode 100644 index 13e4116c..00000000 --- a/examples/clients/groq/README.md +++ /dev/null @@ -1,64 +0,0 @@ -# Groq AI Client Example - -This example demonstrates how to use Groq's AI API with the herolib OpenAI client. Groq provides API compatibility with OpenAI's client libraries, allowing you to leverage Groq's fast inference speeds with minimal changes to your existing code. - -## Prerequisites - -- V programming language installed -- A Groq API key (get one from [Groq's website](https://console.groq.com/keys)) - -## Setup - -1. Copy the `.env.example` file to `.env`: - -```bash -cp .env.example .env -``` - -2. Edit the `.env` file and replace `your-groq-api-key-here` with your actual Groq API key. - -3. Load the environment variables: - -```bash -source .env -``` - -## Running the Example - -Execute the script with: - -```bash -v run groq_client.vsh -``` - -Or make it executable first: - -```bash -chmod +x groq_client.vsh -./groq_client.vsh -``` - -## How It Works - -The example uses the existing OpenAI client from herolib but configures it to use Groq's API endpoint: - -1. It retrieves the Groq API key from the environment variables -2. Configures the OpenAI client with the Groq API key -3. Overrides the default OpenAI URL with Groq's API URL (`https://api.groq.com/openai/v1`) -4. Sends a chat completion request to Groq's API -5. Displays the response - -## Supported Models - -Groq supports various models including: - -- llama2-70b-4096 -- mixtral-8x7b-32768 -- gemma-7b-it - -For a complete and up-to-date list of supported models, refer to the [Groq API documentation](https://console.groq.com/docs/models). - -## Notes - -- The example uses the `gpt_3_5_turbo` enum from the OpenAI client, but Groq will automatically map this to an appropriate model on their end. -- For production use, you may want to explicitly specify one of Groq's supported models. \ No newline at end of file diff --git a/examples/clients/groq/groq_client.vsh b/examples/clients/groq/groq_client.vsh deleted file mode 100755 index e419cc19..00000000 --- a/examples/clients/groq/groq_client.vsh +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run - -module main - -import freeflowuniverse.herolib.clients.openai -import os - -fn main() { - // Get API key from environment variable - key := os.getenv('GROQ_API_KEY') - if key == '' { - println('Error: GROQ_API_KEY environment variable not set') - println('Please set it by running: source .env') - exit(1) - } - - // Get the configured client - mut client := openai.OpenAI{ - name: 'groq' - api_key: key - server_url: 'https://api.groq.com/openai/v1' - } - - // Define the model and message for chat completion - // Note: Use a model that Groq supports, like llama2-70b-4096 or mixtral-8x7b-32768 - model := 'qwen-2.5-coder-32b' - - // Create a chat completion request - res := client.chat_completion(model, openai.Messages{ - messages: [ - openai.Message{ - role: .user - content: 'What are the key differences between Groq and other AI inference providers?' - }, - ] - })! - - // Print the response - println('\nGroq AI Response:') - println('==================') - println(res.choices[0].message.content) - println('\nUsage Statistics:') - println('Prompt tokens: ${res.usage.prompt_tokens}') - println('Completion tokens: ${res.usage.completion_tokens}') - println('Total tokens: ${res.usage.total_tokens}') -} diff --git a/install_v.sh b/install_v.sh index ee4f8a2b..e4d8e2e9 100755 --- a/install_v.sh +++ b/install_v.sh @@ -446,9 +446,12 @@ v-install() { v-analyzer() { + set -ex + # Install v-analyzer if requested if [ "$INSTALL_ANALYZER" = true ]; then echo "Installing v-analyzer..." + cd /tmp v download -RD https://raw.githubusercontent.com/vlang/v-analyzer/main/install.vsh # Check if v-analyzer bin directory exists @@ -517,10 +520,7 @@ if [ "$RESET" = true ] || ! command_exists v; then v-install - # Only install v-analyzer if not in GitHub Actions environment - if ! is_github_actions; then - v-analyzer - fi + fi @@ -534,6 +534,10 @@ fi if [ "$INSTALL_ANALYZER" = true ]; then + # Only install v-analyzer if not in GitHub Actions environment + if ! is_github_actions; then + v-analyzer + fi echo "Run 'source ~/.bashrc' or 'source ~/.zshrc' to update PATH for v-analyzer" fi diff --git a/lib/clients/openai/audio.v b/lib/clients/openai/audio.v index 92132ebd..79d5c8d3 100644 --- a/lib/clients/openai/audio.v +++ b/lib/clients/openai/audio.v @@ -114,7 +114,7 @@ fn (mut f OpenAI) create_audio_request(args AudioArgs, endpoint string) !AudioRe @[params] pub struct CreateSpeechArgs { pub: - model ModelType = .tts_1 + model string = "tts_1" input string @[required] voice Voice = .alloy response_format AudioFormat = .mp3 @@ -135,7 +135,7 @@ pub fn (mut f OpenAI) create_speech(args CreateSpeechArgs) ! { mut output_file := os.open_file(args.output_path, 'w+')! req := CreateSpeechRequest{ - model: modelname_str(args.model) + model: args.model input: args.input voice: voice_str(args.voice) response_format: audio_format_str(args.response_format) diff --git a/lib/clients/openai/client_test.v b/lib/clients/openai/client_test.v index c066079c..0a1c2bf8 100644 --- a/lib/clients/openai/client_test.v +++ b/lib/clients/openai/client_test.v @@ -3,14 +3,15 @@ module openai import os fn test_chat_completion() { - key := os.getenv('OPENAI_API_KEY') - heroscript := '!!openai.configure api_key: "${key}"' - - play(heroscript: heroscript)! - mut client := get()! - res := client.chat_completion(.gpt_4o_2024_08_06.str(), Messages{ + client.model_default = 'llama-3.3-70b-versatile' + + println(client.list_models()!) + + raise("sss") + + res := client.chat_completion( Messages{ messages: [ Message{ role: .user @@ -24,82 +25,82 @@ 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}"' +// fn test_embeddings() { +// key := os.getenv('OPENAI_API_KEY') +// heroscript := '!!openai.configure api_key: "${key}"' - play(heroscript: heroscript)! +// play(heroscript: heroscript)! - mut client := get()! +// mut client := get()! - res := client.create_embeddings( - input: ['The food was delicious and the waiter..'] - model: .text_embedding_ada - )! +// 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 -} +// 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}"' +// fn test_files() { +// key := os.getenv('OPENAI_API_KEY') +// heroscript := '!!openai.configure api_key: "${key}"' - play(heroscript: heroscript)! +// play(heroscript: heroscript)! - mut client := get()! - uploaded_file := client.upload_file( - filepath: '${os.dir(@FILE) + '/testdata/testfile.txt'}' - purpose: .assistants - )! +// 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' +// assert uploaded_file.filename == 'testfile.txt' +// assert uploaded_file.purpose == 'assistants' - got_file := client.get_file(uploaded_file.id)! - assert got_file == uploaded_file +// 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 - )! +// 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' +// assert uploaded_file2.filename == 'testfile2.txt' +// assert uploaded_file2.purpose == 'assistants' - mut got_list := client.list_files()! +// mut got_list := client.list_files()! - assert got_list.data.len >= 2 // there could be other older 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 - } +// mut ids := []string{} +// for file in got_list.data { +// ids << file.id +// } - assert uploaded_file.id in ids - assert uploaded_file2.id in ids +// assert uploaded_file.id in ids +// assert uploaded_file2.id in ids - for file in got_list.data { - client.delete_file(file.id)! - } +// for file in got_list.data { +// client.delete_file(file.id)! +// } - got_list = client.list_files()! - assert got_list.data.len == 0 -} +// 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}"' +// fn test_audio() { +// key := os.getenv('OPENAI_API_KEY') +// heroscript := '!!openai.configure api_key: "${key}"' - play(heroscript: heroscript)! +// play(heroscript: heroscript)! - mut client := get()! +// mut client := get()! - // create speech - client.create_speech( - input: 'the quick brown fox jumps over the lazy dog' - output_path: '/tmp/output.mp3' - )! +// // 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') -} +// assert os.exists('/tmp/output.mp3') +// } diff --git a/lib/clients/openai/completions.v b/lib/clients/openai/completions.v index 9b9f1822..e6d44647 100644 --- a/lib/clients/openai/completions.v +++ b/lib/clients/openai/completions.v @@ -48,13 +48,25 @@ mut: messages []MessageRaw } +@[params] +pub struct CompletionArgs{ +pub mut: + model string + msgs Messages + +} + // 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(model_type string, msgs Messages) !ChatCompletion { - mut m := ChatMessagesRaw{ - model: model_type +pub fn (mut f OpenAI) chat_completion(args_ CompletionArgs) !ChatCompletion { + mut args:=args_ + if args.model==""{ + args.model = f.model_default } - for msg in msgs.messages { + mut m := ChatMessagesRaw{ + model: args.model + } + for msg in args.msgs.messages { mr := MessageRaw{ role: roletype_str(msg.role) content: msg.content @@ -62,10 +74,10 @@ pub fn (mut f OpenAI) chat_completion(model_type string, msgs Messages) !ChatCom m.messages << mr } data := json.encode(m) - println('data: ${data}') + // println('data: ${data}') mut conn := f.connection()! r := conn.post_json_str(prefix: 'chat/completions', data: data)! - println('res: ${r}') + // println('res: ${r}') res := json.decode(ChatCompletion, r)! return res diff --git a/lib/clients/openai/model_enums.v b/lib/clients/openai/model_enums.v index b4ff6273..7b3be146 100644 --- a/lib/clients/openai/model_enums.v +++ b/lib/clients/openai/model_enums.v @@ -1,57 +1,5 @@ module openai -pub enum ModelType { - gpt_4o_2024_08_06 - gpt_3_5_turbo - gpt_4 - gpt_4_0613 - gpt_4_32k - gpt_4_32k_0613 - gpt_3_5_turbo_0613 - gpt_3_5_turbo_16k - gpt_3_5_turbo_16k_0613 - whisper_1 - tts_1 -} - -fn modelname_str(e ModelType) string { - return match e { - .tts_1 { - 'tts-1' - } - .gpt_4o_2024_08_06 { - 'gpt-4o-2024-08-06' - } - .gpt_4 { - 'gpt-4' - } - .gpt_3_5_turbo { - 'gpt-3.5-turbo' - } - .gpt_4_0613 { - 'gpt-4-0613' - } - .gpt_4_32k { - 'gpt-4-32k' - } - .gpt_4_32k_0613 { - 'gpt-4-32k-0613' - } - .gpt_3_5_turbo_0613 { - 'gpt-3.5-turbo-0613' - } - .gpt_3_5_turbo_16k { - 'gpt-3.5-turbo-16k' - } - .gpt_3_5_turbo_16k_0613 { - 'gpt-3.5-turbo-16k-0613' - } - .whisper_1 { - 'whisper-1' - } - } -} - pub enum RoleType { system user diff --git a/lib/clients/openai/openai_factory_.v b/lib/clients/openai/openai_factory_.v new file mode 100644 index 00000000..301fc4af --- /dev/null +++ b/lib/clients/openai/openai_factory_.v @@ -0,0 +1,112 @@ +module openai + +import freeflowuniverse.herolib.core.base +import freeflowuniverse.herolib.core.playbook +import freeflowuniverse.herolib.ui.console + +__global ( + openai_global map[string]&OpenAI + openai_default string +) + +/////////FACTORY + +@[params] +pub struct ArgsGet { +pub mut: + name string +} + +fn args_get(args_ ArgsGet) ArgsGet { + mut args := args_ + if args.name == '' { + args.name = 'default' + } + return args +} + +pub fn get(args_ ArgsGet) !&OpenAI { + mut context := base.context()! + mut args := args_get(args_) + mut obj := OpenAI{name:args.name} + if args.name !in openai_global { + if !exists(args)! { + set(obj)! + } else { + heroscript := context.hero_config_get('openai', args.name)! + mut obj_ := heroscript_loads(heroscript)! + set_in_mem(obj_)! + } + } + return openai_global[args.name] or { + println(openai_global) + // bug if we get here because should be in globals + panic('could not get config for openai with name, is bug, was for: ${args.name}') + } +} + +// register the config for the future +pub fn set(o OpenAI) ! { + set_in_mem(o)! + mut context := base.context()! + heroscript := heroscript_dumps(o)! + context.hero_config_set('openai', o.name, heroscript)! +} + +// does the config exists? +pub fn exists(args_ ArgsGet) !bool { + mut context := base.context()! + mut args := args_get(args_) + return context.hero_config_exists('openai', args.name) +} + +pub fn delete(args_ ArgsGet) ! { + mut args := args_get(args_) + mut context := base.context()! + context.hero_config_delete('openai', args.name)! + if args.name in openai_global { + // del openai_global[args.name] + } +} + +// only sets in mem, does not set as config +fn set_in_mem(o OpenAI) ! { + mut o2 := obj_init(o)! + openai_global[o.name] = &o2 + openai_default = o.name +} + +@[params] +pub struct PlayArgs { +pub mut: + heroscript string // if filled in then plbook will be made out of it + plbook ?playbook.PlayBook + reset bool +} + +pub fn play(args_ PlayArgs) ! { + mut args := args_ + + mut plbook := args.plbook or { playbook.new(text: args.heroscript)! } + + mut install_actions := plbook.find(filter: 'openai.configure')! + if install_actions.len > 0 { + for install_action in install_actions { + heroscript := install_action.heroscript() + mut obj2 := heroscript_loads(heroscript)! + set(obj2)! + } + } +} + +// switch instance to be used for openai +pub fn switch(name string) { + openai_default = name +} + +// helpers + +@[params] +pub struct DefaultConfigArgs { + instance string = 'default' +} diff --git a/lib/clients/openai/openai_model.v b/lib/clients/openai/openai_model.v new file mode 100644 index 00000000..5cad7870 --- /dev/null +++ b/lib/clients/openai/openai_model.v @@ -0,0 +1,93 @@ +module openai + +import freeflowuniverse.herolib.data.encoderhero +import freeflowuniverse.herolib.core.httpconnection +import os + +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 + conn ?&httpconnection.HTTPConnection @[skip; str: skip] +} + +// your checking & initialization code if needed +fn obj_init(mycfg_ OpenAI) !OpenAI { + mut mycfg := mycfg_ + if mycfg.api_key==""{ + + mut 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 + } + } + return mycfg +} + +pub fn (mut client OpenAI) connection() !&httpconnection.HTTPConnection { + mut c := client.conn or { + mut c2 := httpconnection.new( + name: 'openaiconnection_${client.name}' + url: client.url + cache: false + retry: 20 + )! + c2 + } + c.default_header.set(.authorization, 'Bearer ${client.api_key}') + client.conn = c + return c +} + + +/////////////NORMALLY NO NEED TO TOUCH + +pub fn heroscript_dumps(obj OpenAI) !string { + return encoderhero.encode[OpenAI](obj)! +} + +pub fn heroscript_loads(heroscript string) !OpenAI { + mut obj := encoderhero.decode[OpenAI](heroscript)! + return obj +} diff --git a/lib/clients/openai/openai_model_.v b/lib/clients/openai/openai_model_.v deleted file mode 100644 index 84ec4640..00000000 --- a/lib/clients/openai/openai_model_.v +++ /dev/null @@ -1,67 +0,0 @@ -module openai - -import freeflowuniverse.herolib.data.paramsparser -import freeflowuniverse.herolib.core.httpconnection -import os - -pub const version = '1.14.3' -const singleton = false -const default = true - -// TODO: THIS IS EXAMPLE CODE AND NEEDS TO BE CHANGED IN LINE TO STRUCT BELOW, IS STRUCTURED AS HEROSCRIPT -pub fn heroscript_default() !string { - heroscript := " - !!openai.configure - name:'openai' - api_key: ${os.getenv('OPENAI_API_KEY')} - " - - return heroscript -} - -// THIS THE THE SOURCE OF THE INFORMATION OF THIS FILE, HERE WE HAVE THE CONFIG OBJECT CONFIGURED AND MODELLED - -pub struct OpenAI { -pub mut: - name string = 'default' - api_key string @[secret] - server_url string - conn ?&httpconnection.HTTPConnection -} - -// fn cfg_play(p paramsparser.Params) ! { -// // THIS IS EXAMPLE CODE AND NEEDS TO BE CHANGED IN LINE WITH struct above -// mut mycfg := OpenAI{ -// name: p.get_default('name', 'default')! -// api_key: p.get('api_key')! -// } -// set(mycfg)! -// } - -fn obj_init(obj_ OpenAI) !OpenAI { - // never call get here, only thing we can do here is work on object itself - mut obj := obj_ - return obj -} - -pub fn (mut client OpenAI) connection() !&httpconnection.HTTPConnection { - server_url := if client.server_url != '' { - client.server_url - } else { - 'https://api.openai.com/v1' - } - mut c := client.conn or { - mut c2 := httpconnection.new( - name: 'openaiconnection_${client.name}' - url: server_url - cache: false - retry: 20 - )! - c2 - } - - c.default_header.set(.authorization, 'Bearer ${client.api_key}') - - client.conn = c - return c -} diff --git a/lib/clients/openai/readme.md b/lib/clients/openai/readme.md index 0b44cc19..64825b53 100644 --- a/lib/clients/openai/readme.md +++ b/lib/clients/openai/readme.md @@ -6,7 +6,7 @@ To get started -import freeflowuniverse.herolib.clients. openai +import freeflowuniverse.herolib.clients.openai mut client:= openai.get()! @@ -20,8 +20,5 @@ client... ## example heroscript ```hero -!!openai.configure - secret: '...' - host: 'localhost' - port: 8888 +!!openai.configure key ``` diff --git a/lib/core/generator/generic/templates/objname_factory_.vtemplate b/lib/core/generator/generic/templates/objname_factory_.vtemplate index a3eb0ff4..2dd51550 100644 --- a/lib/core/generator/generic/templates/objname_factory_.vtemplate +++ b/lib/core/generator/generic/templates/objname_factory_.vtemplate @@ -39,7 +39,7 @@ fn args_get (args_ ArgsGet) ArgsGet { pub fn get(args_ ArgsGet) !&${args.classname} { mut context:=base.context()! mut args := args_get(args_) - mut obj := ${args.classname}{} + mut obj := ${args.classname}{name:args.name} if !(args.name in ${args.name}_global) { if ! exists(args)!{ set(obj)! diff --git a/lib/mcp/README.md b/lib/mcp/README.md index 707ca45c..a2b3328d 100644 --- a/lib/mcp/README.md +++ b/lib/mcp/README.md @@ -43,22 +43,3 @@ config := mcp.ServerConfiguration{ mut server := mcp.new_server(handlers, config)! server.start()! ``` - -## Development Tools - -The module includes several development tools accessible through the `v_do` directory: - -- **test**: Run tests for V files -- **run**: Execute V files -- **compile**: Compile V files -- **vet**: Perform static analysis on V files - -## Dependencies - -- `freeflowuniverse.herolib.schemas.jsonrpc`: For JSON-RPC communication -- `x.json2`: For JSON serialization/deserialization -- Standard V libraries: `time`, `os`, `log` - -## License - -This module is part of the HeroLib project. See the project's license for more information. diff --git a/lib/osal/env.v b/lib/osal/env.v index e302c577..9328de89 100644 --- a/lib/osal/env.v +++ b/lib/osal/env.v @@ -56,6 +56,15 @@ pub fn env_get(key string) !string { return os.environ()[key]! } +pub fn env_exists(key string) !bool { + k:=os.environ() + if key in k{ + return true + } + return false +} + + // Returns the requested environment variable if it exists or returns the provided default value if it does not pub fn env_get_default(key string, def string) string { return os.environ()[key] or { return def }