This commit is contained in:
zramsay 2024-12-20 11:53:42 -05:00
parent a57ab292db
commit 1a9869b0d9
4 changed files with 244 additions and 2 deletions

View File

@ -0,0 +1,41 @@
import { NextRequest, NextResponse } from 'next/server'
export async function POST(req: NextRequest): Promise<NextResponse> {
try {
const { prompt } = await req.json()
if (!prompt) {
return NextResponse.json(
{ error: 'Prompt is required' },
{ status: 400 }
)
}
const response = await fetch('https://ollama.rxpwnz.xyz/api/generate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'llama2',
prompt: prompt,
stream: false
}),
})
if (!response.ok) {
throw new Error(`Ollama API error: ${response.status}`)
}
const data = await response.json()
return NextResponse.json({ response: data.response })
} catch (error) {
console.error('Ollama generation error:', error)
return NextResponse.json(
{ error: error instanceof Error ? error.message : 'Failed to generate text' },
{ status: 500 }
)
}
}
export const dynamic = 'force-dynamic'

View File

@ -3,7 +3,9 @@
import React, { useState } from 'react'
import WalletHeader from '../components/WalletHeader'
import AIServiceCard from '../components/AIServiceCard'
import TextGenerationCard from '../components/TextGenerationCard'
import { generateWithFlux, FluxGenerationResult } from '../services/fluxService'
import { generateWithOllama, OllamaGenerationResult } from '../services/ollamaService'
import { processMTMPayment } from '../services/paymentService'
interface WalletState {
@ -63,6 +65,26 @@ const Page: React.FC = (): React.ReactElement => {
return generateWithFlux(prompt)
}
const handleOllamaGeneration = async (prompt: string): Promise<OllamaGenerationResult> => {
if (!walletState.connected || !walletState.publicKey || !window.solflare) {
return { error: 'Wallet not connected' }
}
// First process payment
const paymentResult = await processMTMPayment(
walletState.publicKey,
2, // 2 MTM tokens for text generation
window.solflare
)
if (!paymentResult.success) {
return { error: paymentResult.error }
}
// Then generate text
return generateWithOllama(prompt)
}
return (
<div className="min-h-screen w-full flex flex-col items-center bg-gradient-to-b from-gray-900 via-gray-800 to-gray-900">
<div className="container max-w-6xl mx-auto px-4 py-8">
@ -86,13 +108,26 @@ const Page: React.FC = (): React.ReactElement => {
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<AIServiceCard
title="Flux Meme Generator"
description="Generate creative memes using Flux AI"
description="Generate creative memes and images using Flux AI"
tokenCost={1}
isWalletConnected={walletState.connected}
onGenerate={handleFluxGeneration}
/>
{/* Add more AI service cards here */}
<TextGenerationCard
title="Ollama AI Chat"
description="Get intelligent responses using local LLaMA2 model"
tokenCost={2}
isWalletConnected={walletState.connected}
onGenerate={handleOllamaGeneration}
/>
</div>
{/* Info Section */}
<div className="mt-12 text-center text-gray-400">
<p className="text-sm">
Powered by Flux AI and Ollama LLaMA2 Requires MTM tokens for generation
</p>
</div>
</div>
</div>

View File

@ -0,0 +1,131 @@
'use client'
import React, { useState } from 'react'
interface TextGenerationCardProps {
title: string
description: string
tokenCost: number
isWalletConnected: boolean
onGenerate: (prompt: string) => Promise<{ textResponse?: string, error?: string }>
}
interface GenerationState {
loading: boolean
processing: boolean
textResponse: string | null
error: string | null
}
const TextGenerationCard: React.FC<TextGenerationCardProps> = ({
title,
description,
tokenCost,
isWalletConnected,
onGenerate
}) => {
const [inputText, setInputText] = useState<string>('')
const [generationState, setGenerationState] = useState<GenerationState>({
loading: false,
processing: false,
textResponse: null,
error: null,
})
const handleGenerate = async (): Promise<void> => {
if (!inputText || !isWalletConnected) return
setGenerationState({
...generationState,
loading: true,
error: null,
})
try {
const result = await onGenerate(inputText)
if (result.error) {
setGenerationState({
...generationState,
loading: false,
error: result.error,
})
return
}
if (result.textResponse) {
setGenerationState({
loading: false,
processing: false,
textResponse: result.textResponse,
error: null,
})
} else {
throw new Error('No response received')
}
} catch (error) {
setGenerationState({
...generationState,
loading: false,
error: error instanceof Error ? error.message : 'Generation failed',
})
}
}
return (
<div className="w-full bg-gray-800/50 backdrop-blur-lg rounded-2xl shadow-xl border border-gray-700/50 mb-8">
<div className="p-6">
<div className="mb-4">
<h2 className="text-2xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-green-400 to-emerald-600">
{title}
</h2>
<p className="text-gray-400 mt-2">{description}</p>
<div className="mt-2 inline-block px-3 py-1 bg-green-500/20 rounded-full text-green-300 text-sm">
Cost: {tokenCost} MTM
</div>
</div>
<div className="space-y-4">
<textarea
value={inputText}
onChange={(e) => setInputText(e.target.value)}
placeholder="Enter your question here..."
disabled={!isWalletConnected}
className="w-full bg-gray-900/50 text-gray-100 border border-gray-700 rounded-xl p-4
placeholder-gray-500 focus:border-green-500 focus:ring-2 focus:ring-green-500/20
focus:outline-none min-h-[120px] transition-all duration-200
disabled:opacity-50 disabled:cursor-not-allowed"
rows={4}
/>
<button
onClick={handleGenerate}
disabled={!isWalletConnected || generationState.loading || !inputText}
className="w-full bg-gradient-to-r from-green-500 to-emerald-500 hover:from-green-600
hover:to-emerald-600 text-white font-semibold py-4 px-6 rounded-xl
transition-all duration-200 shadow-lg hover:shadow-green-500/25
disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:shadow-none"
>
{generationState.loading ? 'Processing...' : `Pay ${tokenCost} MTM & Generate`}
</button>
</div>
{generationState.error && (
<div className="mt-4 bg-red-900/20 border border-red-500/20 text-red-400 px-4 py-3 rounded-xl text-center">
{generationState.error}
</div>
)}
{generationState.textResponse && (
<div className="mt-6 bg-gray-900/50 rounded-xl p-6 border border-gray-700">
<h3 className="text-lg font-semibold text-green-400 mb-3">Response:</h3>
<div className="text-gray-300 whitespace-pre-wrap">
{generationState.textResponse}
</div>
</div>
)}
</div>
</div>
)
}
export default TextGenerationCard

View File

@ -0,0 +1,35 @@
export interface OllamaGenerationResult {
textResponse?: string
error?: string
}
export async function generateWithOllama(prompt: string): Promise<OllamaGenerationResult> {
try {
const response = await fetch('/api/ollama', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ prompt }),
})
if (!response.ok) {
throw new Error('Failed to generate text')
}
const data = await response.json()
console.log('Raw Ollama response:', data)
if (data.response) {
return { textResponse: data.response }
} else {
console.error('Unexpected response structure:', data)
throw new Error('Invalid response format from Ollama API')
}
} catch (error) {
console.error('Generation error:', error)
return {
error: error instanceof Error ? error.message : 'Generation failed'
}
}
}