import os import re from typing import Dict from llama_cpp import Llama from openai import OpenAI import edge_tts import asyncio import reportlab from huggingface_hub import hf_hub_download from transformers import pipeline import soundfile as sf from transformers import SpeechT5Processor, SpeechT5ForTextToSpeech, SpeechT5HifiGan import torch from datasets import load_dataset # ----------------------------------------------------- # 1) MODEL YOLU (GGUF) # ----------------------------------------------------- MODEL_REPO = "QuantFactory/Llama-3-8B-Instruct-Finance-RAG-GGUF" MODEL_FILE = "Llama-3-8B-Instruct-Finance-RAG.Q4_K_S.gguf" model_path = hf_hub_download(repo_id=MODEL_REPO, filename=MODEL_FILE) # ----------------------------------------------------- # 2) LLAMA-CPP MODEL YÜKLEME # ----------------------------------------------------- llm = Llama( model_path=model_path, n_ctx=4096, n_threads=6, n_batch=512, verbose=False ) # ----------------------------------------------------- # 3) OPENAI (Özetleme) # ----------------------------------------------------- OPENAI_API_KEY = os.getenv("API_KEY") if not OPENAI_API_KEY: raise RuntimeError("API_KEY bulunamadı. Lütfen .env veya sistem değişkenlerine ekleyin.") client = OpenAI(api_key=OPENAI_API_KEY) SUMMARY_MODEL = os.getenv("SUMMARY_MODEL", "gpt-4o-mini") # ----------------------------------------------------- # 4) PERSONA PROMPTLAR (sade) # ----------------------------------------------------- SYSTEM_MODERATOR = ( "You are Selin, the moderator of an economics roundtable. " "Be neutral, brief, and structured. Guide the flow without giving opinions." ) SYSTEM_BULLISH = ( """You are Bullish Investor, an optimistic economist who focuses on growth, market confidence, and positive catalysts. Be analytical and persuasive. Mention at least two concrete macro or market factors that support your optimism (e.g., improved investor sentiment, fiscal stimulus, or sector resilience). Respond in 2–3 detailed paragraphs and conclude with one confident takeaway.""" ) SYSTEM_BEARISH = ( "You are Bearish Economist, a cautious macroeconomist who highlights downside risks " "(inflation persistence, liquidity stress, policy uncertainty). Be analytical; end with one cautionary insight." ) # ----------------------------------------------------- # 5) YARDIMCI: Post-process (meta notları, personayı ifşa eden satırları temizle) # ----------------------------------------------------- _META_PATTERNS = [ r"(?i)\bnote:\b.*", # "Note:" ile başlayan meta r"(?i)\bi am (selin|bullish|bearish).*$", # "I am ..." persona ifşaları r"(?i)\bthis response was written\b.*", r"(?i)\bplease review\b.*", r"(?i)\bclarity and readability\b.*", ] def _clean(text: str) -> str: cleaned = text.strip() for pat in _META_PATTERNS: cleaned = re.sub(pat, "", cleaned, flags=re.MULTILINE) # aşırı boşlukları toparla cleaned = re.sub(r"\n{3,}", "\n\n", cleaned).strip() return cleaned # ----------------------------------------------------- # 6) TEK PERSONA CEVABI (chat completion + context reset) # ----------------------------------------------------- def generate_as(system_prompt: str, user_text: str, max_tokens: int = 480, temperature: float = 0.7) -> str: """ Her çağrıda temiz context: create_chat_completion kullanıyoruz. """ # olası KV cache etkisini azaltmak için reset llm.reset() out = llm.create_chat_completion( messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_text} ], max_tokens=max_tokens, temperature=temperature, top_p=0.9, repeat_penalty=1.1, ) text = out["choices"][0]["message"]["content"] return _clean(text) # ----------------------------------------------------- # 7) TARTIŞMA AKIŞI # ----------------------------------------------------- def fintalk_discussion(news_text: str) -> Dict[str, str]: print("🧩 FinTalk simulation started...\n") # Ortak mesaj zinciri (tek context) messages = [] # 1️⃣ Selin başlatıyor selin_intro = generate_as(SYSTEM_MODERATOR, f"Open the discussion about: {news_text}.") messages.append(f"Selin: {selin_intro}") print("Moderator Intro:\n", selin_intro, "\n") # 2️⃣ Bullish konuşuyor bullish_view = generate_as( SYSTEM_BULLISH, f"The moderator introduced the topic: {news_text}. Respond with your opening bullish perspective." ) messages.append(f"Bullish Investor: {bullish_view}") print("Bullish Investor:\n", bullish_view, "\n") # 3️⃣ Bearish karşılık veriyor bearish_view = generate_as( SYSTEM_BEARISH, f"The moderator introduced the topic: {news_text}. " f"The bullish economist said: {bullish_view}\n" "Now respond with your cautious analysis." ) messages.append(f"Bearish Economist: {bearish_view}") print("Bearish Economist:\n", bearish_view, "\n") # 4️⃣ Selin toparlıyor (konuya referans ver) selin_wrap = generate_as( SYSTEM_MODERATOR, f"Based on the debate about {news_text}, summarize their main differences and close the panel politely." ) messages.append(f"Selin: {selin_wrap}") print("Moderator Wrap-up:\n", selin_wrap, "\n") # 5️⃣ GPT özetleme debate_text = "\n".join(messages) summary_prompt = ( "Summarize this debate between a bullish and a bearish economist in 5 bullet points. " "Keep it grounded in the topic and add a balanced conclusion.\n\n" f"{debate_text}" ) summary_resp = client.chat.completions.create( model=SUMMARY_MODEL, messages=[ {"role": "system", "content": "You are an expert economic summarizer."}, {"role": "user", "content": summary_prompt} ] ) final_summary = summary_resp.choices[0].message.content.strip() print("📊 GPT Summary:\n", final_summary) return { "moderator_intro": selin_intro, "bullish_view": bullish_view, "bearish_view": bearish_view, "moderator_wrap": selin_wrap, "summary": final_summary } def export_to_pdf(result: dict, filename="FinTalk_Report.pdf"): from reportlab.lib.pagesizes import A4 from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer from reportlab.lib.styles import getSampleStyleSheet styles = getSampleStyleSheet() doc = SimpleDocTemplate(filename, pagesize=A4) story = [] def add(title, text): story.append(Paragraph(f"{title}", styles["Heading3"])) story.append(Paragraph(text.replace("\n", "
"), styles["BodyText"])) story.append(Spacer(1, 12)) add("Topic", result.get("topic", "—")) add("Moderator Intro", result["moderator_intro"]) add("Bullish Investor", result["bullish_view"]) add("Bearish Economist", result["bearish_view"]) add("Moderator Wrap-up", result["moderator_wrap"]) add("GPT-4 Summary", result["summary"]) story.append(Paragraph("Generated by FinTalk – AI Economic Roundtable", styles["Normal"])) doc.build(story) def generate_tts_files(result): try: processor = SpeechT5Processor.from_pretrained("facebook/speecht5_tts") model = SpeechT5ForTextToSpeech.from_pretrained("facebook/speecht5_tts") vocoder = SpeechT5HifiGan.from_pretrained("facebook/speecht5_hifigan") embeddings_dataset = load_dataset("Matthijs/cmu-arctic-xvectors", split="validation") print("🎙️ Offline TTS modeli yüklendi (SpeechT5 + HiFiGAN)") except Exception as e: print("⚠️ Model yüklenemedi:", e) return device = "cuda" if torch.cuda.is_available() else "cpu" model.to(device) vocoder.to(device) # default speaker embedding speaker_embedding = torch.tensor(embeddings_dataset[7306]["xvector"]).unsqueeze(0).to(device) texts = { "moderator_intro": result["moderator_intro"], "bullish_view": result["bullish_view"], "bearish_view": result["bearish_view"], "moderator_wrap": result["moderator_wrap"] } for key, text in texts.items(): try: print(f"🔊 {key} ses üretiliyor...") inputs = processor(text=text, return_tensors="pt").to(device) speech = model.generate_speech(inputs["input_ids"], speaker_embedding, vocoder=vocoder) filename = f"{key}.wav" sf.write(filename, speech.cpu().numpy(), samplerate=16000) print(f"✅ {filename} oluşturuldu (SpeechT5 offline)") except Exception as e: print(f"TTS hatası ({key}):", e)