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)