Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kn write fn back front #11

Merged
merged 7 commits into from
May 31, 2023
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ Branch Example: `kn-feature-name-example`
- NPM
- Git
- Docker Engine
- pkg-config
- cairo

### Development

Expand Down
5 changes: 5 additions & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Backend Python gitignore file

# Etc
created-document.pdf
created-document.tex
created-document.aux

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
114 changes: 93 additions & 21 deletions backend/main.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
from collections import namedtuple
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
import io
import os
import subprocess
import requests

# Python package for PDF parsing
import PyPDF3

# Importing fastAPI
from fastapi import FastAPI, HTTPException
from fastapi.responses import FileResponse, JSONResponse
from fastapi import FastAPI, Request
from fastapi.responses import FileResponse
from fastapi.middleware.cors import CORSMiddleware
import uvicorn

Expand All @@ -19,26 +23,36 @@

# Importing pocketbase sdk
from pocketbase import PocketBase
from pocketbase.client import FileUpload

load_dotenv()

pocketbase_client = PocketBase("http://localhost:8090")
from retry import retry

# Define the maximum number of retries and the delay between retries
max_retries = 5
retry_delay = 2

# Function to create PocketBase client with retries
@retry(tries=max_retries, delay=retry_delay)
def create_pocketbase_client():
pocketbase_client = PocketBase("http://localhost:8090")

# Login as admin
admin_data = pocketbase_client.admins.auth_with_password(os.getenv("POCKETBASE_ADMIN_EMAIL"), os.getenv("POCKETBASE_ADMIN_PASSWORD"))
# Login as admin
pocketbase_client.admins.auth_with_password(
os.getenv("POCKETBASE_ADMIN_EMAIL"), os.getenv("POCKETBASE_ADMIN_PASSWORD")
)

# If the above code executes successfully, return the PocketBase client
return pocketbase_client

# Create PocketBase client with retries
pocketbase_client = create_pocketbase_client()

apikey = os.getenv("OPENAI_API_KEY")
# use the gpt-3.5-turbo LLM
openai_model = ChatOpenAI(openai_api_key=apikey, model_name = 'gpt-3.5-turbo')

chat_prompt = ChatPromptTemplate.from_template("tell me a joke about {subject}")
chat_prompt_value = chat_prompt.format_prompt(subject="soccer")

llm_chain = LLMChain(
prompt = chat_prompt,
llm = openai_model
)

app = FastAPI()

app.add_middleware(
Expand Down Expand Up @@ -83,6 +97,71 @@ async def read_api_documents_calculate_stats(document_id: str, user_id: str):
}
pocketbase_client.collection('documents').update(recordId, data)

@app.post("/api/documents/create/{user_id}")
async def read_api_document_create(user_id: str, request: Request):
# Accessing Request body and converting it to a dictionary
body = await request.json()

# Sending topic to gpt to generate latex output of the text
topic = body.get('topic')

# Create a LaTeX prompt using this topic
latex_prompt = ChatPromptTemplate.from_template("Write a section about {subject}, it should be in LaTeX format.")
latex_prompt_value = latex_prompt.format_prompt(subject=topic)

llm_chain = LLMChain(
prompt = latex_prompt,
llm = openai_model
)

# Generate LaTeX content using this prompt
latex_content = llm_chain.run(latex_prompt_value)
latex_content = "\\documentclass{article}\n\\begin{document}\n" + latex_content + "\n\\end{document}"

# Write the LaTeX content to a file
latex_file_name = "created-document.tex"
with open(latex_file_name, "w") as file:
file.write(latex_content)

# Generate a PDF from the LaTeX file
current_dir = os.getcwd()
generate_pdf_from_latex(latex_file_name, current_dir)

# The name of the generated PDF file
pdf_file_name = latex_file_name.replace('.tex', '.pdf')
# The path to the generated PDF file
pdf_file_path = os.path.join(current_dir, pdf_file_name)

# Calculate the total number of pages and words in the document
total_pages = get_pdf_page_count(pdf_file_path)
total_words = get_pdf_word_count(pdf_file_path)

# Create a new document in the database
data = {
"owner": user_id,
"name": pdf_file_name,
"document": FileUpload((pdf_file_name, open(pdf_file_path, "rb"))),
"type": "Created",
"page_count": total_pages,
"word_count": total_words
}

pocketbase_client.collection("documents").create(data)

# Delete the generated LaTeX and PDF files
os.remove(latex_file_name)
os.remove(pdf_file_path)

def generate_pdf_from_latex(latex_file_name, output_directory):
# Save the current working directory
original_cwd = os.getcwd()
# Change the current working directory
os.chdir(output_directory)
# Generate a PDF from the LaTeX file
subprocess.check_call(['pdflatex', latex_file_name])
# Restore the original working directory
os.chdir(original_cwd)

def get_pdf_page_count(file_content):
pdf_reader = PyPDF3.PdfFileReader(file_content)
total_pages = len(pdf_reader.pages)
Expand All @@ -96,13 +175,6 @@ def get_pdf_word_count(file_content):
total_words += len(page.extractText().split())
return total_words

@app.get("/api/joke")
async def read_():
# joke question
question = "Tell me a joke"
response = llm_chain.run(question)
return {"message": response}

@app.get("/logo.png")
async def logo():
return FileResponse('logo.png', media_type='image/png')
Expand Down
5 changes: 4 additions & 1 deletion backend/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ fastapi
uvicorn
openai
python-dotenv
PyPDF3
pocketbase
PyPDF3
retry
reportlab
3 changes: 3 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ services:
image: adm-backend
container_name: adm-backend
restart: unless-stopped
network_mode: host
build:
context: ./backend
dockerfile: Dockerfile.backend
env_file:
- ./backend/.env
depends_on:
- pocketbase
ports:
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/lib/components/ActionCards.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import IconCreate from '~icons/solar/clipboard-add-outline';
</script>

<div class="card bg-base-200 w-96 flex-1 shadow-lg">
<div class="card bg-base-200 h-96 w-96 flex-1 shadow-lg">
<div class="card-body">
<h2 class="card-title">Read a new file</h2>
<p>Upload a new file and ask it your questions!</p>
Expand All @@ -17,7 +17,7 @@
</div>
</div>
</div>
<div class="card bg-base-200 w-96 flex-1 shadow-lg">
<div class="card bg-base-200 h-96 w-96 flex-1 shadow-lg">
<div class="card-body">
<h2 class="card-title">Create a new file</h2>
<p>Tell us what you want and create your file!</p>
Expand Down
32 changes: 0 additions & 32 deletions frontend/src/routes/dashboard/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,6 @@
import ActionCards from '$lib/components/ActionCards.svelte';
import FileTable from '$lib/components/FileTable.svelte';
import Stats from '$lib/components/Stats.svelte';

let joke: { message: string } | null = null;

async function fetchData() {
try {
const response = await fetch('http://localhost:5003/api/joke');
if (!response.ok) {
// if HTTP-status is 200-299
// get the error message from the server, or default to a response status text
throw new Error(response.statusText);
}
joke = await response.json();
console.log(joke);
} catch (error) {
console.error('Fetch error:', error);
}
}
</script>

<div class="flex flex-col gap-12">
Expand All @@ -31,21 +14,6 @@
<div class="flex gap-4">
<ActionCards />
</div>
<div class="flex">
<div class="card bg-base-200 w-96 flex-1 shadow-lg">
<div class="card-body">
<h2 class="card-title">Generate a joke!</h2>
{#if joke}
<p class="text-success">{joke.message}</p>
{:else}
<p>Click to generate a joke.</p>
{/if}
<div class="card-actions justify-end">
<button class="btn btn-primary" on:click={fetchData}>New Joke</button>
</div>
</div>
</div>
</div>
<div class="flex flex-grow">
<FileTable />
</div>
Expand Down
38 changes: 37 additions & 1 deletion frontend/src/routes/dashboard/file-create/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,42 @@
import { redirect } from '@sveltejs/kit';
import type { Actions } from './$types';
import { error, redirect } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';

export const actions: Actions = {
createDocument: async ({ locals, request }) => {
const data = await request.formData();
const topicRequested = data.get('topic') as string;

if (topicRequested.length === 0) {
throw error(400, 'Please fill in a topic');
}

try {
// Python backend to creating document
const response = await fetch(`http://localhost:5003/api/documents/create/${locals.user.id}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
topic: topicRequested
})
});

if (!response.ok) {
// if HTTP-status is 200-299
// get the error message from the server, or default to a response status text
throw new Error(response.statusText);
}
} catch (err) {
console.error(err);
throw error(400, 'Something went wrong creating your document');
}

throw redirect(303, '/dashboard/file-create/preview');
}
};

export const load: PageServerLoad = async ({ locals }) => {
if (!locals.user) {
throw redirect(303, '/login');
Expand Down
Loading