PraneshJs commited on
Commit
f1a0b85
·
verified ·
1 Parent(s): c4b61c9

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +131 -0
app.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os, requests, base64, tempfile, subprocess, shutil, fnmatch, json
2
+ import gradio as gr
3
+ from dotenv import load_dotenv
4
+ from urllib.parse import urlparse
5
+
6
+ load_dotenv()
7
+ OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
8
+
9
+ def clone_repo(repo_url):
10
+ tmp_dir = tempfile.mkdtemp()
11
+ subprocess.run(["git", "clone", "--depth", "1", repo_url, tmp_dir], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
12
+ return tmp_dir
13
+
14
+ def read_repo_files(repo_dir):
15
+ patterns = ["*.py", "*.js", "*.jsx", "*.ts", "*.tsx", "*.html", "*.json", "*.go", "*.java", "*.vue"]
16
+ repo_content = []
17
+ for root, _, files in os.walk(repo_dir):
18
+ for pattern in patterns:
19
+ for filename in fnmatch.filter(files, pattern):
20
+ filepath = os.path.join(root, filename)
21
+ try:
22
+ with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
23
+ content = f.read()
24
+ if len(content) > 2000:
25
+ content = content[:2000]
26
+ repo_content.append(f"{filename}:\n{content}")
27
+ except:
28
+ pass
29
+ return "\n\n".join(repo_content)
30
+
31
+ def build_structured_prompt(user_prompt, repo_data=None):
32
+ """
33
+ Constructs a rich, JSON-style system prompt for structured control.
34
+ """
35
+ system_instructions = {
36
+ "role": "LinkedIn AI Content Creator",
37
+ "goal": "Generate a viral, engaging, and insightful LinkedIn post about the project.",
38
+ "requirements": {
39
+ "tone": "Professional yet personal",
40
+ "style": "Storytelling, informative, slightly persuasive",
41
+ "length": "Long-form (150–300 words)",
42
+ "hashtags": "Add 5–10 trending tech-related hashtags automatically",
43
+ "extras": [
44
+ "Include a strong opening hook",
45
+ "End with a call to action (e.g., inviting engagement or collaboration)",
46
+ "Highlight innovation and personal growth even for small projects",
47
+ "Use emojis naturally to increase engagement"
48
+ ]
49
+ },
50
+ "output_format": "Return only the final LinkedIn post text. No explanations."
51
+ }
52
+
53
+ structured_prompt = {
54
+ "system_prompt": system_instructions,
55
+ "user_prompt": user_prompt,
56
+ "project_context": repo_data if repo_data else "User provided only a topic, no repository content."
57
+ }
58
+
59
+ # Convert to JSON for clarity and structure
60
+ return json.dumps(structured_prompt, indent=2)
61
+
62
+ def generate_post(topic, user_prompt):
63
+ if not topic:
64
+ return "⚠️ Please provide a topic or GitHub repo link."
65
+
66
+ repo_data = None
67
+ repo_dir = None
68
+
69
+ if topic.startswith("http") and "github.com" in topic:
70
+ try:
71
+ repo_dir = clone_repo(topic)
72
+ repo_data = read_repo_files(repo_dir)
73
+ except Exception as e:
74
+ return f"❌ Failed to fetch repo: {e}"
75
+ finally:
76
+ if repo_dir and os.path.exists(repo_dir):
77
+ shutil.rmtree(repo_dir, ignore_errors=True)
78
+
79
+ structured_prompt = build_structured_prompt(user_prompt, repo_data)
80
+
81
+ payload = {
82
+ "model": "deepseek/deepseek-chat-v3-0324:free",
83
+ "messages": [
84
+ {"role": "system", "content": "You are an expert social media strategist for AI and software projects."},
85
+ {"role": "user", "content": structured_prompt}
86
+ ]
87
+ }
88
+
89
+ try:
90
+ res = requests.post(
91
+ "https://openrouter.ai/api/v1/chat/completions",
92
+ headers={
93
+ "Authorization": f"Bearer {OPENROUTER_API_KEY}",
94
+ "Content-Type": "application/json"
95
+ },
96
+ json=payload,
97
+ timeout=180
98
+ )
99
+ res.raise_for_status()
100
+ return res.json()["choices"][0]["message"]["content"]
101
+ except Exception as e:
102
+ return f"❌ API Error: {e}"
103
+
104
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
105
+ gr.Markdown("""
106
+ ## 🚀 Advanced LinkedIn Post Generator
107
+ Create **viral, long-form LinkedIn posts** powered by **OpenRouter AI**.
108
+
109
+ 🧠 This AI automatically:
110
+ - Extracts meaningful info from GitHub repos
111
+ - Uses JSON-structured prompting for deep control
112
+ - Adds hashtags, hooks, and calls to action
113
+ """)
114
+
115
+ with gr.Row():
116
+ topic = gr.Textbox(label="Topic or GitHub Repo Link", placeholder="Enter project topic or GitHub repo URL...")
117
+
118
+ user_prompt = gr.Textbox(
119
+ label="Custom Prompt",
120
+ placeholder="Example: Write an inspiring post highlighting the innovation and teamwork behind this project...",
121
+ lines=10
122
+ )
123
+
124
+ generate_btn = gr.Button("✨ Generate LinkedIn Post")
125
+ output = gr.Textbox(label="Generated LinkedIn Post", lines=15)
126
+
127
+ generate_btn.click(fn=generate_post, inputs=[topic, user_prompt], outputs=output)
128
+
129
+ if __name__ == "__main__":
130
+ port = int(os.environ.get("PORT", 7860))
131
+ demo.launch(server_name="0.0.0.0", server_port=port, share=False, debug=True)