zenaight commited on
Commit
debdd9b
·
1 Parent(s): 9496828

Add application file

Browse files
Files changed (5) hide show
  1. .DS_Store +0 -0
  2. Dockerfile +17 -0
  3. README.md +12 -11
  4. app/main.py +254 -0
  5. requirements.txt +12 -0
.DS_Store ADDED
Binary file (6.15 kB). View file
 
Dockerfile ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11.8-slim
2
+
3
+ # Set working directory
4
+ WORKDIR /app
5
+
6
+ # Install dependencies
7
+ COPY requirements.txt .
8
+ RUN pip install --no-cache-dir -r requirements.txt
9
+
10
+ # Copy the FastAPI app
11
+ COPY ./app /app
12
+
13
+ # Expose Hugging Face-required port
14
+ EXPOSE 7860
15
+
16
+ # Run the app
17
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -1,11 +1,12 @@
1
- ---
2
- title: Planify
3
- emoji: 🐠
4
- colorFrom: yellow
5
- colorTo: blue
6
- sdk: docker
7
- pinned: false
8
- license: unknown
9
- ---
10
-
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
1
+ ---
2
+ title: BP FastAPI
3
+ emoji: 📈
4
+ colorFrom: purple
5
+ colorTo: blue
6
+ sdk: docker
7
+ pinned: false
8
+ license: other
9
+ short_description: Fast API Business Plan Generator
10
+ ---
11
+
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app/main.py ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ##########################
2
+ #NEW TEST#
3
+ ##########################
4
+ import os
5
+ import asyncio
6
+ import logging
7
+ from typing import List, Dict, Any, Optional
8
+
9
+ from dotenv import load_dotenv
10
+ load_dotenv() # Load environment variables from .env into os.environ
11
+
12
+ from fastapi import FastAPI, HTTPException
13
+ from fastapi.middleware.cors import CORSMiddleware
14
+ from pydantic import BaseModel
15
+
16
+ # Import LangChain components
17
+ from langchain_community.chat_models import ChatOpenAI
18
+ from langchain.prompts import PromptTemplate
19
+ from langchain.chains import LLMChain
20
+
21
+ # Import the base LLM class to build our custom wrapper
22
+ from langchain.llms.base import LLM
23
+
24
+ from huggingface_hub import InferenceClient
25
+
26
+ # Set up logging
27
+ logging.basicConfig(level=logging.INFO)
28
+
29
+ # Create the FastAPI app
30
+ app = FastAPI()
31
+
32
+ # Allow all origins (adjust for production usage)
33
+ app.add_middleware(
34
+ CORSMiddleware,
35
+ allow_origins=["*"],
36
+ allow_credentials=True,
37
+ allow_methods=["*"],
38
+ allow_headers=["*"],
39
+ )
40
+
41
+ # Fixed list of business questions (order matters)
42
+ QUESTIONS = [
43
+ "What is your business name?",
44
+ "What product or service do you offer?",
45
+ "Who is your target customer?",
46
+ "What problem does your business solve?",
47
+ "Who are your competitors?",
48
+ "What is your unique value proposition?",
49
+ "What is your pricing strategy?",
50
+ "What are your short-term goals?",
51
+ "What are your long-term goals?",
52
+ "How will you acquire customers?",
53
+ ]
54
+
55
+ # Data model for incoming business plan generation requests
56
+ class GenerateRequest(BaseModel):
57
+ answers: List[str]
58
+ model: str
59
+
60
+ def generate_model_output(model: str, provider: str, api_key: str, prompt: str, max_tokens: int = 500) -> str:
61
+ """
62
+ A helper function that wraps the Hugging Face Inference API call.
63
+ """
64
+ client = InferenceClient(provider=provider, api_key=api_key)
65
+ completion = client.chat.completions.create(
66
+ model=model,
67
+ messages=[{"role": "user", "content": prompt}],
68
+ max_tokens=max_tokens,
69
+ )
70
+ return completion.choices[0].message.content
71
+
72
+ ###############################################################################
73
+ # HFInferenceLLM: A wrapper for Hugging Face models that matches the LLM interface.
74
+ ###############################################################################
75
+ class HFInferenceLLM(LLM):
76
+ model: str
77
+ provider: str
78
+ api_key: str
79
+ max_tokens: int
80
+
81
+ def __init__(self, model: str, provider: str = "hf-inference", api_key: str = "", max_tokens: int = 500):
82
+ self.model = model
83
+ self.provider = provider
84
+ self.api_key = api_key
85
+ self.max_tokens = max_tokens
86
+
87
+ @property
88
+ def _llm_type(self) -> str:
89
+ return "hf_inference"
90
+
91
+ def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:
92
+ """
93
+ Calls the Hugging Face API using the provided prompt.
94
+ The `stop` parameter is not implemented (or forwarded) here.
95
+ """
96
+ return generate_model_output(
97
+ model=self.model,
98
+ provider=self.provider,
99
+ api_key=self.api_key,
100
+ prompt=prompt,
101
+ max_tokens=self.max_tokens
102
+ )
103
+
104
+ def get_num_tokens(self, prompt: str) -> int:
105
+ """
106
+ A simple implementation that counts tokens as space-separated words.
107
+ You may replace this with a more accurate token counter.
108
+ """
109
+ return len(prompt.split())
110
+
111
+ ###############################################################################
112
+ # get_llm: Return an LLM instance based on the selected model.
113
+ ###############################################################################
114
+ def get_llm(model_name: str):
115
+ hf_token = os.getenv("HUGGINGFACEHUB_API_TOKEN")
116
+ if model_name == "GPT":
117
+ return ChatOpenAI(model_name="gpt-4o-mini-2024-07-18", temperature=0.7)
118
+ elif model_name == "Llama":
119
+ # Use the appropriate Llama model identifier.
120
+ return HFInferenceLLM(
121
+ model="huggyllama/llama-2", # <-- change this to your desired Llama model
122
+ provider="hf-inference",
123
+ api_key=hf_token,
124
+ max_tokens=500
125
+ )
126
+ elif model_name == "Qwen-2.5":
127
+ return HFInferenceLLM(
128
+ model="Qwen/Qwen2.5-72B-Instruct",
129
+ provider="hf-inference",
130
+ api_key=hf_token,
131
+ max_tokens=500
132
+ )
133
+ elif model_name == "Mistral":
134
+ return HFInferenceLLM(
135
+ model="mistralai/Mistral-7B-Instruct-v0.3",
136
+ provider="hf-inference",
137
+ api_key=hf_token,
138
+ max_tokens=500
139
+ )
140
+ else:
141
+ # Default to GPT if the provided model name is unrecognized.
142
+ return ChatOpenAI(model_name="gpt-4o-mini-2024-07-18", temperature=0.7)
143
+
144
+ ###############################################################################
145
+ # FastAPI Endpoints
146
+ ###############################################################################
147
+
148
+ @app.get("/suggestions", response_model=List[Dict[str, Any]])
149
+ async def get_suggestions() -> List[Dict[str, Any]]:
150
+ """
151
+ For each fixed business question, generate three concise bullet-point suggestions.
152
+ This endpoint uses gpt-4o-mini-2024-07-18 via LangChain.
153
+ """
154
+ suggestions_list = []
155
+
156
+ suggestion_template_str = (
157
+ "For the following business question, provide exactly 3 concise bullet-point suggestions or name suggestions if it fits the question. "
158
+ "Do not include any extra text.\n\nQuestion: \"{question}\"\n\nSuggestions:\n-"
159
+ )
160
+ suggestion_prompt = PromptTemplate(
161
+ input_variables=["question"],
162
+ template=suggestion_template_str
163
+ )
164
+
165
+ # Use ChatOpenAI (gpt-4o-mini-2024-07-18) to generate suggestions.
166
+ suggestion_chain = LLMChain(
167
+ llm=ChatOpenAI(model_name="gpt-4o-mini-2024-07-18", temperature=0.7),
168
+ prompt=suggestion_prompt
169
+ )
170
+
171
+ for question in QUESTIONS:
172
+ try:
173
+ raw_text = await asyncio.to_thread(suggestion_chain.run, {"question": question})
174
+ except Exception as e:
175
+ raise HTTPException(status_code=500, detail=str(e))
176
+ suggestion_array = [
177
+ line.replace("-", "").strip() for line in raw_text.split("\n") if line.strip()
178
+ ]
179
+ suggestions_list.append({"question": question, "suggestions": suggestion_array})
180
+
181
+ return suggestions_list
182
+
183
+ @app.post("/generate")
184
+ async def generate_business_plan(data: GenerateRequest):
185
+ """
186
+ Combine the questionnaire answers with their corresponding questions,
187
+ build a detailed Markdown prompt, and generate a full business plan using
188
+ the selected model.
189
+ """
190
+ if len(data.answers) != len(QUESTIONS):
191
+ raise HTTPException(status_code=400, detail="Expected exactly 10 answers.")
192
+
193
+ q_and_a = "\n".join(
194
+ [f"{idx+1}. {question}: {data.answers[idx]}" for idx, question in enumerate(QUESTIONS)]
195
+ )
196
+
197
+ plan_template_str = (
198
+ "Based on the following responses to business questions:\n"
199
+ "{q_and_a}\n\n"
200
+ "Generate a detailed business plan in Markdown format. Your response must include exactly the following sections and subheadings using proper Markdown syntax:\n\n"
201
+ "## Executive Summary\n"
202
+ "Provide a brief summary of the business, its purpose, and key objectives.\n\n"
203
+ "## Market Analysis\n"
204
+ "### Industry Overview\n"
205
+ "Describe the overall industry trends and market dynamics.\n\n"
206
+ "### Target Market\n"
207
+ "Define the primary target audience, including demographics and psychographics.\n\n"
208
+ "### Competitive Analysis\n"
209
+ "Analyze the competitive landscape and explain what differentiates the business from competitors.\n\n"
210
+ "## Operations Plan\n"
211
+ "### Location\n"
212
+ "Specify the business location(s) and rationale for the choice.\n\n"
213
+ "### Distribution\n"
214
+ "Explain the distribution channels and logistics plan for delivering the product or service.\n\n"
215
+ "### Staffing\n"
216
+ "Outline the staffing requirements and key roles necessary for operations.\n\n"
217
+ "## Financial Plan\n"
218
+ "### Revenue Streams\n"
219
+ "Identify the primary and secondary sources of revenue.\n\n"
220
+ "### Cost Structure\n"
221
+ "Detail the major cost components and how costs will be managed.\n\n"
222
+ "### Funding Requirements\n"
223
+ "Specify the funding needed to launch and sustain the business.\n\n"
224
+ "### Profitability\n"
225
+ "Outline the financial projections and timeline to profitability.\n\n"
226
+ "## Conclusion\n"
227
+ "Summarize the vision, key takeaways, and future direction of the business.\n\n"
228
+ "Follow this template exactly, and be concise."
229
+ )
230
+
231
+ plan_prompt = PromptTemplate(
232
+ input_variables=["q_and_a"],
233
+ template=plan_template_str
234
+ )
235
+
236
+ # Get the LLM instance based on the selected model.
237
+ llm_selected = get_llm(data.model)
238
+ plan_chain = LLMChain(llm=llm_selected, prompt=plan_prompt)
239
+
240
+ logging.info("Generated prompt for business plan:\n" + plan_template_str.format(q_and_a=q_and_a))
241
+
242
+ try:
243
+ full_plan = await asyncio.to_thread(plan_chain.run, {"q_and_a": q_and_a})
244
+ except Exception as e:
245
+ raise HTTPException(status_code=500, detail=str(e))
246
+
247
+ return {
248
+ "summary": "Generated Business Plan",
249
+ "plan": full_plan,
250
+ }
251
+
252
+ @app.get("/")
253
+ def root():
254
+ return {"status": "FastAPI is running 🚀"}
requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ httpx
4
+ langchain[community]
5
+ langgraph
6
+ openai
7
+ pydantic
8
+ loguru
9
+ python-dotenv
10
+ huggingface_hub
11
+ langchain-community>=0.2.0
12
+