Spaces:
Sleeping
Sleeping
| import json | |
| import re | |
| import time | |
| from typing import List | |
| from dotenv import load_dotenv | |
| from langchain_openai import ChatOpenAI | |
| class VariationGenerator: | |
| def __init__( | |
| self, | |
| category: str = "finance", | |
| model: str = "gpt-4o-mini", | |
| temperature: float = 0.3, | |
| output_file: str = "financial_kb_output.json" | |
| ): | |
| self.category = category | |
| self.output_file = output_file | |
| self.llm = ChatOpenAI( | |
| model=model, | |
| temperature=temperature | |
| ) | |
| # ========================= | |
| # LOAD QUESTIONS FROM FILE | |
| # ========================= | |
| def load_questions(self, file_path: str) -> List[str]: | |
| with open(file_path, "r") as f: | |
| lines = [line.strip() for line in f if line.strip()] | |
| print(f"✅ Loaded {len(lines)} questions from {file_path}") | |
| return lines | |
| # ========================= | |
| # CLEAN QUESTION | |
| # ========================= | |
| def clean_question(self, question: str) -> str: | |
| question = question.strip() | |
| # remove extra spaces before ? | |
| question = re.sub(r"\s+\?", "?", question) | |
| # ensure first letter capitalized | |
| question = question[0].upper() + question[1:] | |
| if not question.endswith("?"): | |
| question += "?" | |
| return question | |
| # ========================= | |
| # KEYWORDS | |
| # ========================= | |
| def extract_keywords(self, question: str) -> List[str]: | |
| words = re.sub(r"[^\w\s]", "", question.lower()).split() | |
| stop_words = {"what", "is", "the", "a", "an", "how", "does", "do"} | |
| keywords = [w for w in words if w not in stop_words] | |
| return keywords[:5] | |
| # ========================= | |
| # VARIATIONS | |
| # ========================= | |
| def generate_variations(self, question: str) -> List[str]: | |
| base = question.replace("?", "").lower() | |
| variations = [ | |
| f"What is {base}?", | |
| f"Can you explain {base}?", | |
| f"How does {base} work?", | |
| f"What does {base} mean?", | |
| f"How do I understand {base}?", | |
| f"Can you give a simple explanation of {base}?" | |
| ] | |
| # Remove duplicates | |
| return list(set(variations)) | |
| # ========================= | |
| # LLM ANSWER | |
| # ========================= | |
| def generate_answer(self, question: str) -> str: | |
| prompt = f""" | |
| You are a financial expert. | |
| Answer the question clearly and concisely. | |
| Rules: | |
| - Max 3 sentences | |
| - Beginner friendly | |
| - No fluff | |
| - No repetition | |
| Question: | |
| {question} | |
| """ | |
| response = self.llm.invoke(prompt) | |
| return response.content.strip() | |
| # ========================= | |
| # BUILD RECORD | |
| # ========================= | |
| def build_record(self, question: str, record_id: int) -> dict: | |
| clean_q = self.clean_question(question) | |
| return { | |
| "id": record_id, | |
| "category": self.category, | |
| "question": clean_q, | |
| "answer": self.generate_answer(clean_q), | |
| "keywords": self.extract_keywords(clean_q), | |
| "variations": self.generate_variations(clean_q) | |
| } | |
| # ========================= | |
| # PROCESS ALL QUESTIONS | |
| # ========================= | |
| def process_file(self, input_file: str): | |
| questions = self.load_questions("kb_unique_questions.txt") | |
| records = [] | |
| for idx, q in enumerate(questions, start=1): | |
| try: | |
| record = self.build_record(q, idx) | |
| records.append(record) | |
| print(f"✅ Processed {idx}: {record['question']}") | |
| # Prevent rate limiting | |
| time.sleep(0.5) | |
| except Exception as e: | |
| print(f"❌ Failed at {idx}: {q} | Error: {e}") | |
| self.save_to_json(records) | |
| # ========================= | |
| # SAVE ALL RECORDS | |
| # ========================= | |
| def save_to_json(self, records: List[dict]): | |
| with open(self.output_file, "w") as f: | |
| json.dump(records, f, indent=2) | |
| print(f"💾 Saved {len(records)} records to {self.output_file}") | |
| if __name__ == "__main__": | |
| load_dotenv() | |
| generator = VariationGenerator() | |
| generator.process_file("kb_unique_questions.txt") |