npm package: @plastichub/osr-ai
Description: AI service prompter
Latest version: 0.1.6

# OSR-AI

AI service prompter

## Installation

1. ```npm i -g @plastichub/osr-ai```
2. create a file with your OpenAI key, in ```C:\\Users\\TeleTubbie\\.config\\osr\\config.json```, with the following content

```json
{
    "openai": {
        "see":"https://platform.openai.com/api-keys"
        "key": "some katbotisch key"
    }
}
```

### CLI parameters

- `--src` : the path to a source file
- `--files` : for binary files as images, please use this instead
- `--dst` : the path to the output file (single quotes!), defaults to `${SRC_DIR}/${SRC_NAME}-output.md`
- `--logLevel` : `warn|info|trace|debug|error|fatal`, defaults to `info`
- `--filters` : a list of filters to be applied
                     `Markdown
                     JSONUnescape
                     JSONPretty
                     AlphaSort
                     code
                     JSONParse
                     trim`
                     defaults to `code` (OpenAI returns Markdown escaped code sequences)
- `--cache` : enable cache, when enabled (default), it skips the request when the destination file already exists
- `--model` : OpenAI model, defaults to `chatgpt-4o-latest`, see official documentation or run `osr-ai chatgpt --help`

### Example, describe the content of a file

```sh
osr-ai chatgpt prompt --source="./tests/chatgpt/pipe.txt" --query="whats in here, add a link to their homepage, check it and add a summary of their activities, as markdown table"
```

**Or**

```sh
osr-ai chatgpt prompt --source=".tests/chatgpt/pipe.txt" --query="./query.md"
```

whereby `./query.md` contains the query : `whats in here, add a link to their homepage, check it and add a summary of their activities, as markdown table`

**Or**

```sh
cat tests/chatgpt/pipe.txt | osr-ai chatgpt prompt  --query="whats in here, add a link to their homepage, check it and add a summary of their activities, as markdown table"
```

whereby pipe.txt contains

```txt
abb
bigtree
cead
cidepa
kuga
motovario
nagami
siemens
teknic
```

**Output**

| Company  | Homepage                                      | Summary                                                 |
|----------|-----------------------------------------------|---------------------------------------------------------|
| abb      | [Homepage](https://www.abb.com)                | ABB is a leading global technology company. They focus on electrification, robotics, and automation solutions. |
| bigtree  | [Homepage](https://www.bigtree.com)            | Bigtree is a software development company specializing in web and mobile applications. |
| cead     | [Homepage](https://www.cead.com)               | CEAD is a company that specializes in 3D printing and additive manufacturing solutions. |
| cidepa   | [Homepage](https://www.cidepa.com)             | Cidepa is a manufacturer of industrial machinery and equipment. |
| kuga     | [Homepage](https://www.kuga.com)               | Kuga is an automotive company that designs and manufactures electric vehicles. |
| motovario | [Homepage](https://www.motovario.com)          | Motovario is a global manufacturer of power transmission and motion control solutions. |
| nagami   | [Homepage](https://www.nagami.design)          | Nagami is a design studio specializing in computational design and digital fabrication. |
| siemens  | [Homepage](https://www.siemens.com)            | Siemens is a multinational conglomerate that provides a wide range of products and services in various industries. |
| teknic   | [Homepage](https://www.teknic.com)             | Teknic is a manufacturer of high-performance motion control products. |

---

## Example, describe the content of an image ([Example](./tests/chatgpt/files/2.jpg))

```sh
osr-ai chatgpt prompt --files='./tests/chatgpt/files/2.jpg' --query="whats in here, as json" --dst='&{FILE_DIR}/&{FILE_NAME}-content.json`
```

output

```json
{
  "image": {
    "people": [
      {
        "handle": "@judi_wakhungu",
        "position": "left",
        "description": "A person wearing an orange shirt, a hat, and glasses, holding a phone."
      },
      {
        "handle": null,
        "position": "center",
        "description": "A person standing in the doorway, wearing a white shirt and a cap."  
      },
      {
        "handle": "@katatungo",
        "position": "right",
        "description": "A person wearing a white t-shirt with text, and black pants."        
      }
    ],
    "textOverlay": "This door is not painted...",
    "door": {
      "description": "A rustic, two-part wooden door with blue and teal hues and a gold latch."
    },
    "tags": [
      "@katatungo",
      "@judi_wakhungu"
    ]
  }
}
```

## Example, transform code
```sh
osr-ai chatgpt prompt --source="./tests/chatgpt/constants.ts" --query="rewrite this enum as object literal" --model=gpt-4 --debug
```

whereby ```./tests/chatgpt/constants.ts``` contains

```ts
export enum SpainCities {
    Madrid = "40.4168,-3.7038,12",
    Barcelona = "41.3851,2.1734,12",
    Valencia = "39.4699,-0.3763,12",
    Seville = "37.3891,-5.9845,12",
    Malaga = "36.7213,-4.4214,12",
    Bilbao = "43.2630,-2.9340,12",
    Alicante = "38.3452,-0.4810,12",
    Zaragoza = "41.6488,-0.8891,12",
    Palma = "39.5696,2.6502,12",
    Murcia = "37.9922,-1.1307,12",
    Granada = "37.1773,-3.5986,12",
    Cordoba = "37.8882,-4.7794,12",
    Valladolid = "41.6520,-4.7286,12",
    Vigo = "42.2406,-8.7207,12",
    Gijon = "43.5322,-5.6611,12",
    Lleida = "41.6176,0.6200,12",
    Tarragona = "41.1189,1.2445,12",
    Cadiz = "36.5297,-6.2924,12",
    Almeria = "36.8340,-2.4637,12",
    Oviedo = "43.3614,-5.8593,12",
    Badajoz = "38.8794,-6.9706,12",
    Santander = "43.4623,-3.8090,12",
    Logrono = "42.4627,-2.4441,12",
    Salamanca = "40.9701,-5.6635,12",
    Pamplona = "42.8125,-1.6458,12",
}
```

**Output**
```ts
export const BarcelonaTowns = {
    Barcelona: "41.3850639,2.1734035",
    Badalona: "41.453966,2.24487",
    "L'HospitaletDeLlobregat": "41.3618046,2.0977132",
    Terrassa: "41.5654824,2.0109316",
    Sabadell: "41.5441063,2.1068342",
    Mataro: "41.540977,2.4440367",
    SantaColomaDeGramenet: "41.4679772,2.2081475",
    CornellaDeLlobregat: "41.3666298,2.0971758",
    SantCugatDelValles: "41.4888889,2.1019444",
    Castelldefels: "41.2755556,1.995",
    CerdanyolaDelValles: "41.4913889,2.1169444",
    Granollers: "41.6072222,2.2686111",
    VilanovaIGeltru: "41.2155556,1.7383333",
    Viladecans: "41.3163889,2.0052778",
    ElPratDeLlobregat: "41.2971628,2.0700942",
    MolletDelValles: "41.5272964,2.1870736",
    Gava: "41.3166667,2.0666667",
    SantBoiDeLlobregat: "41.3669444,2.0569444",
}
```

## Example, transcribe an audio file, to text

```sh
osr-ai chatgpt transcribe --debug --source="./tests/chatgpt/real.mp3" --dst="./tests/chatgpt/real.txt"
```

## Example, create code for SCAD

```sh
osr-ai chatgpt prompt --query="create a scene, with all possible primitives, lined up along one line, for SCAD" --model=gpt-4 --dst="./tests/chatgpt/primitives.scad" --system="./tests/chatgpt/scad-system.json"
```

whereby ```./tests/chatgpt/scad-system.json``` refers to the OpenAI assistant instructions, helping to reuse optimizations and rules:
```json
[
    {
        "role": "system",
        "content": "don't add footer comments"
    },
    {
        "role": "system",
        "content": "don't wrap it in markdown codeblocks"
    },
    {
        "role": "system",
        "content": "don't add header or footer notes" 
    },
    {
        "role": "system",
        "content": "comment all SCAD functions" 
    }  
]
```

**Output** (works perfectly :)

```scad
//Create a cube with side length 10 at origin
translate([-35, 0, 0])  
cube(10, center = true);  

//Create a sphere with diameter 10 at coordinate (20,0,0)
translate([-15, 0, 0])  
sphere(5); 

//Create a cylinder with height 10, lower diameter 10, upper diameter 5 at coordinate (40,0,0)
translate([5, 0, 0])  
cylinder(h = 10, r1 = 5, r2 = 2.5, center = true);   

//Create a polyhedron with vertices at (0,0,0), (10,0,0), (0,10,0), and (0,0,10) at coordinate (60,0,0)
translate([25, 0, 0]) 
polyhedron(points=[[-5,-5,-5],[5,-5,-5],[-5,5,-5],[0,0,5]], faces=[[0,1,2],[0,2,3],[0,3,1],[1,3,2]]); 
```

### Example, summarize the code from above

```sh
osr-ai chatgpt prompt --source="./tests/chatgpt/primitives.scad" --model=gpt-4 --dst="./tests/chatgpt/primitives-next.scad" --system="./tests/chatgpt/scad-system.json" --query="whats this code doing, it's for OpenSCAD"
```

**Output**

```
This OpenSCAD code does the following:

- Creates a cube with a side length of 10 at the origin, translated from the origin by -35 units along the X-axis. The cube is centered at this new location. 

- Creates a sphere with a diameter of 10 units, translated from the origin by -15 units along the X-axis.

- Creates a cylinder with a height of 10 units, a lower diameter of 10 units, and an upper diameter of 5 units. This is translated from the origin by 5 units along the X-axis, and the cylinder is centered at its location.

- Creates a polyhedron with vertices defined by the points (0,0,0), (10,0,0), (0,10,0), and (0,0,10). It is translated from the origin by 25 units along the X-axis.

In summary, the code creates a sequence of four different 3D geometric forms (a cube, a sphere, a cylinder, and a polyhedron). Each shape is positioned in a line along the X-axis with specifically defined spaces between them.
```


### Example, convert C code to Javascript

```sh
osr-ai chatgpt prompt --source="./tests/chatgpt/math_statistics.h" --model=gpt-4 --dst="./tests/chatgpt/math_statistics.js" --system="./tests/chatgpt/scad-system.json" --query="Write it as Javascript"
```

whereby math_statistics.h is 
```
// C++11 solution that is standards compliant. Return type is deduced automatically
template <class L, class R>
static inline constexpr auto MIN(const L lhs, const R rhs) -> decltype(lhs + rhs)
{
  return lhs < rhs ? lhs : rhs;
}
template <class L, class R>
static inline constexpr auto MAX(const L lhs, const R rhs) -> decltype(lhs + rhs)
{
  return lhs > rhs ? lhs : rhs;
}
template <class T>
static inline constexpr const T ABS(const T v)
{
  return v >= 0 ? v : -v;
}
#else
// Using GCC extensions, but Travis GCC version does not like it and gives
//  "error: statement-expressions are not allowed outside functions nor in template-argument lists"
#define MIN(a, b) \
  ({__typeof__(a) _a = (a); \
      __typeof__(b) _b = (b); \
      _a < _b ? _a : _b; })

#define MAX(a, b) \
  ({__typeof__(a) _a = (a); \
      __typeof__(b) _b = (b); \
      _a > _b ? _a : _b; })

#define ABS(a) \
  ({__typeof__(a) _a = (a); \
      _a >= 0 ? _a : -_a; })

#endif

class Statistic
{
public:
  Statistic();  // "switches on/off" stdev run time
  void clear(); // "switches on/off" stdev run time
  void add(const float);

  // returns the number of values added
  uint32_t count() const { return _cnt; }; // zero if empty
  float sum() const { return _sum; };      // zero if empty
  float minimum() const { return _min; };  // zero if empty
  float maximum() const { return _max; };  // zero if empty
  float average() const;                   // NAN if empty
  float mean() const;                      // zero if empty

#ifdef STAT_USE_STDEV
  float variance() const;       // NAN if empty
  float pop_stdev() const;      // population stdev  // NAN if empty
  float unbiased_stdev() const; // NAN if empty
#endif

protected:
  uint32_t _cnt;
  float _sum;
  float _min;
  float _max;
#ifdef STAT_USE_STDEV
  float _ssqdif; // sum of squares difference
#endif
};
```

**Output**

```javascript
class Statistics {
  constructor() {
    this._cnt = 0;
    this._sum = 0;
    this._min = null;
    this._max = null;
    this._ssqdif = 0;
  }

  clear() {
    this._cnt = 0;
    this._sum = 0;
    this._min = null;
    this._max = null;
    this._ssqdif = 0;
  }

  add(value) {
    if (typeof this._min === 'undefined' || this._min > value) this._min = value;
    if (typeof this._max === 'undefined' || this._max < value) this._max = value;
    this._sum += value;
    this._cnt += 1;
    this._ssqdif += value * value; // for variance and stdev
  }

  count() {
    return this._cnt;
  }

  sum() {
    return this._sum;
  }

  minimum() {
    return this._min;
  }

  maximum() {
    return this._max;
  }

  average() {
    return this._cnt ? (this._sum / this._cnt) : NaN;
  }

  mean() {
    return this.average();
  }

  variance() {
    if (!this._cnt) return NaN;
    let mean = this.average();
    return (this._ssqdif - 2 * mean * this._sum + this._cnt * mean * mean) / this._cnt;
  }

  pop_stdev() {
    return Math.sqrt(this.variance());
  }

  unbiased_stdev() {
    if (this._cnt < 2) return NaN;
    let mean = this.average();
    return Math.sqrt((this._ssqdif - 2 * mean * this._sum + this._cnt * mean * mean) / (this._cnt - 1));
  }
}

function min(lhs, rhs) {
  return lhs < rhs ? lhs : rhs;
}
function max(lhs, rhs) {
  return lhs > rhs ? lhs : rhs;
}
function abs(v) {
  return v >= 0 ? v : -v;
}
```

### Example, lets get cozy, find some hotels on a lonely island, for a lonely rider :)

```sh
osr-ai chatgpt prompt --model=gpt-4 --dst="./tests/chatgpt/hotels.md" --query="Create a list of hotels, on Lamu, Kenya. Create a markdown bullet list, with price, link, and a link on GoogleMaps - add average rating"
```

**Output**

- Price: $200 per night
  - [Booking Link](http://www.lamuhouse.com/)
  - [Google Maps Location](https://goo.gl/maps/cZzYZ4BDppS2)
  - Average Rating: 4.5/5

* __Majlis Resort__
  - Price: $350 per night
  - [Booking Link](http://www.themajlisresorts.com/)
  - [Google Maps Location](https://goo.gl/maps/9UZGJNMCASF2)
  - Average Rating: 4.7/5

* __Forodhani House__
  - Price: $150 per night
  - [Booking Link](http://www.forodhanihouse.com/)
  - [Google Maps Location](https://goo.gl/maps/N7Zo8o8zRc32)
  - Average Rating: 4.2/5

* __Baytil Ajaib__
  - Price: $100 per night
  - [Booking Link](http://www.baytilajaib.com)
  - [Google Maps Location](https://goo.gl/maps/6W9VJhBbMHT2)
  - Average Rating: 4.8/5

* __Petley's Inn__
  - Price: $50 per night
  - [Booking Link](http://www.petleysinn.com/)
  - [Google Maps Location](https://goo.gl/maps/v3JFSgjSvXY6ez5u8)
  - Average Rating: 3.7/5
## Todos

## ChatGPT

- [x] model select
- [ ] loaders
- [ ] language system defaults
- [ ] output templates
- [ ] auto-functions, eg "create file , ... "
- [ ] support Urls, for source, and stdin

## OSR Todos

- [ ] Loader (mime/glob) -> storage (mem, mongo,...) -> query -> cache
- [ ] session cache (chat history replay)

## References

### API Shit

- [JSON Schema to TS](https://www.npmjs.com/package/json-schema-to-ts)

### OpenAI

- [Docs](https://platform.openai.com/docs/overview)

### Google

- [Inpaint](https://cloud.google.com/vertex-ai/generative-ai/docs/image/edit-inpainting)

### Google Gemini

- [Intro Model Tuning](https://ai.google.dev/gemini-api/docs/model-tuning)
- [Function Calling](https://ai.google.dev/gemini-api/docs/function-calling/tutorial?lang=node)

### LLM Tooling

- [langchain - loaders](https://js.langchain.com/docs/integrations/document_loaders/file_loaders/)

### Misc

- [Voice control for VScode](https://serenade.ai/docs#command-modes)

### Images

- [ml-mgie (modifier)](https://github.com/apple/ml-mgie?tab=readme-ov-file)