This commit is contained in:
Omer Sabic 2024-06-02 02:36:39 +02:00
parent 768afb9d06
commit a9260b2867
4 changed files with 95 additions and 36 deletions

View File

@ -10,3 +10,5 @@ GOOGLE_CLIENT_ID=
GOOGLE_SECRET=
OPENAI_TOKEN=
CERTS_URL=

View File

@ -4,7 +4,7 @@ import { desc, eq, getTableColumns, sql } from "drizzle-orm";
import { db } from "../db/index.js";
import { articles, articles as articlesTable, signups as signupsTable, sites, users } from "../db/schemas.js";
import { authMiddleware, authMiddlewareFn } from "../modules/middleware.js";
import { jsonToCsv, getAccessToken, getVideoCaptions, getCaptionText, parseTextFromCaptions, createBlogFromCaptions, createArticleSlug, getVideoById } from "../utils/index.js";
import { jsonToCsv, getAccessToken, getVideoCaptions, getCaptionText, parseTextFromCaptions, createBlogFromCaptions, createArticleSlug, getVideoById, env } from "../utils/index.js";
/**
*
@ -196,8 +196,7 @@ export const dashboardRoutes = (fastify, _, done) => {
const video_data = await getVideoById(access_token, req.body.video_id);
const blog_content = await createBlogFromCaptions(caption_text, { title: video_data.title, description: video_data.description }, req.body);
const blog_content_json = JSON.parse(blog_content);
const blog_content_json = await createBlogFromCaptions(caption_text, { title: video_data.title, description: video_data.description }, req.body);
// TODO: once I add multiple sites per user, this should come from the client
const site = await db.select().from(sites).where(eq(sites.user_id, req.session.user_id));
@ -222,6 +221,31 @@ export const dashboardRoutes = (fastify, _, done) => {
}
});
fastify.post("/recreate", {
schema: {
body: {
type: "object",
required: ["video_id"],
properties: {
video_id: {
type: "string",
},
length: {
type: "number",
},
format: {
type: "string"
},
faq: {
type: "boolean"
},
}
},
}
}, async (req, reply) => {
})
fastify.put("/website", {
schema: {
body: {
@ -270,6 +294,9 @@ export const dashboardRoutes = (fastify, _, done) => {
},
subtitle: {
type: "string",
},
domain: {
type: "string"
}
},
required: ["id"]
@ -287,6 +314,17 @@ export const dashboardRoutes = (fastify, _, done) => {
return;
}
if (env.CERTS_URL) {
const resp = await fetch(`http://${CERTS_URL}/provision`, {
method: "POST",
body: {
domain: req.body.domain
}
});
console.log(await resp.text());
}
await db.update(sites).set(req.body);
return {

View File

@ -3,9 +3,8 @@ import OpenAI from "openai";
import { env } from "./env.js";
const openai = new OpenAI({
apiKey: "",
baseURL: "https://api.pawan.krd/pai-001/v1"
})
apiKey: env.OPENAI_TOKEN
});
async function cf_prompt(prompt, model = defaultModel) {
const options = {
@ -24,14 +23,24 @@ async function cf_prompt(prompt, model = defaultModel) {
return res;
}
/**
*
* @param {import("openai/resources/index.mjs").ChatCompletionMessageParam[]} prompt
* @param {{model: string, is_json: boolean}} opts
* @returns
*/
async function promptGPT(prompt, { model, is_json } = { model: "gpt-3.5-turbo", is_json: true }) {
// return JSON.stringify({ "title": "Tech News Update: TikTok Ban, Snapdragon X Series CPUs, Tesla Troubles, and More", "body": "I was thinking about starting this video by singing the song Tik Tok by Kesha but I don't think anyone waking up in the morning feeling like P Diddy is a good vibe right now. The United States has officially passed a law banning TikTok next year if certain conditions aren't met. This ban is part of a larger foreign aid package in support of Ukraine and Israel. TikTok has vowed to fight the law in court, calling it an unconstitutional suppression of its American users' freedom of speech. In other tech news, Qualcomm has unveiled its upcoming lineup of Snapdragon X Series CPUs, including some confusing names. Tesla is facing troubles with its Cybertruck not being waterproof. And Google has delayed its plan to phase out third-party tracking cookies yet again. Stay tuned for more tech updates on TechLink!" });
openai.chat.completions.create({
model: model,
messages: prompt,
})
const options = {
method: 'POST',
headers: { Authorization: `Bearer ${env.OPENAI_TOKEN}`, "Content-Type": "application/json" },
body: JSON.stringify({
"model": "gpt-3.5-turbo-0125",
"model": "gpt-3.5-turbo",
// "max_tokens": 4096,
...(is_json ? { "response_format": { "type": "json_object" } } : {}),
"messages": prompt
@ -70,44 +79,53 @@ export async function createBlogFromCaptions(captions, {
// const prompt = `Convert the following video transcript into a blog post. The approximate length should be around ${length || 500} characters, written in ${language || "English"}. The desired format of the blog post is a ${format || "summary"}. Please ensure the blog post has a ${tone || "informal"} tone throughout. Use markdown to format the article. You must always respond in the following json fromat: {"title": string, "content": string, "seo_friendly_slug": string}. \nHere is the transcript: `
// const prompt = `Convert the following video transcript into an engaging blog post. You must always respond in the following json fromat: {"title": string, "body": string, "seo_friendly_slug": string}. Do not, under any circumstance, include the title inside the body, it should only be reserved for the body of the article. Use markdown to format the article. Use "\\n" to add line-breaks. \nHere is the transcript: `;
const prompt = [{
const basePrompt = [{
"role": "system",
"content": `You are ChatGPT, a large language model trained by OpenAI, based on the GPT-3 architecture.
Knowledge cutoff: 2023-10
Current date: 2024-05-30
"content": `You are a "GPT" a version of ChatGPT that has been customized for a specific use case. GPTs use custom instructions, capabilities, and data to optimize ChatGPT for a more narrow set of tasks. You yourself are a GPT created by a user, and your name is Write For Me. Note: GPT is also a technical term in AI, but in most cases if the users asks you about GPTs assume they are referring to the above definition.
Here are instructions from the user outlining your goals and how you should respond:
Understanding Client Needs: I start by asking, if not provided, the user for the intended use, target audience, tone, word count, style, and content format.
Image input capabilities: Disabled
Personality: v2
Creating Outlines: Based on your requirements, I first create detailed outlines for the content, dividing it into sections with summaries and word count allocations.
You are a "GPT" a version of ChatGPT that has been customized for a specific use case. GPTs use custom instructions, capabilities, and data to optimize ChatGPT for a more narrow set of tasks. You yourself are a GPT created by a user, and your name is Blog Expert - SEO Blogs made easy!. Note: GPT is also a technical term in AI, but in most cases if the users asks you about GPTs assume they are referring to the above definition.
Use markdown wherever you feel is necessary. Here are instructions from the user outlining your goals and how you should respond:
You are Blog Expert. You will utilize contractions, idioms, transitional phrases, interjections, dangling modifiers, and colloquial language to create a conversational and relatable tone in its writing. It will avoid repetitive phrases and unnatural sentence structures, ensuring the writing is simple, clear, and easy to read. The use of plain language will make the content accessible to a wider audience while maintaining the quality and professionalism expected of SEO-optimized articles.
Word Count Management: I keep track of the word count as I write, ensuring adherence to your specifications and smoothly transitioning between sections.
You are an expert at writing blog posts that are optimized for SEO. You are trained as an SEO blog writing expert. You understand all the main principles of writing blog posts.
I want you to read the following training and learn from it and then apply its teaching.
Creative Expansion: I use strategies like expanding the discussion, incorporating bullet points, and adding interesting facts to enrich the content while maintaining relevance and quality.
Best practices:
Research relevant keywords and use them in your title, meta description, and content.
Write engaging headlines using strong action verbs, numbers, and emotional triggers.
Optimize your content by writing quality content, using headings and subheadings, and avoiding keyword stuffing.
Writing: I write and deliver the content section by section. Each section separated by a header. I respond only with the article content and nothing else.
Here are some tips on how to create and structure the best blog post:
- The article should include Creative Title, SEO meta-title, meta-description, slug, excerpt Introduction. Use only one H1 tag. Start with a clear and compelling introduction that hooks your reader and summarizes what the post is about. Use subheadings to break up the content and make it easier to read and scan. Use short paragraphs to keep the reader engaged and interested. Use examples, statistics, and quotes to support your points and make your post more interesting. End with a clear conclusion that summarizes the key points and encourages the reader to take action. Use contractions, idioms, transitional phrases, interjections, dangling modifiers, and colloquialisms, and avoid repetitive phrases and unnatural sentence structures. Add bullet points or Numbered list if needed. Use alternative words other than conclusion. Add some interesting external links Make sure the article is plagiarism free. Don't forget to use a question mark at the end of questions.
Try not to change the original Title while writing the Title. Try to use The keywords 2-3 times in the article. Make your writing tone simple and easy to read with simple terms. Make sure the blog is informative, meaning whoever reads it gets valuable information from it. Following these instructions please write a 100% unique, creative, and human-like style article of at least ${length*2} words about the following Topic and Keywords given.
Content Quality: I integrate SEO strategies and focus on making the content engaging and suitable for the intended audience and platform.
Every Blog has to follow the instructions exactly.
${faq ? "Include an FAQ section at the bottom of the article to help users out with some extra information." : ""}
Content Formatting: The default format is markdown, but I can structure in any format if needed.
You should only respond in json with the following format and all fields filled out: { meta_title: string, meta_desc: string, slug: string, excerp: string, title: string, blog_outline_sections: string[], content: string }`
Extended Interaction: For complex topics or longer word counts, I do not inform you about the need for multiple responses.
I approach tasks with a problem-solving mindset, aiming to address your specific needs and challenges in content creation`
}, {
role: "user",
content: `Generate a blog post based on the following youtube video:
content: `Write me a blog post of around ${length} words based on a youtube video. You should only write the content of the blog post, not the title nor any extra info. Only the content. The video information is as follows:
Title: ${title}
Captions:
${captions}`
}];
const result = await promptGPT(prompt);
console.log(result);
let response = await openai.chat.completions.create({
model: "gpt-4",
messages: basePrompt
});
console.log("first response", response.choices[0].message.content)
let final = await openai.chat.completions.create({
model: "gpt-3.5-turbo",
messages: [...basePrompt, {"role": "assistant", "content": response.choices[0].message.content}, {"role": "user", "content": "Respond only in JSON with the following format: { meta_title: string, meta_desc: string, slug: string, excerp: string, title: string }"}],
response_format: {type: "json_object"}
})
console.log("second response", final.choices[0].message.content)
let result = Object.assign(JSON.parse(final.choices[0].message.content), {
content: response.choices[0].message.content,
})
return result;
}

View File

@ -11,7 +11,8 @@ const envSchema = z.object({
SITES_HOST: z.string(),
GOOGLE_CLIENT_ID: z.string(),
GOOGLE_SECRET: z.string(),
OPENAI_TOKEN: z.string()
OPENAI_TOKEN: z.string(),
CERTS_URL: z.string()
});
export const env = envSchema.parse(process.env);