Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@
import React from 'react';
import { ConnectButton, useWallet } from '@suiet/wallet-kit';
import Image from 'next/image';

const Header = () => {
const wallet = useWallet();
console.log(wallet.address, wallet.connected);
const { address, connected } = useWallet();

return (
<div className="w-[75dvw] grid grid-cols-1 md:flex justify-between">
{/* <p style={{
fontFamily:"Manrope",
}} className="text-lg text-right md:text-left">Atoma's Coin Sage</p> */}
<span className="flex items-center">
<Image src="/coinSageLogo.png" width={50} height={50} alt="atomasage logo" />
<Image src="/coinSageLogo.png" width={50} height={50} alt="atomasage logo" priority />
<p
style={{
fontFamily: 'fantasy'
Expand All @@ -22,8 +20,15 @@ const Header = () => {
</p>
</span>

<div className="w-10 md:block z-20 hidden ">
<ConnectButton className="" label="Connect Wallet" />
<div className="flex items-center gap-4">
{connected && (
<span className="text-sm text-gray-600">
{address?.slice(0, 6)}...{address?.slice(-4)}
</span>
)}
<div className="w-40 md:block z-20">
<ConnectButton label="Connect Wallet" />
</div>
</div>
</div>
);
Expand Down
18 changes: 18 additions & 0 deletions apps/client/app/components/ui/WalletStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use client';
import { useWallet } from '@suiet/wallet-kit';

const WalletStatus = () => {
const { connected } = useWallet();

if (!connected) {
return (
<div className="text-center p-4 my-4 bg-yellow-50 border border-yellow-200 rounded-lg text-yellow-700">
Please connect your wallet to start chatting and save your conversation history
</div>
);
}

return null;
};

export default WalletStatus;
13 changes: 13 additions & 0 deletions apps/client/app/components/ui/loadingPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import PulseLoader from './pulseLoader';

export default function LoadingPage() {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="flex flex-col items-center gap-4">
<div className="w-16 h-16 border-4 border-gray-300 border-t-blue-500 rounded-full animate-spin" />
<p className="text-lg text-gray-600">AtomaSage</p>
</div>
</div>
);
}
9 changes: 9 additions & 0 deletions apps/client/app/components/ui/pulseLoader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const PulseLoader = () => (
<div className="flex space-x-2">
<div className="w-4 h-4 bg-blue-500 rounded-full animate-pulse"></div>
<div className="w-4 h-4 bg-blue-500 rounded-full animate-pulse [animation-delay:0.2s]"></div>
<div className="w-4 h-4 bg-blue-500 rounded-full animate-pulse [animation-delay:0.4s]"></div>
</div>
);

export default PulseLoader;
8 changes: 8 additions & 0 deletions apps/client/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,11 @@ button {
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
} */

.sui-wallet-kit-button {
@apply px-4 py-2 rounded-lg bg-blue-600 text-white hover:bg-blue-700 transition-colors !important;
}

.sui-wallet-kit-button span {
@apply text-sm font-medium !important;
}
4 changes: 2 additions & 2 deletions apps/client/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import './globals.css';
import { Manrope } from 'next/font/google';
import Header from './components/ui/Header';
import Header from './components/layout/Header';
import Providers from '@/app/providers';
import '@suiet/wallet-kit/style.css';
import './walletCustomCss.css';
import Sidebar from './components/ui/Sidebar';
import Sidebar from './components/layout/Sidebar';

const manrope = Manrope({ subsets: ['latin'] });

Expand Down
55 changes: 35 additions & 20 deletions apps/client/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,60 @@
'use client';
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import PulseLoader from './components/ui/pulseLoader';
import api from './lib/api';
import { useWallet } from '@suiet/wallet-kit';
import JSONFormatter from './utils/JSONFormatter';

import { keywords } from './data';

import Messages from './components/sections/Messages';
import SampleQuestions from './components/sections/SampleQuestions';
import LoadingPage from './components/ui/loadingPage';

export default function Home() {
const [messages, setMessages] = useState<
{ text: string; sender: 'user' | 'llm'; isHTML?: boolean }[]
>([]);
const [inputValue, setInputValue] = useState('');
const [isThinking, setIsThinking] = useState(false);
const { address } = useWallet();
const { address, connected } = useWallet();
const [isLoading, setIsLoading] = useState(false);

// Load chat history when wallet connects
useEffect(() => {
if (address && connected) {
loadChatHistory();
// // Send initial wallet connection message
// handleSend(`Connected wallet: ${address}`);
}
}, [address, connected]);

const loadChatHistory = async () => {
try {
setIsLoading(true);
const response = await api.get(`/query/history/${address}`);
setMessages(response.data);
} catch (error) {
console.error('Error loading chat history:', error);
} finally {
setIsLoading(false);
}
};

const handleSend = async (message?: string) => {
const userMessage = message || inputValue.trim();

if (userMessage) {
setMessages((prev) => [...prev, { text: userMessage, sender: 'user' }]);
setIsThinking(true);
setInputValue('');
setIsThinking(true);

try {
let modifiedMessage = userMessage;

const containsKeywords = keywords.some((keyword) =>
userMessage.toLowerCase().includes(keyword)
);
// Always send the wallet address with the query
const response = await api.post('/query', {
query: userMessage,
walletAddress: address
});

if (containsKeywords) {
modifiedMessage = `${userMessage}. My wallet address is ${address}.`;
}

console.log(modifiedMessage, 'modified');
const response = await api.post('/query', { query: modifiedMessage });
console.log(response);
const res = response.data[0];
console.log(res);
let llmResponse = '';

if (typeof res.response === 'string') {
Expand All @@ -65,7 +79,7 @@ export default function Home() {
}
}
};

if (isLoading) return <LoadingPage />;
return (
<div className="h-[90dvh] w-[90dvw] flex justify-center relative items-center flex-col bg-gradient-to-b from-white to-gray-100">
{/* Chat messages */}
Expand All @@ -81,7 +95,8 @@ export default function Home() {

{isThinking && (
<div className="relative mb-3 p-3 rounded-md w-fit max-w-[70%] bg-gray-300 text-black self-start mr-auto text-left">
Please wait...
{/* Please wait... */}
<PulseLoader />
</div>
)}
</div>
Expand Down
18 changes: 10 additions & 8 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,26 @@
},
"dependencies": {
"@atoma-agents/sui-agent": "workspace:*",
"@types/dotenv": "^8.2.0",
"cors": "^2.8.5",
"dotenv": "^16.4.7",
"express": "^4.21.2"
"express": "^4.21.2",
"mongoose": "^8.10.0"
},
"devDependencies": {
"@types/cors": "^2.8.17",
"@types/express": "^5.0.0",
"@types/jest": "^29.5.12",
"@types/node": "^20.11.19",
"@types/supertest": "^6.0.2",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.57.0",
"nodemon": "^3.1.9",
"ts-node": "^10.9.2",
"typescript": "^5.7.3",
"@types/jest": "^29.5.12",
"@types/supertest": "^6.0.2",
"jest": "^29.7.0",
"nodemon": "^3.1.9",
"supertest": "^6.3.4",
"ts-jest": "^29.1.2"
"ts-jest": "^29.1.2",
"ts-node": "^10.9.2",
"typescript": "^5.7.3"
}
}
}
5 changes: 5 additions & 0 deletions apps/web/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import express, { Application } from 'express';
import cors from 'cors';
import v1routes from './routes/v1';
import { connectDB } from './utils/db';
//import queryRouter from './routes/v1/query';

/**
* Express application instance.
Expand All @@ -27,6 +29,9 @@ app.use(cors()); // Enable CORS for all routes
*/
app.use(v1routes);

// Connect to MongoDB
connectDB().catch(console.error);

/**
* @exports app
* @type {Application}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as dotenv from 'dotenv';
import dotenv from 'dotenv';

// Load environment variables
dotenv.config();
Expand Down
38 changes: 38 additions & 0 deletions apps/web/src/models/ChatHistory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import mongoose, { Schema, Document } from 'mongoose';

export interface IMessage {
text: string;
sender: 'user' | 'llm';
isHTML?: boolean;
timestamp: Date;
}

export interface IChatHistory extends Document {
walletAddress: string;
messages: IMessage[];
createdAt: Date;
updatedAt: Date;
}

const ChatHistorySchema = new Schema(
{
walletAddress: {
type: String,
required: true,
index: true
},
messages: [
{
text: { type: String, required: true },
sender: { type: String, enum: ['user', 'llm'], required: true },
isHTML: { type: Boolean, default: false },
timestamp: { type: Date, default: Date.now }
}
]
},
{
timestamps: true
}
);

export default mongoose.model<IChatHistory>('ChatHistory', ChatHistorySchema);
58 changes: 56 additions & 2 deletions apps/web/src/routes/v1/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Router } from 'express';
import { Request, Response } from 'express';
import { config } from '../../config';
import Agent from '@atoma-agents/sui-agent/src/agents/SuiAgent';
import ChatHistory from '../../models/ChatHistory';

const suiAgent = new Agent(config.atomaSdkBearerAuth);
const queryRouter: Router = Router();

Expand All @@ -13,15 +15,53 @@ queryRouter.get('/health', (req: Request, res: Response) => {
// Query endpoint
const handleQuery = async (req: Request, res: Response): Promise<void> => {
try {
const { query } = req.body;
const { query, walletAddress } = req.body;

if (!query) {
res.status(400).json({
error: 'Missing query in request body'
});

return;
}
// Get agent response first
const result = await suiAgent.SuperVisorAgent(query, walletAddress);

// Only try to save chat history if walletAddress is provided
if (walletAddress) {
try {
// Get or create chat history for this wallet
let chatHistory = await ChatHistory.findOne({ walletAddress });
if (!chatHistory) {
chatHistory = new ChatHistory({ walletAddress, messages: [] });
}

// Add user message to history
chatHistory.messages.push({
text: query,
sender: 'user',
timestamp: new Date()
});

// Add agent response to history
chatHistory.messages.push({
text:
typeof result[0].response === 'string'
? result[0].response
: JSON.stringify(result[0].response),
sender: 'llm',
isHTML: true,
timestamp: new Date()
});

// Save chat history
await chatHistory.save();
} catch (chatError) {
console.warn('Error saving chat history:', chatError);
// Continue with the response even if chat history fails
}
}

const result = await suiAgent.SuperVisorAgent(query);
res.status(200).json(result);
} catch (error) {
console.error('Error handling query:', error);
Expand All @@ -31,6 +71,20 @@ const handleQuery = async (req: Request, res: Response): Promise<void> => {
}
};

// Get chat history endpoint
queryRouter.get('/history/:walletAddress', async (req: Request, res: Response) => {
try {
const { walletAddress } = req.params;
const chatHistory = await ChatHistory.findOne({ walletAddress });
res.status(200).json(chatHistory?.messages || []);
} catch (error) {
console.error('Error fetching chat history:', error);
res.status(500).json({
error: 'Internal server error'
});
}
});

// Handle unsupported methods
const handleUnsupportedMethod = (req: Request, res: Response): void => {
res.status(405).json({
Expand Down
Loading