ai-functions 0.0.4 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/example.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AI } from './ai.js'
1
+ import { AI } from './proxy.js'
2
2
 
3
3
  const { ai, list, gpt } = AI()
4
4
 
@@ -16,11 +16,23 @@ const writeBlogPost = title => gpt`write a blog post in markdown starting with "
16
16
 
17
17
  async function* writeBlog(count, topic) {
18
18
  for await (const title of listBlogPosts(count, topic)) {
19
- const content = await writeBlogPost(title)
20
- yield { title, content }
19
+ const contentPromise = writeBlogPost(title).then(content => {
20
+ console.log({ title, content })
21
+ return { title, content }
22
+ })
23
+ yield { title, contentPromise }
21
24
  }
22
25
  }
23
26
 
24
- for await (const post of writeBlog(5, 'future of car sales')) {
27
+ for await (const post of writeBlog(3, 'future of car sales')) {
25
28
  console.log({ post })
26
- }
29
+ }
30
+
31
+ const product = await ai.categorizeProduct({ domain: 'OpenSaaS.org' }, {
32
+ productType: 'App | API | Marketplace | Platform | Packaged Service | Professional Service | Website',
33
+ customer: 'ideal customer profile in 3-5 words',
34
+ solution: 'describe the offer in 4-10 words',
35
+ description: 'website meta description',
36
+ })
37
+
38
+ console.log({ product })
package/fetcher.js ADDED
@@ -0,0 +1,48 @@
1
+ const headers = {
2
+ 'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
3
+ 'Content-Type': 'application/json',
4
+ }
5
+ const openaiFetch = obj => fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers, body: JSON.stringify(obj) }).then(res => res.json())
6
+
7
+ const openaiStream = obj => fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers, body: JSON.stringify(obj) })
8
+
9
+
10
+ const response = await openaiStream({
11
+ model: 'gpt-3.5-turbo',
12
+ messages: [{ role: 'user', content: 'Tell me a funny joke about OpenAI' }],
13
+ stream: true
14
+ })
15
+
16
+ const decoder = new TextDecoder('utf-8')
17
+ let completion = ''
18
+
19
+ try {
20
+ for await (const chunk of response.body) {
21
+ let done = false
22
+ const currentChunk = decoder.decode(chunk)
23
+ const lines = currentChunk.split('\n').filter(Boolean)
24
+ // console.log(lines)
25
+ for (const line of lines) {
26
+ if (line.includes('[DONE]')) {
27
+ done = true
28
+ break
29
+ }
30
+ try {
31
+ const data = JSON.parse(line.replace('data: ', ''))
32
+ if (data.choices[0].delta.content) {
33
+ const deltaContent = data.choices[0].delta.content
34
+ completion += deltaContent
35
+ console.log(deltaContent)
36
+ }
37
+ // console.log(chunks)
38
+ } catch (error) {
39
+ console.log(error.message, line)
40
+ }
41
+ }
42
+ if (done) break
43
+ }
44
+ } catch (err) {
45
+ console.error(err.stack);
46
+ }
47
+ console.log({ completion })
48
+
package/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export * from './ai.js'
1
+ export * from './proxy.js'
2
2
  export * from './schema.js'
3
3
  export * from './withAI.js'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-functions",
3
- "version": "0.0.4",
3
+ "version": "0.1.0",
4
4
  "description": "Library for Developing and Managing AI Functions (including OpenAI GPT4 / GPT3.5)",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -1,13 +1,18 @@
1
- import { OpenAI } from 'openai'
2
- import camelcaseKeys from 'camelcase-keys'
1
+ // import { OpenAI } from 'openai'
2
+ // import camelcaseKeys from 'camelcase-keys'
3
3
  import { dump } from 'js-yaml'
4
4
  import { schema } from './schema.js'
5
5
 
6
6
  export const AI = opts => {
7
7
  const { system, model = 'gpt-3.5-turbo', apiKey, OPENAI_API_KEY, ...rest } = opts || {}
8
8
 
9
- const openai = new OpenAI({ apiKey: apiKey ?? OPENAI_API_KEY, ...rest })
10
-
9
+ // const openai = new OpenAI({ apiKey: apiKey ?? OPENAI_API_KEY, ...rest })
10
+ const headers = {
11
+ 'Authorization': `Bearer ${apiKey ?? OPENAI_API_KEY ?? globalThis.process?.env?.OPENAI_API_KEY}`,
12
+ 'Content-Type': 'application/json',
13
+ }
14
+ const openaiFetch = obj => fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers, body: JSON.stringify(obj) }).then(res => res.json())
15
+
11
16
  const gpt = async (strings, ...values) => {
12
17
  const user = values.map((value, i) => strings[i] + value).join('') + strings[strings.length - 1]
13
18
  const prompt = {
@@ -17,7 +22,7 @@ export const AI = opts => {
17
22
  ],
18
23
  }
19
24
  if (system) prompt.messages.unshift({ role: 'system', content: system })
20
- const completion = await openai.chat.completions.create(prompt)
25
+ const completion = await openaiFetch(prompt)
21
26
  return completion.choices?.[0].message.content
22
27
  }
23
28
 
@@ -39,7 +44,7 @@ export const AI = opts => {
39
44
  ...rest,
40
45
  }
41
46
  if (system) prompt.messages.unshift({ role: 'system', content: system })
42
- const completion = await openai.chat.completions.create(prompt)
47
+ const completion = await openaiFetch(prompt)
43
48
  let data, error
44
49
  const { message } = completion.choices?.[0]
45
50
  prompt.messages.push(message)
@@ -55,7 +60,7 @@ export const AI = opts => {
55
60
  const cost = Math.round((gpt4
56
61
  ? completion.usage.prompt_tokens * 0.003 + completion.usage.completion_tokens * 0.006
57
62
  : completion.usage.prompt_tokens * 0.00015 + completion.usage.completion_tokens * 0.0002) * 100000) / 100000
58
- completion.usage = camelcaseKeys(completion.usage)
63
+ // completion.usage = camelcaseKeys(completion.usage)
59
64
  console.log({ data, content, error, cost })
60
65
  return meta ? { prompt, content, data, error, cost, ...completion } : data ?? content
61
66
  }
@@ -70,36 +75,47 @@ export const AI = opts => {
70
75
  stream: true,
71
76
  }
72
77
  if (system) prompt.messages.unshift({ role: 'system', content: system })
73
- const stream = await openai.chat.completions.create(prompt)
78
+ const response = await fetch('https://api.openai.com/v1/chat/completions', { method: 'POST', headers, body: JSON.stringify(prompt) })
79
+ const decoder = new TextDecoder('utf-8')
80
+
74
81
  let content = ''
75
82
  let seperator = undefined
76
83
  let numberedList = undefined
77
84
 
78
- for await (const part of stream) {
79
- const { delta, finish_reason } = part.choices[0]
80
- content += delta?.content || ''
81
- if (seperator === undefined && content.length > 4) {
82
- numberedList = content.match(/(\d+\.\s)/g)
83
- seperator = numberedList ? '\n' : ', '
84
- }
85
+ for await (const chunk of response.body) {
86
+ const lines = decoder.decode(chunk).split('\n').filter(Boolean)
87
+ for (const line of lines) {
88
+ try {
89
+ if (line.includes('[DONE]')) break
90
+ const part = JSON.parse(line.replace('data: ', ''))
91
+ const { delta, finish_reason } = part.choices[0]
92
+ content += delta?.content || ''
93
+ if (seperator === undefined && content.length > 4) {
94
+ numberedList = content.match(/(\d+\.\s)/g)
95
+ seperator = numberedList ? '\n' : ', '
96
+ }
97
+
98
+ const numberedRegex = /\d+\.\s(?:")?([^"]+)(?:")?/
85
99
 
86
- const numberedRegex = /\d+\.\s(?:")?([^"]+)(?:")?/
100
+ if (content.includes(seperator)) {
101
+ // get the string before the newline, and modify `content` to be the string after the newline
102
+ // then yield the string before the newline
103
+ const items = content.split(seperator)
104
+ while (items.length > 1) {
105
+ const item = items.shift()
106
+ yield numberedList ? item.match(numberedRegex)?.[1] : item
107
+ }
108
+ content = items[0]
109
+ }
87
110
 
88
- if (content.includes(seperator)) {
89
- // get the string before the newline, and modify `content` to be the string after the newline
90
- // then yield the string before the newline
91
- const items = content.split(seperator)
92
- while (items.length > 1) {
93
- const item = items.shift()
94
- yield numberedList ? item.match(numberedRegex)?.[1] : item
111
+ if (finish_reason) yield numberedList ? content.match(numberedRegex)?.[1] : content
112
+ } catch (error) {
113
+ console.log(error.message, line)
95
114
  }
96
- content = items[0]
97
115
  }
98
-
99
- if (finish_reason) yield numberedList ? content.match(numberedRegex)?.[1] : content
100
116
  }
101
117
 
102
118
  }
103
119
 
104
- return { ai, list, gpt, openai }
120
+ return { ai, list, gpt }
105
121
  }
package/withAI.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AI } from './ai.js'
1
+ import { AI } from './proxy.js'
2
2
 
3
3
  export const withAI = options => (req, env) => {
4
4
  const { ai, gpt, list } = AI({ apiKey: env.OPENAI_API_KEY, ...options })
File without changes