diff --git a/ai-server/backend/ai/embedding.py b/ai-server/backend/ai/embedding.py new file mode 100644 index 0000000..4f1a98a --- /dev/null +++ b/ai-server/backend/ai/embedding.py @@ -0,0 +1,9 @@ +from langchain_ibm import WatsonxEmbeddings +from backend.config.settings import settings + +watson_embedding = WatsonxEmbeddings( + model_id="ibm/granite-embedding-278m-multilingual", + url=f"{settings.watsonx_url}", + api_key=f"{settings.watsonx_api_key}", + project_id=f"{settings.watsonx_project_id}", +) \ No newline at end of file diff --git a/ai-server/backend/ai/llm.py b/ai-server/backend/ai/llm.py new file mode 100644 index 0000000..5f52f60 --- /dev/null +++ b/ai-server/backend/ai/llm.py @@ -0,0 +1,17 @@ +from langchain_ibm import ChatWatsonx +from backend.config.settings import settings +from langchain_openai import ChatOpenAI + +watson_llm = ChatWatsonx( + model_id="ibm/granite-4-h-small", + url=f"{settings.watsonx_url}", + api_key=f"{settings.watsonx_api_key}", + project_id=f"{settings.watsonx_project_id}", + max_tokens=2000, +) + +hugging_llm = ChatOpenAI( + base_url="https://router.huggingface.co/v1", + api_key=f"{settings.hf_token}", + model_name="Qwen/Qwen3-8B:nscale", +) \ No newline at end of file diff --git a/ai-server/backend/config/settings.py b/ai-server/backend/config/settings.py new file mode 100644 index 0000000..e96a0ef --- /dev/null +++ b/ai-server/backend/config/settings.py @@ -0,0 +1,13 @@ +from pydantic import Field +from pydantic_settings import BaseSettings, SettingsConfigDict + +class Settings(BaseSettings): + model_config = SettingsConfigDict(env_file="backend/.env", extra="ignore") + # 사용할 모델 + watsonx_api_key: str = Field(alias="WATSONX_API_KEY") + watsonx_project_id: str = Field(alias="WATSONX_PROJECT_ID") + watsonx_url: str = Field(alias="WATSONX_URL") + hf_token: str = Field(alias="HF_TOKEN") + serper_api_key: str = Field(alias="SERPER_API_KEY") + +settings = Settings() \ No newline at end of file diff --git a/ai-server/backend/graph/graph.py b/ai-server/backend/graph/graph.py new file mode 100644 index 0000000..e69de29 diff --git a/ai-server/backend/main.py b/ai-server/backend/main.py new file mode 100644 index 0000000..35a9c93 --- /dev/null +++ b/ai-server/backend/main.py @@ -0,0 +1,44 @@ +from fastapi import FastAPI +from starlette.staticfiles import StaticFiles +from contextlib import asynccontextmanager + +from backend.routers.stock_router import router as stock_router + +from backend.repository.db_init import Base, SessionLocal, engine + +# from backend.routers.evalu_router import router as evalu_router +# from backend.routers.assistant_router import router as assistant_router +# from backend.routers.call_router import router as call_router +# from backend.repository.seed import seed_customers + +@asynccontextmanager +async def lifespan(app: FastAPI): + print("서버 시작") + + # Base 에 등록된 모든 모델에 테이블 자동 생성 + Base.metadata.create_all(bind=engine) + print("[DB] 테이블 생성 완료 (또는 이미 존재)") + + yield + print("서버 종료") + +# app = FastAPI() +# app = FastAPI(title="상담 LLM", version="1.0", lifespan=lifespan) +app = FastAPI(title="$ Stock AI", version="1.0", lifespan=lifespan, description=""" + #### $주식 AI 분석 FastAPI + LangGraph + yfinance + ChromaDB + + ### 주요 기능 + | 번호 | 기능 | 엔드포인트 | + | --- | --- | --- | + |1 | 기업 종합 분석 | 'POST /api/stock/analysis' + |2 | 투자 의견 조회 | 'GET /api/stock/opinion/{analysis_id}' + """, +) + +# static 폴더 지정 +# app.mount("/static", StaticFiles(directory="backend/static"), name="static") + +# 라우터 등록 +app.include_router(stock_router) +# app.include_router(assistant_router) +# app.include_router(evalu_router) \ No newline at end of file diff --git a/ai-server/backend/prompts/prompt.py b/ai-server/backend/prompts/prompt.py new file mode 100644 index 0000000..e69de29 diff --git a/ai-server/backend/repository/db_init.py b/ai-server/backend/repository/db_init.py new file mode 100644 index 0000000..b0bcbee --- /dev/null +++ b/ai-server/backend/repository/db_init.py @@ -0,0 +1,23 @@ +from sqlalchemy import create_engine +from sqlalchemy.orm import DeclarativeBase, sessionmaker +from pathlib import Path + +Path("db").mkdir(parents=True, exist_ok=True) + +# echo sql 구문 출력시키는 +engine = create_engine('sqlite:///db/ai.db', echo=True) + +# 세션 팩토리 생성 +SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False) + +# Base = declarative_Base() +class Base(DeclarativeBase): + pass + +# session 을 다른 모듈에서 사용할 수 있도록 제공 +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() \ No newline at end of file diff --git a/ai-server/backend/routers/router.py b/ai-server/backend/routers/router.py new file mode 100644 index 0000000..e69de29 diff --git a/ai-server/backend/schemas/schema.py b/ai-server/backend/schemas/schema.py new file mode 100644 index 0000000..e69de29 diff --git a/ai-server/backend/services/service.py b/ai-server/backend/services/service.py new file mode 100644 index 0000000..e69de29