|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from urllib.parse import urlparse, parse_qs |
|
import gradio as gr |
|
import requests |
|
from bs4 import BeautifulSoup |
|
import openai |
|
from openai import OpenAI |
|
import speech_recognition as sr |
|
from transformers import pipeline |
|
|
|
from transformers.pipelines.audio_utils import ffmpeg_read |
|
|
|
from youtube_transcript_api import YouTubeTranscriptApi, TranscriptsDisabled |
|
from youtube_transcript_api.formatters import TextFormatter |
|
|
|
from urllib.parse import urlparse, parse_qs |
|
import json |
|
|
|
import os |
|
import yaml |
|
import pandas as pd |
|
import numpy as np |
|
|
|
from datetime import datetime, timedelta |
|
|
|
|
|
|
|
|
|
openai_api_key = os.environ["OPENAI_API_KEY"] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_youtube_url(url): |
|
try: |
|
|
|
parsed_url = urlparse(url) |
|
|
|
|
|
if parsed_url.netloc in ["www.youtube.com", "youtube.com", "m.youtube.com", "youtu.be"]: |
|
|
|
if "youtube.com" in parsed_url.netloc: |
|
return "v" in parse_qs(parsed_url.query) |
|
|
|
elif "youtu.be" in parsed_url.netloc: |
|
return len(parsed_url.path.strip("/")) > 0 |
|
return False |
|
except Exception as e: |
|
return False |
|
|
|
def get_youtube_transcript(youtube_url): |
|
try: |
|
|
|
parsed_url = urlparse(youtube_url) |
|
video_id = parse_qs(parsed_url.query).get("v") |
|
|
|
if not video_id: |
|
return "Invalid YouTube URL. Please provide a valid URL." |
|
|
|
video_id = video_id[0] |
|
|
|
|
|
transcript = YouTubeTranscriptApi.get_transcript(video_id, proxies={"https": "http://localhost:8080"}) |
|
|
|
|
|
formatter = TextFormatter() |
|
formatted_transcript = formatter.format_transcript(transcript) |
|
|
|
return formatted_transcript |
|
|
|
except Exception as e: |
|
return f"An error occurred: {str(e)}" |
|
|
|
|
|
|
|
|
|
|
|
def check_subtitles(video_id): |
|
try: |
|
transcripts = YouTubeTranscriptApi.list_transcripts(video_id) |
|
print(f"Available transcripts: {transcripts}") |
|
return True |
|
except TranscriptsDisabled: |
|
print("Subtitles are disabled for this video.") |
|
return False |
|
except Exception as e: |
|
print(f"An unexpected error occurred: {e}") |
|
return False |
|
|
|
|
|
video_id = "Um017R5Kr3A" |
|
check_subtitles(video_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
client = OpenAI(api_key=openai_api_key) |
|
|
|
|
|
|
|
|
|
def process_webpage(url): |
|
try: |
|
if is_youtube_url(url): |
|
rendered_content = get_youtube_transcript(url) |
|
else: |
|
|
|
response = requests.get(url) |
|
soup = BeautifulSoup(response.text, "html.parser") |
|
html_content = str(soup.prettify()) |
|
|
|
for script in soup(["script", "style"]): |
|
script.decompose() |
|
rendered_content = soup.get_text(separator="\n").strip().replace("\n\n", "") |
|
|
|
text_content = rendered_content[:2000] |
|
|
|
|
|
summary_prompt = f"Summarize the following content:\n{text_content}\n Please use the language of the originial content" |
|
perspectives_prompt = f"Generate a reflective review for the following content:\n{text_content}\n Please output the perspectives in no more than 5 very concise bullet points. Please use the language of the originial content" |
|
|
|
summary_response = client.chat.completions.create( |
|
model="gpt-4o", |
|
messages=[{"role": "user", "content": summary_prompt}], |
|
max_tokens=500, |
|
) |
|
perspectives_response = client.chat.completions.create( |
|
model="gpt-4o", |
|
messages=[{"role": "user", "content": perspectives_prompt}], |
|
max_tokens=500, |
|
) |
|
|
|
summary = summary_response.choices[0].message.content.strip() |
|
perspectives = perspectives_response.choices[0].message.content.strip() |
|
|
|
return rendered_content, summary, perspectives |
|
except Exception as e: |
|
return f"Error fetching or processing content: {str(e)}", "", "" |
|
|
|
|
|
|
|
|
|
|
|
|
|
def chat_with_ai(chat_history, user_input, content): |
|
try: |
|
messages = [{"role": "system", "content": "You are a helpful assistant."}] |
|
|
|
|
|
for user, bot in chat_history: |
|
messages.append({"role": "user", "content": user}) |
|
messages.append({"role": "assistant", "content": bot}) |
|
|
|
|
|
messages.append({"role": "user", "content": f"Based on this content: {content}\n\n{user_input}"}) |
|
|
|
|
|
ai_response = client.chat.completions.create( |
|
model="gpt-4o", |
|
messages=messages, |
|
max_tokens=300, |
|
) |
|
reply = ai_response.choices[0].message.content.strip() |
|
chat_history.append((user_input, reply)) |
|
return chat_history |
|
except Exception as e: |
|
return chat_history + [(user_input, f"Error: {str(e)}")] |
|
|
|
|
|
|
|
|
|
|
|
def generate_reflection(chat_history): |
|
""" |
|
Generate a reflection based on the chat history. |
|
|
|
Args: |
|
chat_history (list of tuples): List of (user_input, ai_reply) pairs. |
|
|
|
Returns: |
|
str: A reflective summary generated by AI. |
|
""" |
|
try: |
|
messages = [{"role": "system", "content": "You are a professional content summarizer. Generate thoughtful reflections."}] |
|
|
|
|
|
for user, bot in chat_history: |
|
messages.append({"role": "user", "content": user}) |
|
messages.append({"role": "assistant", "content": bot}) |
|
|
|
|
|
messages.append({"role": "user", "content": "Please provide a concise, reflective summary of this conversation."}) |
|
|
|
|
|
ai_response = client.chat.completions.create( |
|
model="gpt-4o", |
|
messages=messages, |
|
max_tokens=200, |
|
) |
|
reflection = ai_response.choices[0].message.content.strip() |
|
return reflection |
|
except Exception as e: |
|
return f"Error generating reflection: {str(e)}" |
|
|
|
|
|
|
|
|
|
|
|
import requests |
|
|
|
def post_to_linkedin(access_token, reflection, visibility="PUBLIC"): |
|
""" |
|
Post a reflection to LinkedIn. |
|
|
|
Args: |
|
access_token (str): LinkedIn API access token. |
|
reflection (str): The content to post. |
|
visibility (str): Visibility setting ("PUBLIC" or "CONNECTIONS"). Defaults to "PUBLIC". |
|
|
|
Returns: |
|
str: Confirmation or error message. |
|
""" |
|
try: |
|
url = "https://api.linkedin.com/v2/ugcPosts" |
|
headers = { |
|
"Authorization": f"Bearer {access_token}", |
|
"Content-Type": "application/json", |
|
} |
|
your_linkedin_person_id = 'jay' |
|
payload = { |
|
"author": f"urn:li:person:{your_linkedin_person_id}", |
|
"lifecycleState": "PUBLISHED", |
|
"visibility": {"com.linkedin.ugc.MemberNetworkVisibility": visibility}, |
|
"specificContent": { |
|
"com.linkedin.ugc.ShareContent": { |
|
"shareCommentary": { |
|
"text": reflection |
|
}, |
|
"shareMediaCategory": "NONE" |
|
} |
|
} |
|
} |
|
|
|
response = requests.post(url, headers=headers, json=payload) |
|
if response.status_code == 201: |
|
return "Reflection successfully posted to LinkedIn!" |
|
else: |
|
return f"Failed to post to LinkedIn. Error: {response.json()}" |
|
except Exception as e: |
|
return f"Error posting to LinkedIn: {str(e)}" |
|
|
|
|
|
copy_to_clipboard_js = """ |
|
function copyToClipboard(text) { |
|
navigator.clipboard.writeText(text).then(() => { |
|
alert("Text copied to clipboard!"); |
|
}).catch(err => { |
|
alert("Failed to copy text: " + err); |
|
}); |
|
} |
|
""" |
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown("## Curify Digest: Consume and interact with content") |
|
|
|
with gr.Row(): |
|
|
|
with gr.Column(): |
|
gr.Markdown("## Render Webpage") |
|
url_input = gr.Textbox(label="Enter URL") |
|
|
|
fetch_btn = gr.Button("Fetch and Process Webpage") |
|
text_output = gr.Textbox(label="Webpage Content", lines=7) |
|
summary_output = gr.Textbox(label="Summary", lines=5) |
|
perspectives_output = gr.Textbox(label="Perspectives", lines=5) |
|
|
|
|
|
with gr.Column(): |
|
gr.Markdown("## Interactive Chatbot") |
|
chatbot_history_gr = gr.Chatbot(label="Chat History") |
|
user_input = gr.Textbox(label="Ask a Question", placeholder="Type your question here...") |
|
chatbot_btn = gr.Button("Chat") |
|
|
|
|
|
with gr.Column(): |
|
reflection_btn = gr.Button("Generate reflection") |
|
reflection_output = gr.Textbox(label="Reflections", lines=5) |
|
|
|
custom_js = """ |
|
<script> |
|
function copyToClipboard() { |
|
const textbox = document.querySelector("textarea[aria-label='Reflections']"); |
|
if (textbox) { |
|
navigator.clipboard.writeText(textbox.value).then(() => { |
|
alert("Text copied to clipboard!"); |
|
}).catch(err => { |
|
alert("Failed to copy text: " + err); |
|
}); |
|
} |
|
} |
|
</script> |
|
<button onclick="copyToClipboard()">Copy to clipboard</button> |
|
""" |
|
gr.HTML(custom_js) |
|
|
|
fetch_btn.click( |
|
process_webpage, |
|
inputs=url_input, |
|
outputs=[text_output, summary_output, perspectives_output], |
|
) |
|
|
|
chatbot_btn.click( |
|
chat_with_ai, |
|
inputs=[chatbot_history_gr, user_input, text_output], |
|
outputs=chatbot_history_gr, |
|
) |
|
|
|
reflection_btn.click( |
|
generate_reflection, |
|
inputs=chatbot_history_gr, |
|
outputs=reflection_output, |
|
) |
|
|
|
demo.launch(share=True) |
|
|
|
|
|
|