Skip to content

Commit

Permalink
Merge pull request #77 from Pash10g/mongo-feed
Browse files Browse the repository at this point in the history
MongoFeed project
  • Loading branch information
ajosh0504 authored Feb 11, 2025
2 parents c773907 + 8ce90be commit 98ea5dc
Show file tree
Hide file tree
Showing 117 changed files with 9,081 additions and 0 deletions.
5 changes: 5 additions & 0 deletions apps/mongo-feed/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
.env
.env.local
package-lock.json
.next
117 changes: 117 additions & 0 deletions apps/mongo-feed/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# MongoFeed

MongoFeed is a comprehensive platform for product feedback analysis and sentiment tracking. It leverages MongoDB for data storage and Amazon Bedrock for AI-powered sentiment analysis, providing valuable insights into customer feedback and product reviews.

> ♥️ Inpired by a customer success story : [Syncly](https://www.mongodb.com/customers/syncly)
## Hosted Version

https://mongo-feed.vercel.app

## Features

- File upload for product feedback analysis (JSON, HTML, images)
- Chat paste functionality for direct input of customer interactions
- Sentiment analysis using Amazon Bedrock AI
- Real-time processing queue for feedback analysis
- Interactive charts and visualizations:
- Feedback trends over time
- Sentiment distribution
- Top issues identification
- Agent performance tracking and sentiment analysis

## Prerequisites

Before you begin, ensure you have the following installed:
- Node.js (v14 or later)
- npm (v6 or later)
- MongoDB (6.0+)
- An AWS account with access to Amazon Bedrock and Claude 3.5 V2 model

## Installation

1. **Clone the repository:**
```bash
git clone <repository-url>
cd mongo-feed
```

2. **Install dependencies:**
```bash
npm install
```

3. **Configure environment variables:**
- Create a `.env.local` file in the root directory.
- Add your MongoDB connection string and AWS Bedrock credentials.
```env
MONGODB_URI=your_mongodb_connection_string
AWS_REGION=your_aws_region
AWS_ACCESS_KEY_ID=your_aws_access_key_id
AWS_SECRET_ACCESS_KEY=your_aws_secret_access_key
```
**Note:** Ensure you have the necessary permissions for Amazon Bedrock and MongoDB.
## Development
1. **Run the development server:**
```bash
npm run dev
```
Open [http://localhost:3000](http://localhost:3000) in your browser to view the application.

## Building for Production

1. **Build the application:**
```bash
npm run build
```

2. **Start the production server:**
```bash
npm run start
```

## Usage

To use MongoFeed:

1. **Access the application** in your browser at [http://localhost:3000](http://localhost:3000) after running the development or production server.
2. **Upload Feedback Files or Paste Chat Interactions:**
- Navigate to the feedback input section.
- Choose to upload files (JSON, HTML, images) or paste text from chat interactions.
- Follow the on-screen instructions to input your feedback data.
3. **View Sentiment Analysis Results and Visualizations:**
- Once the feedback is processed, navigate to the dashboard.
- Explore interactive charts and visualizations to understand:
- Feedback trends over time
- Sentiment distribution across feedback
- Top issues identified from the feedback
4. **Navigate the Dashboard:**
- Use the dashboard to access different features, such as:
- Real-time processing queue monitoring.
- Agent performance tracking and sentiment analysis (if applicable).
- Detailed views of individual feedback entries and their sentiment analysis.

## Configuration

- **Environment Variables:**
- `MONGODB_URI`: MongoDB connection string for your MongoDB database.
- `AWS_REGION`: AWS region where your Bedrock service is configured.
- `AWS_ACCESS_KEY_ID`: AWS access key ID for authentication.
- `AWS_SECRET_ACCESS_KEY`: AWS secret access key for authentication.

- **Other configurations:**
- The application may have additional configurations that can be set in the `.env.local` file or through the application's settings panel. Refer to the application documentation for advanced configuration options.

## Contributing

If you'd like to contribute to MongoFeed, please follow these guidelines:
1. Fork the repository.
2. Create a branch for your feature or bug fix.
3. Ensure your code adheres to the project's coding standards.
4. Submit a pull request with a clear description of your changes.

## License

[Specify the project license, e.g., MIT License]
45 changes: 45 additions & 0 deletions apps/mongo-feed/app/api/agent-analysis/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { NextResponse } from "next/server"
import clientPromise from "@/lib/mongodb"

export const dynamic = "force-dynamic"
export const revalidate = 0

export async function GET() {
try {
const client = await clientPromise
const db = client.db("mongofeed")

const agentAnalysis = await db
.collection("chat_analyses")
.aggregate([
{ $unwind: "$messages" },
{ $match: { "messages.role": "Agent" } },
{
$group: {
_id: "$messages.agentName",
positiveSentiment: { $sum: { $cond: [{ $eq: ["$messages.sentiment", "positive"] }, 1, 0] } },
neutralSentiment: { $sum: { $cond: [{ $eq: ["$messages.sentiment", "neutral"] }, 1, 0] } },
negativeSentiment: { $sum: { $cond: [{ $eq: ["$messages.sentiment", "negative"] }, 1, 0] } },
totalInteractions: { $sum: 1 },
},
},
{
$project: {
agentName: "$_id",
positiveSentiment: 1,
neutralSentiment: 1,
negativeSentiment: 1,
totalInteractions: 1,
_id: 0,
},
},
{ $sort: { totalInteractions: -1 } },
])
.toArray()

return NextResponse.json(agentAnalysis)
} catch (error) {
console.error("Error fetching agent analysis:", error)
return NextResponse.json({ error: "An error occurred while fetching agent analysis." }, { status: 500 })
}
}
50 changes: 50 additions & 0 deletions apps/mongo-feed/app/api/agent-sentiment/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { NextResponse } from "next/server"
import clientPromise from "@/lib/mongodb"

export const dynamic = "force-dynamic"
export const revalidate = 0

export async function GET() {
try {
const client = await clientPromise
const db = client.db("mongofeed")

// First get all agents with their sentiment data
const agentData = await db
.collection("agent_sentiment")
.aggregate([
{
$lookup: {
from: "chat_analyses",
let: { agentName: "$agentName" },
pipeline: [
{
$match: {
$expr: { $eq: ["$analysis.agentName", "$$agentName"] },
},
},
{ $sort: { createdAt: -1 } },
{ $limit: 5 },
{
$project: {
id: { $toString: "$_id" },
date: "$createdAt",
summary: "$analysis.summary",
sentiment: "$analysis.overallSentiment",
issues: "$analysis.mainTopics",
},
},
],
as: "recentChats",
},
},
{ $sort: { totalInteractions: -1 } },
])
.toArray()

return NextResponse.json(agentData)
} catch (error) {
console.error("Error fetching agent sentiment:", error)
return NextResponse.json({ error: "An error occurred while fetching agent sentiment." }, { status: 500 })
}
}
55 changes: 55 additions & 0 deletions apps/mongo-feed/app/api/analyze-feedback/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { type NextRequest, NextResponse } from "next/server"
import { analyzeAgentFeedback, analyzeProductReview } from "@/lib/analyze-content"
import clientPromise from "@/lib/mongodb"

export const dynamic = "force-dynamic"
export const runtime = "nodejs"

export async function POST(req: NextRequest) {
try {
const formData = await req.formData()
const file = formData.get("file") as File
const type = formData.get("type") as string

if (!file) {
return NextResponse.json({ error: "No file uploaded" }, { status: 400 })
}

const contentType = file.type
const fileName = file.name

let content: string | ArrayBuffer
if (contentType.startsWith("image/")) {
content = await file.arrayBuffer()
} else {
const buffer = await file.arrayBuffer()
content = new TextDecoder().decode(buffer)
}

let analysisResult

if (type === "agent") {
analysisResult = await analyzeAgentFeedback(content as string)
} else if (type === "product") {
analysisResult = await analyzeProductReview(content, contentType, fileName)
} else {
return NextResponse.json({ error: "Invalid analysis type" }, { status: 400 })
}

// Store the analysis result in MongoDB
const client = await clientPromise
const db = client.db("mongofeed")
await db.collection("chat_analyses").insertOne({
type,
contentType,
fileName,
analysis: analysisResult,
createdAt: new Date(),
})

return NextResponse.json({ sentiments: analysisResult })
} catch (error) {
console.error("Error analyzing feedback:", error)
return NextResponse.json({ error: "An error occurred while analyzing feedback." }, { status: 500 })
}
}
34 changes: 34 additions & 0 deletions apps/mongo-feed/app/api/analyze-sentiment/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { NextRequest, NextResponse } from 'next/server';
import { bedrock } from '@/lib/bedrock';
import { generateText } from 'ai';

export async function POST(req: NextRequest) {
try {
const data = await req.json();
const documents = data.documents;

if (!Array.isArray(documents)) {
return NextResponse.json({ error: 'Invalid input. Expected an array of documents.' }, { status: 400 });
}

const sentiments = await Promise.all(
documents.map(async (doc) => {
try {
const { text } = await generateText({
model: bedrock('aanthropic.claude-3-5-sonnet-20241022-v2:0'),
prompt: `Analyze the sentiment of the following text and respond with only one word: "positive", "negative", or "neutral". Text: "${doc}"`,
});
return text.trim().toLowerCase();
} catch (error) {
console.error('Error analyzing individual document:', error);
return 'error';
}
})
);

return NextResponse.json({ sentiments });
} catch (error) {
console.error('Error analyzing sentiment:', error);
return NextResponse.json({ error: 'An error occurred while analyzing sentiment.' }, { status: 500 });
}
}
Loading

0 comments on commit 98ea5dc

Please sign in to comment.