Skip to content

Commit

Permalink
Merge pull request #95 from berkingurcan/add-feedback-api
Browse files Browse the repository at this point in the history
Add feedback api
  • Loading branch information
berkingurcan authored Feb 4, 2025
2 parents ab60868 + 80606b2 commit 7121928
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 18 deletions.
83 changes: 76 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ It has also node server for Govbot. First 3 endpoint is used for to integrate di

### 1. Create a Proposal

**URL**:
**ENDPOINT**:
`POST /api/govbot/proposal`

**Headers**:
Expand All @@ -386,7 +386,7 @@ It has also node server for Govbot. First 3 endpoint is used for to integrate di

### 2. Add Feedback to a Proposal

**URL**:
**ENDPOINT**:
`POST /api/govbot/proposal`

**Headers**:
Expand All @@ -404,7 +404,7 @@ It has also node server for Govbot. First 3 endpoint is used for to integrate di

### 3. Health Check

**URL**:
**ENDPOINT**:
`GET /api/govbot/`

**Headers**:
Expand All @@ -420,7 +420,7 @@ No header.

### 4. Health Check for Redis Integration and API

**URL**:
**ENDPOINT**:
`GET /api/govbot/health`

**Headers**:
Expand All @@ -439,7 +439,7 @@ No header.

### 5. Add Proposal to DB

**URL**:
**ENDPOINT**:
`POST /api/govbot/proposals`

**Headers**:
Expand Down Expand Up @@ -475,7 +475,7 @@ No header.

### 6. Summarize Proposal by ID

**URL**:
**ENDPOINT**:
`POST /api/govbot/proposals/:id/summarize`

**Headers**:
Expand All @@ -495,7 +495,7 @@ No header.

### 7. Get Proposal Summary by Proposal ID

**URL**:
**ENDPOINT**:
`GET /api/govbot/proposals/:id/summary`

**Headers**:
Expand All @@ -513,6 +513,75 @@ No header.
}
```

### 8. Add Feedback

**ENDPOINT**:
`POST /proposals/:proposalId/feedbacks`

**Headers**:

- Content-Type: `application/json`
- Authorization: `Bearer <AUTH_SECRET>`

**Request Body (JSON)**:

```json
{
"username": "Alice",
"feedbackContent": "This is a great proposal!"
}
```

**Example Response**

```json
{
"proposalId": "1234",
"username": "Alice",
"feedbackContent": "This is a great proposal!"
}
```

### 9. Summarize Feedbacks for Proposal

**ENDPOINT**:
`POST /proposals/:proposalId/feedbacks/summary`

**Headers**:

- Content-Type: `application/json`
- Authorization: `Bearer <AUTH_SECRET>`

No request body required.

**Example Response**

```json
{
"proposalId": 1234,
"feedbackSummary": "Generated feedback summary text..."
}
```

### 10. Get Feedback Summary

**ENDPOINT**:
`GET /proposals/:proposalId/feedbacks/summary`

**Headers**:

- Content-Type: `application/json`
- Authorization: `Bearer <AUTH_SECRET>`

**Example Response**

```json
{
"proposalId": 1234,
"feedbackSummary": "Generated feedback summary text..."
}
```

## Contributions

To make a contribution, follow these steps:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "discord-bot",
"type": "module",
"version": "0.4.1",
"version": "0.4.3",
"description": "",
"main": "index.js",
"scripts": {
Expand Down
66 changes: 58 additions & 8 deletions src/controllers/controllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,36 @@ async function proposalSummarizer(
return summary;
}

function feedbackSummarizer(text: string): string {
if (!text) return "No content to summarize.";
return `DUMMY SUMMARY: ${text.slice(0, 100)}...`;
type FeedbackDictionary = { [username: string]: string };

async function feedbackSummarizer(
proposalName: string,
proposalDescription: string,
proposalAuthor: string,
fundingRoundId: string,
feedbacks: FeedbackDictionary,
): Promise<string> {
const FEEDBACK_PROMPT = FEEDBACK_SUMMARIZE_PROMPT(
proposalName,
proposalDescription,
proposalAuthor,
fundingRoundId,
feedbacks,
);
const completion = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{
role: "user",
content: FEEDBACK_PROMPT,
},
],
});

const summary = completion.choices[0].message.content;
log.debug(summary);

return summary;
}

// ------------------------------------------------------------------
Expand Down Expand Up @@ -265,18 +292,41 @@ export const summarizeFeedbacks = async (
const { proposalId } = req.params;
const feedbackKey = `proposal_feedbacks:${proposalId}`;

// Retrieve feedbacks for the proposal
const feedbackData = await redisClient.get(feedbackKey);
if (!feedbackData) {
res.status(404).json({ error: "No feedbacks found for this proposal." });
return;
}

const feedbacks: ProposalFeedback[] = JSON.parse(feedbackData);

// TODO: makes this AI process friendly :D
// Combine all feedback text into one string
const combinedText = feedbacks.map((f) => f.feedbackContent).join("\n");
const proposalKey = `proposal:${proposalId}`;
const proposalData = await redisClient.get(proposalKey);
if (!proposalData) {
res.status(404).json({ error: "Proposal not found." });
return;
}
const proposal: GovbotProposal = JSON.parse(proposalData);

const feedbacksDictionary: FeedbackDictionary = feedbacks.reduce(
(dict, feedback) => {
if (dict[feedback.username]) {
dict[feedback.username] += "\n" + feedback.feedbackContent;
} else {
dict[feedback.username] = feedback.feedbackContent;
}
return dict;
},
{} as FeedbackDictionary,
);

const summaryText = feedbackSummarizer(combinedText);
const summaryText = await feedbackSummarizer(
proposal.proposalName,
proposal.proposalDescription,
proposal.proposalAuthor,
proposal.fundingRoundId.toString(), // Ensure fundingRoundId is a string.
feedbacksDictionary,
);

const feedbacksSummary: ProposalFeedbacksSummary = {
proposalId: parseInt(proposalId, 10),
Expand Down
41 changes: 39 additions & 2 deletions src/helpers/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,42 @@ Summary Guideline:
* Keep the summary within 3-6 sentences while maintaining clarity and completeness.
`.trim();

export const FEEDBACK_SUMMARIZE_PROMPT = (username, feedbackContent) =>
``.trim();
type FeedbackDictionary = { [username: string]: string };

function formatFeedbacks(feedbacks: FeedbackDictionary): string {
return Object.entries(feedbacks)
.map(([username, feedback]) => `${username}: "${feedback}"`)
.join("\n");
}

export const FEEDBACK_SUMMARIZE_PROMPT = (
proposalName,
proposalDescription,
proposalAuthor,
fundingRoundId,
feedbacks,
) =>
`
You are an AI assistant that specializes in summarizing project proposals and their associated feedbacks.
Your task is to generate a concise and insightful summary for the given project proposals and especially
their feedbacks for Mina Ecosystem Funding program. You need to include all meaningful summarized feedbacks.
You are given these datas to summarize:
- Proposal Name: ${proposalName}
- Description: ${proposalDescription}
- Author: ${proposalAuthor}
- Funding Round ID: ${fundingRoundId}
- Feedbacks: ${formatFeedbacks(feedbacks)}
Summary Guideline:
Your response should focus primarily on analyzing and summarizing the feedback.
* Brief Proposal Summary: A 2-3 sentence summary explaining the core idea, objective, and significance of the proposal.
* Key Strengths (Based on Feedbacks): Highlight the main positive aspects of the proposal as mentioned by users.
* Main Concerns (Based on Feedbacks): Identify common criticisms, potential risks, or areas that need improvement.
* Recurring Themes in Feedback: Identify common points that multiple users have mentioned.
Include insights such as usability concerns, technical feasibility, business potential, or ethical considerations.
* Overall Sentiment: Determine whether the general sentiment is positive, neutral, or negative based on user feedback.
* Constructive Suggestions: If applicable, provide recommendations for improving the proposal.
* Edge Opinions: Include edge sentiments if you thinks it is meaningful as an great AI Agent.
`.trim();

0 comments on commit 7121928

Please sign in to comment.