Skip to content

Commit

Permalink
feat: add AI summary
Browse files Browse the repository at this point in the history
  • Loading branch information
pscott committed Mar 22, 2024
1 parent b66c51a commit 64d3c3f
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 3 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
"graphql": "^16.7.1",
"multiformats": "^9",
"mysql": "^2.18.1",
"node-fetch": "^2.7.0"
"node-fetch": "^2.7.0",
"openai": "^4.29.2"
},
"devDependencies": {
"@snapshot-labs/eslint-config": "^0.1.0-beta.15",
Expand Down
25 changes: 25 additions & 0 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import mintPayload from './lib/nftClaimer/mint';
import deployPayload from './lib/nftClaimer/deploy';
import { queue, getProgress } from './lib/queue';
import { snapshotFee } from './lib/nftClaimer/utils';
import AISummary from './lib/ai';

const router = express.Router();

Expand Down Expand Up @@ -37,6 +38,29 @@ router.all('/votes/:id', async (req, res) => {
}
});

router.post('/ai/summary/:id', async (req, res) => {
const { id } = req.params;
const aiSummary = new AISummary(id, storageEngine(process.env.AI_SUMMARY_SUBDIR));

try {
let cachedSummary = await aiSummary.getCache()

Check failure on line 46 in src/api.ts

View workflow job for this annotation

GitHub Actions / lint (18) / Lint

'cachedSummary' is never reassigned. Use 'const' instead

Check failure on line 46 in src/api.ts

View workflow job for this annotation

GitHub Actions / lint (18) / Lint

Insert `;`

let summary = '';

if (cachedSummary === false) {
summary = (await aiSummary.createCache()).toString();
} else {
console.log(cachedSummary.toString());
summary = cachedSummary.toString();
}

return rpcSuccess(res.status(200), summary, id);
} catch (e) {
capture(e);
return rpcError(res, 'INTERNAL_ERROR', id);
}
});

router.get('/moderation', async (req, res) => {
const { list } = req.query;

Expand Down Expand Up @@ -87,4 +111,5 @@ router.post('/nft-claimer/mint', async (req, res) => {
}
});

Check failure on line 112 in src/api.ts

View workflow job for this annotation

GitHub Actions / lint (18) / Lint

Delete `⏎`


export default router;
8 changes: 8 additions & 0 deletions src/helpers/snapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export type Proposal = {
space: Space;
votes: number;
author: string;
title: string;
body: string;
discussion: string;
};

export type Vote = {
Expand All @@ -23,6 +26,7 @@ export type Vote = {
export type Space = {
id: string;
network: string;
name: string;
};

const httpLink = createHttpLink({
Expand Down Expand Up @@ -65,10 +69,14 @@ const PROPOSAL_QUERY = gql`
state
choices
votes
title
body
discussion
author
space {
id
network
name
}
}
}
Expand Down
64 changes: 64 additions & 0 deletions src/lib/ai.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import express from 'express';

Check failure on line 1 in src/lib/ai.ts

View workflow job for this annotation

GitHub Actions / lint (18) / Lint

'express' is defined but never used
import bodyParser from 'body-parser';

Check failure on line 2 in src/lib/ai.ts

View workflow job for this annotation

GitHub Actions / lint (18) / Lint

'bodyParser' is defined but never used
import { capture } from '@snapshot-labs/snapshot-sentry';
import { URL } from 'url';

Check failure on line 4 in src/lib/ai.ts

View workflow job for this annotation

GitHub Actions / lint (18) / Lint

'URL' is defined but never used
import { rpcError, fetchWithKeepAlive } from '../helpers/utils';

Check failure on line 5 in src/lib/ai.ts

View workflow job for this annotation

GitHub Actions / lint (18) / Lint

'rpcError' is defined but never used

Check failure on line 5 in src/lib/ai.ts

View workflow job for this annotation

GitHub Actions / lint (18) / Lint

'fetchWithKeepAlive' is defined but never used
import OpenAI from 'openai';
import { fetchProposal } from '../helpers/snapshot';
import { IStorage } from './storage/types';
import { Proposal } from '../helpers/snapshot';
import Cache from './cache';

const openai = new OpenAI({ apiKey: process.env.apiKey });

class AISummary extends Cache {
proposal?: Proposal | null;

Check failure on line 15 in src/lib/ai.ts

View workflow job for this annotation

GitHub Actions / lint (18) / Lint

Delete `··`

constructor(id: string, storage: IStorage) {

Check failure on line 17 in src/lib/ai.ts

View workflow job for this annotation

GitHub Actions / lint (18) / Lint

Delete `··`
super(id, storage);
this.filename = `snapshot-votes-report-${this.id}.csv`;
}

async isCacheable() {
this.proposal = await fetchProposal(this.id);
console.log(this.proposal);

if (!this.proposal) {
return Promise.reject('RECORD_NOT_FOUND');
}

return true;
}

getContent = async () => {
this.isCacheable();
console.log("--ID: " + this.id);
try {
const proposal = await fetchProposal(this.id);
const body = proposal?.body;
const title = proposal?.title;
const spaceName = proposal?.space?.name;
const completion = await openai.chat.completions.create({
messages: [{ role: 'system', content: `The following is a governance proposal of ${spaceName}. Generate me a summary in 300 characters max. Here's the title of the proposal: '${title}' . Here's the content of the proposal: '${body}'` }],
model: 'gpt-4-turbo-preview',
});

if (completion.choices.length === 0) {
throw new Error('No completion in response');
}
const res = completion?.choices[0];

if (res.message.content === null) {
throw new Error('No content in response');
}

const content = res.message?.content;
return content;
} catch (e: any) {
capture(e);
throw (e);
}
};
}

export default AISummary;
Loading

0 comments on commit 64d3c3f

Please sign in to comment.