Skip to content

Commit

Permalink
Update version 1.2.1
Browse files Browse the repository at this point in the history
Co-authored-by: Yunmo Koo <[email protected]>
Co-authored-by: Taebum Kim <[email protected]>
Co-authored-by: Jiwoong Kwon <[email protected]>
  • Loading branch information
3 people committed Feb 14, 2024
1 parent fd8da7d commit 5899205
Show file tree
Hide file tree
Showing 26 changed files with 546 additions and 304 deletions.
23 changes: 19 additions & 4 deletions friendli/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import friendli
from friendli.di.injector import get_injector
from friendli.errors import APIError, AuthorizationError, AuthTokenNotFoundError
from friendli.logging import logger
from friendli.utils.fs import get_friendli_directory
from friendli.utils.request import DEFAULT_REQ_TIMEOUT, decode_http_err
from friendli.utils.url import URLProvider
Expand Down Expand Up @@ -52,16 +53,30 @@ def get_auth_header(
"""
token_: Optional[str]

token_from_cfg = get_token(TokenType.ACCESS)
token_from_env = friendli.token

if token is not None:
token_ = token
elif friendli.token:
token_ = friendli.token
elif token_from_env:
if token_from_cfg:
logger.warning(
"You've entered your login information in two places - through the "
"'FRIENDLI_TOKEN' environment variable and the 'friendli login' CLI "
"command. We will use the access token from the 'FRIENDLI_TOKEN' "
"environment variable and ignore the login session details. This might "
"lead to unexpected authorization errors. If you prefer to use the "
"login session instead, unset the 'FRIENDLI_TOKEN' environment "
"variable. If you don't want to see this warning again, run "
"'friendli logout' to remove the login session."
)
token_ = token_from_env
else:
token_ = get_token(TokenType.ACCESS)
token_ = token_from_cfg

if token_ is None:
raise AuthTokenNotFoundError(
"Should set FRIENDLI_TOKEN environment variable or sign in with 'friendli login'."
"Should set 'FRIENDLI_TOKEN' environment variable or sign in with 'friendli login'."
)

headers = {"Authorization": f"Bearer {token_}"}
Expand Down
12 changes: 12 additions & 0 deletions friendli/cli/api/chat_completions.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ def create(
min=1,
help="The maximum number of tokens to generate.",
),
stop: Optional[List[str]] = typer.Option(
None,
"--stop",
"-S",
help=(
"When one of the stop phrases appears in the generation result, the API "
"will stop generation. The stop phrases are excluded from the result. "
"Repeat this option to use multiple stop phrases."
),
),
temperature: Optional[float] = typer.Option(
None,
"--temperature",
Expand Down Expand Up @@ -120,6 +130,7 @@ def create(
presence_penalty=presence_penalty,
max_tokens=max_tokens,
n=n,
stop=stop,
temperature=temperature,
top_p=top_p,
)
Expand All @@ -137,6 +148,7 @@ def create(
presence_penalty=presence_penalty,
max_tokens=max_tokens,
n=n,
stop=stop,
temperature=temperature,
top_p=top_p,
)
Expand Down
14 changes: 13 additions & 1 deletion friendli/cli/api/completions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

from __future__ import annotations

from typing import Optional
from typing import List, Optional

import typer

Expand Down Expand Up @@ -53,6 +53,16 @@ def create(
min=1,
help="The maximum number of tokens to generate.",
),
stop: Optional[List[str]] = typer.Option(
None,
"--stop",
"-S",
help=(
"When one of the stop phrases appears in the generation result, the API "
"will stop generation. The stop phrases are excluded from the result. "
"Repeat this option to use multiple stop phrases."
),
),
temperature: Optional[float] = typer.Option(
None,
"--temperature",
Expand Down Expand Up @@ -113,6 +123,7 @@ def create(
presence_penalty=presence_penalty,
max_tokens=max_tokens,
n=n,
stop=stop,
temperature=temperature,
top_p=top_p,
)
Expand All @@ -130,6 +141,7 @@ def create(
presence_penalty=presence_penalty,
max_tokens=max_tokens,
n=n,
stop=stop,
temperature=temperature,
top_p=top_p,
)
Expand Down
127 changes: 127 additions & 0 deletions friendli/cli/login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Copyright (c) 2024-present, FriendliAI Inc. All rights reserved.

"""CLI command to sign in Friendli."""

from __future__ import annotations

import threading
import time
import webbrowser
from contextlib import contextmanager
from typing import Iterator, Tuple

import typer
import uvicorn
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import HTMLResponse

from friendli.client.login import LoginClient
from friendli.di.injector import get_injector
from friendli.utils.url import URLProvider

server_app = FastAPI()


@contextmanager
def run_server(port: int) -> Iterator[None]:
"""Run temporary local server to handle SSO redirection."""
config = uvicorn.Config(
app=server_app, host="127.0.0.1", port=port, log_level="error"
)
server = uvicorn.Server(config)
thread = threading.Thread(target=server.run)
thread.start()
try:
yield
finally:
server.should_exit = True
thread.join()


def oauth2_login() -> Tuple[str, str]:
"""Login with SSO."""
injector = get_injector()
url_provider = injector.get(URLProvider)
authorization_url = url_provider.get_suite_uri("/login/cli")

access_token = None
refresh_token = None

@server_app.get("/sso")
async def callback(request: Request) -> HTMLResponse:
nonlocal access_token
nonlocal refresh_token

access_token = request.query_params.get("access_token")
refresh_token = request.query_params.get("refresh_token")

if not access_token:
raise HTTPException(
status_code=400, detail="Access token not found in cookies"
)

success_page = r"""
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SSO Login Success</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
}
.message-box {
text-align: center;
padding: 40px;
border: 1px solid #d0d0d0;
background-color: #ffffff;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
</style>
</head>
<body>
<div class="message-box">
<h1>Authentication was successful</h1>
<p>You can now close this window and return to CLI.</p>
<p>Redirecting to <a href="https://docs.periflow.ai/">Friendli Documentation</a> in <span id="countdown">10</span> seconds.</p>
</div>
<script>
var timeLeft = 10;
var countdownElement = document.getElementById("countdown");
var timerId = setInterval(function() {
timeLeft--;
countdownElement.innerHTML = timeLeft;
if (timeLeft <= 0) {
clearInterval(timerId);
window.location.href = "https://docs.periflow.ai/";
}
}, 1000);
</script>
</body>
</html>
"""
return HTMLResponse(content=success_page, status_code=200)

typer.secho(
f"Opening browser for authentication: {authorization_url}", fg=typer.colors.BLUE
)

webbrowser.open(authorization_url)

with run_server(33333):
while access_token is None or refresh_token is None:
time.sleep(1)

return access_token, refresh_token


def pwd_login(email: str, pwd: str) -> Tuple[str, str]:
"""Login with email and password."""
client = LoginClient()
return client.login(email, pwd)
Loading

0 comments on commit 5899205

Please sign in to comment.