Skip to content

Commit

Permalink
feat(rune): extend soul companion with openai
Browse files Browse the repository at this point in the history
  • Loading branch information
dasein108 committed Jun 30, 2024
1 parent fc508fc commit 9ea833d
Show file tree
Hide file tree
Showing 14 changed files with 157 additions and 79 deletions.
7 changes: 5 additions & 2 deletions docs/scripting.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,14 @@ cyb::search_by_embedding(text:string, count: int) -> string[];

#### Experemental

OpenAI promts(beta, in developement)
OpenAI promts(beta)

- api key should be added using cyb-keys
- this is wrapper around [openai api](https://platform.openai.com/docs/api-reference/chat/create)

```
// Apply prompt OpenAI and get result
cyb::open_ai_prompt(prompt: string; params: json) -> string;
cyb::open_ai_completions(messages: object[]; apiKey: string; params: json) -> string | AsyncIterable<string>;
```

#### Debug
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@
"core-js": "^3.30.0",
"crypto": "^1.0.1",
"cyb-cozo-lib-wasm": "^0.7.145",
"cyb-rune-wasm": "^0.0.84",
"cyb-rune-wasm": "^0.0.841",
"datastore-core": "^9.2.3",
"datastore-idb": "^2.1.4",
"dateformat": "^3.0.3",
Expand Down
34 changes: 18 additions & 16 deletions src/containers/ipfs/components/SoulCompanion/SoulCompanion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function SoulCompanion({
if (details.type && details.type !== 'text' && details.text) {
setStatus('done');
setMetaItems([
{ type: 'text', text: `Skip companion for '${details.content}'.` },
[{ type: 'text', text: `Skip companion for '${details.content}'.` }],
]);
return;
}
Expand Down Expand Up @@ -65,21 +65,23 @@ function SoulCompanion({
);
}
return (
<div>
<ul className={styles.itemLinks}>
{metaItems.map((item, index) => (
<li key={`soul_comp_${index}`}>
{item.type === 'text' && (
<p className={styles.itemText}>{item.text}</p>
)}
{item.type === 'link' && (
<Link className={styles.itemLink} to={item.url}>
{shortenString(item.title, 64)}
</Link>
)}
</li>
))}
</ul>
<div className={styles.soulCompanion}>
{metaItems.map((row, index) => (
<ul className={styles.itemLinks} key={`soul_comp_row_${index}`}>
{row.map((item, index) => (
<li key={`soul_comp_col_${index}`}>
{item.type === 'text' && (
<p className={styles.itemText}>{item.text}</p>
)}
{item.type === 'link' && (
<Link className={styles.itemLink} to={item.url}>
{shortenString(item.title, 64)}
</Link>
)}
</li>
))}
</ul>
))}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
.itemLinks {
display: flex;
margin: -10px 0;

list-style-type: none;
font-size: 14px;
}

.soulCompanion {
margin: -10px 0;
}

.itemText {
font-size: 14px;
display: block;
Expand Down
42 changes: 27 additions & 15 deletions src/contexts/scripting/scripting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,17 @@ function ScriptingProvider({ children }: { children: React.ReactNode }) {
const dispatch = useAppDispatch();

useEffect(() => {
runeBackend.pushContext('secrets', secrets);

const setupObservervable = async () => {
const { isSoulInitialized$ } = runeBackend;

const soulSubscription = (await isSoulInitialized$).subscribe((v) => {
setIsSoulInitialized(!!v);
if (v) {
runeRef.current = runeBackend;
console.log('👻 soul initalized');
}
setIsSoulInitialized(!!v);
});

const embeddingApiSubscription = (await embeddingApi$).subscribe(
Expand All @@ -72,28 +74,38 @@ function ScriptingProvider({ children }: { children: React.ReactNode }) {
};

setupObservervable();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

const runeEntryPoints = useAppSelector(selectRuneEntypoints);

const citizenship = useAppSelector(selectCurrentPassport);
const secrets = useAppSelector((state) => state.scripting.context.secrets);

useEffect(() => {
(async () => {
if (citizenship) {
const particleCid = citizenship.extension.particle;
if (!isSoulInitialized || !runeRef.current) {
return;
}

if (citizenship) {
const particleCid = citizenship.extension.particle;

runeRef.current.pushContext('user', {
address: citizenship.owner,
nickname: citizenship.extension.nickname,
citizenship,
particle: particleCid,
} as UserContext);
} else {
runeRef.current.popContext(['user']);
}
}, [citizenship, isSoulInitialized]);

await runeBackend.pushContext('user', {
address: citizenship.owner,
nickname: citizenship.extension.nickname,
citizenship,
particle: particleCid,
} as UserContext);
} else {
await runeBackend.popContext(['user', 'secrets']);
}
})();
}, [citizenship, runeBackend]);
useEffect(() => {
if (isSoulInitialized && runeRef.current) {
runeRef.current.pushContext('secrets', secrets);
}
}, [secrets, isSoulInitialized]);

useEffect(() => {
(async () => {
Expand Down
2 changes: 1 addition & 1 deletion src/features/ipfs/Drive/BackendStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { downloadJson } from 'src/utils/json';
import { useBackend } from 'src/contexts/backend/backend';
import { EmbeddinsDbEntity } from 'src/services/CozoDb/types/entities';
import { isObject } from 'lodash';
import { promptToOpenAI } from 'src/services/scripting/services/llmRequests/openai';
import { openAICompletion } from 'src/services/scripting/services/llmRequests/openai';

const getProgressTrackingInfo = (progress?: ProgressTracking) => {
if (!progress) {
Expand Down
2 changes: 1 addition & 1 deletion src/redux/reducers/scripting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const initialScriptEntrypoints: ScriptEntrypoints = {

const initialState: SliceState = {
context: {
secrets: loadJsonFromLocalStorage('secrets', {}) as TabularKeyValues,
secrets: loadJsonFromLocalStorage('secrets', {}),
params: {},
user: {},
},
Expand Down
13 changes: 5 additions & 8 deletions src/services/scripting/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,9 @@ function enigine() {

const pushContext = <K extends keyof ScriptContext>(
name: K,
value: ScriptContext[K] | TabularKeyValues
value: ScriptContext[K] //| TabularKeyValues
) => {
if (name === 'secrets') {
context[name] = toRecord(value as TabularKeyValues);
return;
}

// context[name] = toRecord(value as TabularKeyValues);
context[name] = value;
};

Expand Down Expand Up @@ -151,6 +147,7 @@ function enigine() {
params: scriptParams,
};

// console.log('-----run', scriptParams);
const outputData = await compile(compilerParams, compileConfig);

// Parse the JSON string
Expand Down Expand Up @@ -270,7 +267,7 @@ function enigine() {
if (resultType === 'error') {
return {
action: 'error',
metaItems: [{ type: 'text', text: 'No particle entrypoint' }],
metaItems: [[{ type: 'text', text: 'No particle entrypoint' }]],
};
}

Expand All @@ -291,7 +288,7 @@ function enigine() {
console.error('---askCompanion error', output);
return {
action: 'error',
metaItems: [{ type: 'text', text: output.error }],
metaItems: [[{ type: 'text', text: output.error }]],
};
}

Expand Down
3 changes: 3 additions & 0 deletions src/services/scripting/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Nullable } from 'src/types';
import { v4 as uuidv4 } from 'uuid';

export async function getScriptFromParticle(cid?: Nullable<string>) {
throw new Error('Not implemented');
Expand Down Expand Up @@ -50,3 +51,5 @@ export function extractRuneScript(markdown: string) {
// if no rune tag, consider this like pure script
return hasRune ? script : md;
}

export const generateRefId = () => uuidv4().toString();
20 changes: 19 additions & 1 deletion src/services/scripting/rune/default/particle.rn
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub async fn moon_domain_resolver() {
pub async fn ask_companion(cid, content_type, content) {
// plain text item
let links = [meta_text("similar: ")];
let rows = [links];

// search closest 5 particles using local data from the brain
let similar_results = cyb::search_by_embedding(content, 5).await;
Expand All @@ -37,7 +38,24 @@ pub async fn ask_companion(cid, content_type, content) {
links = [meta_text("no similar particles found")];
}

return content_result(links)
let secrets = cyb::context.secrets;
if let Some(api_key) = secrets.get("openAI_key") {
let messages = [
#{
"role": "system",
"content": "You should give description or summary of any content. aswer should not exceed 32 words"
},
#{
"role": "user",
"content": content
}
];

let inference = cyb::open_ai_completions(messages, api_key, #{"model": "gpt-3.5-turbo"}).await;
rows.push([meta_text(`inference: ${inference}`)]);
}

return content_result(rows)
}

// Transform content of the particle
Expand Down
89 changes: 65 additions & 24 deletions src/services/scripting/services/llmRequests/openai.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,76 @@
/* eslint-disable import/prefer-default-export */
/* eslint-disable import/no-unused-modules */
import axios from 'axios';
import axios, { ResponseType } from 'axios';

// https://platform.openai.com/docs/models/overview
// gpt-3.5-turbo

// https://platform.openai.com/docs/api-reference/chat/create
export const promptToOpenAI = async (
prompt: string,
type OpenAiMessage = {
role: 'system' | 'user' | 'assistant';
content: string;
};

interface OpenAIParams {
model: string;
messages: OpenAiMessage[];
[key: string]: any;
}

const defaultOpenAIParams: Partial<OpenAIParams> = {
model: 'gpt-3.5-turbo',
};

export const openAICompletion = async (
messages: OpenAiMessage[],
apiKey: string,
params: any = {
model: 'text-davinci-003', // 'gpt-3.5-turbo',
maxTokens: 500,
stop: '.',
n: 1,
}
) => {
//prompt: `Complete this sentence: "${input}"`,
const response = await axios.post(
'https://api.openai.com/v1/completions',
{
prompt,
params: Partial<OpenAIParams> = {}
): Promise<string | AsyncIterable<string>> => {
const requestOptions = {
method: 'post',
url: 'https://api.openai.com/v1/chat/completions',
data: {
messages,
...defaultOpenAIParams,
...params,
},
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
},
responseType: (params.stream ? 'stream' : 'json') as ResponseType,
};

const response = await axios(requestOptions);

if (!params.stream) {
// Non-streaming request
console.log('response', response);
return response.data.choices[0].message.content;
} else {
// Streaming request
const asyncIterable: AsyncIterable<string> = {
[Symbol.asyncIterator]: async function* () {
let result = '';
for await (const chunk of response.data) {
const str = chunk.toString();
const lines = str.split('\n').filter((line) => line.trim() !== '');
for (const line of lines) {
const message = line.replace(/^data: /, '');
if (message === '[DONE]') {
return;
}
try {
const parsed = JSON.parse(message);
result += parsed.choices[0].delta.content;
yield parsed.choices[0].delta.content;
} catch (error) {
console.error('Error parsing stream message:', message, error);
}
}
}
},
}
);
console.log('response', response);
return response.data.choices[0].text;
};

return asyncIterable;
}
};
2 changes: 1 addition & 1 deletion src/services/scripting/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ type MetaTextComponent = {

type ScriptMyCampanion = {
action: 'pass' | 'answer' | 'error';
metaItems: (MetaLinkComponent | MetaTextComponent)[];
metaItems: (MetaLinkComponent | MetaTextComponent)[][];
};

// type ScriptScopeParams = {
Expand Down
7 changes: 3 additions & 4 deletions src/services/scripting/wasmBindings.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable import/no-unused-modules */
import { getFromLink, getToLink } from 'src/utils/search/utils';
import runeDeps from './runeDeps';
import { promptToOpenAI } from './services/llmRequests/openai';
import { openAICompletion } from './services/llmRequests/openai';

// let runeDeps;

Expand Down Expand Up @@ -34,9 +34,8 @@ export async function jsAddContenToIpfs(content) {
return runeDeps.addContenToIpfs(content);
}

export async function jsPromptToOpenAI(prompt, apiKey, params, refId) {
console.log('jsPromptToOpenAI', prompt, apiKey, params, refId);
const result = await promptToOpenAI(prompt, apiKey, params);
export async function jsOpenAICompletions(messages, apiKey, params, refId) {
const result = await openAICompletion(messages, apiKey, params);
return result;
}

Expand Down
Loading

0 comments on commit 9ea833d

Please sign in to comment.