mirror of
https://github.com/run-llama/app-creator.git
synced 2026-06-30 21:08:04 -04:00
added date to output folder
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
# Ignore all files in the output folder
|
||||
output/**/*
|
||||
@@ -31,21 +31,32 @@ async function outputResult(
|
||||
model: string,
|
||||
packageResult: PackageResult,
|
||||
) {
|
||||
// Generate timestamp
|
||||
const timestamp = new Date().toISOString().slice(0, 10);
|
||||
|
||||
// Create output directory if it doesn't exist
|
||||
const outputDir = path.join("output", name, model);
|
||||
const outputDir = path.join("output", timestamp, name, model);
|
||||
await fs.mkdir(outputDir, { recursive: true });
|
||||
|
||||
// Iterate over all files in the packageResult and store each file with their correct path
|
||||
for (const file of packageResult.files) {
|
||||
const filePath = path.join(outputDir, file.path);
|
||||
const fileDir = path.dirname(filePath);
|
||||
try {
|
||||
// Iterate over all files in the packageResult and store each file with their correct path
|
||||
for (const file of packageResult.files) {
|
||||
const filePath = path.join(outputDir, file.path);
|
||||
const fileDir = path.dirname(filePath);
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
await fs.mkdir(fileDir, { recursive: true });
|
||||
// Create directory if it doesn't exist
|
||||
await fs.mkdir(fileDir, { recursive: true });
|
||||
|
||||
// Write file content
|
||||
await fs.writeFile(filePath, file.content);
|
||||
console.log(`File written to: ${filePath}`);
|
||||
// Write file content
|
||||
await fs.writeFile(filePath, file.content);
|
||||
console.log(`File written to: ${filePath}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error in outputResult:", error);
|
||||
const errorLogPath = path.join(outputDir, "error.log");
|
||||
const errorContent = `Error: ${error}\n\nPackageResult structure:\n${JSON.stringify(packageResult, null, 2)}`;
|
||||
await fs.writeFile(errorLogPath, errorContent);
|
||||
console.log(`Error details written to: ${errorLogPath}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
DATABASE_URL=postgres://username:password@localhost:5432/todo_db
|
||||
@@ -0,0 +1,7 @@
|
||||
export default function Header() {
|
||||
return (
|
||||
<header className="bg-blue-500 p-4 text-white text-center">
|
||||
<h1 className="text-2xl">Todo App</h1>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
export default function Task({ task, onDelete, onToggle }) {
|
||||
return (
|
||||
<div className="flex justify-between items-center p-2 border-b">
|
||||
<span className={task.completed ? 'line-through' : ''}>{task.task}</span>
|
||||
<div>
|
||||
<button onClick={() => onToggle(task.id, !task.completed)} className="bg-green-500 text-white p-1 rounded">
|
||||
{task.completed ? 'Undo' : 'Complete'}
|
||||
</button>
|
||||
<button onClick={() => onDelete(task.id)} className="bg-red-500 text-white p-1 rounded ml-2">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import Task from './Task';
|
||||
|
||||
export default function TaskList({ tasks, onDelete, onToggle }) {
|
||||
return (
|
||||
<div>
|
||||
{tasks.map((task) => (
|
||||
<Task key={task.id} task={task} onDelete={onDelete} onToggle={onToggle} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
const { Pool } = require('pg');
|
||||
|
||||
const pool = new Pool({
|
||||
connectionString: process.env.DATABASE_URL,
|
||||
});
|
||||
|
||||
const query = (text, params) => pool.query(text, params);
|
||||
|
||||
module.exports = {
|
||||
query,
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "todo-app",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "latest",
|
||||
"react": "latest",
|
||||
"react-dom": "latest",
|
||||
"pg": "^8.7.1",
|
||||
"tailwindcss": "^3.0.0",
|
||||
"postcss": "^8.0.0",
|
||||
"autoprefixer": "^10.0.0",
|
||||
"swr": "^1.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import db from '../../lib/db';
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method === 'GET') {
|
||||
const { rows } = await db.query('SELECT * FROM tasks');
|
||||
return res.status(200).json(rows);
|
||||
}
|
||||
|
||||
if (req.method === 'POST') {
|
||||
const { task } = req.body;
|
||||
const { rows } = await db.query('INSERT INTO tasks (task, completed) VALUES ($1, $2) RETURNING *', [task, false]);
|
||||
return res.status(201).json(rows[0]);
|
||||
}
|
||||
|
||||
if (req.method === 'DELETE') {
|
||||
const { id } = req.body;
|
||||
await db.query('DELETE FROM tasks WHERE id = $1', [id]);
|
||||
return res.status(204).json({});
|
||||
}
|
||||
|
||||
if (req.method === 'PUT') {
|
||||
const { id, completed } = req.body;
|
||||
await db.query('UPDATE tasks SET completed = $1 WHERE id = $2', [completed, id]);
|
||||
return res.status(204).json({});
|
||||
}
|
||||
|
||||
res.setHeader('Allow', ['GET', 'POST', 'DELETE', 'PUT']);
|
||||
res.status(405).end(`Method ${req.method} Not Allowed`);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import Header from '../components/Header';
|
||||
import TaskList from '../components/TaskList';
|
||||
import fetcher from '../utils/fetcher';
|
||||
|
||||
export default function Home() {
|
||||
const [tasks, setTasks] = useState([]);
|
||||
const [taskInput, setTaskInput] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
const loadTasks = async () => {
|
||||
const data = await fetcher('/api/tasks');
|
||||
setTasks(data);
|
||||
};
|
||||
loadTasks();
|
||||
}, []);
|
||||
|
||||
const addTask = async () => {
|
||||
if (!taskInput) return;
|
||||
const newTask = await fetcher('/api/tasks', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ task: taskInput }),
|
||||
});
|
||||
setTasks([...tasks, newTask]);
|
||||
setTaskInput('');
|
||||
};
|
||||
|
||||
const deleteTask = async (id) => {
|
||||
await fetcher('/api/tasks', {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id }),
|
||||
});
|
||||
setTasks(tasks.filter((task) => task.id !== id));
|
||||
};
|
||||
|
||||
const toggleTask = async (id, completed) => {
|
||||
await fetcher('/api/tasks', {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id, completed }),
|
||||
});
|
||||
setTasks(tasks.map(task => (task.id === id ? { ...task, completed } : task)));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container mx-auto">
|
||||
<Header />
|
||||
<div className="p-4">
|
||||
<input
|
||||
type="text"
|
||||
value={taskInput}
|
||||
onChange={(e) => setTaskInput(e.target.value)}
|
||||
className="border p-2 w-full"
|
||||
placeholder="Add a new task"
|
||||
/>
|
||||
<button onClick={addTask} className="bg-blue-500 text-white p-2 mt-2">Add Task</button>
|
||||
</div>
|
||||
<TaskList tasks={tasks} onDelete={deleteTask} onToggle={toggleTask} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
|
||||
darkMode: false,
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
variants: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
const fetcher = (url, options) => fetch(url, options).then((res) => res.json());
|
||||
|
||||
export default fetcher;
|
||||
@@ -0,0 +1 @@
|
||||
DATABASE_URL="postgresql://<username>:<password>@localhost:5432/<database_name>"
|
||||
@@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
|
||||
const Task = ({ task, onDelete, onComplete }) => {
|
||||
return (
|
||||
<div className="flex justify-between items-center border-b py-2">
|
||||
<div className={task.completed ? "line-through" : ""}>{task.title}</div>
|
||||
<div>
|
||||
<button
|
||||
onClick={() => onComplete(task.id)}
|
||||
className="mr-2 text-green-500"
|
||||
>
|
||||
Complete
|
||||
</button>
|
||||
<button onClick={() => onDelete(task.id)} className="text-red-500">
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Task;
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "my-todo-app",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"prisma": "prisma"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^3.0.0",
|
||||
"next": "latest",
|
||||
"react": "latest",
|
||||
"react-dom": "latest",
|
||||
"tailwindcss": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prisma": "^3.0.0",
|
||||
"autoprefixer": "^10.0.0",
|
||||
"postcss": "^8.0.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import '../styles/globals.css';
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />;
|
||||
}
|
||||
|
||||
export default MyApp;
|
||||
@@ -0,0 +1,31 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method === 'GET') {
|
||||
const tasks = await prisma.task.findMany();
|
||||
res.status(200).json(tasks);
|
||||
} else if (req.method === 'POST') {
|
||||
const { title } = req.body;
|
||||
const task = await prisma.task.create({
|
||||
data: { title, completed: false },
|
||||
});
|
||||
res.status(201).json(task);
|
||||
} else if (req.method === 'DELETE') {
|
||||
const { id } = req.body;
|
||||
await prisma.task.delete({
|
||||
where: { id },
|
||||
});
|
||||
res.status(204).end();
|
||||
} else if (req.method === 'PATCH') {
|
||||
const { id, completed } = req.body;
|
||||
const task = await prisma.task.update({
|
||||
where: { id },
|
||||
data: { completed },
|
||||
});
|
||||
res.status(200).json(task);
|
||||
} else {
|
||||
res.status(405).end();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import Task from '../components/Task';
|
||||
|
||||
export default function Home() {
|
||||
const [tasks, setTasks] = useState([]);
|
||||
const [newTask, setNewTask] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
fetchTasks();
|
||||
}, []);
|
||||
|
||||
async function fetchTasks() {
|
||||
const res = await fetch('/api/tasks');
|
||||
const data = await res.json();
|
||||
setTasks(data);
|
||||
}
|
||||
|
||||
async function addTask() {
|
||||
const res = await fetch('/api/tasks', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ title: newTask }),
|
||||
});
|
||||
const data = await res.json();
|
||||
setTasks((prev) => [...prev, data]);
|
||||
setNewTask('');
|
||||
}
|
||||
|
||||
async function deleteTask(id) {
|
||||
await fetch('/api/tasks', {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ id }),
|
||||
});
|
||||
setTasks((prev) => prev.filter((task) => task.id !== id));
|
||||
}
|
||||
|
||||
async function completeTask(id) {
|
||||
const task = tasks.find((task) => task.id === id);
|
||||
await fetch('/api/tasks', {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ id, completed: !task.completed }),
|
||||
});
|
||||
setTasks((prev) =>
|
||||
prev.map((task) =>
|
||||
task.id === id ? { ...task, completed: !task.completed } : task
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container mx-auto p-4">
|
||||
<h1 className="text-2xl font-bold mb-4">Todo App</h1>
|
||||
<div className="mb-4">
|
||||
<input
|
||||
type="text"
|
||||
value={newTask}
|
||||
onChange={(e) => setNewTask(e.target.value)}
|
||||
className="border p-2 mr-2"
|
||||
/>
|
||||
<button onClick={addTask} className="bg-blue-500 text-white p-2">
|
||||
Add Task
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
{tasks.map((task) => (
|
||||
<Task
|
||||
key={task.id}
|
||||
task={task}
|
||||
onDelete={deleteTask}
|
||||
onComplete={completeTask}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
model Task {
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
completed Boolean @default(false)
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
|
||||
darkMode: false,
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
variants: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
let prisma;
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
prisma = new PrismaClient();
|
||||
} else {
|
||||
if (!global.prisma) {
|
||||
global.prisma = new PrismaClient();
|
||||
}
|
||||
prisma = global.prisma;
|
||||
}
|
||||
|
||||
export default prisma;
|
||||
@@ -0,0 +1,28 @@
|
||||
import { useState } from 'react'
|
||||
|
||||
export default function AddTaskForm({ addTask }) {
|
||||
const [title, setTitle] = useState('')
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault()
|
||||
if (title.trim()) {
|
||||
addTask(title)
|
||||
setTitle('')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} className="flex mb-4">
|
||||
<input
|
||||
type="text"
|
||||
className="flex-grow border rounded px-3 py-2 mr-2 focus:outline-none"
|
||||
placeholder="Add a new task"
|
||||
value={title}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
/>
|
||||
<button type="submit" className="bg-blue-500 text-white px-4 py-2 rounded">
|
||||
Add
|
||||
</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
export default function TaskItem({ task, toggleTask, deleteTask }) {
|
||||
return (
|
||||
<li className="flex items-center justify-between p-2 border-b">
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={task.completed}
|
||||
onChange={() => toggleTask(task.id, !task.completed)}
|
||||
className="mr-2"
|
||||
/>
|
||||
<span className={task.completed ? 'line-through text-gray-500' : ''}>
|
||||
{task.title}
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => deleteTask(task.id)}
|
||||
className="text-red-500 hover:text-red-700"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import TaskItem from './TaskItem'
|
||||
|
||||
export default function TaskList({ tasks, toggleTask, deleteTask }) {
|
||||
if (tasks.length === 0) {
|
||||
return <p className="text-center text-gray-500">No tasks available.</p>
|
||||
}
|
||||
|
||||
return (
|
||||
<ul>
|
||||
{tasks.map(task => (
|
||||
<TaskItem key={task.id} task={task} toggleTask={toggleTask} deleteTask={deleteTask} />
|
||||
))}
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
let prisma
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
prisma = new PrismaClient()
|
||||
} else {
|
||||
if (!global.prisma) {
|
||||
global.prisma = new PrismaClient()
|
||||
}
|
||||
prisma = global.prisma
|
||||
}
|
||||
|
||||
export default prisma
|
||||
@@ -0,0 +1,6 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "todo-app",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"prisma": "prisma"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "latest",
|
||||
"react": "latest",
|
||||
"react-dom": "latest",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"postcss": "^8.4.21",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"prisma": "^4.13.0",
|
||||
"@prisma/client": "^4.13.0",
|
||||
"axios": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "8.39.0",
|
||||
"eslint-config-next": "13.4.19"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import prisma from '../../lib/db'
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method === 'GET') {
|
||||
const tasks = await prisma.task.findMany({
|
||||
orderBy: { createdAt: 'desc' },
|
||||
})
|
||||
res.status(200).json(tasks)
|
||||
} else if (req.method === 'POST') {
|
||||
const { title } = req.body
|
||||
if (!title) {
|
||||
return res.status(400).json({ error: 'Title is required' })
|
||||
}
|
||||
const task = await prisma.task.create({
|
||||
data: { title },
|
||||
})
|
||||
res.status(201).json(task)
|
||||
} else if (req.method === 'PUT') {
|
||||
const { id, completed } = req.body
|
||||
if (id === undefined || completed === undefined) {
|
||||
return res.status(400).json({ error: 'ID and completed status are required' })
|
||||
}
|
||||
const task = await prisma.task.update({
|
||||
where: { id: Number(id) },
|
||||
data: { completed: Boolean(completed) },
|
||||
})
|
||||
res.status(200).json(task)
|
||||
} else if (req.method === 'DELETE') {
|
||||
const { id } = req.body
|
||||
if (id === undefined) {
|
||||
return res.status(400).json({ error: 'ID is required' })
|
||||
}
|
||||
await prisma.task.delete({
|
||||
where: { id: Number(id) },
|
||||
})
|
||||
res.status(204).end()
|
||||
} else {
|
||||
res.setHeader('Allow', ['GET', 'POST', 'PUT', 'DELETE'])
|
||||
res.status(405).end(`Method ${req.method} Not Allowed`)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import axios from 'axios'
|
||||
import AddTaskForm from '../components/AddTaskForm'
|
||||
import TaskList from '../components/TaskList'
|
||||
|
||||
export default function Home() {
|
||||
const [tasks, setTasks] = useState([])
|
||||
|
||||
const fetchTasks = async () => {
|
||||
const res = await axios.get('/api/tasks')
|
||||
setTasks(res.data)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchTasks()
|
||||
}, [])
|
||||
|
||||
const addTask = async (title) => {
|
||||
const res = await axios.post('/api/tasks', { title })
|
||||
setTasks([res.data, ...tasks])
|
||||
}
|
||||
|
||||
const toggleTask = async (id, completed) => {
|
||||
const res = await axios.put('/api/tasks', { id, completed })
|
||||
setTasks(tasks.map(task => task.id === id ? res.data : task))
|
||||
}
|
||||
|
||||
const deleteTask = async (id) => {
|
||||
await axios.delete('/api/tasks', { data: { id } })
|
||||
setTasks(tasks.filter(task => task.id !== id))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100 flex items-center justify-center">
|
||||
<div className="bg-white p-8 rounded shadow-md w-full max-w-md">
|
||||
<h1 className="text-2xl font-bold mb-4 text-center">Todo App</h1>
|
||||
<AddTaskForm addTask={addTask} />
|
||||
<TaskList tasks={tasks} toggleTask={toggleTask} deleteTask={deleteTask} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
model Task {
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
completed Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -0,0 +1,11 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./pages/**/*.{js,ts,jsx,tsx}",
|
||||
"./components/**/*.{js,ts,jsx,tsx}"
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# Question and Answer App
|
||||
|
||||
This is a simple Python application that allows users to ask questions and retrieve answers from a database.
|
||||
|
||||
## How to Use
|
||||
|
||||
1. Clone the repository.
|
||||
2. Install the necessary dependencies:
|
||||
```
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
3. Run the application:
|
||||
```
|
||||
python app.py
|
||||
```
|
||||
4. Enter your questions, and if the application does not have an answer, you can provide one to be stored for future reference.
|
||||
|
||||
## File Structure
|
||||
|
||||
- `app.py`: Main application file.
|
||||
- `database.py`: Handles database operations for question and answer storage.
|
||||
- `models.py`: Placeholder for models (currently unused).
|
||||
- `data/qa_database.json`: JSON file for storing question-answer pairs.
|
||||
@@ -0,0 +1,21 @@
|
||||
import json
|
||||
from database import Database
|
||||
|
||||
def main():
|
||||
db = Database('data/qa_database.json')
|
||||
|
||||
while True:
|
||||
question = input("Please enter your question (or type 'exit' to quit): ")
|
||||
if question.lower() == 'exit':
|
||||
break
|
||||
|
||||
answer = db.lookup_answer(question)
|
||||
if answer:
|
||||
print(f"Answer: {answer}")
|
||||
else:
|
||||
new_answer = input("I don't have an answer for that. Please provide an answer: ")
|
||||
db.store_qa_pair(question, new_answer)
|
||||
print("Thank you! Your question and answer have been saved.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,29 @@
|
||||
import json
|
||||
from difflib import get_close_matches
|
||||
|
||||
class Database:
|
||||
def __init__(self, filepath):
|
||||
self.filepath = filepath
|
||||
self.load_data()
|
||||
|
||||
def load_data(self):
|
||||
try:
|
||||
with open(self.filepath, 'r') as file:
|
||||
self.data = json.load(file)
|
||||
except FileNotFoundError:
|
||||
self.data = {}
|
||||
|
||||
def save_data(self):
|
||||
with open(self.filepath, 'w') as file:
|
||||
json.dump(self.data, file, indent=4)
|
||||
|
||||
def lookup_answer(self, question):
|
||||
questions = list(self.data.keys())
|
||||
close_matches = get_close_matches(question, questions)
|
||||
if close_matches:
|
||||
return self.data[close_matches[0]]
|
||||
return None
|
||||
|
||||
def store_qa_pair(self, question, answer):
|
||||
self.data[question] = answer
|
||||
self.save_data()
|
||||
@@ -0,0 +1,2 @@
|
||||
# Placeholder for future model definitions if needed.
|
||||
# Currently, this file is kept for potential extension of the application.
|
||||
@@ -0,0 +1 @@
|
||||
difflib
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,53 @@
|
||||
import os
|
||||
import sys
|
||||
from database import Database
|
||||
|
||||
def main():
|
||||
db_path = os.path.join(os.path.dirname(__file__), 'data', 'qa.db')
|
||||
try:
|
||||
db = Database(db_path)
|
||||
except Exception as e:
|
||||
print(f"Failed to connect to the database: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
print("Welcome to the QA App. Type 'exit' to quit.")
|
||||
|
||||
while True:
|
||||
try:
|
||||
question = input("\nEnter your question: ").strip()
|
||||
if question.lower() == 'exit':
|
||||
print("Goodbye!")
|
||||
break
|
||||
if not question:
|
||||
print("Please enter a valid question.")
|
||||
continue
|
||||
|
||||
answer = db.get_answer(question)
|
||||
if answer:
|
||||
print(f"Answer: {answer}")
|
||||
else:
|
||||
# Check for similar questions
|
||||
similar_question = db.find_similar_question(question)
|
||||
if similar_question:
|
||||
print(f"Did you mean: '{similar_question}'?")
|
||||
user_choice = input("Press 'y' to use the suggested question or 'n' to provide a new answer: ").strip().lower()
|
||||
if user_choice == 'y':
|
||||
answer = db.get_answer(similar_question)
|
||||
print(f"Answer: {answer}")
|
||||
continue
|
||||
|
||||
user_answer = input("I don't have an answer for that. Please provide the answer: ").strip()
|
||||
if user_answer:
|
||||
try:
|
||||
db.add_qa_pair(question, user_answer)
|
||||
print("Your answer has been saved. Thank you!")
|
||||
except Exception as e:
|
||||
print(f"Failed to save the answer: {e}")
|
||||
except KeyboardInterrupt:
|
||||
print("\nGoodbye!")
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred: {e}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1 @@
|
||||
*This is the SQLite database file. It will be created automatically when you run `app.py` if it does not exist.*
|
||||
@@ -0,0 +1,74 @@
|
||||
import os
|
||||
import sqlite3
|
||||
from utils import get_close_match
|
||||
|
||||
class Database:
|
||||
def __init__(self, db_path):
|
||||
self.db_path = db_path
|
||||
self.conn = self.connect()
|
||||
self.create_table()
|
||||
|
||||
def connect(self):
|
||||
try:
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
return conn
|
||||
except sqlite3.Error as e:
|
||||
raise Exception(f"SQLite connection error: {e}")
|
||||
|
||||
def create_table(self):
|
||||
try:
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS qa (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
question TEXT UNIQUE COLLATE NOCASE,
|
||||
answer TEXT
|
||||
)
|
||||
''')
|
||||
self.conn.commit()
|
||||
except sqlite3.Error as e:
|
||||
raise Exception(f"Failed to create table: {e}")
|
||||
|
||||
def get_all_questions(self):
|
||||
try:
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("SELECT question, answer FROM qa")
|
||||
return cursor.fetchall()
|
||||
except sqlite3.Error as e:
|
||||
raise Exception(f"Failed to fetch questions: {e}")
|
||||
|
||||
def get_answer(self, user_question, threshold=0.7):
|
||||
try:
|
||||
questions = [q for q, _ in self.get_all_questions()]
|
||||
close_question = get_close_match(user_question, questions, threshold)
|
||||
if close_question:
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("SELECT answer FROM qa WHERE question = ?", (close_question,))
|
||||
result = cursor.fetchone()
|
||||
if result:
|
||||
return result[0]
|
||||
return None
|
||||
except Exception as e:
|
||||
raise Exception(f"Error retrieving answer: {e}")
|
||||
|
||||
def find_similar_question(self, user_question, threshold=0.7):
|
||||
try:
|
||||
questions = [q for q, _ in self.get_all_questions()]
|
||||
return get_close_match(user_question, questions, threshold)
|
||||
except Exception as e:
|
||||
print(f"Error finding similar question: {e}")
|
||||
return None
|
||||
|
||||
def add_qa_pair(self, question, answer):
|
||||
try:
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("INSERT INTO qa (question, answer) VALUES (?, ?)", (question, answer))
|
||||
self.conn.commit()
|
||||
except sqlite3.IntegrityError:
|
||||
raise Exception("This question already exists in the database.")
|
||||
except sqlite3.Error as e:
|
||||
raise Exception(f"Failed to add QA pair: {e}")
|
||||
|
||||
def __del__(self):
|
||||
if self.conn:
|
||||
self.conn.close()
|
||||
@@ -0,0 +1,2 @@
|
||||
# Python version required
|
||||
python_version >=3.7
|
||||
@@ -0,0 +1,22 @@
|
||||
from difflib import SequenceMatcher
|
||||
|
||||
def similarity(a, b):
|
||||
"""
|
||||
Calculate the similarity ratio between two strings.
|
||||
"""
|
||||
return SequenceMatcher(None, a, b).ratio()
|
||||
|
||||
def get_close_match(user_question, questions, threshold=0.7):
|
||||
"""
|
||||
Find the closest matching question from a list of questions based on similarity threshold.
|
||||
"""
|
||||
best_match = None
|
||||
highest_sim = 0
|
||||
for q in questions:
|
||||
sim = similarity(user_question.lower(), q.lower())
|
||||
if sim > highest_sim:
|
||||
highest_sim = sim
|
||||
best_match = q
|
||||
if highest_sim >= threshold:
|
||||
return best_match
|
||||
return None
|
||||
@@ -0,0 +1,60 @@
|
||||
import sys
|
||||
from database import Database
|
||||
from difflib import get_close_matches
|
||||
|
||||
def main():
|
||||
"""Main function to run the question-answer application."""
|
||||
try:
|
||||
with Database('questions.db') as db:
|
||||
while True:
|
||||
try:
|
||||
question = input("Please enter your question (or type 'exit' to quit): ").strip()
|
||||
if question.lower() == 'exit':
|
||||
print("Goodbye!")
|
||||
break
|
||||
if not question:
|
||||
print("Question cannot be empty.")
|
||||
continue
|
||||
|
||||
questions = db.get_all_questions()
|
||||
matches = get_close_matches(question, questions, n=5, cutoff=0.5)
|
||||
|
||||
if matches:
|
||||
print("Did you mean:")
|
||||
for idx, match in enumerate(matches, 1):
|
||||
print(f"{idx}. {match}")
|
||||
choice = input("Please enter the number of the closest match or 0 if none: ").strip()
|
||||
if choice.isdigit():
|
||||
choice_num = int(choice)
|
||||
if 1 <= choice_num <= len(matches):
|
||||
selected_question = matches[choice_num - 1]
|
||||
answer = db.get_answer(selected_question)
|
||||
print(f"Answer: {answer}")
|
||||
elif choice_num == 0:
|
||||
print("Sorry, I don't know the answer to that question.")
|
||||
new_answer = input("Please provide the answer so I can learn: ").strip()
|
||||
if not new_answer:
|
||||
print("Answer cannot be empty.")
|
||||
continue
|
||||
db.add_question_answer(question, new_answer)
|
||||
print("Thank you! I've learned something new.")
|
||||
else:
|
||||
print("Invalid selection.")
|
||||
else:
|
||||
print("Invalid input. Please enter a number.")
|
||||
else:
|
||||
print("Sorry, I don't know the answer to that question.")
|
||||
new_answer = input("Please provide the answer so I can learn: ").strip()
|
||||
if not new_answer:
|
||||
print("Answer cannot be empty.")
|
||||
continue
|
||||
db.add_question_answer(question, new_answer)
|
||||
print("Thank you! I've learned something new.")
|
||||
except KeyboardInterrupt:
|
||||
print("\nGoodbye!")
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"An unexpected error occurred: {e}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,50 @@
|
||||
import sqlite3
|
||||
|
||||
class Database:
|
||||
"""A class to handle database operations for question-answer pairs."""
|
||||
|
||||
def __init__(self, db_name):
|
||||
"""Initialize the database connection and create the table if it doesn't exist."""
|
||||
self.conn = sqlite3.connect(db_name)
|
||||
self.create_table()
|
||||
|
||||
def __enter__(self):
|
||||
"""Enter the runtime context related to this object."""
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
"""Exit the runtime context and close the database connection."""
|
||||
self.close()
|
||||
|
||||
def create_table(self):
|
||||
"""Create the qa_pairs table if it does not already exist."""
|
||||
query = '''CREATE TABLE IF NOT EXISTS qa_pairs (
|
||||
question TEXT PRIMARY KEY,
|
||||
answer TEXT NOT NULL
|
||||
);'''
|
||||
self.conn.execute(query)
|
||||
self.conn.commit()
|
||||
|
||||
def get_all_questions(self):
|
||||
"""Retrieve all questions from the database."""
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("SELECT question FROM qa_pairs")
|
||||
results = cursor.fetchall()
|
||||
return [row[0] for row in results]
|
||||
|
||||
def get_answer(self, question):
|
||||
"""Retrieve the answer for the given question."""
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("SELECT answer FROM qa_pairs WHERE question = ?", (question,))
|
||||
result = cursor.fetchone()
|
||||
return result[0] if result else None
|
||||
|
||||
def add_question_answer(self, question, answer):
|
||||
"""Add a new question and answer pair to the database."""
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("INSERT OR REPLACE INTO qa_pairs (question, answer) VALUES (?, ?)", (question, answer))
|
||||
self.conn.commit()
|
||||
|
||||
def close(self):
|
||||
"""Close the database connection."""
|
||||
self.conn.close()
|
||||
@@ -0,0 +1 @@
|
||||
# No external packages required. Uses only Python standard library.
|
||||
+1
-1
@@ -23,7 +23,7 @@ export const packager = async (context: Context, ev: PackageEvent) => {
|
||||
|
||||
// use own llm for extracting the files
|
||||
const llm = new OpenAI({
|
||||
model: "gpt-4o-mini",
|
||||
model: "gpt-4o",
|
||||
additionalChatOptions: { response_format: { type: "json_object" } },
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user