cyb/src/features/ipfs/Drive/index.tsx

import { Pane } from '@cybercongress/gravity';
import classNames from 'classnames';
import { saveAs } from 'file-saver';
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import { Button, Button as CybButton, Input, Select } from 'src/components';
import Display from 'src/components/containerGradient/Display/Display';
import { Colors } from 'src/components/containerGradient/types';
import Table from 'src/components/Table/Table';

import { useBackend } from 'src/contexts/backend/backend';
import { useDevice } from 'src/contexts/device';
import { useScripting } from 'src/contexts/scripting/scripting';
import { toListOfObjects } from 'src/services/CozoDb/utils';
import BackendStatus from './BackendStatus';
import cozoPresets from './cozo_presets.json';
import styles from './drive.scss';
import FileInputButton from './FileInputButton';

const DEFAULT_PRESET_NAME = '๐Ÿ’ก defaul commands...';

const presetsAsSelectOptions = [
  { text: DEFAULT_PRESET_NAME, value: '' },
  ...Object.entries(cozoPresets).map(([key, value]) => ({
    text: key,
    value: Array.isArray(value) ? value.join('\r\n') : value,
  })),
];

const diffMs = (t0: number, t1: number) => `${(t1 - t0).toFixed(1)}ms`;

function Drive() {
  const [queryText, setQueryText] = useState('');
  const [isLoaded, _setIsLoaded] = useState(true);
  const [inProgress, setInProgress] = useState(false);
  const [statusMessage, setStatusMessage] = useState('');
  const [searchEmbedding, setSearchEmbedding] = useState('');
  // const [summarizeCid, setSummarizeCid] = useState('');
  const [outputText, _setOutputText] = useState('');
  // const [questionText, setQuestionText] = useState('');
  const [_embeddingsProcessStatus, _setEmbeddingsProcessStatus] = useState('');

  const [errorMessage, setErrorMessage] = useState<string | undefined>();
  const [queryResults, setQueryResults] = useState<{ rows: []; cols: [] }>();
  const { cozoDbRemote, isReady, ipfsApi } = useBackend();
  const { embeddingApi } = useScripting();
  const { viewportWidth } = useDevice();
  const isMobile = viewportWidth <= 768;
  // const embeddingApi = useEmbeddingApi();

  // console.log('-----syncStatus', syncState, dbPendingWrites);

  function runQuery(queryArg?: string) {
    const query = queryArg || queryText.trim();
    if (query) {
      setInProgress(true);
      setErrorMessage('');
      setStatusMessage('');
      setQueryResults(undefined);
      requestAnimationFrame(() => {
        setTimeout(async () => {
          try {
            const t0 = performance.now();
            const result = await cozoDbRemote!.runCommand(query);
            const t1 = performance.now();

            try {
              setStatusMessage(`finished with ${result.rows.length} rows in ${diffMs(t0, t1)}`);
              if (!result.headers) {
                result.headers = result.rows[0].map((_, i) => i.toString()) || [];
              }
              const rows = toListOfObjects(result);
              const cols = result.headers.map((n) => ({
                // header: n,
                accessorKey: n,
                header: () => n,
                cell: (item) => {
                  const value = item.getValue();
                  if (['cid'].indexOf(n) > -1) {
                    return (
                      <a href={`/ipfs/${value}`} target="_blank" rel="noopener noreferrer">
                        {`${value.slice(0, 10)}...${value.slice(-10)}`}
                      </a>
                    );
                  }

                  return value;
                },
              }));

              // parse object-type values to string to be able to display them in the table
              const rowsNormalized = rows.map((row) => {
                const updatedRow = {};
                for (const [key, value] of Object.entries(row)) {
                  if (typeof value === 'object') {
                    updatedRow[key] = JSON.stringify(value);
                  } else if (typeof value === 'boolean') {
                    updatedRow[key] = value.toString();
                  } else {
                    updatedRow[key] = value;
                  }
                }
                return updatedRow;
              });

              setQueryResults({ rows: rowsNormalized, cols });
            } catch (e: DBResultError | any) {
              console.error('Query failed', e);
              setStatusMessage(`finished with errors`);
              if (e.display) {
                setErrorMessage(e.display);
              }
            }
          } catch (e) {
            setStatusMessage(`query failed`);
            setErrorMessage(e.message);
            console.log(e);
          } finally {
            setInProgress(false);
          }
        }, 0);
      });
    }
  }

  const exportReations = async () => {
    const result = await cozoDbRemote!.exportRelations(['pin', 'particle', 'link']);
    console.log('---export data', result);
    try {
      const blob = new Blob([JSON.stringify(result.data)], {
        type: 'text/plain;charset=utf-8',
      });
      saveAs(blob, 'export.json');
    } catch (e) {
      console.log('cozoDb: Failed to import', e);
    }
  };

  const importReations = async (file: any) => {
    const content = await file.text();

    const res = await cozoDbRemote!.importRelations(content);
    console.log('----import result', res);
  };

  const runExampleScript = async (value: string) => {
    setQueryText(value);
    runQuery(value);
  };

  // const createParticleEmbeddingsClick = async () => {
  //   const data = await cozoDbRemote?.runCommand(
  //     '?[cid, text] := *particle{cid, mime, text, blocks, size, size_local, type}, mime="text/plain"',
  //     true
  //   );

  //   let index = 0;
  //   const totalItems = data!.rows.length;
  //   setEmbeddingsProcessStatus(`Starting... Total particles (0/${totalItems})`);

  //   // eslint-disable-next-line no-restricted-syntax
  //   for await (const row of data!.rows) {
  //     const [cid, text] = row;
  //     const vec = await mlApi?.createEmbedding(text as string);
  //     const res = await cozoDbRemote?.executePutCommand('embeddings', [
  //       {
  //         cid,
  //         vec,
  //       } as EmbeddinsDbEntity,
  //     ]);
  //     index++;
  //     setEmbeddingsProcessStatus(
  //       `Processing particles (${index}/${totalItems})....`
  //     );
  //   }
  //   setEmbeddingsProcessStatus(
  //     `Embeddings complete for (0/${totalItems}) particles!`
  //   );
  // };

  const searchByEmbeddingsClick = async () => {
    const vec = await embeddingApi?.createEmbedding(searchEmbedding);
    const queryText = `
    e[dist, cid] := ~embeddings:semantic{cid | query: vec([${vec}]), bind_distance: dist, k: 20, ef: 50}
    ?[dist, cid, text] := e[dist, cid], *particle{cid, text}
    `;
    setQueryText(queryText);
    runQuery(queryText);
  };

  // const summarizeClick = async () => {
  //   const text = (await ipfsApi!.fetchWithDetails(summarizeCid, 'text'))
  //     ?.content;
  //   const output = await mlApi?.getSummary(text!);
  //   setOutputText(output);

  // };

  // const questionClick = async () => {
  //   const text = (await ipfsApi!.fetchWithDetails(summarizeCid, 'text'))
  //     ?.content;
  //   const output = await mlApi?.getQA(questionText, text!);
  //   setOutputText(output);

  // };

  function onSearchEmbeddingChange(event: React.ChangeEvent<HTMLInputElement>) {
    const { value } = event.target;
    setSearchEmbedding(value);
  }

  // function onSummarizeCidChange(event: React.ChangeEvent<HTMLInputElement>) {
  //   const { value } = event.target;
  //   setSummarizeCid(value);
  // }

  // function onQuestionChange(event: React.ChangeEvent<HTMLInputElement>) {
  //   const { value } = event.target;
  //   setQuestionText(value);
  // }

  const desktopOnly = isMobile ? styles.mobileDisabled : undefined;

  return (
    <>
      <div className={styles.main}>
        <Display color={Colors.ORANGE}>
          <p>
            this is tech preview of cyb brain. it does not adds any new functionality across the
            app, yet
          </p>
          <p>features:</p>
          <div>- log you links while you surf</div>
          <div>- connect external ipfs node for performance</div>
          <div>
            - sync your <Link to="/search/ipfs">ipfs</Link> pins
          </div>
          <div>
            - import your transactions and cybergraph from <Link to="/search/bostrom">bostrom</Link>
          </div>
          <div>
            - query using ai oriented{' '}
            <a href="https://www.cozodb.org/" target="_blank" rel="noopener">
              datalog
            </a>
          </div>
          <p>
            link your feedback <Link to="/search/brain%20feedback">brain feedback</Link>
          </p>
        </Display>
        <div className={desktopOnly}>
          <BackendStatus />
        </div>
        <Pane width="100%" className={desktopOnly}>
          <div>{outputText}</div>
          <div className={styles.buttonPanel}>
            <Input
              value={searchEmbedding}
              onChange={(e) => onSearchEmbeddingChange(e)}
              placeholder="enter sentence...."
            />
            <Button small onClick={searchByEmbeddingsClick}>
              ๐Ÿงฌ Search by embedding
            </Button>
          </div>
        </Pane>
        <Pane width="100%" className={desktopOnly}>
          <textarea
            placeholder="Enter your query here..."
            onChange={(e) => setQueryText(e.target.value)}
            value={queryText}
            className={styles.queryInput}
            rows={10}
          />
          <div className={styles.commandPanel}>
            <div className={styles.subPanel}>
              <CybButton disabled={!isLoaded || inProgress} onClick={() => runQuery()} small>
                {isLoaded
                  ? inProgress
                    ? 'Query is running'
                    : '๐ŸŸง Run script'
                  : 'Loading WASM ...'}
              </CybButton>
              <Select
                width="250px"
                valueSelect=""
                small
                onChangeSelect={runExampleScript}
                options={presetsAsSelectOptions}
              />
            </div>
            <div className={styles.subPanel}>
              <CybButton disabled={!isLoaded || !isReady} onClick={exportReations} small>
                export
              </CybButton>
              <FileInputButton caption="import" processFile={importReations} />
            </div>
          </div>
        </Pane>
        {statusMessage && (
          <Pane width="100%" marginTop={10}>
            <div className={styles.statusMessage}>{statusMessage}</div>
          </Pane>
        )}
      </div>
      {queryResults ? (
        queryResults.cols.length > 0 ? (
          <div className={classNames('bp5-dark', styles.results)}>
            <Table columns={queryResults.cols} data={queryResults.rows} />
          </div>
        ) : null
      ) : (
        <div className={styles.errorMessage}>{errorMessage}</div>
      )}
    </>
  );
}

export default Drive;

Synonyms

cyb/src/index.tsx
pussy-ts/src/index.tsx
bostrom.network/src/pages/Index.tsx
pussy-landing/src/pages/index.tsx
pussy.meme/src/pages/index.tsx
pussy-ts/src/containers/txs/index.tsx
pussy-ts/src/containers/mint/index.tsx
cyb/src/containers/mint/index.tsx
pussy-ts/src/components/ButtonSwap/index.tsx
pussy-ts/src/components/denom/index.tsx
cyb/src/containers/Objects/index.tsx
cyb/src/components/btnGrd/index.tsx
pussy-ts/src/components/Select/index.tsx
cyb/src/components/actionBar/index.tsx
pussy-ts/src/components/BandwidthBar/index.tsx
cyb/src/components/Select/index.tsx
pussy-ts/src/containers/portal/index.tsx
pussy-ts/src/components/btnGrd/index.tsx
cyb/src/components/TextMarkdown/index.tsx
cyb/src/containers/energy/index.tsx
pussy-ts/src/components/MainContainer/index.tsx
pussy-ts/src/components/actionBar/index.tsx
cyb/src/containers/portal/index.tsx
cyb/src/components/ButtonSwap/index.tsx
cyb/src/containers/nebula/index.tsx
pussy-ts/src/components/DonutChart/index.tsx
cyb/src/components/DonutChart/index.tsx
pussy-ts/src/containers/nebula/index.tsx
cyb/src/components/BandwidthBar/index.tsx
pussy-ts/src/containers/energy/index.tsx
cyb/src/components/denom/index.tsx
cyb/src/containers/sigma/index.tsx
cyb/src/components/Input/index.tsx
pussy-ts/src/containers/sigma/index.tsx
pussy-ts/src/containers/taverna/index.tsx
pussy-ts/src/components/Input/index.tsx
cyb/src/containers/blok/index.tsx
cyb/src/components/PDF/index.tsx
cyb/src/containers/txs/index.tsx
cyb/src/containers/taverna/index.tsx
cyb/src/components/MainContainer/index.tsx
pussy-ts/src/components/TextMarkdown/index.tsx
pussy-ts/src/components/PDF/index.tsx
cyb/src/containers/portal/citizenship/index.tsx
pussy-landing/src/components/xp/btnGrd/index.tsx
cyb/src/containers/portal/pasport/index.tsx
pussy-landing/src/components/xp/stars/index.tsx
cyb/src/components/buttons/ButtonIcon/index.tsx
cyb/src/containers/wasm/codes/index.tsx
pussy-ts/src/features/ipfs/Drive/index.tsx
pussy-ts/src/containers/portal/gift/index.tsx
pussy-ts/src/features/ipfs/ipfsSettings/index.tsx
pussy-ts/src/components/buttons/ButtonIcon/index.tsx
pussy-ts/src/containers/portal/release/index.tsx
cyb/src/containers/portal/release/index.tsx
pussy-ts/src/containers/portal/pasport/index.tsx
cyb/src/features/ipfs/ipfsSettings/index.tsx
pussy-ts/src/containers/portal/citizenship/index.tsx
cyb/src/containers/portal/gift/index.tsx
cyb/src/components/contentIpfs/component/gateway/index.tsx
pussy-ts/src/containers/portal/components/ReleaseStatus/index.tsx
pussy-ts/src/components/contentIpfs/component/gateway/index.tsx
pussy-ts/src/containers/sigma/components/CardPassport/index.tsx
cyb/src/containers/sigma/components/CardPassport/index.tsx
cyb/src/components/contentIpfs/component/img/index.tsx
pussy-ts/src/components/contentIpfs/component/img/index.tsx
cyb/src/containers/portal/components/ActionBar/index.tsx
pussy-ts/src/components/contentIpfs/component/link/index.tsx
cyb/src/containers/portal/components/ReleaseStatus/index.tsx
cyb/src/containers/portal/components/stars/index.tsx
pussy-ts/src/containers/portal/components/stars/index.tsx
cyb/src/components/contentIpfs/component/link/index.tsx
pussy-ts/src/containers/sigma/components/cardUi/TitleCard/index.tsx
cyb/src/containers/sigma/components/cardUi/TitleCard/index.tsx
cyb/src/containers/sigma/components/cardUi/RowBalancesDetails/index.tsx
pussy-ts/src/containers/sigma/components/cardUi/RowBalancesDetails/index.tsx

Neighbours